Chromium Code Reviews| 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 #include <memory> | 9 #include <memory> |
| 10 #include <set> | 10 #include <set> |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 85 BlobStorageContext::BlobFlattener::BlobFlattener( | 85 BlobStorageContext::BlobFlattener::BlobFlattener( |
| 86 const BlobDataBuilder& input_builder, | 86 const BlobDataBuilder& input_builder, |
| 87 BlobEntry* output_blob, | 87 BlobEntry* output_blob, |
| 88 BlobStorageRegistry* registry) { | 88 BlobStorageRegistry* registry) { |
| 89 const std::string& uuid = input_builder.uuid_; | 89 const std::string& uuid = input_builder.uuid_; |
| 90 std::set<std::string> dependent_blob_uuids; | 90 std::set<std::string> dependent_blob_uuids; |
| 91 | 91 |
| 92 size_t num_files_with_unknown_size = 0; | 92 size_t num_files_with_unknown_size = 0; |
| 93 size_t num_building_dependent_blobs = 0; | 93 size_t num_building_dependent_blobs = 0; |
| 94 | 94 |
| 95 bool found_memory_transport = false; | |
| 96 bool found_file_transport = false; | |
| 97 | |
| 95 base::CheckedNumeric<uint64_t> checked_total_size = 0; | 98 base::CheckedNumeric<uint64_t> checked_total_size = 0; |
| 96 base::CheckedNumeric<uint64_t> checked_total_memory_size = 0; | 99 base::CheckedNumeric<uint64_t> checked_total_memory_size = 0; |
| 97 base::CheckedNumeric<uint64_t> checked_memory_quota_needed = 0; | 100 base::CheckedNumeric<uint64_t> checked_transport_quota_needed = 0; |
| 101 base::CheckedNumeric<uint64_t> checked_copy_quota_needed = 0; | |
| 98 | 102 |
| 99 for (scoped_refptr<BlobDataItem> input_item : input_builder.items_) { | 103 for (scoped_refptr<BlobDataItem> input_item : input_builder.items_) { |
| 100 const DataElement& input_element = input_item->data_element(); | 104 const DataElement& input_element = input_item->data_element(); |
| 101 DataElement::Type type = input_element.type(); | 105 DataElement::Type type = input_element.type(); |
| 102 uint64_t length = input_element.length(); | 106 uint64_t length = input_element.length(); |
| 103 | 107 |
| 104 RecordBlobItemSizeStats(input_element); | 108 RecordBlobItemSizeStats(input_element); |
| 105 | 109 |
| 106 if (IsBytes(type)) { | 110 if (IsBytes(type)) { |
| 107 DCHECK_NE(0 + DataElement::kUnknownSize, input_element.length()); | 111 DCHECK_NE(0 + DataElement::kUnknownSize, input_element.length()); |
| 108 checked_memory_quota_needed += length; | 112 found_memory_transport = true; |
| 113 if (found_file_transport) { | |
| 114 // We cannot have both memory and file transport items. | |
| 115 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; | |
| 116 return; | |
| 117 } | |
| 118 checked_transport_quota_needed += length; | |
| 109 checked_total_size += length; | 119 checked_total_size += length; |
| 110 scoped_refptr<ShareableBlobDataItem> item = new ShareableBlobDataItem( | 120 scoped_refptr<ShareableBlobDataItem> item = new ShareableBlobDataItem( |
| 111 std::move(input_item), ShareableBlobDataItem::QUOTA_NEEDED); | 121 std::move(input_item), ShareableBlobDataItem::QUOTA_NEEDED); |
| 112 pending_memory_items.push_back(item); | 122 pending_transport_items.push_back(item); |
| 113 transport_items.push_back(item.get()); | 123 transport_items.push_back(item.get()); |
| 114 output_blob->AppendSharedBlobItem(std::move(item)); | 124 output_blob->AppendSharedBlobItem(std::move(item)); |
| 115 continue; | 125 continue; |
| 116 } | 126 } |
| 117 if (type == DataElement::TYPE_BLOB) { | 127 if (type == DataElement::TYPE_BLOB) { |
| 118 BlobEntry* ref_entry = registry->GetEntry(input_element.blob_uuid()); | 128 BlobEntry* ref_entry = registry->GetEntry(input_element.blob_uuid()); |
| 119 | 129 |
| 120 if (!ref_entry || input_element.blob_uuid() == uuid) { | 130 if (!ref_entry || input_element.blob_uuid() == uuid) { |
| 121 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; | 131 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; |
| 122 return; | 132 return; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 !slice.total_memory_size.IsValid()) { | 177 !slice.total_memory_size.IsValid()) { |
| 168 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; | 178 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; |
| 169 return; | 179 return; |
| 170 } | 180 } |
| 171 checked_total_memory_size += slice.total_memory_size; | 181 checked_total_memory_size += slice.total_memory_size; |
| 172 | 182 |
| 173 if (slice.first_source_item) { | 183 if (slice.first_source_item) { |
| 174 copies.push_back(ItemCopyEntry(slice.first_source_item, | 184 copies.push_back(ItemCopyEntry(slice.first_source_item, |
| 175 slice.first_item_slice_offset, | 185 slice.first_item_slice_offset, |
| 176 slice.dest_items.front())); | 186 slice.dest_items.front())); |
| 177 pending_memory_items.push_back(slice.dest_items.front()); | 187 pending_copy_items.push_back(slice.dest_items.front()); |
| 178 } | 188 } |
| 179 if (slice.last_source_item) { | 189 if (slice.last_source_item) { |
| 180 copies.push_back( | 190 copies.push_back( |
| 181 ItemCopyEntry(slice.last_source_item, 0, slice.dest_items.back())); | 191 ItemCopyEntry(slice.last_source_item, 0, slice.dest_items.back())); |
| 182 pending_memory_items.push_back(slice.dest_items.back()); | 192 pending_copy_items.push_back(slice.dest_items.back()); |
| 183 } | 193 } |
| 184 checked_memory_quota_needed += slice.copying_memory_size; | 194 checked_copy_quota_needed += slice.copying_memory_size; |
| 185 | 195 |
| 186 for (auto& shareable_item : slice.dest_items) { | 196 for (auto& shareable_item : slice.dest_items) { |
| 187 output_blob->AppendSharedBlobItem(std::move(shareable_item)); | 197 output_blob->AppendSharedBlobItem(std::move(shareable_item)); |
| 188 } | 198 } |
| 189 continue; | 199 continue; |
| 190 } | 200 } |
| 191 | 201 |
| 192 DCHECK(!BlobDataBuilder::IsFutureFileItem(input_element)) | 202 // If the source item is a temporary file item, then we need to keep track |
| 193 << "File allocation not implemented."; | 203 // of that and mark is as needing quota. |
|
kinuko
2016/11/27 14:45:22
mark is -> mark it ?
dmurph
2016/11/28 19:20:36
Done.
| |
| 204 scoped_refptr<ShareableBlobDataItem> item; | |
| 205 if (BlobDataBuilder::IsFutureFileItem(input_element)) { | |
| 206 found_file_transport = true; | |
| 207 if (found_memory_transport) { | |
| 208 // We cannot have both memory and file transport items. | |
| 209 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; | |
| 210 return; | |
| 211 } | |
| 212 item = new ShareableBlobDataItem(std::move(input_item), | |
| 213 ShareableBlobDataItem::QUOTA_NEEDED); | |
| 214 pending_transport_items.push_back(item); | |
| 215 transport_items.push_back(item.get()); | |
| 216 checked_transport_quota_needed += length; | |
| 217 } else { | |
| 218 item = new ShareableBlobDataItem( | |
| 219 std::move(input_item), | |
| 220 ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA); | |
| 221 } | |
| 194 if (length == DataElement::kUnknownSize) | 222 if (length == DataElement::kUnknownSize) |
| 195 num_files_with_unknown_size++; | 223 num_files_with_unknown_size++; |
| 196 | 224 |
| 197 scoped_refptr<ShareableBlobDataItem> item = new ShareableBlobDataItem( | |
| 198 std::move(input_item), ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA); | |
| 199 | |
| 200 checked_total_size += length; | 225 checked_total_size += length; |
| 201 output_blob->AppendSharedBlobItem(std::move(item)); | 226 output_blob->AppendSharedBlobItem(std::move(item)); |
| 202 } | 227 } |
| 203 | 228 |
| 204 if (num_files_with_unknown_size > 1 && input_builder.items_.size() > 1) { | 229 if (num_files_with_unknown_size > 1 && input_builder.items_.size() > 1) { |
| 205 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; | 230 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; |
| 206 return; | 231 return; |
| 207 } | 232 } |
| 208 if (!checked_total_size.IsValid() || !checked_total_memory_size.IsValid() || | 233 if (!checked_total_size.IsValid() || !checked_total_memory_size.IsValid() || |
| 209 !checked_memory_quota_needed.IsValid()) { | 234 !checked_transport_quota_needed.IsValid() || |
| 235 !checked_copy_quota_needed.IsValid()) { | |
| 210 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; | 236 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; |
| 211 return; | 237 return; |
| 212 } | 238 } |
| 213 total_size = checked_total_size.ValueOrDie(); | 239 total_size = checked_total_size.ValueOrDie(); |
| 214 total_memory_size = checked_total_memory_size.ValueOrDie(); | 240 total_memory_size = checked_total_memory_size.ValueOrDie(); |
| 215 memory_quota_needed = checked_memory_quota_needed.ValueOrDie(); | 241 transport_quota_needed = checked_transport_quota_needed.ValueOrDie(); |
| 216 if (memory_quota_needed) { | 242 copy_quota_needed = checked_copy_quota_needed.ValueOrDie(); |
| 243 transport_quota_type = found_file_transport ? TransportQuotaType::FILE | |
| 244 : TransportQuotaType::MEMORY; | |
| 245 if (transport_quota_needed) { | |
| 217 status = BlobStatus::PENDING_QUOTA; | 246 status = BlobStatus::PENDING_QUOTA; |
| 218 } else { | 247 } else { |
| 219 status = BlobStatus::PENDING_INTERNALS; | 248 status = BlobStatus::PENDING_INTERNALS; |
| 220 } | 249 } |
| 221 } | 250 } |
| 222 | 251 |
| 223 BlobStorageContext::BlobFlattener::~BlobFlattener() {} | 252 BlobStorageContext::BlobFlattener::~BlobFlattener() {} |
| 224 | 253 |
| 225 BlobStorageContext::BlobSlice::BlobSlice(const BlobEntry& source, | 254 BlobStorageContext::BlobSlice::BlobSlice(const BlobEntry& source, |
| 226 uint64_t slice_offset, | 255 uint64_t slice_offset, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 291 case DataElement::TYPE_FILE: { | 320 case DataElement::TYPE_FILE: { |
| 292 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.File", | 321 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.File", |
| 293 read_size / 1024); | 322 read_size / 1024); |
| 294 std::unique_ptr<DataElement> element(new DataElement()); | 323 std::unique_ptr<DataElement> element(new DataElement()); |
| 295 element->SetToFilePathRange( | 324 element->SetToFilePathRange( |
| 296 source_item->path(), source_item->offset() + item_offset, read_size, | 325 source_item->path(), source_item->offset() + item_offset, read_size, |
| 297 source_item->expected_modification_time()); | 326 source_item->expected_modification_time()); |
| 298 data_item = | 327 data_item = |
| 299 new BlobDataItem(std::move(element), source_item->data_handle_); | 328 new BlobDataItem(std::move(element), source_item->data_handle_); |
| 300 | 329 |
| 301 DCHECK(!BlobDataBuilder::IsFutureFileItem(source_item->data_element())) | 330 if (BlobDataBuilder::IsFutureFileItem(source_item->data_element())) { |
| 302 << "File allocation unimplemented."; | 331 // Since we don't have file path / reference for our future file, we |
| 332 // create another file item with this temporary file name. When our | |
| 333 // blob is finished constructing, all dependent blobs are done, and we | |
| 334 // can copy the handle over. | |
| 335 if (item_index == first_item_index) { | |
| 336 first_item_slice_offset = item_offset; | |
| 337 first_source_item = source_items[item_index]; | |
| 338 } else { | |
| 339 last_source_item = source_items[item_index]; | |
| 340 } | |
| 341 state = ShareableBlobDataItem::QUOTA_NEEDED; | |
| 342 } | |
| 303 break; | 343 break; |
| 304 } | 344 } |
| 305 case DataElement::TYPE_FILE_FILESYSTEM: { | 345 case DataElement::TYPE_FILE_FILESYSTEM: { |
| 306 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.FileSystem", | 346 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.FileSystem", |
| 307 read_size / 1024); | 347 read_size / 1024); |
| 308 std::unique_ptr<DataElement> element(new DataElement()); | 348 std::unique_ptr<DataElement> element(new DataElement()); |
| 309 element->SetToFileSystemUrlRange( | 349 element->SetToFileSystemUrlRange( |
| 310 source_item->filesystem_url(), source_item->offset() + item_offset, | 350 source_item->filesystem_url(), source_item->offset() + item_offset, |
| 311 read_size, source_item->expected_modification_time()); | 351 read_size, source_item->expected_modification_time()); |
| 312 data_item = new BlobDataItem(std::move(element)); | 352 data_item = new BlobDataItem(std::move(element)); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 334 item_offset = 0; | 374 item_offset = 0; |
| 335 } | 375 } |
| 336 } | 376 } |
| 337 | 377 |
| 338 BlobStorageContext::BlobSlice::~BlobSlice() {} | 378 BlobStorageContext::BlobSlice::~BlobSlice() {} |
| 339 | 379 |
| 340 BlobStorageContext::BlobStorageContext() | 380 BlobStorageContext::BlobStorageContext() |
| 341 : memory_controller_(base::FilePath(), scoped_refptr<base::TaskRunner>()), | 381 : memory_controller_(base::FilePath(), scoped_refptr<base::TaskRunner>()), |
| 342 ptr_factory_(this) {} | 382 ptr_factory_(this) {} |
| 343 | 383 |
| 344 BlobStorageContext::~BlobStorageContext() { | 384 BlobStorageContext::BlobStorageContext( |
| 345 } | 385 const base::FilePath& storage_directory, |
| 386 scoped_refptr<base::TaskRunner> file_runner) | |
| 387 : memory_controller_(std::move(storage_directory), std::move(file_runner)), | |
| 388 ptr_factory_(this) {} | |
| 389 | |
| 390 BlobStorageContext::~BlobStorageContext() {} | |
| 346 | 391 |
| 347 std::unique_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID( | 392 std::unique_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID( |
| 348 const std::string& uuid) { | 393 const std::string& uuid) { |
| 349 BlobEntry* entry = registry_.GetEntry(uuid); | 394 BlobEntry* entry = registry_.GetEntry(uuid); |
| 350 if (!entry) | 395 if (!entry) |
| 351 return nullptr; | 396 return nullptr; |
| 352 return CreateHandle(uuid, entry); | 397 return CreateHandle(uuid, entry); |
| 353 } | 398 } |
| 354 | 399 |
| 355 std::unique_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL( | 400 std::unique_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL( |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 << "If we have pending content then there needs to be a callback " | 468 << "If we have pending content then there needs to be a callback " |
| 424 "present."; | 469 "present."; |
| 425 | 470 |
| 426 entry->set_size(flattener.total_size); | 471 entry->set_size(flattener.total_size); |
| 427 entry->set_status(flattener.status); | 472 entry->set_status(flattener.status); |
| 428 std::unique_ptr<BlobDataHandle> handle = CreateHandle(content.uuid_, entry); | 473 std::unique_ptr<BlobDataHandle> handle = CreateHandle(content.uuid_, entry); |
| 429 | 474 |
| 430 UMA_HISTOGRAM_COUNTS("Storage.Blob.ItemCount", entry->items().size()); | 475 UMA_HISTOGRAM_COUNTS("Storage.Blob.ItemCount", entry->items().size()); |
| 431 UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalSize", | 476 UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalSize", |
| 432 flattener.total_memory_size / 1024); | 477 flattener.total_memory_size / 1024); |
| 478 | |
| 479 uint64_t total_memory_needed = | |
| 480 flattener.copy_quota_needed + | |
| 481 (flattener.transport_quota_type == TransportQuotaType::MEMORY | |
| 482 ? flattener.transport_quota_needed | |
| 483 : 0); | |
| 433 UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalUnsharedSize", | 484 UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalUnsharedSize", |
| 434 flattener.memory_quota_needed / 1024); | 485 total_memory_needed / 1024); |
| 435 | 486 |
| 436 size_t num_building_dependent_blobs = 0; | 487 size_t num_building_dependent_blobs = 0; |
| 437 std::vector<std::unique_ptr<BlobDataHandle>> dependent_blobs; | 488 std::vector<std::unique_ptr<BlobDataHandle>> dependent_blobs; |
| 438 // We hold a handle to all blobs we're using. This is important, as our memory | 489 // We hold a handle to all blobs we're using. This is important, as our memory |
| 439 // accounting can be delayed until OnEnoughSizeForBlobData is called, and we | 490 // accounting can be delayed until OnEnoughSizeForBlobData is called, and we |
| 440 // only free memory on canceling when we've done this accounting. If a | 491 // only free memory on canceling when we've done this accounting. If a |
| 441 // dependent blob is dereferenced, then we're the last blob holding onto that | 492 // dependent blob is dereferenced, then we're the last blob holding onto that |
| 442 // data item, and we need to account for that. So we prevent that case by | 493 // data item, and we need to account for that. So we prevent that case by |
| 443 // holding onto all blobs. | 494 // holding onto all blobs. |
| 444 for (const std::pair<std::string, BlobEntry*>& pending_blob : | 495 for (const std::pair<std::string, BlobEntry*>& pending_blob : |
| 445 flattener.dependent_blobs) { | 496 flattener.dependent_blobs) { |
| 446 dependent_blobs.push_back( | 497 dependent_blobs.push_back( |
| 447 CreateHandle(pending_blob.first, pending_blob.second)); | 498 CreateHandle(pending_blob.first, pending_blob.second)); |
| 448 if (BlobStatusIsPending(pending_blob.second->status())) { | 499 if (BlobStatusIsPending(pending_blob.second->status())) { |
| 449 pending_blob.second->building_state_->build_completion_callbacks | 500 pending_blob.second->building_state_->build_completion_callbacks |
| 450 .push_back(base::Bind(&BlobStorageContext::OnDependentBlobFinished, | 501 .push_back(base::Bind(&BlobStorageContext::OnDependentBlobFinished, |
| 451 ptr_factory_.GetWeakPtr(), content.uuid_)); | 502 ptr_factory_.GetWeakPtr(), content.uuid_)); |
| 452 num_building_dependent_blobs++; | 503 num_building_dependent_blobs++; |
| 453 } | 504 } |
| 454 } | 505 } |
| 455 | 506 |
| 456 entry->set_building_state(base::MakeUnique<BlobEntry::BuildingState>( | 507 entry->set_building_state(base::MakeUnique<BlobEntry::BuildingState>( |
| 457 !flattener.transport_items.empty(), transport_allowed_callback, | 508 !flattener.pending_transport_items.empty(), transport_allowed_callback, |
| 458 num_building_dependent_blobs)); | 509 num_building_dependent_blobs)); |
| 459 BlobEntry::BuildingState* building_state = entry->building_state_.get(); | 510 BlobEntry::BuildingState* building_state = entry->building_state_.get(); |
| 460 std::swap(building_state->copies, flattener.copies); | 511 std::swap(building_state->copies, flattener.copies); |
| 461 std::swap(building_state->dependent_blobs, dependent_blobs); | 512 std::swap(building_state->dependent_blobs, dependent_blobs); |
| 462 std::swap(building_state->transport_items, flattener.transport_items); | 513 std::swap(building_state->transport_items, flattener.transport_items); |
| 463 | 514 |
| 464 // Break ourselves if we have an error. BuildingState must be set first so the | 515 // Break ourselves if we have an error. BuildingState must be set first so the |
| 465 // callback is called correctly. | 516 // callback is called correctly. |
| 466 if (BlobStatusIsError(flattener.status)) { | 517 if (BlobStatusIsError(flattener.status)) { |
| 467 CancelBuildingBlobInternal(entry, flattener.status); | 518 CancelBuildingBlobInternal(entry, flattener.status); |
| 468 return handle; | 519 return handle; |
| 469 } | 520 } |
| 470 | 521 |
| 471 if (!memory_controller_.CanReserveQuota(flattener.memory_quota_needed)) { | 522 // Avoid the state where we might grant only one quota. |
| 523 if (!memory_controller_.CanReserveQuota(flattener.copy_quota_needed + | |
| 524 flattener.transport_quota_needed)) { | |
| 472 CancelBuildingBlobInternal(entry, BlobStatus::ERR_OUT_OF_MEMORY); | 525 CancelBuildingBlobInternal(entry, BlobStatus::ERR_OUT_OF_MEMORY); |
| 473 return handle; | 526 return handle; |
| 474 } | 527 } |
| 475 | 528 |
| 476 if (flattener.memory_quota_needed > 0) { | 529 if (flattener.copy_quota_needed > 0) { |
| 477 // The blob can complete during the execution of this line. | 530 // The blob can complete during the execution of this line. |
| 478 base::WeakPtr<QuotaAllocationTask> pending_request = | 531 base::WeakPtr<QuotaAllocationTask> pending_request = |
| 479 memory_controller_.ReserveMemoryQuota( | 532 memory_controller_.ReserveMemoryQuota( |
| 480 std::move(flattener.pending_memory_items), | 533 std::move(flattener.pending_copy_items), |
| 481 base::Bind(&BlobStorageContext::OnEnoughSizeForMemory, | 534 base::Bind(&BlobStorageContext::OnEnoughSpaceForCopies, |
| 482 ptr_factory_.GetWeakPtr(), content.uuid_)); | 535 ptr_factory_.GetWeakPtr(), content.uuid_)); |
| 483 // Building state will be null if the blob is already finished. | 536 // Building state will be null if the blob is already finished. |
| 484 if (entry->building_state_) | 537 if (entry->building_state_) |
| 485 entry->building_state_->memory_quota_request = std::move(pending_request); | 538 entry->building_state_->copy_quota_request = std::move(pending_request); |
| 539 } | |
| 540 | |
| 541 if (flattener.transport_quota_needed > 0) { | |
| 542 // The blob can complete during the execution of this line. | |
|
kinuko
2016/11/27 14:45:22
This comment looks misplaced (must be placed befor
dmurph
2016/11/28 19:20:36
Done.
| |
| 543 base::WeakPtr<QuotaAllocationTask> pending_request; | |
| 544 | |
| 545 switch (flattener.transport_quota_type) { | |
| 546 case TransportQuotaType::MEMORY: | |
| 547 pending_request = memory_controller_.ReserveMemoryQuota( | |
| 548 std::move(flattener.pending_transport_items), | |
| 549 base::Bind(&BlobStorageContext::OnEnoughSpaceForTransportByMemory, | |
| 550 ptr_factory_.GetWeakPtr(), content.uuid_)); | |
| 551 break; | |
| 552 case TransportQuotaType::FILE: | |
| 553 pending_request = memory_controller_.ReserveFileQuota( | |
| 554 std::move(flattener.pending_transport_items), | |
| 555 base::Bind(&BlobStorageContext::OnEnoughSpaceForTransportByFiles, | |
| 556 ptr_factory_.GetWeakPtr(), content.uuid_)); | |
| 557 break; | |
| 558 } | |
| 559 | |
| 560 // Building state will be null if the blob is already finished. | |
| 561 if (entry->building_state_) | |
| 562 entry->building_state_->transport_quota_request = | |
| 563 std::move(pending_request); | |
| 486 } | 564 } |
| 487 | 565 |
| 488 if (entry->CanFinishBuilding()) | 566 if (entry->CanFinishBuilding()) |
| 489 FinishBuilding(entry); | 567 FinishBuilding(entry); |
| 490 | 568 |
| 491 return handle; | 569 return handle; |
| 492 } | 570 } |
| 493 | 571 |
| 494 void BlobStorageContext::CancelBuildingBlob(const std::string& uuid, | 572 void BlobStorageContext::CancelBuildingBlob(const std::string& uuid, |
| 495 BlobStatus reason) { | 573 BlobStatus reason) { |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 615 // Our source item can be a file if it was a slice of an unpopulated file, | 693 // Our source item can be a file if it was a slice of an unpopulated file, |
| 616 // or a slice of data that was then paged to disk. | 694 // or a slice of data that was then paged to disk. |
| 617 size_t dest_size = static_cast<size_t>(copy.dest_item->item()->length()); | 695 size_t dest_size = static_cast<size_t>(copy.dest_item->item()->length()); |
| 618 DataElement::Type dest_type = copy.dest_item->item()->type(); | 696 DataElement::Type dest_type = copy.dest_item->item()->type(); |
| 619 switch (copy.source_item->item()->type()) { | 697 switch (copy.source_item->item()->type()) { |
| 620 case DataElement::TYPE_BYTES: { | 698 case DataElement::TYPE_BYTES: { |
| 621 DCHECK_EQ(dest_type, DataElement::TYPE_BYTES_DESCRIPTION); | 699 DCHECK_EQ(dest_type, DataElement::TYPE_BYTES_DESCRIPTION); |
| 622 const char* src_data = | 700 const char* src_data = |
| 623 copy.source_item->item()->bytes() + copy.source_item_offset; | 701 copy.source_item->item()->bytes() + copy.source_item_offset; |
| 624 copy.dest_item->item()->item_->SetToBytes(src_data, dest_size); | 702 copy.dest_item->item()->item_->SetToBytes(src_data, dest_size); |
| 625 } break; | 703 break; |
| 626 case DataElement::TYPE_FILE: | 704 } |
| 705 case DataElement::TYPE_FILE: { | |
| 706 // If we expected a memory item (and our source was paged to disk) we | |
| 707 // free that memory. | |
| 708 if (dest_type == DataElement::TYPE_BYTES_DESCRIPTION) | |
| 709 copy.dest_item->set_memory_allocation(nullptr); | |
| 710 | |
| 711 const DataElement& source_element = | |
| 712 copy.source_item->item()->data_element(); | |
| 713 std::unique_ptr<DataElement> new_element(new DataElement()); | |
| 714 new_element->SetToFilePathRange( | |
| 715 source_element.path(), | |
| 716 source_element.offset() + copy.source_item_offset, dest_size, | |
| 717 source_element.expected_modification_time()); | |
| 718 scoped_refptr<BlobDataItem> new_item(new BlobDataItem( | |
| 719 std::move(new_element), copy.source_item->item()->data_handle_)); | |
| 720 copy.dest_item->set_item(std::move(new_item)); | |
| 721 break; | |
| 722 } | |
| 627 case DataElement::TYPE_UNKNOWN: | 723 case DataElement::TYPE_UNKNOWN: |
| 628 case DataElement::TYPE_BLOB: | 724 case DataElement::TYPE_BLOB: |
| 629 case DataElement::TYPE_BYTES_DESCRIPTION: | 725 case DataElement::TYPE_BYTES_DESCRIPTION: |
| 630 case DataElement::TYPE_FILE_FILESYSTEM: | 726 case DataElement::TYPE_FILE_FILESYSTEM: |
| 631 case DataElement::TYPE_DISK_CACHE_ENTRY: | 727 case DataElement::TYPE_DISK_CACHE_ENTRY: |
| 632 NOTREACHED(); | 728 NOTREACHED(); |
| 633 break; | 729 break; |
| 634 } | 730 } |
| 635 copy.dest_item->set_state(ShareableBlobDataItem::POPULATED_WITH_QUOTA); | 731 copy.dest_item->set_state(ShareableBlobDataItem::POPULATED_WITH_QUOTA); |
| 636 } | 732 } |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 663 BlobEntry::BuildingState* building_state = entry->building_state_.get(); | 759 BlobEntry::BuildingState* building_state = entry->building_state_.get(); |
| 664 if (building_state->transport_allowed_callback) { | 760 if (building_state->transport_allowed_callback) { |
| 665 base::ResetAndReturn(&building_state->transport_allowed_callback) | 761 base::ResetAndReturn(&building_state->transport_allowed_callback) |
| 666 .Run(BlobStatus::PENDING_TRANSPORT, std::move(files)); | 762 .Run(BlobStatus::PENDING_TRANSPORT, std::move(files)); |
| 667 return; | 763 return; |
| 668 } | 764 } |
| 669 DCHECK(files.empty()); | 765 DCHECK(files.empty()); |
| 670 NotifyTransportCompleteInternal(entry); | 766 NotifyTransportCompleteInternal(entry); |
| 671 } | 767 } |
| 672 | 768 |
| 673 void BlobStorageContext::OnEnoughSizeForMemory(const std::string& uuid, | 769 void BlobStorageContext::OnEnoughSpaceForTransportByFiles( |
| 674 bool success) { | 770 const std::string& uuid, |
| 771 bool success, | |
| 772 std::vector<BlobMemoryController::FileCreationInfo> files) { | |
| 675 if (!success) { | 773 if (!success) { |
| 676 CancelBuildingBlob(uuid, BlobStatus::ERR_OUT_OF_MEMORY); | 774 CancelBuildingBlob(uuid, BlobStatus::ERR_OUT_OF_MEMORY); |
| 677 return; | 775 return; |
| 678 } | 776 } |
| 679 BlobEntry* entry = registry_.GetEntry(uuid); | 777 BlobEntry* entry = registry_.GetEntry(uuid); |
| 680 if (!entry || !entry->building_state_.get()) | 778 if (!entry || !entry->building_state_.get()) |
| 681 return; | 779 return; |
| 682 BlobEntry::BuildingState& building_state = *entry->building_state_; | 780 BlobEntry::BuildingState& building_state = *entry->building_state_; |
| 683 DCHECK(!building_state.memory_quota_request); | 781 DCHECK(!building_state.transport_quota_request); |
| 782 DCHECK(building_state.transport_items_present); | |
| 684 | 783 |
| 685 if (building_state.transport_items_present) { | 784 entry->set_status(BlobStatus::PENDING_TRANSPORT); |
| 686 entry->set_status(BlobStatus::PENDING_TRANSPORT); | 785 RequestTransport(entry, std::move(files)); |
| 687 RequestTransport(entry, | |
| 688 std::vector<BlobMemoryController::FileCreationInfo>()); | |
| 689 } else { | |
| 690 entry->set_status(BlobStatus::PENDING_INTERNALS); | |
| 691 } | |
| 692 | 786 |
| 693 if (entry->CanFinishBuilding()) | 787 if (entry->CanFinishBuilding()) |
| 694 FinishBuilding(entry); | 788 FinishBuilding(entry); |
| 789 } | |
| 790 | |
| 791 void BlobStorageContext::OnEnoughSpaceForTransportByMemory( | |
| 792 const std::string& uuid, | |
| 793 bool success) { | |
| 794 OnEnoughSpaceForTransportByFiles( | |
| 795 uuid, success, std::vector<BlobMemoryController::FileCreationInfo>()); | |
| 796 } | |
| 797 | |
| 798 void BlobStorageContext::OnEnoughSpaceForCopies(const std::string& uuid, | |
| 799 bool success) { | |
| 800 if (!success) { | |
| 801 CancelBuildingBlob(uuid, BlobStatus::ERR_OUT_OF_MEMORY); | |
| 802 return; | |
| 803 } | |
| 804 BlobEntry* entry = registry_.GetEntry(uuid); | |
| 805 if (!entry) | |
| 806 return; | |
| 807 | |
| 808 if (entry->CanFinishBuilding()) | |
| 809 FinishBuilding(entry); | |
| 695 } | 810 } |
| 696 | 811 |
| 697 void BlobStorageContext::OnDependentBlobFinished( | 812 void BlobStorageContext::OnDependentBlobFinished( |
| 698 const std::string& owning_blob_uuid, | 813 const std::string& owning_blob_uuid, |
| 699 BlobStatus status) { | 814 BlobStatus status) { |
| 700 BlobEntry* entry = registry_.GetEntry(owning_blob_uuid); | 815 BlobEntry* entry = registry_.GetEntry(owning_blob_uuid); |
| 701 if (!entry || !entry->building_state_) | 816 if (!entry || !entry->building_state_) |
| 702 return; | 817 return; |
| 703 | 818 |
| 704 if (BlobStatusIsError(status)) { | 819 if (BlobStatusIsError(status)) { |
| 705 DCHECK_NE(BlobStatus::ERR_BLOB_DEREFERENCED_WHILE_BUILDING, status) | 820 DCHECK_NE(BlobStatus::ERR_BLOB_DEREFERENCED_WHILE_BUILDING, status) |
| 706 << "Referenced blob should never be dereferenced while we " | 821 << "Referenced blob should never be dereferenced while we " |
| 707 << "are depending on it, as our system holds a handle."; | 822 << "are depending on it, as our system holds a handle."; |
| 708 CancelBuildingBlobInternal(entry, BlobStatus::ERR_REFERENCED_BLOB_BROKEN); | 823 CancelBuildingBlobInternal(entry, BlobStatus::ERR_REFERENCED_BLOB_BROKEN); |
| 709 return; | 824 return; |
| 710 } | 825 } |
| 711 DCHECK_GT(entry->building_state_->num_building_dependent_blobs, 0u); | 826 DCHECK_GT(entry->building_state_->num_building_dependent_blobs, 0u); |
| 712 --entry->building_state_->num_building_dependent_blobs; | 827 --entry->building_state_->num_building_dependent_blobs; |
| 713 | 828 |
| 714 if (entry->CanFinishBuilding()) | 829 if (entry->CanFinishBuilding()) |
| 715 FinishBuilding(entry); | 830 FinishBuilding(entry); |
| 716 } | 831 } |
| 717 | 832 |
| 718 void BlobStorageContext::ClearAndFreeMemory(BlobEntry* entry) { | 833 void BlobStorageContext::ClearAndFreeMemory(BlobEntry* entry) { |
| 719 if (entry->building_state_) { | 834 if (entry->building_state_) { |
| 720 BlobEntry::BuildingState* building_state = entry->building_state_.get(); | 835 BlobEntry::BuildingState* building_state = entry->building_state_.get(); |
| 721 if (building_state->memory_quota_request) { | 836 if (building_state->copy_quota_request) { |
| 722 building_state->memory_quota_request->Cancel(); | 837 building_state->copy_quota_request->Cancel(); |
| 838 } | |
| 839 if (building_state->transport_quota_request) { | |
| 840 building_state->transport_quota_request->Cancel(); | |
| 723 } | 841 } |
| 724 } | 842 } |
| 725 entry->ClearItems(); | 843 entry->ClearItems(); |
| 726 entry->ClearOffsets(); | 844 entry->ClearOffsets(); |
| 727 entry->set_size(0); | 845 entry->set_size(0); |
| 728 } | 846 } |
| 729 | 847 |
| 730 } // namespace storage | 848 } // namespace storage |
| OLD | NEW |