Mercurial > hg > orthanc-object-storage
comparison Common/StoragePlugin.cpp @ 77:80792bb9600e
new HybridMode
author | Alain Mazy <am@osimis.io> |
---|---|
date | Fri, 14 Oct 2022 10:36:02 +0200 |
parents | ba1be668e475 |
children | d7295e8678d7 |
comparison
equal
deleted
inserted
replaced
75:ac596874d997 | 77:80792bb9600e |
---|---|
38 #include <boost/filesystem.hpp> | 38 #include <boost/filesystem.hpp> |
39 #include <boost/filesystem/fstream.hpp> | 39 #include <boost/filesystem/fstream.hpp> |
40 | 40 |
41 #include "../Common/EncryptionHelpers.h" | 41 #include "../Common/EncryptionHelpers.h" |
42 #include "../Common/EncryptionConfigurator.h" | 42 #include "../Common/EncryptionConfigurator.h" |
43 #include "../Common/FileSystemStoragePlugin.h" | |
43 | 44 |
44 #include <Logging.h> | 45 #include <Logging.h> |
45 #include <SystemToolbox.h> | 46 #include <SystemToolbox.h> |
46 | 47 |
47 static std::unique_ptr<IStoragePlugin> plugin; | 48 static std::unique_ptr<IStoragePlugin> primaryPlugin; |
49 static std::unique_ptr<IStoragePlugin> secondaryPlugin; | |
48 | 50 |
49 static std::unique_ptr<EncryptionHelpers> crypto; | 51 static std::unique_ptr<EncryptionHelpers> crypto; |
50 static bool cryptoEnabled = false; | 52 static bool cryptoEnabled = false; |
51 static std::string fileSystemRootPath; | 53 static std::string fileSystemRootPath; |
52 static bool migrationFromFileSystemEnabled = false; | |
53 static std::string objectsRootPath; | 54 static std::string objectsRootPath; |
55 static std::string hybridModeNameForLogs = ""; | |
56 | |
57 typedef enum | |
58 { | |
59 HybridMode_WriteToFileSystem, // write to disk, try to read first from disk and then, from object-storage | |
60 HybridMode_WriteToObjectStorage, // write to object storage, try to read first from object storage and then, from disk | |
61 HybridMode_Disabled // read and write only from/to object-storage | |
62 } HybridMode; | |
63 | |
64 static HybridMode hybridMode = HybridMode_Disabled; | |
65 | |
66 static bool IsReadFromDisk() | |
67 { | |
68 return hybridMode != HybridMode_Disabled; | |
69 } | |
70 | |
71 static bool IsHybridModeEnabled() | |
72 { | |
73 return hybridMode != HybridMode_Disabled; | |
74 } | |
75 | |
76 typedef void LogErrorFunction(const std::string& message); | |
77 | |
54 | 78 |
55 | 79 |
56 static OrthancPluginErrorCode StorageCreate(const char* uuid, | 80 static OrthancPluginErrorCode StorageCreate(const char* uuid, |
57 const void* content, | 81 const void* content, |
58 int64_t size, | 82 int64_t size, |
59 OrthancPluginContentType type) | 83 OrthancPluginContentType type) |
60 { | 84 { |
61 try | 85 try |
62 { | 86 { |
63 std::unique_ptr<IStoragePlugin::IWriter> writer(plugin->GetWriterForObject(uuid, type, cryptoEnabled)); | 87 OrthancPlugins::LogInfo(primaryPlugin->GetNameForLogs() + ": creating attachment " + std::string(uuid) + " of type " + boost::lexical_cast<std::string>(type)); |
88 std::unique_ptr<IStoragePlugin::IWriter> writer(primaryPlugin->GetWriterForObject(uuid, type, cryptoEnabled)); | |
64 | 89 |
65 if (cryptoEnabled) | 90 if (cryptoEnabled) |
66 { | 91 { |
67 std::string encryptedFile; | 92 std::string encryptedFile; |
68 | 93 |
70 { | 95 { |
71 crypto->Encrypt(encryptedFile, (const char*)content, size); | 96 crypto->Encrypt(encryptedFile, (const char*)content, size); |
72 } | 97 } |
73 catch (EncryptionException& ex) | 98 catch (EncryptionException& ex) |
74 { | 99 { |
75 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while encrypting object " + std::string(uuid) + ": " + ex.what()); | 100 OrthancPlugins::LogError(primaryPlugin->GetNameForLogs() + ": error while encrypting object " + std::string(uuid) + ": " + ex.what()); |
76 return OrthancPluginErrorCode_StorageAreaPlugin; | 101 return OrthancPluginErrorCode_StorageAreaPlugin; |
77 } | 102 } |
78 | 103 |
79 writer->Write(encryptedFile.data(), encryptedFile.size()); | 104 writer->Write(encryptedFile.data(), encryptedFile.size()); |
80 } | 105 } |
83 writer->Write(reinterpret_cast<const char*>(content), size); | 108 writer->Write(reinterpret_cast<const char*>(content), size); |
84 } | 109 } |
85 } | 110 } |
86 catch (StoragePluginException& ex) | 111 catch (StoragePluginException& ex) |
87 { | 112 { |
88 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while creating object " + std::string(uuid) + ": " + ex.what()); | 113 OrthancPlugins::LogError(primaryPlugin->GetNameForLogs() + ": error while creating object " + std::string(uuid) + ": " + ex.what()); |
89 return OrthancPluginErrorCode_StorageAreaPlugin; | 114 return OrthancPluginErrorCode_StorageAreaPlugin; |
90 } | 115 } |
91 | 116 |
92 return OrthancPluginErrorCode_Success; | 117 return OrthancPluginErrorCode_Success; |
93 } | 118 } |
94 | 119 |
120 | |
121 static OrthancPluginErrorCode StorageReadRange(IStoragePlugin* plugin, | |
122 LogErrorFunction logErrorFunction, | |
123 OrthancPluginMemoryBuffer64* target, // Memory buffer where to store the content of the range. The memory buffer is allocated and freed by Orthanc. The length of the range of interest corresponds to the size of this buffer. | |
124 const char* uuid, | |
125 OrthancPluginContentType type, | |
126 uint64_t rangeStart) | |
127 { | |
128 assert(!cryptoEnabled); | |
129 | |
130 try | |
131 { | |
132 OrthancPlugins::LogInfo(plugin->GetNameForLogs() + ": reading range of attachment " + std::string(uuid) + " of type " + boost::lexical_cast<std::string>(type)); | |
133 | |
134 std::unique_ptr<IStoragePlugin::IReader> reader(plugin->GetReaderForObject(uuid, type, cryptoEnabled)); | |
135 reader->ReadRange(reinterpret_cast<char*>(target->data), target->size, rangeStart); | |
136 | |
137 return OrthancPluginErrorCode_Success; | |
138 } | |
139 catch (StoragePluginException& ex) | |
140 { | |
141 logErrorFunction(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while reading object " + std::string(uuid) + ": " + std::string(ex.what())); | |
142 return OrthancPluginErrorCode_StorageAreaPlugin; | |
143 } | |
144 } | |
95 | 145 |
96 static OrthancPluginErrorCode StorageReadRange(OrthancPluginMemoryBuffer64* target, // Memory buffer where to store the content of the range. The memory buffer is allocated and freed by Orthanc. The length of the range of interest corresponds to the size of this buffer. | 146 static OrthancPluginErrorCode StorageReadRange(OrthancPluginMemoryBuffer64* target, // Memory buffer where to store the content of the range. The memory buffer is allocated and freed by Orthanc. The length of the range of interest corresponds to the size of this buffer. |
97 const char* uuid, | 147 const char* uuid, |
98 OrthancPluginContentType type, | 148 OrthancPluginContentType type, |
99 uint64_t rangeStart) | 149 uint64_t rangeStart) |
100 { | 150 { |
101 assert(!cryptoEnabled); | 151 OrthancPluginErrorCode res = StorageReadRange(primaryPlugin.get(), |
102 | 152 (IsHybridModeEnabled() ? OrthancPlugins::LogWarning : OrthancPlugins::LogError), // log errors as warning on first try |
153 target, | |
154 uuid, | |
155 type, | |
156 rangeStart); | |
157 | |
158 if (res != OrthancPluginErrorCode_Success && IsHybridModeEnabled()) | |
159 { | |
160 res = StorageReadRange(secondaryPlugin.get(), | |
161 OrthancPlugins::LogError, // log errors as errors on second try | |
162 target, | |
163 uuid, | |
164 type, | |
165 rangeStart); | |
166 } | |
167 return res; | |
168 } | |
169 | |
170 | |
171 | |
172 static OrthancPluginErrorCode StorageReadWhole(IStoragePlugin* plugin, | |
173 LogErrorFunction logErrorFunction, | |
174 OrthancPluginMemoryBuffer64* target, // Memory buffer where to store the content of the file. It must be allocated by the plugin using OrthancPluginCreateMemoryBuffer64(). The core of Orthanc will free it. | |
175 const char* uuid, | |
176 OrthancPluginContentType type) | |
177 { | |
103 try | 178 try |
104 { | 179 { |
180 OrthancPlugins::LogInfo(plugin->GetNameForLogs() + ": reading whole attachment " + std::string(uuid) + " of type " + boost::lexical_cast<std::string>(type)); | |
105 std::unique_ptr<IStoragePlugin::IReader> reader(plugin->GetReaderForObject(uuid, type, cryptoEnabled)); | 181 std::unique_ptr<IStoragePlugin::IReader> reader(plugin->GetReaderForObject(uuid, type, cryptoEnabled)); |
106 reader->ReadRange(reinterpret_cast<char*>(target->data), target->size, rangeStart); | 182 |
183 size_t fileSize = reader->GetSize(); | |
184 size_t size; | |
185 | |
186 if (cryptoEnabled) | |
187 { | |
188 size = fileSize - crypto->OVERHEAD_SIZE; | |
189 } | |
190 else | |
191 { | |
192 size = fileSize; | |
193 } | |
194 | |
195 if (size <= 0) | |
196 { | |
197 logErrorFunction(plugin->GetNameForLogs() + ": error while reading object " + std::string(uuid) + ", size of file is too small: " + boost::lexical_cast<std::string>(fileSize) + " bytes"); | |
198 return OrthancPluginErrorCode_StorageAreaPlugin; | |
199 } | |
200 | |
201 if (OrthancPluginCreateMemoryBuffer64(OrthancPlugins::GetGlobalContext(), target, size) != OrthancPluginErrorCode_Success) | |
202 { | |
203 logErrorFunction(plugin->GetNameForLogs() + ": error while reading object " + std::string(uuid) + ", cannot allocate memory of size " + boost::lexical_cast<std::string>(size) + " bytes"); | |
204 return OrthancPluginErrorCode_StorageAreaPlugin; | |
205 } | |
206 | |
207 if (cryptoEnabled) | |
208 { | |
209 std::vector<char> encrypted(fileSize); | |
210 reader->ReadWhole(encrypted.data(), fileSize); | |
211 | |
212 try | |
213 { | |
214 crypto->Decrypt(reinterpret_cast<char*>(target->data), encrypted.data(), fileSize); | |
215 } | |
216 catch (EncryptionException& ex) | |
217 { | |
218 logErrorFunction(plugin->GetNameForLogs() + ": error while decrypting object " + std::string(uuid) + ": " + ex.what()); | |
219 return OrthancPluginErrorCode_StorageAreaPlugin; | |
220 } | |
221 } | |
222 else | |
223 { | |
224 reader->ReadWhole(reinterpret_cast<char*>(target->data), fileSize); | |
225 } | |
107 } | 226 } |
108 catch (StoragePluginException& ex) | 227 catch (StoragePluginException& ex) |
109 { | 228 { |
110 if (migrationFromFileSystemEnabled) | 229 logErrorFunction(plugin->GetNameForLogs() + ": error while decrypting object " + std::string(uuid) + ": " + ex.what()); |
111 { | 230 return OrthancPluginErrorCode_StorageAreaPlugin; |
112 try | 231 } |
113 { | 232 |
114 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while reading object " + std::string(uuid) + ": " + ex.what() + ", will now try to read it from legacy orthanc storage"); | |
115 std::string path = BaseStoragePlugin::GetOrthancFileSystemPath(uuid, fileSystemRootPath); | |
116 | |
117 std::string stringBuffer; | |
118 Orthanc::SystemToolbox::ReadFileRange(stringBuffer, path, rangeStart, rangeStart + target->size, true); | |
119 | |
120 memcpy(target->data, stringBuffer.data(), stringBuffer.size()); | |
121 | |
122 return OrthancPluginErrorCode_Success; | |
123 } | |
124 catch(Orthanc::OrthancException& e) | |
125 { | |
126 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while reading object " + std::string(uuid) + ": " + std::string(e.What())); | |
127 return OrthancPluginErrorCode_StorageAreaPlugin; | |
128 } | |
129 } | |
130 } | |
131 return OrthancPluginErrorCode_Success; | 233 return OrthancPluginErrorCode_Success; |
132 } | 234 } |
133 | |
134 | 235 |
135 static OrthancPluginErrorCode StorageReadWhole(OrthancPluginMemoryBuffer64* target, // Memory buffer where to store the content of the file. It must be allocated by the plugin using OrthancPluginCreateMemoryBuffer64(). The core of Orthanc will free it. | 236 static OrthancPluginErrorCode StorageReadWhole(OrthancPluginMemoryBuffer64* target, // Memory buffer where to store the content of the file. It must be allocated by the plugin using OrthancPluginCreateMemoryBuffer64(). The core of Orthanc will free it. |
136 const char* uuid, | 237 const char* uuid, |
137 OrthancPluginContentType type) | 238 OrthancPluginContentType type) |
138 { | 239 { |
139 try | 240 OrthancPluginErrorCode res = StorageReadWhole(primaryPlugin.get(), |
140 { | 241 (IsHybridModeEnabled() ? OrthancPlugins::LogWarning : OrthancPlugins::LogError), // log errors as warning on first try |
141 std::unique_ptr<IStoragePlugin::IReader> reader(plugin->GetReaderForObject(uuid, type, cryptoEnabled)); | 242 target, |
142 | 243 uuid, |
143 size_t fileSize = reader->GetSize(); | 244 type); |
144 size_t size; | 245 |
145 | 246 if (res != OrthancPluginErrorCode_Success && IsHybridModeEnabled()) |
146 if (cryptoEnabled) | 247 { |
147 { | 248 res = StorageReadWhole(secondaryPlugin.get(), |
148 size = fileSize - crypto->OVERHEAD_SIZE; | 249 OrthancPlugins::LogError, // log errors as errors on second try |
149 } | 250 target, |
150 else | 251 uuid, |
151 { | 252 type); |
152 size = fileSize; | 253 } |
153 } | 254 return res; |
154 | |
155 if (size <= 0) | |
156 { | |
157 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while reading object " + std::string(uuid) + ", size of file is too small: " + boost::lexical_cast<std::string>(fileSize) + " bytes"); | |
158 return OrthancPluginErrorCode_StorageAreaPlugin; | |
159 } | |
160 | |
161 if (OrthancPluginCreateMemoryBuffer64(OrthancPlugins::GetGlobalContext(), target, size) != OrthancPluginErrorCode_Success) | |
162 { | |
163 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while reading object " + std::string(uuid) + ", cannot allocate memory of size " + boost::lexical_cast<std::string>(size) + " bytes"); | |
164 return OrthancPluginErrorCode_StorageAreaPlugin; | |
165 } | |
166 | |
167 if (cryptoEnabled) | |
168 { | |
169 std::vector<char> encrypted(fileSize); | |
170 reader->ReadWhole(encrypted.data(), fileSize); | |
171 | |
172 try | |
173 { | |
174 crypto->Decrypt(reinterpret_cast<char*>(target->data), encrypted.data(), fileSize); | |
175 } | |
176 catch (EncryptionException& ex) | |
177 { | |
178 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while decrypting object " + std::string(uuid) + ": " + ex.what()); | |
179 return OrthancPluginErrorCode_StorageAreaPlugin; | |
180 } | |
181 } | |
182 else | |
183 { | |
184 reader->ReadWhole(reinterpret_cast<char*>(target->data), fileSize); | |
185 } | |
186 } | |
187 catch (StoragePluginException& ex) | |
188 { | |
189 if (migrationFromFileSystemEnabled) | |
190 { | |
191 try | |
192 { | |
193 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while reading object " + std::string(uuid) + ": " + ex.what() + ", will now try to read it from legacy orthanc storage"); | |
194 std::string path = BaseStoragePlugin::GetOrthancFileSystemPath(uuid, fileSystemRootPath); | |
195 | |
196 std::string stringBuffer; | |
197 Orthanc::SystemToolbox::ReadFile(stringBuffer, path); | |
198 | |
199 if (OrthancPluginCreateMemoryBuffer64(OrthancPlugins::GetGlobalContext(), target, stringBuffer.size()) != OrthancPluginErrorCode_Success) | |
200 { | |
201 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while reading object " + std::string(uuid) + ", cannot allocate memory of size " + boost::lexical_cast<std::string>(stringBuffer.size()) + " bytes"); | |
202 return OrthancPluginErrorCode_StorageAreaPlugin; | |
203 } | |
204 | |
205 memcpy(target->data, stringBuffer.data(), stringBuffer.size()); | |
206 | |
207 return OrthancPluginErrorCode_Success; | |
208 } | |
209 catch(Orthanc::OrthancException& e) | |
210 { | |
211 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while reading object " + std::string(uuid) + ": " + std::string(e.What())); | |
212 return OrthancPluginErrorCode_StorageAreaPlugin; | |
213 } | |
214 } | |
215 else | |
216 { | |
217 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while reading object " + std::string(uuid) + ": " + ex.what()); | |
218 return OrthancPluginErrorCode_StorageAreaPlugin; | |
219 } | |
220 } | |
221 | |
222 return OrthancPluginErrorCode_Success; | |
223 } | 255 } |
224 | 256 |
225 static OrthancPluginErrorCode StorageReadWholeLegacy(void** content, | 257 static OrthancPluginErrorCode StorageReadWholeLegacy(void** content, |
226 int64_t* size, | 258 int64_t* size, |
227 const char* uuid, | 259 const char* uuid, |
238 | 270 |
239 return result; | 271 return result; |
240 } | 272 } |
241 | 273 |
242 | 274 |
275 // static bool StorageRemoveFromDisk(const char* uuid, | |
276 // OrthancPluginContentType type) | |
277 // { | |
278 // try | |
279 // { | |
280 // namespace fs = boost::filesystem; | |
281 // bool fileExisted = false; | |
282 // fs::path path = BaseStoragePlugin::GetOrthancFileSystemPath(uuid, fileSystemRootPath); | |
283 | |
284 // try | |
285 // { | |
286 // fs::remove(path); | |
287 // fileExisted = true; | |
288 // } | |
289 // catch (...) | |
290 // { | |
291 // // Ignore the error | |
292 // fileExisted = false; | |
293 // } | |
294 | |
295 // // Remove the two parent directories, ignoring the error code if | |
296 // // these directories are not empty | |
297 | |
298 // try | |
299 // { | |
300 // boost::system::error_code err; | |
301 // fs::remove(path.parent_path(), err); | |
302 // fs::remove(path.parent_path().parent_path(), err); | |
303 // } | |
304 // catch (...) | |
305 // { | |
306 // // Ignore the error | |
307 // } | |
308 | |
309 // return fileExisted; | |
310 // } | |
311 // catch(Orthanc::OrthancException& e) | |
312 // { | |
313 // OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while deleting object " + std::string(uuid) + ": " + std::string(e.What())); | |
314 // return false; | |
315 // } | |
316 | |
317 // } | |
318 | |
319 | |
320 static OrthancPluginErrorCode StorageRemove(IStoragePlugin* plugin, | |
321 LogErrorFunction logErrorFunction, | |
322 const char* uuid, | |
323 OrthancPluginContentType type) | |
324 { | |
325 try | |
326 { | |
327 OrthancPlugins::LogInfo(plugin->GetNameForLogs() + ": deleting attachment " + std::string(uuid) + " of type " + boost::lexical_cast<std::string>(type)); | |
328 plugin->DeleteObject(uuid, type, cryptoEnabled); | |
329 if ((plugin == primaryPlugin.get()) && IsHybridModeEnabled()) | |
330 { | |
331 // not 100% sure the file has been deleted, try the secondary plugin | |
332 return OrthancPluginErrorCode_StorageAreaPlugin; | |
333 } | |
334 | |
335 return OrthancPluginErrorCode_Success; | |
336 } | |
337 catch (StoragePluginException& ex) | |
338 { | |
339 logErrorFunction(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while deleting object " + std::string(uuid) + ": " + std::string(ex.what())); | |
340 return OrthancPluginErrorCode_StorageAreaPlugin; | |
341 } | |
342 } | |
343 | |
243 static OrthancPluginErrorCode StorageRemove(const char* uuid, | 344 static OrthancPluginErrorCode StorageRemove(const char* uuid, |
244 OrthancPluginContentType type) | 345 OrthancPluginContentType type) |
245 { | 346 { |
246 try | 347 OrthancPluginErrorCode res = StorageRemove(primaryPlugin.get(), |
247 { | 348 (IsHybridModeEnabled() ? OrthancPlugins::LogWarning : OrthancPlugins::LogError), // log errors as warning on first try |
248 plugin->DeleteObject(uuid, type, cryptoEnabled); | 349 uuid, |
249 } | 350 type); |
250 catch (StoragePluginException& ex) | 351 |
251 { | 352 if (res != OrthancPluginErrorCode_Success && IsHybridModeEnabled()) |
252 if (migrationFromFileSystemEnabled) | 353 { |
253 { | 354 res = StorageRemove(secondaryPlugin.get(), |
254 try | 355 OrthancPlugins::LogError, // log errors as errors on second try |
255 { | 356 uuid, |
256 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while deleting object " + std::string(uuid) + ": " + ex.what() + ", will now try to delete it from legacy orthanc storage"); | 357 type); |
257 namespace fs = boost::filesystem; | 358 } |
258 | 359 return res; |
259 fs::path path = BaseStoragePlugin::GetOrthancFileSystemPath(uuid, fileSystemRootPath); | |
260 | |
261 try | |
262 { | |
263 fs::remove(path); | |
264 } | |
265 catch (...) | |
266 { | |
267 // Ignore the error | |
268 } | |
269 | |
270 // Remove the two parent directories, ignoring the error code if | |
271 // these directories are not empty | |
272 | |
273 try | |
274 { | |
275 boost::system::error_code err; | |
276 fs::remove(path.parent_path(), err); | |
277 fs::remove(path.parent_path().parent_path(), err); | |
278 } | |
279 catch (...) | |
280 { | |
281 // Ignore the error | |
282 } | |
283 | |
284 return OrthancPluginErrorCode_Success; | |
285 } | |
286 catch(Orthanc::OrthancException& e) | |
287 { | |
288 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while deleting object " + std::string(uuid) + ": " + std::string(e.What())); | |
289 return OrthancPluginErrorCode_StorageAreaPlugin; | |
290 } | |
291 } | |
292 else | |
293 { | |
294 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": error while deleting object " + std::string(uuid) + ": " + ex.what()); | |
295 return OrthancPluginErrorCode_StorageAreaPlugin; | |
296 } | |
297 } | |
298 | |
299 return OrthancPluginErrorCode_Success; | |
300 } | 360 } |
301 | 361 |
302 | 362 |
303 extern "C" | 363 extern "C" |
304 { | 364 { |
326 return -1; | 386 return -1; |
327 } | 387 } |
328 | 388 |
329 try | 389 try |
330 { | 390 { |
331 plugin.reset(StoragePluginFactory::CreateStoragePlugin(orthancConfig)); | 391 const char* pluginSectionName = StoragePluginFactory::GetConfigurationSectionName(); |
332 | |
333 if (plugin.get() == nullptr) | |
334 { | |
335 return -1; | |
336 } | |
337 | |
338 const char* pluginSectionName = plugin->GetConfigurationSectionName(); | |
339 static const char* const ENCRYPTION_SECTION = "StorageEncryption"; | 392 static const char* const ENCRYPTION_SECTION = "StorageEncryption"; |
340 | 393 |
341 if (orthancConfig.IsSection(pluginSectionName)) | 394 if (orthancConfig.IsSection(pluginSectionName)) |
342 { | 395 { |
343 OrthancPlugins::OrthancConfiguration pluginSection; | 396 OrthancPlugins::OrthancConfiguration pluginSection; |
344 orthancConfig.GetSection(pluginSection, pluginSectionName); | 397 orthancConfig.GetSection(pluginSection, pluginSectionName); |
345 | 398 |
346 migrationFromFileSystemEnabled = pluginSection.GetBooleanValue("MigrationFromFileSystemEnabled", false); | 399 bool migrationFromFileSystemEnabled = pluginSection.GetBooleanValue("MigrationFromFileSystemEnabled", false); |
347 | 400 std::string hybridModeString = pluginSection.GetStringValue("HybridMode", "Disabled"); |
348 if (migrationFromFileSystemEnabled) | 401 |
402 if (migrationFromFileSystemEnabled && hybridModeString == "Disabled") | |
403 { | |
404 hybridMode = HybridMode_WriteToObjectStorage; | |
405 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": 'MigrationFromFileSystemEnabled' configuration is deprecated, use 'HybridMode': 'WriteToObjectStorage' instead"); | |
406 } | |
407 else if (hybridModeString == "WriteToObjectStorage") | |
408 { | |
409 hybridMode = HybridMode_WriteToObjectStorage; | |
410 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": WriteToObjectStorage HybridMode is enabled: writing to object-storage, try reading first from object-storage and, then, from file system"); | |
411 } | |
412 else if (hybridModeString == "WriteToFileSystem") | |
413 { | |
414 hybridMode = HybridMode_WriteToFileSystem; | |
415 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": WriteToFileSystem HybridMode is enabled: writing to file system, try reading first from file system and, then, from object-storage"); | |
416 } | |
417 else | |
418 { | |
419 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": HybridMode is disabled enabled: writing to object-storage and reading only from object-storage"); | |
420 } | |
421 | |
422 if (IsReadFromDisk()) | |
349 { | 423 { |
350 fileSystemRootPath = orthancConfig.GetStringValue("StorageDirectory", "OrthancStorageNotDefined"); | 424 fileSystemRootPath = orthancConfig.GetStringValue("StorageDirectory", "OrthancStorageNotDefined"); |
351 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": migration from file system enabled, source: " + fileSystemRootPath); | 425 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": HybridMode: reading from file system is enabled, source: " + fileSystemRootPath); |
352 } | 426 } |
353 | 427 |
354 objectsRootPath = pluginSection.GetStringValue("RootPath", std::string()); | 428 objectsRootPath = pluginSection.GetStringValue("RootPath", std::string()); |
355 | 429 |
356 if (objectsRootPath.size() >= 1 && objectsRootPath[0] == '/') | 430 if (objectsRootPath.size() >= 1 && objectsRootPath[0] == '/') |
357 { | 431 { |
358 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": The RootPath shall not start with a '/': " + objectsRootPath); | 432 OrthancPlugins::LogError(std::string(StoragePluginFactory::GetStoragePluginName()) + ": The RootPath shall not start with a '/': " + objectsRootPath); |
359 return -1; | 433 return -1; |
360 } | 434 } |
361 | 435 |
362 plugin->SetRootPath(objectsRootPath); | 436 std::string objecstStoragePluginName = StoragePluginFactory::GetStoragePluginName(); |
437 if (hybridMode == HybridMode_WriteToFileSystem) | |
438 { | |
439 objecstStoragePluginName += " (Secondary: object-storage)"; | |
440 } | |
441 else if (hybridMode == HybridMode_WriteToObjectStorage) | |
442 { | |
443 objecstStoragePluginName += " (Primary: object-storage)"; | |
444 } | |
445 | |
446 std::unique_ptr<IStoragePlugin> objectStoragePlugin(StoragePluginFactory::CreateStoragePlugin(objecstStoragePluginName, orthancConfig)); | |
447 | |
448 if (objectStoragePlugin.get() == nullptr) | |
449 { | |
450 return -1; | |
451 } | |
452 | |
453 objectStoragePlugin->SetRootPath(objectsRootPath); | |
454 | |
455 std::unique_ptr<IStoragePlugin> fileSystemStoragePlugin; | |
456 if (IsHybridModeEnabled()) | |
457 { | |
458 bool fsync = orthancConfig.GetBooleanValue("SyncStorageArea", true); | |
459 | |
460 std::string filesystemStoragePluginName = StoragePluginFactory::GetStoragePluginName(); | |
461 if (hybridMode == HybridMode_WriteToFileSystem) | |
462 { | |
463 filesystemStoragePluginName += " (Primary: file-system)"; | |
464 } | |
465 else if (hybridMode == HybridMode_WriteToObjectStorage) | |
466 { | |
467 filesystemStoragePluginName += " (Secondary: file-system)"; | |
468 } | |
469 | |
470 fileSystemStoragePlugin.reset(new FileSystemStoragePlugin(filesystemStoragePluginName, fileSystemRootPath, fsync)); | |
471 } | |
472 | |
473 if (hybridMode == HybridMode_Disabled || hybridMode == HybridMode_WriteToObjectStorage) | |
474 { | |
475 primaryPlugin.reset(objectStoragePlugin.release()); | |
476 | |
477 if (hybridMode == HybridMode_WriteToObjectStorage) | |
478 { | |
479 secondaryPlugin.reset(fileSystemStoragePlugin.release()); | |
480 } | |
481 } | |
482 else if (hybridMode == HybridMode_WriteToFileSystem) | |
483 { | |
484 primaryPlugin.reset(fileSystemStoragePlugin.release()); | |
485 secondaryPlugin.reset(objectStoragePlugin.release()); | |
486 } | |
363 | 487 |
364 if (pluginSection.IsSection(ENCRYPTION_SECTION)) | 488 if (pluginSection.IsSection(ENCRYPTION_SECTION)) |
365 { | 489 { |
366 OrthancPlugins::OrthancConfiguration cryptoSection; | 490 OrthancPlugins::OrthancConfiguration cryptoSection; |
367 pluginSection.GetSection(cryptoSection, ENCRYPTION_SECTION); | 491 pluginSection.GetSection(cryptoSection, ENCRYPTION_SECTION); |
376 } | 500 } |
377 else | 501 else |
378 { | 502 { |
379 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": client-side encryption is disabled"); | 503 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + ": client-side encryption is disabled"); |
380 } | 504 } |
505 | |
506 | |
381 } | 507 } |
382 | 508 |
383 if (cryptoEnabled) | 509 if (cryptoEnabled) |
384 { | 510 { |
385 // with encrypted file, we do not want to support ReadRange. Therefore, we register the old interface | 511 // with encrypted file, we do not want to support ReadRange. Therefore, we register the old interface |
401 | 527 |
402 | 528 |
403 ORTHANC_PLUGINS_API void OrthancPluginFinalize() | 529 ORTHANC_PLUGINS_API void OrthancPluginFinalize() |
404 { | 530 { |
405 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + " plugin is finalizing"); | 531 OrthancPlugins::LogWarning(std::string(StoragePluginFactory::GetStoragePluginName()) + " plugin is finalizing"); |
406 plugin.reset(); | 532 primaryPlugin.reset(); |
533 secondaryPlugin.reset(); | |
407 Orthanc::FinalizeFramework(); | 534 Orthanc::FinalizeFramework(); |
408 } | 535 } |
409 | 536 |
410 | 537 |
411 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() | 538 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() |