| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "storage/browser/blob/blob_storage_context.h" | 5 #include "storage/browser/blob/blob_storage_context.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/callback.h" | 11 #include "base/callback.h" |
| 12 #include "base/location.h" | 12 #include "base/location.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 15 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
| 16 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
| 17 #include "base/thread_task_runner_handle.h" | 17 #include "base/thread_task_runner_handle.h" |
| 18 #include "base/trace_event/trace_event.h" | 18 #include "base/trace_event/trace_event.h" |
| 19 #include "storage/browser/blob/blob_data_builder.h" | 19 #include "storage/browser/blob/blob_data_builder.h" |
| 20 #include "storage/browser/blob/blob_data_handle.h" | 20 #include "storage/browser/blob/blob_data_handle.h" |
| 21 #include "storage/browser/blob/blob_data_item.h" | 21 #include "storage/browser/blob/blob_data_item.h" |
| 22 #include "storage/browser/blob/blob_data_snapshot.h" | 22 #include "storage/browser/blob/blob_data_snapshot.h" |
| 23 #include "storage/browser/blob/shareable_blob_data_item.h" | 23 #include "storage/browser/blob/shareable_blob_data_item.h" |
| 24 #include "url/gurl.h" | 24 #include "url/gurl.h" |
| 25 | 25 |
| 26 namespace storage { | 26 namespace storage { |
| 27 using BlobRegistryEntry = BlobStorageRegistry::Entry; | 27 using BlobRegistryEntry = BlobStorageRegistry::Entry; |
| 28 using BlobState = BlobStorageRegistry::BlobState; | 28 using BlobState = BlobStorageRegistry::BlobState; |
| 29 | 29 |
| 30 BlobStorageContext::BlobStorageContext() : memory_usage_(0) {} | 30 BlobStorageContext::BlobStorageContext() {} |
| 31 |
| 32 BlobStorageContext::BlobStorageContext( |
| 33 bool enable_disk, |
| 34 const base::FilePath& blob_storage_dir, |
| 35 scoped_refptr<base::TaskRunner> file_runner) |
| 36 : memory_controller_(enable_disk, blob_storage_dir, file_runner) {} |
| 31 | 37 |
| 32 BlobStorageContext::~BlobStorageContext() { | 38 BlobStorageContext::~BlobStorageContext() { |
| 33 } | 39 } |
| 34 | 40 |
| 35 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID( | 41 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID( |
| 36 const std::string& uuid) { | 42 const std::string& uuid) { |
| 37 scoped_ptr<BlobDataHandle> result; | 43 scoped_ptr<BlobDataHandle> result; |
| 38 BlobRegistryEntry* entry = registry_.GetEntry(uuid); | 44 BlobRegistryEntry* entry = registry_.GetEntry(uuid); |
| 39 if (!entry || entry->state != BlobState::ACTIVE || entry->exceeded_memory) { | 45 if (!entry || entry->state != BlobState::ACTIVE || entry->exceeded_memory) { |
| 40 LOG(ERROR) << "Could not find blob " << uuid; | 46 LOG(ERROR) << "Could not find blob " << uuid; |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 case BlobState::CONSTRUCTION: | 220 case BlobState::CONSTRUCTION: |
| 215 memory_freeing = entry->data_builder->GetNonsharedMemoryUsage(); | 221 memory_freeing = entry->data_builder->GetNonsharedMemoryUsage(); |
| 216 entry->data_builder->RemoveBlobFromShareableItems(uuid); | 222 entry->data_builder->RemoveBlobFromShareableItems(uuid); |
| 217 break; | 223 break; |
| 218 case BlobState::ASYNC_TRANSPORTATION: | 224 case BlobState::ASYNC_TRANSPORTATION: |
| 219 case BlobState::RESERVED: | 225 case BlobState::RESERVED: |
| 220 break; | 226 break; |
| 221 } | 227 } |
| 222 DCHECK_LE(memory_freeing, memory_usage_); | 228 DCHECK_LE(memory_freeing, memory_usage_); |
| 223 memory_usage_ -= memory_freeing; | 229 memory_usage_ -= memory_freeing; |
| 230 for (const auto& item_refptr : entry->data->items_) { |
| 231 if (item_refptr->num_referencing_blob() == 0) { |
| 232 memory_controller_.RemoveBlobItemInRecents(item_refptr->item_id()); |
| 233 } |
| 234 } |
| 224 registry_.DeleteEntry(uuid); | 235 registry_.DeleteEntry(uuid); |
| 225 } | 236 } |
| 226 } | 237 } |
| 227 | 238 |
| 228 void BlobStorageContext::BlobEntryExceededMemory(BlobRegistryEntry* entry) { | 239 void BlobStorageContext::BlobEntryExceededMemory(BlobRegistryEntry* entry) { |
| 229 // If we're using too much memory, drop this blob's data. | 240 // If we're using too much memory, drop this blob's data. |
| 230 // TODO(michaeln): Blob memory storage does not yet spill over to disk, | 241 // TODO(michaeln): Blob memory storage does not yet spill over to disk, |
| 231 // as a stop gap, we'll prevent memory usage over a max amount. | 242 // as a stop gap, we'll prevent memory usage over a max amount. |
| 232 memory_usage_ -= entry->data_builder->GetNonsharedMemoryUsage(); | 243 memory_usage_ -= entry->data_builder->GetNonsharedMemoryUsage(); |
| 233 entry->exceeded_memory = true; | 244 entry->exceeded_memory = true; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 261 memory_usage_ / 1024); | 272 memory_usage_ / 1024); |
| 262 switch (data_element.type()) { | 273 switch (data_element.type()) { |
| 263 case DataElement::TYPE_BYTES: | 274 case DataElement::TYPE_BYTES: |
| 264 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Bytes", length / 1024); | 275 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Bytes", length / 1024); |
| 265 DCHECK(!offset); | 276 DCHECK(!offset); |
| 266 if (memory_usage_ + length > kBlobStorageMaxMemoryUsage) { | 277 if (memory_usage_ + length > kBlobStorageMaxMemoryUsage) { |
| 267 exceeded_memory = true; | 278 exceeded_memory = true; |
| 268 break; | 279 break; |
| 269 } | 280 } |
| 270 memory_usage_ += length; | 281 memory_usage_ += length; |
| 271 target_blob_builder->AppendSharedBlobItem( | 282 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( |
| 272 new ShareableBlobDataItem(target_blob_uuid, blob_item)); | 283 target_blob_uuid, GetAndIncrementItemId(), blob_item)); |
| 273 break; | 284 break; |
| 274 case DataElement::TYPE_FILE: { | 285 case DataElement::TYPE_FILE: { |
| 275 bool full_file = (length == std::numeric_limits<uint64>::max()); | 286 bool full_file = (length == std::numeric_limits<uint64>::max()); |
| 276 UMA_HISTOGRAM_BOOLEAN("Storage.BlobItemSize.File.Unknown", full_file); | 287 UMA_HISTOGRAM_BOOLEAN("Storage.BlobItemSize.File.Unknown", full_file); |
| 277 if (!full_file) { | 288 if (!full_file) { |
| 278 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.File", | 289 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.File", |
| 279 (length - offset) / 1024); | 290 (length - offset) / 1024); |
| 280 } | 291 } |
| 281 target_blob_builder->AppendSharedBlobItem( | 292 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( |
| 282 new ShareableBlobDataItem(target_blob_uuid, blob_item)); | 293 target_blob_uuid, GetAndIncrementItemId(), blob_item)); |
| 283 break; | 294 break; |
| 284 } | 295 } |
| 285 case DataElement::TYPE_FILE_FILESYSTEM: { | 296 case DataElement::TYPE_FILE_FILESYSTEM: { |
| 286 bool full_file = (length == std::numeric_limits<uint64>::max()); | 297 bool full_file = (length == std::numeric_limits<uint64>::max()); |
| 287 UMA_HISTOGRAM_BOOLEAN("Storage.BlobItemSize.FileSystem.Unknown", | 298 UMA_HISTOGRAM_BOOLEAN("Storage.BlobItemSize.FileSystem.Unknown", |
| 288 full_file); | 299 full_file); |
| 289 if (!full_file) { | 300 if (!full_file) { |
| 290 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.FileSystem", | 301 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.FileSystem", |
| 291 (length - offset) / 1024); | 302 (length - offset) / 1024); |
| 292 } | 303 } |
| 293 target_blob_builder->AppendSharedBlobItem( | 304 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( |
| 294 new ShareableBlobDataItem(target_blob_uuid, blob_item)); | 305 target_blob_uuid, GetAndIncrementItemId(), blob_item)); |
| 295 break; | 306 break; |
| 296 } | 307 } |
| 297 case DataElement::TYPE_BLOB: { | 308 case DataElement::TYPE_BLOB: { |
| 298 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Blob", | 309 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Blob", |
| 299 (length - offset) / 1024); | 310 (length - offset) / 1024); |
| 300 // We grab the handle to ensure it stays around while we copy it. | 311 // We grab the handle to ensure it stays around while we copy it. |
| 301 scoped_ptr<BlobDataHandle> src = | 312 scoped_ptr<BlobDataHandle> src = |
| 302 GetBlobDataFromUUID(data_element.blob_uuid()); | 313 GetBlobDataFromUUID(data_element.blob_uuid()); |
| 303 if (src) { | 314 if (src) { |
| 304 BlobRegistryEntry* other_entry = | 315 BlobRegistryEntry* other_entry = |
| 305 registry_.GetEntry(data_element.blob_uuid()); | 316 registry_.GetEntry(data_element.blob_uuid()); |
| 306 DCHECK(other_entry->data); | 317 DCHECK(other_entry->data); |
| 307 exceeded_memory = !AppendBlob(target_blob_uuid, *other_entry->data, | 318 exceeded_memory = !AppendBlob(target_blob_uuid, *other_entry->data, |
| 308 offset, length, target_blob_builder); | 319 offset, length, target_blob_builder); |
| 309 } | 320 } |
| 310 break; | 321 break; |
| 311 } | 322 } |
| 312 case DataElement::TYPE_DISK_CACHE_ENTRY: { | 323 case DataElement::TYPE_DISK_CACHE_ENTRY: { |
| 313 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.CacheEntry", | 324 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.CacheEntry", |
| 314 (length - offset) / 1024); | 325 (length - offset) / 1024); |
| 315 target_blob_builder->AppendSharedBlobItem( | 326 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( |
| 316 new ShareableBlobDataItem(target_blob_uuid, blob_item)); | 327 target_blob_uuid, GetAndIncrementItemId(), blob_item)); |
| 317 break; | 328 break; |
| 318 } | 329 } |
| 319 case DataElement::TYPE_BYTES_DESCRIPTION: | 330 case DataElement::TYPE_BYTES_DESCRIPTION: |
| 320 case DataElement::TYPE_UNKNOWN: | 331 case DataElement::TYPE_UNKNOWN: |
| 321 NOTREACHED(); | 332 NOTREACHED(); |
| 322 break; | 333 break; |
| 323 } | 334 } |
| 324 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeAfterAppend", | 335 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeAfterAppend", |
| 325 memory_usage_ / 1024); | 336 memory_usage_ / 1024); |
| 326 | 337 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.Bytes", | 382 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.Bytes", |
| 372 new_length / 1024); | 383 new_length / 1024); |
| 373 if (memory_usage_ + new_length > kBlobStorageMaxMemoryUsage) { | 384 if (memory_usage_ + new_length > kBlobStorageMaxMemoryUsage) { |
| 374 return false; | 385 return false; |
| 375 } | 386 } |
| 376 DCHECK(!item.offset()); | 387 DCHECK(!item.offset()); |
| 377 scoped_ptr<DataElement> element(new DataElement()); | 388 scoped_ptr<DataElement> element(new DataElement()); |
| 378 element->SetToBytes(item.bytes() + offset, | 389 element->SetToBytes(item.bytes() + offset, |
| 379 static_cast<int64>(new_length)); | 390 static_cast<int64>(new_length)); |
| 380 memory_usage_ += new_length; | 391 memory_usage_ += new_length; |
| 381 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( | 392 target_blob_builder->AppendSharedBlobItem( |
| 382 target_blob_uuid, new BlobDataItem(element.Pass()))); | 393 new ShareableBlobDataItem(target_blob_uuid, GetAndIncrementItemId(), |
| 394 new BlobDataItem(element.Pass()))); |
| 383 } break; | 395 } break; |
| 384 case DataElement::TYPE_FILE: { | 396 case DataElement::TYPE_FILE: { |
| 385 DCHECK_NE(item.length(), std::numeric_limits<uint64>::max()) | 397 DCHECK_NE(item.length(), std::numeric_limits<uint64>::max()) |
| 386 << "We cannot use a section of a file with an unknown length"; | 398 << "We cannot use a section of a file with an unknown length"; |
| 387 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.File", | 399 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.File", |
| 388 new_length / 1024); | 400 new_length / 1024); |
| 389 scoped_ptr<DataElement> element(new DataElement()); | 401 scoped_ptr<DataElement> element(new DataElement()); |
| 390 element->SetToFilePathRange(item.path(), item.offset() + offset, | 402 element->SetToFilePathRange(item.path(), item.offset() + offset, |
| 391 new_length, | 403 new_length, |
| 392 item.expected_modification_time()); | 404 item.expected_modification_time()); |
| 393 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( | 405 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( |
| 394 target_blob_uuid, | 406 target_blob_uuid, GetAndIncrementItemId(), |
| 395 new BlobDataItem(element.Pass(), item.data_handle_))); | 407 new BlobDataItem(element.Pass(), item.data_handle_))); |
| 396 } break; | 408 } break; |
| 397 case DataElement::TYPE_FILE_FILESYSTEM: { | 409 case DataElement::TYPE_FILE_FILESYSTEM: { |
| 398 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.FileSystem", | 410 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.FileSystem", |
| 399 new_length / 1024); | 411 new_length / 1024); |
| 400 scoped_ptr<DataElement> element(new DataElement()); | 412 scoped_ptr<DataElement> element(new DataElement()); |
| 401 element->SetToFileSystemUrlRange(item.filesystem_url(), | 413 element->SetToFileSystemUrlRange(item.filesystem_url(), |
| 402 item.offset() + offset, new_length, | 414 item.offset() + offset, new_length, |
| 403 item.expected_modification_time()); | 415 item.expected_modification_time()); |
| 404 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( | 416 target_blob_builder->AppendSharedBlobItem( |
| 405 target_blob_uuid, new BlobDataItem(element.Pass()))); | 417 new ShareableBlobDataItem(target_blob_uuid, GetAndIncrementItemId(), |
| 418 new BlobDataItem(element.Pass()))); |
| 406 } break; | 419 } break; |
| 407 case DataElement::TYPE_DISK_CACHE_ENTRY: { | 420 case DataElement::TYPE_DISK_CACHE_ENTRY: { |
| 408 scoped_ptr<DataElement> element(new DataElement()); | 421 scoped_ptr<DataElement> element(new DataElement()); |
| 409 element->SetToDiskCacheEntryRange(item.offset() + offset, | 422 element->SetToDiskCacheEntryRange(item.offset() + offset, |
| 410 new_length); | 423 new_length); |
| 411 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( | 424 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( |
| 412 target_blob_uuid, | 425 target_blob_uuid, GetAndIncrementItemId(), |
| 413 new BlobDataItem(element.Pass(), item.data_handle_, | 426 new BlobDataItem(element.Pass(), item.data_handle_, |
| 414 item.disk_cache_entry(), | 427 item.disk_cache_entry(), |
| 415 item.disk_cache_stream_index()))); | 428 item.disk_cache_stream_index()))); |
| 416 } break; | 429 } break; |
| 417 case DataElement::TYPE_BYTES_DESCRIPTION: | 430 case DataElement::TYPE_BYTES_DESCRIPTION: |
| 418 case DataElement::TYPE_BLOB: | 431 case DataElement::TYPE_BLOB: |
| 419 case DataElement::TYPE_UNKNOWN: | 432 case DataElement::TYPE_UNKNOWN: |
| 420 CHECK(false) << "Illegal blob item type: " << item.type(); | 433 CHECK(false) << "Illegal blob item type: " << item.type(); |
| 421 } | 434 } |
| 422 length -= new_length; | 435 length -= new_length; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 return false; | 482 return false; |
| 470 } | 483 } |
| 471 for (const auto& callback : entry->construction_complete_callbacks) { | 484 for (const auto& callback : entry->construction_complete_callbacks) { |
| 472 base::MessageLoop::current()->PostTask(FROM_HERE, | 485 base::MessageLoop::current()->PostTask(FROM_HERE, |
| 473 base::Bind(callback, false)); | 486 base::Bind(callback, false)); |
| 474 } | 487 } |
| 475 registry_.DeleteEntry(uuid); | 488 registry_.DeleteEntry(uuid); |
| 476 return true; | 489 return true; |
| 477 } | 490 } |
| 478 | 491 |
| 492 uint64_t BlobStorageContext::GetAndIncrementItemId() { |
| 493 return next_item_id_++; |
| 494 } |
| 495 |
| 496 void BlobStorageContext::UpdateItemsInRecents(BlobRegistryEntry* entry) { |
| 497 for (const auto& item_refptr : entry->data->items_) { |
| 498 memory_controller_.UpdateBlobItemInRecents(item_refptr.get()); |
| 499 } |
| 500 } |
| 501 |
| 479 } // namespace storage | 502 } // namespace storage |
| OLD | NEW |