Mercurial > hg > orthanc
annotate 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 |
rev | line source |
---|---|
0 | 1 /** |
59 | 2 * Orthanc - A Lightweight, RESTful DICOM Store |
1900 | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
1288
6e7e5ed91c2d
upgrade to year 2015
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1250
diff
changeset
|
4 * Department, University Hospital of Liege, Belgium |
5640
f7adfb22e20e
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5485
diff
changeset
|
5 * Copyright (C) 2017-2023 Osimis S.A., Belgium |
f7adfb22e20e
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5485
diff
changeset
|
6 * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium |
5485
48b8dae6dc77
upgrade to year 2024
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5430
diff
changeset
|
7 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium |
0 | 8 * |
9 * This program is free software: you can redistribute it and/or | |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
10 * modify it under the terms of the GNU Lesser General Public License |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
11 * as published by the Free Software Foundation, either version 3 of |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
12 * the License, or (at your option) any later version. |
136 | 13 * |
0 | 14 * This program is distributed in the hope that it will be useful, but |
15 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
17 * Lesser General Public License for more details. |
0 | 18 * |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
19 * You should have received a copy of the GNU Lesser General Public |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
20 * License along with this program. If not, see |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
21 * <http://www.gnu.org/licenses/>. |
0 | 22 **/ |
23 | |
24 | |
824
a811bdf8b8eb
precompiled headers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
803
diff
changeset
|
25 #include "../PrecompiledHeaders.h" |
1123 | 26 #include "FilesystemStorage.h" |
5729
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
27 #include <boost/thread.hpp> |
0 | 28 |
29 // http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system | |
30 // http://stackoverflow.com/questions/446358/storing-a-large-number-of-images | |
31 | |
1486
f967bdf8534e
refactoring to Logging.h
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1397
diff
changeset
|
32 #include "../Logging.h" |
234 | 33 #include "../OrthancException.h" |
4484
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
34 #include "../StringMemoryBuffer.h" |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
35 #include "../SystemToolbox.h" |
234 | 36 #include "../Toolbox.h" |
0 | 37 |
38 #include <boost/filesystem/fstream.hpp> | |
1397 | 39 |
0 | 40 |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
41 static std::string ToString(const boost::filesystem::path& p) |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
42 { |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
43 #if BOOST_HAS_FILESYSTEM_V3 == 1 |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
44 return p.filename().string(); |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
45 #else |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
46 return p.filename(); |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
47 #endif |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
48 } |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
49 |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
50 |
59 | 51 namespace Orthanc |
0 | 52 { |
1123 | 53 boost::filesystem::path FilesystemStorage::GetPath(const std::string& uuid) const |
0 | 54 { |
55 namespace fs = boost::filesystem; | |
56 | |
57 if (!Toolbox::IsUuid(uuid)) | |
58 { | |
59 | 59 throw OrthancException(ErrorCode_ParameterOutOfRange); |
0 | 60 } |
61 | |
62 fs::path path = root_; | |
63 | |
64 path /= std::string(&uuid[0], &uuid[2]); | |
65 path /= std::string(&uuid[2], &uuid[4]); | |
66 path /= uuid; | |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
67 |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
68 #if BOOST_HAS_FILESYSTEM_V3 == 1 |
0 | 69 path.make_preferred(); |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
70 #endif |
0 | 71 |
72 return path; | |
73 } | |
74 | |
4185
b289a1234822
giving a try to cross-platform compilation of SyncStorageArea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4119
diff
changeset
|
75 void FilesystemStorage::Setup(const std::string& root) |
0 | 76 { |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
77 //root_ = boost::filesystem::absolute(root).string(); |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
78 root_ = root; |
0 | 79 |
2140 | 80 SystemToolbox::MakeDirectory(root); |
0 | 81 } |
82 | |
4300 | 83 FilesystemStorage::FilesystemStorage(const std::string &root) : |
84 fsyncOnWrite_(false) | |
85 { | |
86 Setup(root); | |
87 } | |
88 | |
89 FilesystemStorage::FilesystemStorage(const std::string &root, | |
90 bool fsyncOnWrite) : | |
91 fsyncOnWrite_(fsyncOnWrite) | |
92 { | |
93 Setup(root); | |
94 } | |
95 | |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
96 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
97 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
98 static const char* GetDescriptionInternal(FileContentType content) |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
99 { |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
100 // This function is for logging only (internal use), a more |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
101 // fully-featured version is available in ServerEnumerations.cpp |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
102 switch (content) |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
103 { |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
104 case FileContentType_Unknown: |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
105 return "Unknown"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
106 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
107 case FileContentType_Dicom: |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
108 return "DICOM"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
109 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
110 case FileContentType_DicomAsJson: |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
111 return "JSON summary of DICOM"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
112 |
4512
cff7fdfc83a4
added FileContentType_DicomUntilPixelData
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4495
diff
changeset
|
113 case FileContentType_DicomUntilPixelData: |
cff7fdfc83a4
added FileContentType_DicomUntilPixelData
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4495
diff
changeset
|
114 return "DICOM until pixel data"; |
cff7fdfc83a4
added FileContentType_DicomUntilPixelData
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4495
diff
changeset
|
115 |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
116 default: |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
117 return "User-defined"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
118 } |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
119 } |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
120 |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
121 |
1135
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
122 void FilesystemStorage::Create(const std::string& uuid, |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
123 const void* content, |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
124 size_t size, |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
125 FileContentType type) |
0 | 126 { |
5430
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
127 Toolbox::ElapsedTimer timer; |
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
128 LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) |
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
129 << "\" type"; |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
130 |
0 | 131 boost::filesystem::path path; |
132 | |
1135
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
133 path = GetPath(uuid); |
0 | 134 |
1135
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
135 if (boost::filesystem::exists(path)) |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
136 { |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
137 // Extremely unlikely case: This Uuid has already been created |
67c3c1e4a6e0
index-only mode, and custom storage area with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1126
diff
changeset
|
138 // in the past. |
5729
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
139 throw OrthancException(ErrorCode_InternalError, "This file UUID already exists"); |
0 | 140 } |
141 | |
5729
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
142 // In very unlikely case (but we've seen it !), 2 threads might enter this same piece |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
143 // of code and both try to create the same directory or a thread could be deleting a |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
144 // directory while another thread needs it -> introduce 3 retries at 1 ms interval |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
145 int retryCount = 0; |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
146 const int maxRetryCount = 3; |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
147 |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
148 while (retryCount < maxRetryCount) |
0 | 149 { |
5729
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
150 retryCount++; |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
151 if (retryCount > 1) |
0 | 152 { |
5729
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
153 boost::this_thread::sleep(boost::posix_time::milliseconds(2 * retryCount + (rand() % 10))); |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
154 LOG(INFO) << "Retrying to create attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
155 << "\" type"; |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
156 } |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
157 |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
158 if (boost::filesystem::exists(path.parent_path())) |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
159 { |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
160 if (!boost::filesystem::is_directory(path.parent_path())) |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
161 { |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
162 throw OrthancException(ErrorCode_DirectoryOverFile); // no need to retry this error |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
163 } |
0 | 164 } |
5729
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
165 else |
0 | 166 { |
5729
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
167 if (!boost::filesystem::create_directories(path.parent_path())) |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
168 { |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
169 if (retryCount >= maxRetryCount) |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
170 { |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
171 throw OrthancException(ErrorCode_FileStorageCannotWrite); |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
172 } |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
173 |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
174 continue; // retry |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
175 } |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
176 } |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
177 |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
178 try |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
179 { |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
180 SystemToolbox::WriteFile(content, size, path.string(), fsyncOnWrite_); |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
181 } |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
182 catch (OrthancException& ex) |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
183 { |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
184 if (retryCount >= maxRetryCount) |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
185 { |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
186 throw ex; |
bdbaccc06e98
Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage at the same time
Alain Mazy <am@orthanc.team>
parents:
5640
diff
changeset
|
187 } |
0 | 188 } |
189 } | |
190 | |
5430
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
191 LOG(INFO) << "Created attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, size) << ")"; |
0 | 192 } |
193 | |
194 | |
4484
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
195 IMemoryBuffer* FilesystemStorage::Read(const std::string& uuid, |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
196 FileContentType type) |
0 | 197 { |
5430
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
198 Toolbox::ElapsedTimer timer; |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
199 LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
200 << "\" content type"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
201 |
4484
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
202 std::string content; |
2140 | 203 SystemToolbox::ReadFile(content, GetPath(uuid).string()); |
4484
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
204 |
5430
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
205 LOG(INFO) << "Read attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, content.size()) << ")"; |
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
206 |
4484
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
207 return StringMemoryBuffer::CreateFromSwap(content); |
0 | 208 } |
209 | |
210 | |
4495
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
211 IMemoryBuffer* FilesystemStorage::ReadRange(const std::string& uuid, |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
212 FileContentType type, |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
213 uint64_t start /* inclusive */, |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
214 uint64_t end /* exclusive */) |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
215 { |
5430
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
216 Toolbox::ElapsedTimer timer; |
4495
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
217 LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
218 << "\" content type (range from " << start << " to " << end << ")"; |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
219 |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
220 std::string content; |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
221 SystemToolbox::ReadFileRange( |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
222 content, GetPath(uuid).string(), start, end, true /* throw if overflow */); |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
223 |
5430
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
224 LOG(INFO) << "Read range of attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, content.size()) << ")"; |
4495
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
225 return StringMemoryBuffer::CreateFromSwap(content); |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
226 } |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
227 |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
228 |
4520
f5cb0c0ffbed
added unit test OrthancFramework.SizeOf to dump sizeof all the public classes in the Orthanc framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4512
diff
changeset
|
229 bool FilesystemStorage::HasReadRange() const |
f5cb0c0ffbed
added unit test OrthancFramework.SizeOf to dump sizeof all the public classes in the Orthanc framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4512
diff
changeset
|
230 { |
f5cb0c0ffbed
added unit test OrthancFramework.SizeOf to dump sizeof all the public classes in the Orthanc framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4512
diff
changeset
|
231 return true; |
f5cb0c0ffbed
added unit test OrthancFramework.SizeOf to dump sizeof all the public classes in the Orthanc framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4512
diff
changeset
|
232 } |
f5cb0c0ffbed
added unit test OrthancFramework.SizeOf to dump sizeof all the public classes in the Orthanc framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4512
diff
changeset
|
233 |
f5cb0c0ffbed
added unit test OrthancFramework.SizeOf to dump sizeof all the public classes in the Orthanc framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4512
diff
changeset
|
234 |
1123 | 235 uintmax_t FilesystemStorage::GetSize(const std::string& uuid) const |
0 | 236 { |
237 boost::filesystem::path path = GetPath(uuid); | |
238 return boost::filesystem::file_size(path); | |
239 } | |
240 | |
241 | |
242 | |
1123 | 243 void FilesystemStorage::ListAllFiles(std::set<std::string>& result) const |
0 | 244 { |
245 namespace fs = boost::filesystem; | |
246 | |
247 result.clear(); | |
248 | |
249 if (fs::exists(root_) && fs::is_directory(root_)) | |
250 { | |
251 for (fs::recursive_directory_iterator current(root_), end; current != end ; ++current) | |
252 { | |
2140 | 253 if (SystemToolbox::IsRegularFile(current->path().string())) |
0 | 254 { |
255 try | |
256 { | |
257 fs::path d = current->path(); | |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
258 std::string uuid = ToString(d); |
0 | 259 if (Toolbox::IsUuid(uuid)) |
260 { | |
261 fs::path p0 = d.parent_path().parent_path().parent_path(); | |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
262 std::string p1 = ToString(d.parent_path().parent_path()); |
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
263 std::string p2 = ToString(d.parent_path()); |
0 | 264 if (p1.length() == 2 && |
265 p2.length() == 2 && | |
266 p1 == uuid.substr(0, 2) && | |
267 p2 == uuid.substr(2, 2) && | |
268 p0 == root_) | |
269 { | |
270 result.insert(uuid); | |
271 } | |
272 } | |
273 } | |
2836
7133ad478eea
fix Debian warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2447
diff
changeset
|
274 catch (fs::filesystem_error&) |
0 | 275 { |
276 } | |
277 } | |
278 } | |
279 } | |
280 } | |
281 | |
282 | |
1123 | 283 void FilesystemStorage::Clear() |
0 | 284 { |
285 namespace fs = boost::filesystem; | |
286 typedef std::set<std::string> List; | |
287 | |
288 List result; | |
289 ListAllFiles(result); | |
290 | |
656 | 291 for (List::const_iterator it = result.begin(); it != result.end(); ++it) |
0 | 292 { |
1126
bf67431a7383
handling of file content type in IStorageArea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1124
diff
changeset
|
293 Remove(*it, FileContentType_Unknown /*ignored in this class*/); |
0 | 294 } |
295 } | |
296 | |
297 | |
1126
bf67431a7383
handling of file content type in IStorageArea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1124
diff
changeset
|
298 void FilesystemStorage::Remove(const std::string& uuid, |
2129
0c09d1af22f3
"/tools/invalidate-tags" to invalidate the JSON summary of all the DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2087
diff
changeset
|
299 FileContentType type) |
0 | 300 { |
2129
0c09d1af22f3
"/tools/invalidate-tags" to invalidate the JSON summary of all the DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2087
diff
changeset
|
301 LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast<int>(type); |
1397 | 302 |
0 | 303 namespace fs = boost::filesystem; |
304 | |
305 fs::path p = GetPath(uuid); | |
147 | 306 |
307 try | |
308 { | |
309 fs::remove(p); | |
310 } | |
148 | 311 catch (...) |
147 | 312 { |
313 // Ignore the error | |
314 } | |
0 | 315 |
316 // Remove the two parent directories, ignoring the error code if | |
317 // these directories are not empty | |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
318 |
142 | 319 try |
320 { | |
147 | 321 #if BOOST_HAS_FILESYSTEM_V3 == 1 |
322 boost::system::error_code err; | |
323 fs::remove(p.parent_path(), err); | |
324 fs::remove(p.parent_path().parent_path(), err); | |
325 #else | |
326 fs::remove(p.parent_path()); | |
327 fs::remove(p.parent_path().parent_path()); | |
328 #endif | |
142 | 329 } |
148 | 330 catch (...) |
142 | 331 { |
332 // Ignore the error | |
333 } | |
334 } | |
335 | |
336 | |
1123 | 337 uintmax_t FilesystemStorage::GetCapacity() const |
0 | 338 { |
339 return boost::filesystem::space(root_).capacity; | |
340 } | |
341 | |
1123 | 342 uintmax_t FilesystemStorage::GetAvailableSpace() const |
0 | 343 { |
344 return boost::filesystem::space(root_).available; | |
345 } | |
4273
0034f855c023
tuning log categories from command-line, and binary compat with orthanc framework 1.7.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4185
diff
changeset
|
346 |
0034f855c023
tuning log categories from command-line, and binary compat with orthanc framework 1.7.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4185
diff
changeset
|
347 |
0034f855c023
tuning log categories from command-line, and binary compat with orthanc framework 1.7.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4185
diff
changeset
|
348 #if ORTHANC_BUILDING_FRAMEWORK_LIBRARY == 1 |
0034f855c023
tuning log categories from command-line, and binary compat with orthanc framework 1.7.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4185
diff
changeset
|
349 FilesystemStorage::FilesystemStorage(std::string root) : |
0034f855c023
tuning log categories from command-line, and binary compat with orthanc framework 1.7.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4185
diff
changeset
|
350 fsyncOnWrite_(false) |
0034f855c023
tuning log categories from command-line, and binary compat with orthanc framework 1.7.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4185
diff
changeset
|
351 { |
0034f855c023
tuning log categories from command-line, and binary compat with orthanc framework 1.7.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4185
diff
changeset
|
352 Setup(root); |
0034f855c023
tuning log categories from command-line, and binary compat with orthanc framework 1.7.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4185
diff
changeset
|
353 } |
0034f855c023
tuning log categories from command-line, and binary compat with orthanc framework 1.7.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4185
diff
changeset
|
354 #endif |
4484
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
355 |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
356 |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
357 #if ORTHANC_BUILDING_FRAMEWORK_LIBRARY == 1 |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
358 void FilesystemStorage::Read(std::string& content, |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
359 const std::string& uuid, |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
360 FileContentType type) |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
361 { |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
362 std::unique_ptr<IMemoryBuffer> buffer(Read(uuid, type)); |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
363 buffer->MoveToString(content); |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
364 } |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
365 #endif |
0 | 366 } |