Mercurial > hg > orthanc
comparison OrthancFramework/Sources/FileStorage/StorageAccessor.cpp @ 5420:d37dff2c0028 am-new-cache
Optimized the MemoryStringCache to prevent loading the same file multiple times if multiple users request the same file at the same time
author | Alain Mazy <am@osimis.io> |
---|---|
date | Mon, 13 Nov 2023 17:01:59 +0100 |
parents | b376abae664a |
children | 48b8dae6dc77 |
comparison
equal
deleted
inserted
replaced
5419:ac4e9fb87615 | 5420:d37dff2c0028 |
---|---|
128 metrics_->IncrementIntegerValue(METRICS_WRITTEN_BYTES, size); | 128 metrics_->IncrementIntegerValue(METRICS_WRITTEN_BYTES, size); |
129 } | 129 } |
130 | 130 |
131 if (cache_ != NULL) | 131 if (cache_ != NULL) |
132 { | 132 { |
133 cache_->Add(uuid, type, data, size); | 133 StorageCache::Accessor cacheAccessor(*cache_); |
134 cacheAccessor.Add(uuid, type, data, size); | |
134 } | 135 } |
135 | 136 |
136 return FileInfo(uuid, type, size, md5); | 137 return FileInfo(uuid, type, size, md5); |
137 } | 138 } |
138 | 139 |
168 metrics_->IncrementIntegerValue(METRICS_WRITTEN_BYTES, compressed.size()); | 169 metrics_->IncrementIntegerValue(METRICS_WRITTEN_BYTES, compressed.size()); |
169 } | 170 } |
170 | 171 |
171 if (cache_ != NULL) | 172 if (cache_ != NULL) |
172 { | 173 { |
173 cache_->Add(uuid, type, data, size); // always add uncompressed data to cache | 174 StorageCache::Accessor cacheAccessor(*cache_); |
175 cacheAccessor.Add(uuid, type, data, size); // always add uncompressed data to cache | |
174 } | 176 } |
175 | 177 |
176 return FileInfo(uuid, type, size, md5, | 178 return FileInfo(uuid, type, size, md5, |
177 CompressionType_ZlibWithSize, compressed.size(), compressedMD5); | 179 CompressionType_ZlibWithSize, compressed.size(), compressedMD5); |
178 } | 180 } |
193 | 195 |
194 | 196 |
195 void StorageAccessor::Read(std::string& content, | 197 void StorageAccessor::Read(std::string& content, |
196 const FileInfo& info) | 198 const FileInfo& info) |
197 { | 199 { |
198 if (cache_ == NULL || | 200 if (cache_ == NULL) |
199 !cache_->Fetch(content, info.GetUuid(), info.GetContentType())) | 201 { |
200 { | 202 ReadWholeInternal(content, info); |
201 switch (info.GetCompressionType()) | 203 } |
202 { | 204 else |
203 case CompressionType_None: | 205 { |
204 { | 206 StorageCache::Accessor cacheAccessor(*cache_); |
205 std::unique_ptr<IMemoryBuffer> buffer; | 207 |
206 | 208 if (!cacheAccessor.Fetch(content, info.GetUuid(), info.GetContentType())) |
207 { | 209 { |
208 MetricsTimer timer(*this, METRICS_READ_DURATION); | 210 ReadWholeInternal(content, info); |
209 buffer.reset(area_.Read(info.GetUuid(), info.GetContentType())); | 211 |
210 } | 212 // always store the uncompressed data in cache |
211 | 213 cacheAccessor.Add(info.GetUuid(), info.GetContentType(), content); |
212 if (metrics_ != NULL) | 214 } |
213 { | 215 } |
214 metrics_->IncrementIntegerValue(METRICS_READ_BYTES, buffer->GetSize()); | 216 } |
215 } | 217 |
216 | 218 void StorageAccessor::ReadWholeInternal(std::string& content, |
217 buffer->MoveToString(content); | 219 const FileInfo& info) |
218 | 220 { |
219 break; | 221 switch (info.GetCompressionType()) |
220 } | 222 { |
221 | 223 case CompressionType_None: |
222 case CompressionType_ZlibWithSize: | 224 { |
223 { | 225 std::unique_ptr<IMemoryBuffer> buffer; |
224 ZlibCompressor zlib; | 226 |
225 | 227 { |
226 std::unique_ptr<IMemoryBuffer> compressed; | 228 MetricsTimer timer(*this, METRICS_READ_DURATION); |
227 | 229 buffer.reset(area_.Read(info.GetUuid(), info.GetContentType())); |
228 { | 230 } |
229 MetricsTimer timer(*this, METRICS_READ_DURATION); | 231 |
230 compressed.reset(area_.Read(info.GetUuid(), info.GetContentType())); | 232 if (metrics_ != NULL) |
231 } | 233 { |
232 | 234 metrics_->IncrementIntegerValue(METRICS_READ_BYTES, buffer->GetSize()); |
233 if (metrics_ != NULL) | 235 } |
234 { | 236 |
235 metrics_->IncrementIntegerValue(METRICS_READ_BYTES, compressed->GetSize()); | 237 buffer->MoveToString(content); |
236 } | 238 |
237 | 239 break; |
238 zlib.Uncompress(content, compressed->GetData(), compressed->GetSize()); | 240 } |
239 | 241 |
240 break; | 242 case CompressionType_ZlibWithSize: |
241 } | 243 { |
242 | 244 ZlibCompressor zlib; |
243 default: | 245 |
244 { | 246 std::unique_ptr<IMemoryBuffer> compressed; |
245 throw OrthancException(ErrorCode_NotImplemented); | 247 |
246 } | 248 { |
247 } | 249 MetricsTimer timer(*this, METRICS_READ_DURATION); |
248 | 250 compressed.reset(area_.Read(info.GetUuid(), info.GetContentType())); |
249 // always store the uncompressed data in cache | 251 } |
250 if (cache_ != NULL) | 252 |
251 { | 253 if (metrics_ != NULL) |
252 cache_->Add(info.GetUuid(), info.GetContentType(), content); | 254 { |
255 metrics_->IncrementIntegerValue(METRICS_READ_BYTES, compressed->GetSize()); | |
256 } | |
257 | |
258 zlib.Uncompress(content, compressed->GetData(), compressed->GetSize()); | |
259 | |
260 break; | |
261 } | |
262 | |
263 default: | |
264 { | |
265 throw OrthancException(ErrorCode_NotImplemented); | |
253 } | 266 } |
254 } | 267 } |
255 | 268 |
256 // TODO Check the validity of the uncompressed MD5? | 269 // TODO Check the validity of the uncompressed MD5? |
257 } | 270 } |
258 | 271 |
259 | 272 |
260 void StorageAccessor::ReadRaw(std::string& content, | 273 void StorageAccessor::ReadRaw(std::string& content, |
261 const FileInfo& info) | 274 const FileInfo& info) |
262 { | 275 { |
263 if (cache_ == NULL || !cache_->Fetch(content, info.GetUuid(), info.GetContentType())) | 276 if (cache_ == NULL || info.GetCompressionType() != CompressionType_None) |
264 { | 277 { |
265 std::unique_ptr<IMemoryBuffer> buffer; | 278 ReadRawInternal(content, info); |
266 | 279 } |
267 { | 280 else |
268 MetricsTimer timer(*this, METRICS_READ_DURATION); | 281 {// use the cache only if the data is uncompressed. |
269 buffer.reset(area_.Read(info.GetUuid(), info.GetContentType())); | 282 StorageCache::Accessor cacheAccessor(*cache_); |
270 } | 283 |
271 | 284 if (!cacheAccessor.Fetch(content, info.GetUuid(), info.GetContentType())) |
272 if (metrics_ != NULL) | 285 { |
273 { | 286 ReadRawInternal(content, info); |
274 metrics_->IncrementIntegerValue(METRICS_READ_BYTES, buffer->GetSize()); | 287 |
275 } | 288 cacheAccessor.Add(info.GetUuid(), info.GetContentType(), content); |
276 | 289 } |
277 buffer->MoveToString(content); | 290 } |
278 } | 291 } |
292 | |
293 void StorageAccessor::ReadRawInternal(std::string& content, | |
294 const FileInfo& info) | |
295 { | |
296 std::unique_ptr<IMemoryBuffer> buffer; | |
297 | |
298 { | |
299 MetricsTimer timer(*this, METRICS_READ_DURATION); | |
300 buffer.reset(area_.Read(info.GetUuid(), info.GetContentType())); | |
301 } | |
302 | |
303 if (metrics_ != NULL) | |
304 { | |
305 metrics_->IncrementIntegerValue(METRICS_READ_BYTES, buffer->GetSize()); | |
306 } | |
307 | |
308 buffer->MoveToString(content); | |
279 } | 309 } |
280 | 310 |
281 | 311 |
282 void StorageAccessor::Remove(const std::string& fileUuid, | 312 void StorageAccessor::Remove(const std::string& fileUuid, |
283 FileContentType type) | 313 FileContentType type) |
298 { | 328 { |
299 Remove(info.GetUuid(), info.GetContentType()); | 329 Remove(info.GetUuid(), info.GetContentType()); |
300 } | 330 } |
301 | 331 |
302 | 332 |
333 void ReadStartRangeFromAreaInternal(std::string& target, | |
334 IStorageArea& area, | |
335 const std::string& fileUuid, | |
336 FileContentType contentType, | |
337 uint64_t end /* exclusive */) | |
338 { | |
339 | |
340 } | |
341 | |
303 void StorageAccessor::ReadStartRange(std::string& target, | 342 void StorageAccessor::ReadStartRange(std::string& target, |
304 const std::string& fileUuid, | 343 const FileInfo& info, |
305 FileContentType contentType, | |
306 uint64_t end /* exclusive */) | 344 uint64_t end /* exclusive */) |
307 { | 345 { |
308 if (cache_ == NULL || !cache_->FetchStartRange(target, fileUuid, contentType, end)) | 346 if (cache_ == NULL) |
309 { | 347 { |
310 std::unique_ptr<IMemoryBuffer> buffer; | 348 ReadStartRangeInternal(target, info, end); |
311 | 349 } |
312 { | 350 else |
313 MetricsTimer timer(*this, METRICS_READ_DURATION); | 351 { |
314 buffer.reset(area_.ReadRange(fileUuid, contentType, 0, end)); | 352 StorageCache::Accessor accessorStartRange(*cache_); |
315 assert(buffer->GetSize() == end); | 353 if (!accessorStartRange.FetchStartRange(target, info.GetUuid(), info.GetContentType(), end)) |
316 } | 354 { |
317 | 355 ReadStartRangeInternal(target, info, end); |
318 if (metrics_ != NULL) | 356 accessorStartRange.AddStartRange(info.GetUuid(), info.GetContentType(), target); |
319 { | 357 } |
320 metrics_->IncrementIntegerValue(METRICS_READ_BYTES, buffer->GetSize()); | 358 else |
321 } | 359 { |
322 | 360 StorageCache::Accessor accessorWhole(*cache_); |
323 buffer->MoveToString(target); | 361 if (!accessorWhole.Fetch(target, info.GetUuid(), info.GetContentType())) |
324 | 362 { |
325 if (cache_ != NULL) | 363 ReadWholeInternal(target, info); |
326 { | 364 accessorWhole.Add(info.GetUuid(), info.GetContentType(), target); |
327 cache_->AddStartRange(fileUuid, contentType, target); | 365 } |
328 } | 366 |
329 } | 367 if (target.size() < end) |
368 { | |
369 throw OrthancException(ErrorCode_CorruptedFile); | |
370 } | |
371 | |
372 target.resize(end); | |
373 } | |
374 } | |
375 } | |
376 | |
377 void StorageAccessor::ReadStartRangeInternal(std::string& target, | |
378 const FileInfo& info, | |
379 uint64_t end /* exclusive */) | |
380 { | |
381 std::unique_ptr<IMemoryBuffer> buffer; | |
382 | |
383 { | |
384 MetricsTimer timer(*this, METRICS_READ_DURATION); | |
385 buffer.reset(area_.ReadRange(info.GetUuid(), info.GetContentType(), 0, end)); | |
386 assert(buffer->GetSize() == end); | |
387 } | |
388 | |
389 if (metrics_ != NULL) | |
390 { | |
391 metrics_->IncrementIntegerValue(METRICS_READ_BYTES, buffer->GetSize()); | |
392 } | |
393 | |
394 buffer->MoveToString(target); | |
330 } | 395 } |
331 | 396 |
332 | 397 |
333 #if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 | 398 #if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 |
334 void StorageAccessor::SetupSender(BufferHttpSender& sender, | 399 void StorageAccessor::SetupSender(BufferHttpSender& sender, |