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