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