# HG changeset patch # User Sebastien Jodogne # Date 1548945207 -3600 # Node ID 6fd38327e777f4e5a9f658362f5c7b3f0f3f02c1 # Parent 07a2f637b76d74ab295103edc7d61b1abe1e20c1 Fix issue #130 (Orthanc failed to start when /tmp partition was full) diff -r 07a2f637b76d -r 6fd38327e777 Core/Compression/ZipWriter.cpp --- a/Core/Compression/ZipWriter.cpp Wed Jan 30 17:50:51 2019 +0100 +++ b/Core/Compression/ZipWriter.cpp Thu Jan 31 15:33:27 2019 +0100 @@ -148,6 +148,7 @@ if (!pimpl_->file_) { + LOG(ERROR) << "Cannot create new ZIP archive: " << path_; throw OrthancException(ErrorCode_CannotWriteFile); } } @@ -169,7 +170,8 @@ if (level >= 10) { throw OrthancException(ErrorCode_ParameterOutOfRange, - "ZIP compression level must be between 0 (no compression) and 9 (highest compression)"); + "ZIP compression level must be between 0 (no compression) " + "and 9 (highest compression)"); } Close(); @@ -208,6 +210,7 @@ if (result != 0) { + LOG(ERROR) << "Cannot add new file inside ZIP archive: " << path; throw OrthancException(ErrorCode_CannotWriteFile); } @@ -239,6 +242,7 @@ if (zipWriteInFileInZip(pimpl_->file_, data, bytes)) { + LOG(ERROR) << "Cannot write data to ZIP archive: " << path_; throw OrthancException(ErrorCode_CannotWriteFile); } @@ -253,6 +257,4 @@ Close(); append_ = append; } - - } diff -r 07a2f637b76d -r 6fd38327e777 Core/TemporaryFile.cpp --- a/Core/TemporaryFile.cpp Wed Jan 30 17:50:51 2019 +0100 +++ b/Core/TemporaryFile.cpp Thu Jan 31 15:33:27 2019 +0100 @@ -34,6 +34,7 @@ #include "PrecompiledHeaders.h" #include "TemporaryFile.h" +#include "OrthancException.h" #include "SystemToolbox.h" #include "Toolbox.h" @@ -41,15 +42,25 @@ namespace Orthanc { - static std::string CreateTemporaryPath(const char* extension) + static std::string CreateTemporaryPath(const char* temporaryDirectory, + const char* extension) { + boost::filesystem::path dir; + + if (temporaryDirectory == NULL) + { #if BOOST_HAS_FILESYSTEM_V3 == 1 - boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path(); + dir = boost::filesystem::temp_directory_path(); #elif defined(__linux__) - boost::filesystem::path tmpDir("/tmp"); + dir = "/tmp"; #else -#error Support your platform here +# error Support your platform here #endif + } + else + { + dir = temporaryDirectory; + } // We use UUID to create unique path to temporary files std::string filename = "Orthanc-" + Orthanc::Toolbox::GenerateUuid(); @@ -59,19 +70,20 @@ filename.append(extension); } - tmpDir /= filename; - return tmpDir.string(); + dir /= filename; + return dir.string(); } TemporaryFile::TemporaryFile() : - path_(CreateTemporaryPath(NULL)) + path_(CreateTemporaryPath(NULL, NULL)) { } - TemporaryFile::TemporaryFile(const char* extension) : - path_(CreateTemporaryPath(extension)) + TemporaryFile::TemporaryFile(const std::string& temporaryDirectory, + const std::string& extension) : + path_(CreateTemporaryPath(temporaryDirectory.c_str(), extension.c_str())) { } @@ -84,12 +96,39 @@ void TemporaryFile::Write(const std::string& content) { - SystemToolbox::WriteFile(content, path_); + try + { + SystemToolbox::WriteFile(content, path_); + } + catch (OrthancException&) + { + LOG(ERROR) << "Can't create temporary file \"" << path_ + << "\" with " << content.size() + << " bytes: Check you have write access to the " + << "temporary directory and that it is not full"; + throw; + } } void TemporaryFile::Read(std::string& content) const { - SystemToolbox::ReadFile(content, path_); + try + { + SystemToolbox::ReadFile(content, path_); + } + catch (OrthancException&) + { + LOG(ERROR) << "Can't read temporary file \"" << path_ + << "\": Another process has corrupted the temporary directory"; + throw; + } + } + + + void TemporaryFile::Touch() + { + std::string empty; + Write(empty); } } diff -r 07a2f637b76d -r 6fd38327e777 Core/TemporaryFile.h --- a/Core/TemporaryFile.h Wed Jan 30 17:50:51 2019 +0100 +++ b/Core/TemporaryFile.h Thu Jan 31 15:33:27 2019 +0100 @@ -53,7 +53,8 @@ public: TemporaryFile(); - TemporaryFile(const char* extension); + TemporaryFile(const std::string& temporaryFolder, + const std::string& extension); ~TemporaryFile(); @@ -65,5 +66,7 @@ void Write(const std::string& content); void Read(std::string& content) const; + + void Touch(); }; } diff -r 07a2f637b76d -r 6fd38327e777 NEWS --- a/NEWS Wed Jan 30 17:50:51 2019 +0100 +++ b/NEWS Thu Jan 31 15:33:27 2019 +0100 @@ -5,8 +5,9 @@ ------- * New configuration options: - - "MetricsEnabled" to track the metrics of Orthanc + - "MetricsEnabled" to enable the tracking of the metrics of Orthanc - "HttpThreadsCount" to set the number of threads in the embedded HTTP server + - "TemporaryDirectory" to set the folder containing the temporary files REST API -------- @@ -24,6 +25,7 @@ ----------- * Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()") +* Fix issue #130 (Orthanc failed to start when /tmp partition was full) Version 1.5.3 (2019-01-25) diff -r 07a2f637b76d -r 6fd38327e777 OrthancServer/OrthancConfiguration.cpp --- a/OrthancServer/OrthancConfiguration.cpp Wed Jan 30 17:50:51 2019 +0100 +++ b/OrthancServer/OrthancConfiguration.cpp Thu Jan 31 15:33:27 2019 +0100 @@ -38,6 +38,7 @@ #include "../Core/Logging.h" #include "../Core/OrthancException.h" #include "../Core/SystemToolbox.h" +#include "../Core/TemporaryFile.h" #include "../Core/Toolbox.h" #include "ServerIndex.h" @@ -47,6 +48,7 @@ static const char* const DICOM_MODALITIES_IN_DB = "DicomModalitiesInDatabase"; static const char* const ORTHANC_PEERS = "OrthancPeers"; static const char* const ORTHANC_PEERS_IN_DB = "OrthancPeersInDatabase"; +static const char* const TEMPORARY_DIRECTORY = "TemporaryDirectory"; namespace Orthanc { @@ -826,4 +828,17 @@ { serverIndex_ = NULL; } + + + TemporaryFile* OrthancConfiguration::CreateTemporaryFile() const + { + if (json_.isMember(TEMPORARY_DIRECTORY)) + { + return new TemporaryFile(GetStringParameter(TEMPORARY_DIRECTORY, ""), ""); + } + else + { + return new TemporaryFile; + } + } } diff -r 07a2f637b76d -r 6fd38327e777 OrthancServer/OrthancConfiguration.h --- a/OrthancServer/OrthancConfiguration.h Wed Jan 30 17:50:51 2019 +0100 +++ b/OrthancServer/OrthancConfiguration.h Thu Jan 31 15:33:27 2019 +0100 @@ -47,6 +47,7 @@ { class HttpServer; class ServerIndex; + class TemporaryFile; class OrthancConfiguration : public boost::noncopyable { @@ -224,5 +225,7 @@ void SetServerIndex(ServerIndex& index); void ResetServerIndex(); + + TemporaryFile* CreateTemporaryFile() const; }; } diff -r 07a2f637b76d -r 6fd38327e777 OrthancServer/OrthancRestApi/OrthancRestArchive.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp Wed Jan 30 17:50:51 2019 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp Thu Jan 31 15:33:27 2019 +0100 @@ -37,6 +37,7 @@ #include "../../Core/HttpServer/FilesystemHttpSender.h" #include "../../Core/OrthancException.h" #include "../../Core/SerializationToolbox.h" +#include "../OrthancConfiguration.h" #include "../ServerContext.h" #include "../ServerJobs/ArchiveJob.h" @@ -136,7 +137,13 @@ if (synchronous) { - boost::shared_ptr tmp(new TemporaryFile); + boost::shared_ptr tmp; + + { + OrthancConfiguration::ReaderLock lock; + tmp.reset(lock.GetConfiguration().CreateTemporaryFile()); + } + job->SetSynchronousTarget(tmp); Json::Value publicContent; diff -r 07a2f637b76d -r 6fd38327e777 OrthancServer/ServerJobs/ArchiveJob.cpp --- a/OrthancServer/ServerJobs/ArchiveJob.cpp Wed Jan 30 17:50:51 2019 +0100 +++ b/OrthancServer/ServerJobs/ArchiveJob.cpp Thu Jan 31 15:33:27 2019 +0100 @@ -39,6 +39,7 @@ #include "../../Core/DicomParsing/DicomDirWriter.h" #include "../../Core/Logging.h" #include "../../Core/OrthancException.h" +#include "../OrthancConfiguration.h" #include "../ServerContext.h" #include @@ -867,13 +868,20 @@ if (synchronousTarget_.get() == NULL) { - asynchronousTarget_.reset(new TemporaryFile); + { + OrthancConfiguration::ReaderLock lock; + asynchronousTarget_.reset(lock.GetConfiguration().CreateTemporaryFile()); + } + target = asynchronousTarget_.get(); } else { target = synchronousTarget_.get(); } + + assert(target != NULL); + target->Touch(); // Make sure we can write to the temporary file if (writer_.get() != NULL) { diff -r 07a2f637b76d -r 6fd38327e777 OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp --- a/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp Wed Jan 30 17:50:51 2019 +0100 +++ b/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp Thu Jan 31 15:33:27 2019 +0100 @@ -43,6 +43,7 @@ #include "../../../Core/TemporaryFile.h" #include "../../../Core/Toolbox.h" #include "../../../Core/SystemToolbox.h" +#include "../../OrthancConfiguration.h" namespace Orthanc { @@ -92,7 +93,11 @@ std::string dicom; instance.ReadDicom(dicom); - tmp.reset(new TemporaryFile); + { + OrthancConfiguration::ReaderLock lock; + tmp.reset(lock.GetConfiguration().CreateTemporaryFile()); + } + tmp->Write(dicom); arguments.push_back(tmp->GetPath()); diff -r 07a2f637b76d -r 6fd38327e777 Resources/Configuration.json --- a/Resources/Configuration.json Wed Jan 30 17:50:51 2019 +0100 +++ b/Resources/Configuration.json Thu Jan 31 15:33:27 2019 +0100 @@ -17,6 +17,16 @@ // a RAM-drive or a SSD device for performance reasons. "IndexDirectory" : "OrthancStorage", + // Path to the directory where Orthanc stores its large temporary + // files. The corresponding filesystem must be properly sized, given + // that for instance a ZIP archive of DICOM images created by a job + // can weight several GBs, and that there might be up to + // "JobsHistorySize" archives to be stored simultaneously. If not + // set, Orthanc will use the default temporary folder of the + // operating system (such as "/tmp/" on UNIX-like systems, or + // "C:/Temp" on Microsoft Windows). + // "TemporaryDirectory" : "/tmp/Orthanc/", + // Enable the transparent compression of the DICOM instances "StorageCompression" : false, diff -r 07a2f637b76d -r 6fd38327e777 UnitTestsSources/ImageTests.cpp --- a/UnitTestsSources/ImageTests.cpp Wed Jan 30 17:50:51 2019 +0100 +++ b/UnitTestsSources/ImageTests.cpp Thu Jan 31 15:33:27 2019 +0100 @@ -185,7 +185,7 @@ { Orthanc::TemporaryFile tmp; - Orthanc::SystemToolbox::WriteFile(s, tmp.GetPath()); + tmp.Write(s); Orthanc::PngReader r2; r2.ReadFromFile(tmp.GetPath()); @@ -411,7 +411,7 @@ { Orthanc::TemporaryFile tmp; - Orthanc::SystemToolbox::WriteFile(s, tmp.GetPath()); + tmp.Write(s); Orthanc::PamReader r2; r2.ReadFromFile(tmp.GetPath()); @@ -433,4 +433,3 @@ } } } -