changeset 3186:92bbc5274220

merge
author Alain Mazy <alain@mazy.be>
date Fri, 01 Feb 2019 17:54:06 +0100
parents c6dab987f43a (current diff) 5d1f5984dc41 (diff)
children 70356580e310
files
diffstat 12 files changed, 124 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Compression/ZipWriter.cpp	Fri Feb 01 17:53:40 2019 +0100
+++ b/Core/Compression/ZipWriter.cpp	Fri Feb 01 17:54:06 2019 +0100
@@ -148,7 +148,8 @@
 
     if (!pimpl_->file_)
     {
-      throw OrthancException(ErrorCode_CannotWriteFile);
+      throw OrthancException(ErrorCode_CannotWriteFile,
+                             "Cannot create new ZIP archive: " + path_);
     }
   }
 
@@ -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,7 +210,8 @@
 
     if (result != 0)
     {
-      throw OrthancException(ErrorCode_CannotWriteFile);
+      throw OrthancException(ErrorCode_CannotWriteFile,
+                             "Cannot add new file inside ZIP archive: " + std::string(path));
     }
 
     hasFileInZip_ = true;
@@ -239,7 +242,8 @@
 
       if (zipWriteInFileInZip(pimpl_->file_, data, bytes))
       {
-        throw OrthancException(ErrorCode_CannotWriteFile);
+        throw OrthancException(ErrorCode_CannotWriteFile,
+                               "Cannot write data to ZIP archive: " + path_);
       }
       
       data += bytes;
@@ -253,6 +257,4 @@
     Close();
     append_ = append;
   }
-    
-
 }
--- a/Core/TemporaryFile.cpp	Fri Feb 01 17:53:40 2019 +0100
+++ b/Core/TemporaryFile.cpp	Fri Feb 01 17:54:06 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& e)
+    {
+      throw OrthancException(e.GetErrorCode(),
+                             "Can't create temporary file \"" + path_ +
+                             "\" with " + boost::lexical_cast<std::string>(content.size()) +
+                             " bytes: Check you have write access to the "
+                             "temporary directory and that it is not full");
+    }
   }
 
 
   void TemporaryFile::Read(std::string& content) const
   {
-    SystemToolbox::ReadFile(content, path_);
+    try
+    {
+      SystemToolbox::ReadFile(content, path_);
+    }
+    catch (OrthancException& e)
+    {
+      throw OrthancException(e.GetErrorCode(),
+                             "Can't read temporary file \"" + path_ +
+                             "\": Another process has corrupted the temporary directory");
+    }
+  }
+
+
+  void TemporaryFile::Touch()
+  {
+    std::string empty;
+    Write(empty);
   }
 }
--- a/Core/TemporaryFile.h	Fri Feb 01 17:53:40 2019 +0100
+++ b/Core/TemporaryFile.h	Fri Feb 01 17:54:06 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();
   };
 }
--- a/NEWS	Fri Feb 01 17:53:40 2019 +0100
+++ b/NEWS	Fri Feb 01 17:54:06 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
 --------
@@ -18,12 +19,14 @@
 Plugins
 -------
 
-* New primitives to set and refresh metrics
+* New primitives in the plugin SDK to set and refresh metrics
 
 Maintenance
 -----------
 
+* Fix regression if calling "/tools/find" with the tag "ModalitiesInStudy"
 * 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)
--- a/OrthancServer/OrthancConfiguration.cpp	Fri Feb 01 17:53:40 2019 +0100
+++ b/OrthancServer/OrthancConfiguration.cpp	Fri Feb 01 17:54:06 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(InterpretStringParameterAsPath(GetStringParameter(TEMPORARY_DIRECTORY, ".")), "");
+    }
+    else
+    {
+      return new TemporaryFile;
+    }
+  }
 }
--- a/OrthancServer/OrthancConfiguration.h	Fri Feb 01 17:53:40 2019 +0100
+++ b/OrthancServer/OrthancConfiguration.h	Fri Feb 01 17:54:06 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;
   };
 }
--- a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp	Fri Feb 01 17:53:40 2019 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp	Fri Feb 01 17:54:06 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<TemporaryFile> tmp(new TemporaryFile);
+      boost::shared_ptr<TemporaryFile> tmp;
+
+      {
+        OrthancConfiguration::ReaderLock lock;
+        tmp.reset(lock.GetConfiguration().CreateTemporaryFile());
+      }
+
       job->SetSynchronousTarget(tmp);
     
       Json::Value publicContent;
--- a/OrthancServer/Search/DatabaseLookup.cpp	Fri Feb 01 17:53:40 2019 +0100
+++ b/OrthancServer/Search/DatabaseLookup.cpp	Fri Feb 01 17:54:06 2019 +0100
@@ -172,7 +172,8 @@
                       (tag, ConstraintType_SmallerOrEqual, upper, caseSensitive, mandatoryTag));
       }
     }
-    else if (dicomQuery.find('\\') != std::string::npos)
+    else if (tag == DICOM_TAG_MODALITIES_IN_STUDY ||
+             dicomQuery.find('\\') != std::string::npos)
     {
       DicomTag fixedTag(tag);
 
--- a/OrthancServer/ServerJobs/ArchiveJob.cpp	Fri Feb 01 17:53:40 2019 +0100
+++ b/OrthancServer/ServerJobs/ArchiveJob.cpp	Fri Feb 01 17:54:06 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 <stdio.h>
@@ -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)
     {
--- a/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp	Fri Feb 01 17:53:40 2019 +0100
+++ b/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp	Fri Feb 01 17:54:06 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());
--- a/Resources/Configuration.json	Fri Feb 01 17:53:40 2019 +0100
+++ b/Resources/Configuration.json	Fri Feb 01 17:54:06 2019 +0100
@@ -17,6 +17,18 @@
   // a RAM-drive or a SSD device for performance reasons.
   "IndexDirectory" : "OrthancStorage",
 
+  // Path to the directory where Orthanc stores its large temporary
+  // files. The content of this folder can be safely deleted if
+  // Orthanc once stopped. The folder must exist. 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 "min(JobsHistorySize,
+  // MediaArchiveSize)" 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,
 
--- a/UnitTestsSources/ImageTests.cpp	Fri Feb 01 17:53:40 2019 +0100
+++ b/UnitTestsSources/ImageTests.cpp	Fri Feb 01 17:54:06 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 @@
     }
   }
 }
-