comparison Plugin/Plugin.cpp @ 75:e15a59a4b4d4

Fix possible deadlock with other plugins in OnChangeCallback()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 23 Sep 2015 13:33:07 +0200
parents ab5218c18b7a
children abdde1dfb3eb
comparison
equal deleted inserted replaced
74:ab5218c18b7a 75:e15a59a4b4d4
40 # define RETURN_SUCCESS 0 40 # define RETURN_SUCCESS 0
41 # define RETURN_FAILURE -1 41 # define RETURN_FAILURE -1
42 #endif 42 #endif
43 43
44 44
45 static OrthancPluginContext* context_ = NULL;
46
47
48
45 class CacheContext 49 class CacheContext
46 { 50 {
47 private: 51 private:
52 class DynamicString : public Orthanc::IDynamicObject
53 {
54 private:
55 std::string value_;
56
57 public:
58 DynamicString(const char* value) : value_(value)
59 {
60 }
61
62 const std::string& GetValue() const
63 {
64 return value_;
65 }
66 };
67
48 Orthanc::FilesystemStorage storage_; 68 Orthanc::FilesystemStorage storage_;
49 Orthanc::SQLite::Connection db_; 69 Orthanc::SQLite::Connection db_;
50 70
51 std::auto_ptr<OrthancPlugins::CacheManager> cache_; 71 std::auto_ptr<OrthancPlugins::CacheManager> cache_;
52 std::auto_ptr<OrthancPlugins::CacheScheduler> scheduler_; 72 std::auto_ptr<OrthancPlugins::CacheScheduler> scheduler_;
53 73
74 Orthanc::SharedMessageQueue newInstances_;
75 bool stop_;
76 boost::thread newInstancesThread_;
77
78
79 static void NewInstancesThread(CacheContext* cache)
80 {
81 while (!cache->stop_)
82 {
83 std::auto_ptr<Orthanc::IDynamicObject> obj(cache->newInstances_.Dequeue(100));
84 if (obj.get() != NULL)
85 {
86 const std::string& instanceId = dynamic_cast<DynamicString&>(*obj).GetValue();
87 printf("[%s]\n", instanceId.c_str());
88
89 // On the reception of a new instance, precompute its spatial position
90 cache->GetScheduler().Prefetch(OrthancPlugins::CacheBundle_InstanceInformation, instanceId);
91
92 // Indalidate the parent series of the instance
93 std::string uri = "/instances/" + std::string(instanceId);
94 Json::Value instance;
95 if (OrthancPlugins::GetJsonFromOrthanc(instance, context_, uri))
96 {
97 std::string seriesId = instance["ParentSeries"].asString();
98 cache->GetScheduler().Invalidate(OrthancPlugins::CacheBundle_SeriesInformation, seriesId);
99 }
100 }
101 }
102 }
103
104
54 public: 105 public:
55 CacheContext(const std::string& path) : storage_(path) 106 CacheContext(const std::string& path) : storage_(path), stop_(false)
56 { 107 {
57 boost::filesystem::path p(path); 108 boost::filesystem::path p(path);
58 db_.Open((p / "cache.db").string()); 109 db_.Open((p / "cache.db").string());
59 110
60 cache_.reset(new OrthancPlugins::CacheManager(db_, storage_)); 111 cache_.reset(new OrthancPlugins::CacheManager(db_, storage_));
61 //cache_->SetSanityCheckEnabled(true); // For debug 112 //cache_->SetSanityCheckEnabled(true); // For debug
62 113
63 scheduler_.reset(new OrthancPlugins::CacheScheduler(*cache_, 100)); 114 scheduler_.reset(new OrthancPlugins::CacheScheduler(*cache_, 100));
115
116 newInstancesThread_ = boost::thread(NewInstancesThread, this);
64 } 117 }
65 118
66 ~CacheContext() 119 ~CacheContext()
67 { 120 {
121 stop_ = true;
122 if (newInstancesThread_.joinable())
123 {
124 newInstancesThread_.join();
125 }
126
68 scheduler_.reset(NULL); 127 scheduler_.reset(NULL);
69 cache_.reset(NULL); 128 cache_.reset(NULL);
70 } 129 }
71 130
72 OrthancPlugins::CacheScheduler& GetScheduler() 131 OrthancPlugins::CacheScheduler& GetScheduler()
73 { 132 {
74 return *scheduler_; 133 return *scheduler_;
75 } 134 }
135
136 void SignalNewInstance(const char* instanceId)
137 {
138 newInstances_.Enqueue(new DynamicString(instanceId));
139 }
76 }; 140 };
77 141
78 142
79 static OrthancPluginContext* context_ = NULL; 143
80 static CacheContext* cache_ = NULL; 144 static CacheContext* cache_ = NULL;
81 145
82 146
83 147
84 static RETURN_TYPE OnChangeCallback(OrthancPluginChangeType changeType, 148 static RETURN_TYPE OnChangeCallback(OrthancPluginChangeType changeType,
88 try 152 try
89 { 153 {
90 if (changeType == OrthancPluginChangeType_NewInstance && 154 if (changeType == OrthancPluginChangeType_NewInstance &&
91 resourceType == OrthancPluginResourceType_Instance) 155 resourceType == OrthancPluginResourceType_Instance)
92 { 156 {
93 // On the reception of a new instance, precompute its spatial position 157 cache_->SignalNewInstance(resourceId);
94 cache_->GetScheduler().Prefetch(OrthancPlugins::CacheBundle_InstanceInformation, resourceId);
95
96 // Indalidate the parent series of the instance
97 std::string uri = "/instances/" + std::string(resourceId);
98 Json::Value instance;
99 if (OrthancPlugins::GetJsonFromOrthanc(instance, context_, uri))
100 {
101 std::string seriesId = instance["ParentSeries"].asString();
102 cache_->GetScheduler().Invalidate(OrthancPlugins::CacheBundle_SeriesInformation, seriesId);
103 }
104 } 158 }
105 159
106 return RETURN_SUCCESS; 160 return RETURN_SUCCESS;
107 } 161 }
108 catch (std::runtime_error& e) 162 catch (std::runtime_error& e)