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,