Mercurial > hg > orthanc
annotate OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp @ 5765:247fc5368693 find-refactoring
un-sharing DatabaseConstraint and ISqlLookupFormatter with orthanc-databases
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 09 Sep 2024 16:14:22 +0200 |
parents | 2fe77dfe0466 |
children | 8279eaab0d1d |
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 | |
5737
2fe77dfe0466
rewrote FileSystemStorage::Create knowing that we should not check the return value of boost::file_system::create_directories and that it throws on errors we were detecting manually
Alain Mazy <am@orthanc.team>
parents:
5736
diff
changeset
|
142 // In very unlikely cases, a thread could be deleting a |
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
|
143 // 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
|
144 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
|
145 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
|
146 |
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 while (retryCount < maxRetryCount) |
0 | 148 { |
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
|
149 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
|
150 if (retryCount > 1) |
0 | 151 { |
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
|
152 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
|
153 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
|
154 << "\" 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 } |
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 |
5737
2fe77dfe0466
rewrote FileSystemStorage::Create knowing that we should not check the return value of boost::file_system::create_directories and that it throws on errors we were detecting manually
Alain Mazy <am@orthanc.team>
parents:
5736
diff
changeset
|
157 try |
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
|
158 { |
5737
2fe77dfe0466
rewrote FileSystemStorage::Create knowing that we should not check the return value of boost::file_system::create_directories and that it throws on errors we were detecting manually
Alain Mazy <am@orthanc.team>
parents:
5736
diff
changeset
|
159 boost::filesystem::create_directories(path.parent_path()); // the function ensures that the directory exists or throws |
0 | 160 } |
5737
2fe77dfe0466
rewrote FileSystemStorage::Create knowing that we should not check the return value of boost::file_system::create_directories and that it throws on errors we were detecting manually
Alain Mazy <am@orthanc.team>
parents:
5736
diff
changeset
|
161 catch (boost::filesystem::filesystem_error& er) |
0 | 162 { |
5737
2fe77dfe0466
rewrote FileSystemStorage::Create knowing that we should not check the return value of boost::file_system::create_directories and that it throws on errors we were detecting manually
Alain Mazy <am@orthanc.team>
parents:
5736
diff
changeset
|
163 if (er.code() == boost::system::errc::file_exists // the last element of the parent_path is a file |
2fe77dfe0466
rewrote FileSystemStorage::Create knowing that we should not check the return value of boost::file_system::create_directories and that it throws on errors we were detecting manually
Alain Mazy <am@orthanc.team>
parents:
5736
diff
changeset
|
164 || er.code() == boost::system::errc::not_a_directory) // one of the element of the parent_path is not a directory |
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 { |
5737
2fe77dfe0466
rewrote FileSystemStorage::Create knowing that we should not check the return value of boost::file_system::create_directories and that it throws on errors we were detecting manually
Alain Mazy <am@orthanc.team>
parents:
5736
diff
changeset
|
166 throw OrthancException(ErrorCode_DirectoryOverFile, "One of the element of the path is a file"); // no need to retry this error |
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 } |
5737
2fe77dfe0466
rewrote FileSystemStorage::Create knowing that we should not check the return value of boost::file_system::create_directories and that it throws on errors we were detecting manually
Alain Mazy <am@orthanc.team>
parents:
5736
diff
changeset
|
168 |
2fe77dfe0466
rewrote FileSystemStorage::Create knowing that we should not check the return value of boost::file_system::create_directories and that it throws on errors we were detecting manually
Alain Mazy <am@orthanc.team>
parents:
5736
diff
changeset
|
169 // ignore other errors and retry |
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
|
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 |
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 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
|
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 SystemToolbox::WriteFile(content, size, path.string(), fsyncOnWrite_); |
5736 | 175 |
176 LOG(INFO) << "Created attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, size) << ")"; | |
177 return; | |
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
|
178 } |
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 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
|
180 { |
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 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
|
182 { |
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 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
|
184 } |
0 | 185 } |
186 } | |
187 } | |
188 | |
189 | |
4484
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
190 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
|
191 FileContentType type) |
0 | 192 { |
5430
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
193 Toolbox::ElapsedTimer timer; |
2087
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
194 LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
195 << "\" content type"; |
e9e6ffbf0fd5
improved logging in FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1911
diff
changeset
|
196 |
4484
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
197 std::string content; |
2140 | 198 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
|
199 |
5430
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
200 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
|
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 return StringMemoryBuffer::CreateFromSwap(content); |
0 | 203 } |
204 | |
205 | |
4495
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
206 IMemoryBuffer* FilesystemStorage::ReadRange(const std::string& uuid, |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
207 FileContentType type, |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
208 uint64_t start /* inclusive */, |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
209 uint64_t end /* exclusive */) |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
210 { |
5430
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
211 Toolbox::ElapsedTimer timer; |
4495
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
212 LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
213 << "\" content type (range from " << start << " to " << end << ")"; |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
214 |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
215 std::string content; |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
216 SystemToolbox::ReadFileRange( |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
217 content, GetPath(uuid).string(), start, end, true /* throw if overflow */); |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
218 |
5430
b83192e7ad10
Now displaying timings when reading from/writing to disk in the verbose logs
Alain Mazy <am@osimis.io>
parents:
5374
diff
changeset
|
219 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
|
220 return StringMemoryBuffer::CreateFromSwap(content); |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
221 } |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
222 |
fa2311f94d9f
IStorageArea::ReadRange()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4484
diff
changeset
|
223 |
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
|
224 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
|
225 { |
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
|
226 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
|
227 } |
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
|
228 |
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 |
1123 | 230 uintmax_t FilesystemStorage::GetSize(const std::string& uuid) const |
0 | 231 { |
232 boost::filesystem::path path = GetPath(uuid); | |
233 return boost::filesystem::file_size(path); | |
234 } | |
235 | |
236 | |
237 | |
1123 | 238 void FilesystemStorage::ListAllFiles(std::set<std::string>& result) const |
0 | 239 { |
240 namespace fs = boost::filesystem; | |
241 | |
242 result.clear(); | |
243 | |
244 if (fs::exists(root_) && fs::is_directory(root_)) | |
245 { | |
246 for (fs::recursive_directory_iterator current(root_), end; current != end ; ++current) | |
247 { | |
2140 | 248 if (SystemToolbox::IsRegularFile(current->path().string())) |
0 | 249 { |
250 try | |
251 { | |
252 fs::path d = current->path(); | |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
253 std::string uuid = ToString(d); |
0 | 254 if (Toolbox::IsUuid(uuid)) |
255 { | |
256 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
|
257 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
|
258 std::string p2 = ToString(d.parent_path()); |
0 | 259 if (p1.length() == 2 && |
260 p2.length() == 2 && | |
261 p1 == uuid.substr(0, 2) && | |
262 p2 == uuid.substr(2, 2) && | |
263 p0 == root_) | |
264 { | |
265 result.insert(uuid); | |
266 } | |
267 } | |
268 } | |
2836
7133ad478eea
fix Debian warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2447
diff
changeset
|
269 catch (fs::filesystem_error&) |
0 | 270 { |
271 } | |
272 } | |
273 } | |
274 } | |
275 } | |
276 | |
277 | |
1123 | 278 void FilesystemStorage::Clear() |
0 | 279 { |
280 namespace fs = boost::filesystem; | |
281 typedef std::set<std::string> List; | |
282 | |
283 List result; | |
284 ListAllFiles(result); | |
285 | |
656 | 286 for (List::const_iterator it = result.begin(); it != result.end(); ++it) |
0 | 287 { |
1126
bf67431a7383
handling of file content type in IStorageArea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1124
diff
changeset
|
288 Remove(*it, FileContentType_Unknown /*ignored in this class*/); |
0 | 289 } |
290 } | |
291 | |
292 | |
1126
bf67431a7383
handling of file content type in IStorageArea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1124
diff
changeset
|
293 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
|
294 FileContentType type) |
0 | 295 { |
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
|
296 LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast<int>(type); |
1397 | 297 |
0 | 298 namespace fs = boost::filesystem; |
299 | |
300 fs::path p = GetPath(uuid); | |
147 | 301 |
302 try | |
303 { | |
304 fs::remove(p); | |
305 } | |
148 | 306 catch (...) |
147 | 307 { |
308 // Ignore the error | |
309 } | |
0 | 310 |
311 // Remove the two parent directories, ignoring the error code if | |
312 // these directories are not empty | |
110
fd7b0a3e6260
support of boost 1.42 for debian
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
313 |
142 | 314 try |
315 { | |
147 | 316 #if BOOST_HAS_FILESYSTEM_V3 == 1 |
317 boost::system::error_code err; | |
318 fs::remove(p.parent_path(), err); | |
319 fs::remove(p.parent_path().parent_path(), err); | |
320 #else | |
321 fs::remove(p.parent_path()); | |
322 fs::remove(p.parent_path().parent_path()); | |
323 #endif | |
142 | 324 } |
148 | 325 catch (...) |
142 | 326 { |
327 // Ignore the error | |
328 } | |
329 } | |
330 | |
331 | |
1123 | 332 uintmax_t FilesystemStorage::GetCapacity() const |
0 | 333 { |
334 return boost::filesystem::space(root_).capacity; | |
335 } | |
336 | |
1123 | 337 uintmax_t FilesystemStorage::GetAvailableSpace() const |
0 | 338 { |
339 return boost::filesystem::space(root_).available; | |
340 } | |
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
|
341 |
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
|
342 |
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
|
343 #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
|
344 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
|
345 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
|
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 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
|
348 } |
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 #endif |
4484
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
350 |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
351 |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
352 #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
|
353 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
|
354 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
|
355 FileContentType type) |
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 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
|
358 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
|
359 } |
64f06e7d5fc7
new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
360 #endif |
0 | 361 } |