Mercurial > hg > orthanc
comparison OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp @ 5729:bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Fri, 26 Jul 2024 16:29:10 +0200 |
parents | f7adfb22e20e |
children | 264d84c1936a |
comparison
equal
deleted
inserted
replaced
5727:843973a0fdfa | 5729:bdbaccc06e98 |
---|---|
22 **/ | 22 **/ |
23 | 23 |
24 | 24 |
25 #include "../PrecompiledHeaders.h" | 25 #include "../PrecompiledHeaders.h" |
26 #include "FilesystemStorage.h" | 26 #include "FilesystemStorage.h" |
27 #include <boost/thread.hpp> | |
27 | 28 |
28 // http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system | 29 // http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system |
29 // http://stackoverflow.com/questions/446358/storing-a-large-number-of-images | 30 // http://stackoverflow.com/questions/446358/storing-a-large-number-of-images |
30 | 31 |
31 #include "../Logging.h" | 32 #include "../Logging.h" |
133 | 134 |
134 if (boost::filesystem::exists(path)) | 135 if (boost::filesystem::exists(path)) |
135 { | 136 { |
136 // Extremely unlikely case: This Uuid has already been created | 137 // Extremely unlikely case: This Uuid has already been created |
137 // in the past. | 138 // in the past. |
138 throw OrthancException(ErrorCode_InternalError); | 139 throw OrthancException(ErrorCode_InternalError, "This file UUID already exists"); |
139 } | 140 } |
140 | 141 |
141 if (boost::filesystem::exists(path.parent_path())) | 142 // In very unlikely case (but we've seen it !), 2 threads might enter this same piece |
142 { | 143 // of code and both try to create the same directory or a thread could be deleting a |
143 if (!boost::filesystem::is_directory(path.parent_path())) | 144 // directory while another thread needs it -> introduce 3 retries at 1 ms interval |
144 { | 145 int retryCount = 0; |
145 throw OrthancException(ErrorCode_DirectoryOverFile); | 146 const int maxRetryCount = 3; |
146 } | 147 |
147 } | 148 while (retryCount < maxRetryCount) |
148 else | 149 { |
149 { | 150 retryCount++; |
150 if (!boost::filesystem::create_directories(path.parent_path())) | 151 if (retryCount > 1) |
151 { | 152 { |
152 throw OrthancException(ErrorCode_FileStorageCannotWrite); | 153 boost::this_thread::sleep(boost::posix_time::milliseconds(2 * retryCount + (rand() % 10))); |
153 } | 154 LOG(INFO) << "Retrying to create attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) |
154 } | 155 << "\" type"; |
155 | 156 } |
156 SystemToolbox::WriteFile(content, size, path.string(), fsyncOnWrite_); | 157 |
158 if (boost::filesystem::exists(path.parent_path())) | |
159 { | |
160 if (!boost::filesystem::is_directory(path.parent_path())) | |
161 { | |
162 throw OrthancException(ErrorCode_DirectoryOverFile); // no need to retry this error | |
163 } | |
164 } | |
165 else | |
166 { | |
167 if (!boost::filesystem::create_directories(path.parent_path())) | |
168 { | |
169 if (retryCount >= maxRetryCount) | |
170 { | |
171 throw OrthancException(ErrorCode_FileStorageCannotWrite); | |
172 } | |
173 | |
174 continue; // retry | |
175 } | |
176 } | |
177 | |
178 try | |
179 { | |
180 SystemToolbox::WriteFile(content, size, path.string(), fsyncOnWrite_); | |
181 } | |
182 catch (OrthancException& ex) | |
183 { | |
184 if (retryCount >= maxRetryCount) | |
185 { | |
186 throw ex; | |
187 } | |
188 } | |
189 } | |
190 | |
157 LOG(INFO) << "Created attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, size) << ")"; | 191 LOG(INFO) << "Created attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, size) << ")"; |
158 } | 192 } |
159 | 193 |
160 | 194 |
161 IMemoryBuffer* FilesystemStorage::Read(const std::string& uuid, | 195 IMemoryBuffer* FilesystemStorage::Read(const std::string& uuid, |