changeset 147:70d1fe6d6309

Avoid hard crash if not enough memory
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 09 Nov 2016 12:43:58 +0100
parents 3cde3e806abe
children 4217644ac904
files Plugin/Cache/CacheManager.cpp Plugin/Cache/CacheManager.h Plugin/Cache/CacheScheduler.cpp Plugin/Cache/CacheScheduler.h Plugin/Plugin.cpp UnitTestsSources/UnitTestsMain.cpp
diffstat 6 files changed, 74 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/Plugin/Cache/CacheManager.cpp	Wed Nov 09 12:20:01 2016 +0100
+++ b/Plugin/Cache/CacheManager.cpp	Wed Nov 09 12:43:58 2016 +0100
@@ -126,6 +126,7 @@
 
   struct CacheManager::PImpl
   {
+    OrthancPluginContext* context_;
     Orthanc::SQLite::Connection& db_;
     Orthanc::FilesystemStorage& storage_;
 
@@ -134,8 +135,10 @@
     BundleQuota  defaultQuota_;
     BundleQuotas  quotas_;
 
-    PImpl(Orthanc::SQLite::Connection& db,
+    PImpl(OrthancPluginContext* context,
+          Orthanc::SQLite::Connection& db,
           Orthanc::FilesystemStorage& storage) :
+      context_(context),
       db_(db), 
       storage_(storage), 
       sanityCheck_(false)
@@ -278,15 +281,22 @@
 
 
 
-  CacheManager::CacheManager(Orthanc::SQLite::Connection& db,
+  CacheManager::CacheManager(OrthancPluginContext* context,
+                             Orthanc::SQLite::Connection& db,
                              Orthanc::FilesystemStorage& storage) :
-    pimpl_(new PImpl(db, storage))
+    pimpl_(new PImpl(context, db, storage))
   {
     Open();
     ReadBundleStatistics();
   }
 
 
+  OrthancPluginContext* CacheManager::GetPluginContext() const
+  {
+    return pimpl_->context_;
+  }
+
+
   void CacheManager::SetSanityCheckEnabled(bool enabled)
   {
     pimpl_->sanityCheck_ = enabled;
--- a/Plugin/Cache/CacheManager.h	Wed Nov 09 12:20:01 2016 +0100
+++ b/Plugin/Cache/CacheManager.h	Wed Nov 09 12:43:58 2016 +0100
@@ -23,6 +23,8 @@
 #include "../../Orthanc/Core/SQLite/Connection.h"
 #include "../../Orthanc/Core/FileStorage/FilesystemStorage.h"
 
+#include <orthanc/OrthancCPlugin.h>
+
 namespace OrthancPlugins
 {
   enum CacheProperty
@@ -69,9 +71,12 @@
 
 
   public:
-    CacheManager(Orthanc::SQLite::Connection& db,
+    CacheManager(OrthancPluginContext* context,
+                 Orthanc::SQLite::Connection& db,
                  Orthanc::FilesystemStorage& storage);
 
+    OrthancPluginContext* GetPluginContext() const;
+
     void SetSanityCheckEnabled(bool enabled);
 
     void Clear();
--- a/Plugin/Cache/CacheScheduler.cpp	Wed Nov 09 12:20:01 2016 +0100
+++ b/Plugin/Cache/CacheScheduler.cpp	Wed Nov 09 12:43:58 2016 +0100
@@ -112,52 +112,65 @@
       {
         std::auto_ptr<DynamicString> prefetch(that->queue_.Dequeue(500));
 
-        if (prefetch.get() != NULL)
+        try
         {
+          if (prefetch.get() != NULL)
           {
-            boost::mutex::scoped_lock lock(that->invalidatedMutex_);
-            that->invalidated_ = false;
-            that->prefetching_ = prefetch->GetValue();
-          }
+            {
+              boost::mutex::scoped_lock lock(that->invalidatedMutex_);
+              that->invalidated_ = false;
+              that->prefetching_ = prefetch->GetValue();
+            }
+
+            {
+              boost::mutex::scoped_lock lock(that->cacheMutex_);
+              if (that->cache_.IsCached(that->bundleIndex_, prefetch->GetValue()))
+              {
+                // This item is already cached
+                continue;
+              }
+            }
+
+            std::string content;
 
-          {
-            boost::mutex::scoped_lock lock(that->cacheMutex_);
-            if (that->cache_.IsCached(that->bundleIndex_, prefetch->GetValue()))
+            try
+            {
+              if (!that->factory_.Create(content, prefetch->GetValue()))
+              {
+                // The factory cannot generate this item
+                continue;
+              }
+            }
+            catch (...)
             {
-              // This item is already cached
+              // Exception
               continue;
             }
+
+            {
+              boost::mutex::scoped_lock lock(that->invalidatedMutex_);
+              if (that->invalidated_)
+              {
+                // This item has been invalidated
+                continue;
+              }
+              
+              {
+                boost::mutex::scoped_lock lock2(that->cacheMutex_);
+                that->cache_.Store(that->bundleIndex_, prefetch->GetValue(), content);
+              }
+            }
           }
-
-          std::string content;
-
-          try
-          {
-            if (!that->factory_.Create(content, prefetch->GetValue()))
-            {
-              // The factory cannot generate this item
-              continue;
-            }
-          }
-          catch (...)
-          {
-            // Exception
-            continue;
-          }
-
-          {
-            boost::mutex::scoped_lock lock(that->invalidatedMutex_);
-            if (that->invalidated_)
-            {
-              // This item has been invalidated
-              continue;
-            }
-              
-            {
-              boost::mutex::scoped_lock lock2(that->cacheMutex_);
-              that->cache_.Store(that->bundleIndex_, prefetch->GetValue(), content);
-            }
-          }
+        }
+        catch (std::bad_alloc&)
+        {
+          OrthancPluginLogError(that->cache_.GetPluginContext(), 
+                                "Not enough memory for the prefetcher of the Web viewer to work");
+        }
+        catch (...)
+        {
+          OrthancPluginLogError(that->cache_.GetPluginContext(), 
+                                "Unhandled native exception inside the prefetcher of the Web viewer");
         }
       }
     }
--- a/Plugin/Cache/CacheScheduler.h	Wed Nov 09 12:20:01 2016 +0100
+++ b/Plugin/Cache/CacheScheduler.h	Wed Nov 09 12:43:58 2016 +0100
@@ -39,8 +39,7 @@
 
     typedef std::map<int, BundleScheduler*>  BundleSchedulers;
 
-    size_t   maxPrefetchSize_;
-
+    size_t                          maxPrefetchSize_;
     boost::mutex                    cacheMutex_;
     boost::mutex                    factoryMutex_;
     boost::recursive_mutex          policyMutex_;
--- a/Plugin/Plugin.cpp	Wed Nov 09 12:20:01 2016 +0100
+++ b/Plugin/Plugin.cpp	Wed Nov 09 12:43:58 2016 +0100
@@ -96,7 +96,7 @@
     boost::filesystem::path p(path);
     db_.Open((p / "cache.db").string());
 
-    cache_.reset(new OrthancPlugins::CacheManager(db_, storage_));
+    cache_.reset(new OrthancPlugins::CacheManager(context_, db_, storage_));
     //cache_->SetSanityCheckEnabled(true);  // For debug
 
     scheduler_.reset(new OrthancPlugins::CacheScheduler(*cache_, 100));
--- a/UnitTestsSources/UnitTestsMain.cpp	Wed Nov 09 12:20:01 2016 +0100
+++ b/UnitTestsSources/UnitTestsMain.cpp	Wed Nov 09 12:43:58 2016 +0100
@@ -51,7 +51,7 @@
     db_.reset(new Orthanc::SQLite::Connection());
     db_->Open("UnitTestsResults/cache.db");
 
-    cache_.reset(new CacheManager(*db_, *storage_));
+    cache_.reset(new CacheManager(NULL, *db_, *storage_));
     cache_->SetSanityCheckEnabled(true);
   }