Mercurial > hg > orthanc
diff OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp @ 5807:8279eaab0d1d attach-custom-data
merged default -> attach-custom-data
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Tue, 24 Sep 2024 11:39:52 +0200 |
parents | d7274e43ea7c 2fe77dfe0466 |
children |
line wrap: on
line diff
--- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -23,6 +24,7 @@ #include "../PrecompiledHeaders.h" #include "FilesystemStorage.h" +#include <boost/thread.hpp> // http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system // http://stackoverflow.com/questions/446358/storing-a-large-number-of-images @@ -122,8 +124,9 @@ size_t size, FileContentType type) { + Toolbox::ElapsedTimer timer; LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) - << "\" type (size: " << (size / (1024 * 1024) + 1) << "MB)"; + << "\" type"; boost::filesystem::path path; @@ -133,37 +136,69 @@ { // Extremely unlikely case: This Uuid has already been created // in the past. - throw OrthancException(ErrorCode_InternalError); + throw OrthancException(ErrorCode_InternalError, "This file UUID already exists"); } - if (boost::filesystem::exists(path.parent_path())) + // In very unlikely cases, a thread could be deleting a + // directory while another thread needs it -> introduce 3 retries at 1 ms interval + int retryCount = 0; + const int maxRetryCount = 3; + + while (retryCount < maxRetryCount) { - if (!boost::filesystem::is_directory(path.parent_path())) + retryCount++; + if (retryCount > 1) + { + boost::this_thread::sleep(boost::posix_time::milliseconds(2 * retryCount + (rand() % 10))); + LOG(INFO) << "Retrying to create attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) + << "\" type"; + } + + try + { + boost::filesystem::create_directories(path.parent_path()); // the function ensures that the directory exists or throws + } + catch (boost::filesystem::filesystem_error& er) { - throw OrthancException(ErrorCode_DirectoryOverFile); + if (er.code() == boost::system::errc::file_exists // the last element of the parent_path is a file + || er.code() == boost::system::errc::not_a_directory) // one of the element of the parent_path is not a directory + { + throw OrthancException(ErrorCode_DirectoryOverFile, "One of the element of the path is a file"); // no need to retry this error + } + + // ignore other errors and retry + } + + try + { + SystemToolbox::WriteFile(content, size, path.string(), fsyncOnWrite_); + + LOG(INFO) << "Created attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, size) << ")"; + return; + } + catch (OrthancException& ex) + { + if (retryCount >= maxRetryCount) + { + throw ex; + } } } - else - { - if (!boost::filesystem::create_directories(path.parent_path())) - { - throw OrthancException(ErrorCode_FileStorageCannotWrite); - } - } - - SystemToolbox::WriteFile(content, size, path.string(), fsyncOnWrite_); } IMemoryBuffer* FilesystemStorage::Read(const std::string& uuid, FileContentType type) { + Toolbox::ElapsedTimer timer; LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) << "\" content type"; std::string content; SystemToolbox::ReadFile(content, GetPath(uuid).string()); + LOG(INFO) << "Read attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, content.size()) << ")"; + return StringMemoryBuffer::CreateFromSwap(content); } @@ -173,6 +208,7 @@ uint64_t start /* inclusive */, uint64_t end /* exclusive */) { + Toolbox::ElapsedTimer timer; LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) << "\" content type (range from " << start << " to " << end << ")"; @@ -180,6 +216,7 @@ SystemToolbox::ReadFileRange( content, GetPath(uuid).string(), start, end, true /* throw if overflow */); + LOG(INFO) << "Read range of attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, content.size()) << ")"; return StringMemoryBuffer::CreateFromSwap(content); }