1 /** 2 * Orthanc - A Lightweight, RESTful DICOM Store 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 4 * Department, University Hospital of Liege, Belgium 5 * Copyright (C) 2017-2021 Osimis S.A., Belgium 6 * 7 * This program is free software: you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public License 9 * as published by the Free Software Foundation, either version 3 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this program. If not, see 19 * <http://www.gnu.org/licenses/>. 20 **/ 21 22 23 #include "../PrecompiledHeaders.h" 24 #include "ParsedDicomCache.h" 25 26 #include "../OrthancException.h" 27 28 namespace Orthanc 29 { 30 class ParsedDicomCache::Item : public ICacheable 31 { 32 private: 33 std::unique_ptr<ParsedDicomFile> dicom_; 34 size_t fileSize_; 35 36 public: Item(ParsedDicomFile * dicom,size_t fileSize)37 Item(ParsedDicomFile* dicom, 38 size_t fileSize) : 39 dicom_(dicom), 40 fileSize_(fileSize) 41 { 42 if (dicom == NULL) 43 { 44 throw OrthancException(ErrorCode_NullPointer); 45 } 46 } 47 GetMemoryUsage() const48 virtual size_t GetMemoryUsage() const ORTHANC_OVERRIDE 49 { 50 return fileSize_; 51 } 52 GetDicom() const53 ParsedDicomFile& GetDicom() const 54 { 55 assert(dicom_.get() != NULL); 56 return *dicom_; 57 } 58 }; 59 60 ParsedDicomCache(size_t size)61 ParsedDicomCache::ParsedDicomCache(size_t size) : 62 cacheSize_(size), 63 largeSize_(0) 64 { 65 if (size == 0) 66 { 67 throw OrthancException(ErrorCode_ParameterOutOfRange); 68 } 69 } 70 71 GetNumberOfItems()72 size_t ParsedDicomCache::GetNumberOfItems() 73 { 74 #if !defined(__EMSCRIPTEN__) 75 boost::mutex::scoped_lock lock(mutex_); 76 #endif 77 78 if (cache_.get() == NULL) 79 { 80 return (largeDicom_.get() == NULL ? 0 : 1); 81 } 82 else 83 { 84 assert(largeDicom_.get() == NULL); 85 assert(largeSize_ == 0); 86 return cache_->GetNumberOfItems(); 87 } 88 } 89 90 GetCurrentSize()91 size_t ParsedDicomCache::GetCurrentSize() 92 { 93 #if !defined(__EMSCRIPTEN__) 94 boost::mutex::scoped_lock lock(mutex_); 95 #endif 96 97 if (cache_.get() == NULL) 98 { 99 return largeSize_; 100 } 101 else 102 { 103 assert(largeDicom_.get() == NULL); 104 assert(largeSize_ == 0); 105 return cache_->GetCurrentSize(); 106 } 107 } 108 109 Invalidate(const std::string & id)110 void ParsedDicomCache::Invalidate(const std::string& id) 111 { 112 #if !defined(__EMSCRIPTEN__) 113 boost::mutex::scoped_lock lock(mutex_); 114 #endif 115 116 if (cache_.get() != NULL) 117 { 118 cache_->Invalidate(id); 119 } 120 121 if (largeId_ == id) 122 { 123 largeDicom_.reset(NULL); 124 largeSize_ = 0; 125 } 126 } 127 128 Acquire(const std::string & id,ParsedDicomFile * dicom,size_t fileSize)129 void ParsedDicomCache::Acquire(const std::string& id, 130 ParsedDicomFile* dicom, // Takes ownership 131 size_t fileSize) 132 { 133 #if !defined(__EMSCRIPTEN__) 134 boost::mutex::scoped_lock lock(mutex_); 135 #endif 136 137 if (fileSize >= cacheSize_) 138 { 139 cache_.reset(NULL); 140 largeDicom_.reset(dicom); 141 largeId_ = id; 142 largeSize_ = fileSize; 143 } 144 else 145 { 146 largeDicom_.reset(NULL); 147 largeSize_ = 0; 148 149 if (cache_.get() == NULL) 150 { 151 cache_.reset(new MemoryObjectCache); 152 cache_->SetMaximumSize(cacheSize_); 153 } 154 155 cache_->Acquire(id, new Item(dicom, fileSize)); 156 } 157 } 158 159 Accessor(ParsedDicomCache & that,const std::string & id)160 ParsedDicomCache::Accessor::Accessor(ParsedDicomCache& that, 161 const std::string& id) : 162 #if !defined(__EMSCRIPTEN__) 163 lock_(that.mutex_), 164 #endif 165 id_(id), 166 file_(NULL), 167 fileSize_(0) 168 { 169 if (that.largeDicom_.get() != NULL && 170 that.largeId_ == id) 171 { 172 file_ = that.largeDicom_.get(); 173 fileSize_ = that.largeSize_; 174 } 175 else if (that.cache_.get() != NULL) 176 { 177 accessor_.reset(new MemoryObjectCache::Accessor( 178 *that.cache_, id, true /* unique */)); 179 if (accessor_->IsValid()) 180 { 181 const Item& item = dynamic_cast<const Item&>(accessor_->GetValue()); 182 file_ = &item.GetDicom(); 183 fileSize_ = item.GetMemoryUsage(); 184 } 185 } 186 } 187 188 IsValid() const189 bool ParsedDicomCache::Accessor::IsValid() const 190 { 191 return file_ != NULL; 192 } 193 194 GetDicom() const195 ParsedDicomFile& ParsedDicomCache::Accessor::GetDicom() const 196 { 197 if (IsValid()) 198 { 199 assert(file_ != NULL); 200 return *file_; 201 } 202 else 203 { 204 throw OrthancException(ErrorCode_BadSequenceOfCalls); 205 } 206 } 207 208 GetFileSize() const209 size_t ParsedDicomCache::Accessor::GetFileSize() const 210 { 211 if (IsValid()) 212 { 213 return fileSize_; 214 } 215 else 216 { 217 throw OrthancException(ErrorCode_BadSequenceOfCalls); 218 } 219 } 220 } 221