Mercurial > hg > orthanc
comparison OrthancServer/ServerIndex.cpp @ 278:771f12042be9
more efficient determination of storage size for recycling
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sun, 09 Dec 2012 21:51:57 +0100 |
parents | d384af918264 |
children | 4eea080e6e7a |
comparison
equal
deleted
inserted
replaced
277:58f969933720 | 278:771f12042be9 |
---|---|
58 ServerContext& context_; | 58 ServerContext& context_; |
59 bool hasRemainingLevel_; | 59 bool hasRemainingLevel_; |
60 ResourceType remainingType_; | 60 ResourceType remainingType_; |
61 std::string remainingPublicId_; | 61 std::string remainingPublicId_; |
62 std::list<std::string> pendingFilesToRemove_; | 62 std::list<std::string> pendingFilesToRemove_; |
63 uint64_t sizeOfFilesToRemove_; | |
63 | 64 |
64 public: | 65 public: |
65 ServerIndexListener(ServerContext& context) : | 66 ServerIndexListener(ServerContext& context) : |
66 context_(context), | 67 context_(context) |
67 hasRemainingLevel_(false) | 68 { |
68 { | 69 Reset(); |
69 assert(ResourceType_Patient < ResourceType_Study && | 70 assert(ResourceType_Patient < ResourceType_Study && |
70 ResourceType_Study < ResourceType_Series && | 71 ResourceType_Study < ResourceType_Series && |
71 ResourceType_Series < ResourceType_Instance); | 72 ResourceType_Series < ResourceType_Instance); |
72 } | 73 } |
73 | 74 |
74 void Reset() | 75 void Reset() |
75 { | 76 { |
77 sizeOfFilesToRemove_ = 0; | |
76 hasRemainingLevel_ = false; | 78 hasRemainingLevel_ = false; |
77 pendingFilesToRemove_.clear(); | 79 pendingFilesToRemove_.clear(); |
80 } | |
81 | |
82 uint64_t GetSizeOfFilesToRemove() | |
83 { | |
84 return sizeOfFilesToRemove_; | |
78 } | 85 } |
79 | 86 |
80 void CommitFilesToRemove() | 87 void CommitFilesToRemove() |
81 { | 88 { |
82 for (std::list<std::string>::iterator | 89 for (std::list<std::string>::iterator |
110 | 117 |
111 virtual void SignalFileDeleted(const FileInfo& info) | 118 virtual void SignalFileDeleted(const FileInfo& info) |
112 { | 119 { |
113 assert(Toolbox::IsUuid(info.GetUuid())); | 120 assert(Toolbox::IsUuid(info.GetUuid())); |
114 pendingFilesToRemove_.push_back(info.GetUuid()); | 121 pendingFilesToRemove_.push_back(info.GetUuid()); |
122 sizeOfFilesToRemove_ += info.GetCompressedSize(); | |
115 } | 123 } |
116 | 124 |
117 bool HasRemainingLevel() const | 125 bool HasRemainingLevel() const |
118 { | 126 { |
119 return hasRemainingLevel_; | 127 return hasRemainingLevel_; |
132 } | 140 } |
133 }; | 141 }; |
134 } | 142 } |
135 | 143 |
136 | 144 |
145 class ServerIndex::Transaction | |
146 { | |
147 private: | |
148 ServerIndex& index_; | |
149 std::auto_ptr<SQLite::Transaction> transaction_; | |
150 bool isCommitted_; | |
151 | |
152 public: | |
153 Transaction(ServerIndex& index) : | |
154 index_(index), | |
155 isCommitted_(false) | |
156 { | |
157 assert(index_.currentStorageSize_ == index_.db_->GetTotalCompressedSize()); | |
158 | |
159 index_.listener_->Reset(); | |
160 transaction_.reset(index_.db_->StartTransaction()); | |
161 transaction_->Begin(); | |
162 } | |
163 | |
164 void Commit(uint64_t sizeOfAddedFiles) | |
165 { | |
166 if (!isCommitted_) | |
167 { | |
168 transaction_->Commit(); | |
169 | |
170 // We can remove the files once the SQLite transaction has | |
171 // been successfully committed. Some files might have to be | |
172 // deleted because of recycling. | |
173 index_.listener_->CommitFilesToRemove(); | |
174 | |
175 index_.currentStorageSize_ += sizeOfAddedFiles; | |
176 | |
177 assert(index_.currentStorageSize_ >= index_.listener_->GetSizeOfFilesToRemove()); | |
178 index_.currentStorageSize_ -= index_.listener_->GetSizeOfFilesToRemove(); | |
179 | |
180 assert(index_.currentStorageSize_ == index_.db_->GetTotalCompressedSize()); | |
181 | |
182 isCommitted_ = true; | |
183 } | |
184 } | |
185 }; | |
186 | |
187 | |
137 bool ServerIndex::DeleteResource(Json::Value& target, | 188 bool ServerIndex::DeleteResource(Json::Value& target, |
138 const std::string& uuid, | 189 const std::string& uuid, |
139 ResourceType expectedType) | 190 ResourceType expectedType) |
140 { | 191 { |
141 boost::mutex::scoped_lock lock(mutex_); | 192 boost::mutex::scoped_lock lock(mutex_); |
142 listener_->Reset(); | 193 listener_->Reset(); |
143 | 194 |
144 std::auto_ptr<SQLite::Transaction> t(db_->StartTransaction()); | 195 Transaction t(*this); |
145 t->Begin(); | |
146 | 196 |
147 int64_t id; | 197 int64_t id; |
148 ResourceType type; | 198 ResourceType type; |
149 if (!db_->LookupResource(uuid, id, type) || | 199 if (!db_->LookupResource(uuid, id, type) || |
150 expectedType != type) | 200 expectedType != type) |
167 else | 217 else |
168 { | 218 { |
169 target["RemainingAncestor"] = Json::nullValue; | 219 target["RemainingAncestor"] = Json::nullValue; |
170 } | 220 } |
171 | 221 |
172 t->Commit(); | 222 t.Commit(0); |
173 | |
174 // We can remove the files once the SQLite transaction has been | |
175 // successfully committed | |
176 listener_->CommitFilesToRemove(); | |
177 | 223 |
178 return true; | 224 return true; |
179 } | 225 } |
180 | 226 |
181 | 227 |
218 } | 264 } |
219 | 265 |
220 db_.reset(new DatabaseWrapper(p.string() + "/index", *listener_)); | 266 db_.reset(new DatabaseWrapper(p.string() + "/index", *listener_)); |
221 } | 267 } |
222 | 268 |
269 currentStorageSize_ = db_->GetTotalCompressedSize(); | |
270 | |
223 // Initial recycling if the parameters have changed since the last | 271 // Initial recycling if the parameters have changed since the last |
224 // execution of Orthanc | 272 // execution of Orthanc |
225 StandaloneRecycling(); | 273 StandaloneRecycling(); |
226 | 274 |
227 unsigned int sleep; | 275 unsigned int sleep; |
257 | 305 |
258 DicomInstanceHasher hasher(dicomSummary); | 306 DicomInstanceHasher hasher(dicomSummary); |
259 | 307 |
260 try | 308 try |
261 { | 309 { |
262 std::auto_ptr<SQLite::Transaction> t(db_->StartTransaction()); | 310 Transaction t(*this); |
263 t->Begin(); | |
264 | 311 |
265 int64_t patient, study, series, instance; | 312 int64_t patient, study, series, instance; |
266 ResourceType type; | 313 ResourceType type; |
267 bool isNewSeries = false; | 314 bool isNewSeries = false; |
268 | 315 |
367 if (seriesStatus == SeriesStatus_Complete) | 414 if (seriesStatus == SeriesStatus_Complete) |
368 { | 415 { |
369 db_->LogChange(ChangeType_CompletedSeries, series, ResourceType_Series); | 416 db_->LogChange(ChangeType_CompletedSeries, series, ResourceType_Series); |
370 } | 417 } |
371 | 418 |
372 t->Commit(); | 419 t.Commit(instanceSize); |
373 | |
374 // We can remove the files once the SQLite transaction has been | |
375 // successfully committed. Some files might have to be deleted | |
376 // because of recycling. | |
377 listener_->CommitFilesToRemove(); | |
378 | 420 |
379 return StoreStatus_Success; | 421 return StoreStatus_Success; |
380 } | 422 } |
381 catch (OrthancException& e) | 423 catch (OrthancException& e) |
382 { | 424 { |
393 static const uint64_t MB = 1024 * 1024; | 435 static const uint64_t MB = 1024 * 1024; |
394 | 436 |
395 boost::mutex::scoped_lock lock(mutex_); | 437 boost::mutex::scoped_lock lock(mutex_); |
396 target = Json::objectValue; | 438 target = Json::objectValue; |
397 | 439 |
398 uint64_t cs = db_->GetTotalCompressedSize(); | 440 uint64_t cs = currentStorageSize_; |
441 assert(cs == db_->GetTotalCompressedSize()); | |
399 uint64_t us = db_->GetTotalUncompressedSize(); | 442 uint64_t us = db_->GetTotalUncompressedSize(); |
400 target["TotalDiskSpace"] = boost::lexical_cast<std::string>(cs); | 443 target["TotalDiskSpace"] = boost::lexical_cast<std::string>(cs); |
401 target["TotalUncompressedSize"] = boost::lexical_cast<std::string>(us); | 444 target["TotalUncompressedSize"] = boost::lexical_cast<std::string>(us); |
402 target["TotalDiskSpaceMB"] = boost::lexical_cast<unsigned int>(cs / MB); | 445 target["TotalDiskSpaceMB"] = boost::lexical_cast<unsigned int>(cs / MB); |
403 target["TotalUncompressedSizeMB"] = boost::lexical_cast<unsigned int>(us / MB); | 446 target["TotalUncompressedSizeMB"] = boost::lexical_cast<unsigned int>(us / MB); |
766 | 809 |
767 bool ServerIndex::IsRecyclingNeeded(uint64_t instanceSize) | 810 bool ServerIndex::IsRecyclingNeeded(uint64_t instanceSize) |
768 { | 811 { |
769 if (maximumStorageSize_ != 0) | 812 if (maximumStorageSize_ != 0) |
770 { | 813 { |
771 uint64_t currentSize = db_->GetTotalCompressedSize(); | 814 uint64_t currentSize = currentStorageSize_ - listener_->GetSizeOfFilesToRemove(); |
815 assert(db_->GetTotalCompressedSize() == currentSize); | |
816 | |
772 if (currentSize + instanceSize > maximumStorageSize_) | 817 if (currentSize + instanceSize > maximumStorageSize_) |
773 { | 818 { |
774 return true; | 819 return true; |
775 } | 820 } |
776 } | 821 } |
869 } | 914 } |
870 | 915 |
871 void ServerIndex::StandaloneRecycling() | 916 void ServerIndex::StandaloneRecycling() |
872 { | 917 { |
873 // WARNING: No mutex here, do not include this as a public method | 918 // WARNING: No mutex here, do not include this as a public method |
874 std::auto_ptr<SQLite::Transaction> t(db_->StartTransaction()); | 919 Transaction t(*this); |
875 t->Begin(); | |
876 Recycle(0, ""); | 920 Recycle(0, ""); |
877 t->Commit(); | 921 t.Commit(0); |
878 listener_->CommitFilesToRemove(); | |
879 } | 922 } |
880 | 923 |
881 | 924 |
882 bool ServerIndex::IsProtectedPatient(const std::string& publicId) | 925 bool ServerIndex::IsProtectedPatient(const std::string& publicId) |
883 { | 926 { |