Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Unified Diff: storage/browser/blob/blob_storage_context.cc

Issue 2516713002: [BlobStorage] Implementing disk. (Closed)
Patch Set: removed cleanup check, as mac doesn't run out event loops Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « storage/browser/blob/blob_storage_context.h ('k') | storage/common/blob_storage/blob_storage_constants.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: storage/browser/blob/blob_storage_context.cc
diff --git a/storage/browser/blob/blob_storage_context.cc b/storage/browser/blob/blob_storage_context.cc
index 1fecda89f5b6799136cab3bc4089840251ad8f3b..acc086e57c04070c32968b932f0dbec5ebc218e8 100644
--- a/storage/browser/blob/blob_storage_context.cc
+++ b/storage/browser/blob/blob_storage_context.cc
@@ -92,9 +92,13 @@ BlobStorageContext::BlobFlattener::BlobFlattener(
size_t num_files_with_unknown_size = 0;
size_t num_building_dependent_blobs = 0;
+ bool found_memory_transport = false;
+ bool found_file_transport = false;
+
base::CheckedNumeric<uint64_t> checked_total_size = 0;
base::CheckedNumeric<uint64_t> checked_total_memory_size = 0;
- base::CheckedNumeric<uint64_t> checked_memory_quota_needed = 0;
+ base::CheckedNumeric<uint64_t> checked_transport_quota_needed = 0;
+ base::CheckedNumeric<uint64_t> checked_copy_quota_needed = 0;
for (scoped_refptr<BlobDataItem> input_item : input_builder.items_) {
const DataElement& input_element = input_item->data_element();
@@ -105,11 +109,19 @@ BlobStorageContext::BlobFlattener::BlobFlattener(
if (IsBytes(type)) {
DCHECK_NE(0 + DataElement::kUnknownSize, input_element.length());
- checked_memory_quota_needed += length;
+ found_memory_transport = true;
+ if (found_file_transport) {
+ // We cannot have both memory and file transport items.
+ status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
+ return;
+ }
+ contains_unpopulated_transport_items |=
+ (type == DataElement::TYPE_BYTES_DESCRIPTION);
+ checked_transport_quota_needed += length;
checked_total_size += length;
scoped_refptr<ShareableBlobDataItem> item = new ShareableBlobDataItem(
std::move(input_item), ShareableBlobDataItem::QUOTA_NEEDED);
- pending_memory_items.push_back(item);
+ pending_transport_items.push_back(item);
transport_items.push_back(item.get());
output_blob->AppendSharedBlobItem(std::move(item));
continue;
@@ -174,14 +186,14 @@ BlobStorageContext::BlobFlattener::BlobFlattener(
copies.push_back(ItemCopyEntry(slice.first_source_item,
slice.first_item_slice_offset,
slice.dest_items.front()));
- pending_memory_items.push_back(slice.dest_items.front());
+ pending_copy_items.push_back(slice.dest_items.front());
}
if (slice.last_source_item) {
copies.push_back(
ItemCopyEntry(slice.last_source_item, 0, slice.dest_items.back()));
- pending_memory_items.push_back(slice.dest_items.back());
+ pending_copy_items.push_back(slice.dest_items.back());
}
- checked_memory_quota_needed += slice.copying_memory_size;
+ checked_copy_quota_needed += slice.copying_memory_size;
for (auto& shareable_item : slice.dest_items) {
output_blob->AppendSharedBlobItem(std::move(shareable_item));
@@ -189,14 +201,30 @@ BlobStorageContext::BlobFlattener::BlobFlattener(
continue;
}
- DCHECK(!BlobDataBuilder::IsFutureFileItem(input_element))
- << "File allocation not implemented.";
+ // If the source item is a temporary file item, then we need to keep track
+ // of that and mark it as needing quota.
+ scoped_refptr<ShareableBlobDataItem> item;
+ if (BlobDataBuilder::IsFutureFileItem(input_element)) {
+ found_file_transport = true;
+ if (found_memory_transport) {
+ // We cannot have both memory and file transport items.
+ status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
+ return;
+ }
+ contains_unpopulated_transport_items = true;
+ item = new ShareableBlobDataItem(std::move(input_item),
+ ShareableBlobDataItem::QUOTA_NEEDED);
+ pending_transport_items.push_back(item);
+ transport_items.push_back(item.get());
+ checked_transport_quota_needed += length;
+ } else {
+ item = new ShareableBlobDataItem(
+ std::move(input_item),
+ ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA);
+ }
if (length == DataElement::kUnknownSize)
num_files_with_unknown_size++;
- scoped_refptr<ShareableBlobDataItem> item = new ShareableBlobDataItem(
- std::move(input_item), ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA);
-
checked_total_size += length;
output_blob->AppendSharedBlobItem(std::move(item));
}
@@ -206,14 +234,18 @@ BlobStorageContext::BlobFlattener::BlobFlattener(
return;
}
if (!checked_total_size.IsValid() || !checked_total_memory_size.IsValid() ||
- !checked_memory_quota_needed.IsValid()) {
+ !checked_transport_quota_needed.IsValid() ||
+ !checked_copy_quota_needed.IsValid()) {
status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
return;
}
total_size = checked_total_size.ValueOrDie();
total_memory_size = checked_total_memory_size.ValueOrDie();
- memory_quota_needed = checked_memory_quota_needed.ValueOrDie();
- if (memory_quota_needed) {
+ transport_quota_needed = checked_transport_quota_needed.ValueOrDie();
+ copy_quota_needed = checked_copy_quota_needed.ValueOrDie();
+ transport_quota_type = found_file_transport ? TransportQuotaType::FILE
+ : TransportQuotaType::MEMORY;
+ if (transport_quota_needed) {
status = BlobStatus::PENDING_QUOTA;
} else {
status = BlobStatus::PENDING_INTERNALS;
@@ -298,8 +330,16 @@ BlobStorageContext::BlobSlice::BlobSlice(const BlobEntry& source,
data_item =
new BlobDataItem(std::move(element), source_item->data_handle_);
- DCHECK(!BlobDataBuilder::IsFutureFileItem(source_item->data_element()))
- << "File allocation unimplemented.";
+ if (BlobDataBuilder::IsFutureFileItem(source_item->data_element())) {
+ // The source file isn't a real file yet (path is fake), so store the
+ // items we need to copy from later.
+ if (item_index == first_item_index) {
+ first_item_slice_offset = item_offset;
+ first_source_item = source_items[item_index];
+ } else {
+ last_source_item = source_items[item_index];
+ }
+ }
break;
}
case DataElement::TYPE_FILE_FILESYSTEM: {
@@ -341,8 +381,13 @@ BlobStorageContext::BlobStorageContext()
: memory_controller_(base::FilePath(), scoped_refptr<base::TaskRunner>()),
ptr_factory_(this) {}
-BlobStorageContext::~BlobStorageContext() {
-}
+BlobStorageContext::BlobStorageContext(
+ base::FilePath storage_directory,
+ scoped_refptr<base::TaskRunner> file_runner)
+ : memory_controller_(std::move(storage_directory), std::move(file_runner)),
+ ptr_factory_(this) {}
+
+BlobStorageContext::~BlobStorageContext() {}
std::unique_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID(
const std::string& uuid) {
@@ -414,14 +459,9 @@ std::unique_ptr<BlobDataHandle> BlobStorageContext::BuildBlob(
// stores the complete item representation in the internal data.
BlobFlattener flattener(content, entry, &registry_);
- DCHECK(flattener.status != BlobStatus::PENDING_TRANSPORT ||
- !transport_allowed_callback)
- << "There is no pending content for the user to populate, so the "
- "callback should be null.";
- DCHECK(flattener.status != BlobStatus::PENDING_TRANSPORT ||
+ DCHECK(!flattener.contains_unpopulated_transport_items ||
transport_allowed_callback)
- << "If we have pending content then there needs to be a callback "
- "present.";
+ << "If we have pending unpopulated content then a callback is required";
entry->set_size(flattener.total_size);
entry->set_status(flattener.status);
@@ -430,8 +470,14 @@ std::unique_ptr<BlobDataHandle> BlobStorageContext::BuildBlob(
UMA_HISTOGRAM_COUNTS("Storage.Blob.ItemCount", entry->items().size());
UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalSize",
flattener.total_memory_size / 1024);
+
+ uint64_t total_memory_needed =
+ flattener.copy_quota_needed +
+ (flattener.transport_quota_type == TransportQuotaType::MEMORY
+ ? flattener.transport_quota_needed
+ : 0);
UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalUnsharedSize",
- flattener.memory_quota_needed / 1024);
+ total_memory_needed / 1024);
size_t num_building_dependent_blobs = 0;
std::vector<std::unique_ptr<BlobDataHandle>> dependent_blobs;
@@ -454,7 +500,7 @@ std::unique_ptr<BlobDataHandle> BlobStorageContext::BuildBlob(
}
entry->set_building_state(base::MakeUnique<BlobEntry::BuildingState>(
- !flattener.transport_items.empty(), transport_allowed_callback,
+ !flattener.pending_transport_items.empty(), transport_allowed_callback,
num_building_dependent_blobs));
BlobEntry::BuildingState* building_state = entry->building_state_.get();
std::swap(building_state->copies, flattener.copies);
@@ -468,21 +514,52 @@ std::unique_ptr<BlobDataHandle> BlobStorageContext::BuildBlob(
return handle;
}
- if (!memory_controller_.CanReserveQuota(flattener.memory_quota_needed)) {
+ // Avoid the state where we might grant only one quota.
+ if (!memory_controller_.CanReserveQuota(flattener.copy_quota_needed +
+ flattener.transport_quota_needed)) {
CancelBuildingBlobInternal(entry, BlobStatus::ERR_OUT_OF_MEMORY);
return handle;
}
- if (flattener.memory_quota_needed > 0) {
- // The blob can complete during the execution of this line.
+ if (flattener.copy_quota_needed > 0) {
+ // The blob can complete during the execution of |ReserveMemoryQuota|.
base::WeakPtr<QuotaAllocationTask> pending_request =
memory_controller_.ReserveMemoryQuota(
- std::move(flattener.pending_memory_items),
- base::Bind(&BlobStorageContext::OnEnoughSizeForMemory,
+ std::move(flattener.pending_copy_items),
+ base::Bind(&BlobStorageContext::OnEnoughSpaceForCopies,
ptr_factory_.GetWeakPtr(), content.uuid_));
// Building state will be null if the blob is already finished.
if (entry->building_state_)
- entry->building_state_->memory_quota_request = std::move(pending_request);
+ entry->building_state_->copy_quota_request = std::move(pending_request);
+ }
+
+ if (flattener.transport_quota_needed > 0) {
+ base::WeakPtr<QuotaAllocationTask> pending_request;
+
+ switch (flattener.transport_quota_type) {
+ case TransportQuotaType::MEMORY: {
+ // The blob can complete during the execution of |ReserveMemoryQuota|.
+ std::vector<BlobMemoryController::FileCreationInfo> empty_files;
+ pending_request = memory_controller_.ReserveMemoryQuota(
+ std::move(flattener.pending_transport_items),
+ base::Bind(&BlobStorageContext::OnEnoughSpaceForTransport,
+ ptr_factory_.GetWeakPtr(), content.uuid_,
+ base::Passed(&empty_files)));
+ break;
+ }
+ case TransportQuotaType::FILE:
+ pending_request = memory_controller_.ReserveFileQuota(
+ std::move(flattener.pending_transport_items),
+ base::Bind(&BlobStorageContext::OnEnoughSpaceForTransport,
+ ptr_factory_.GetWeakPtr(), content.uuid_));
+ break;
+ }
+
+ // Building state will be null if the blob is already finished.
+ if (entry->building_state_) {
+ entry->building_state_->transport_quota_request =
+ std::move(pending_request);
+ }
}
if (entry->CanFinishBuilding())
@@ -622,8 +699,26 @@ void BlobStorageContext::FinishBuilding(BlobEntry* entry) {
const char* src_data =
copy.source_item->item()->bytes() + copy.source_item_offset;
copy.dest_item->item()->item_->SetToBytes(src_data, dest_size);
- } break;
- case DataElement::TYPE_FILE:
+ break;
+ }
+ case DataElement::TYPE_FILE: {
+ // If we expected a memory item (and our source was paged to disk) we
+ // free that memory.
+ if (dest_type == DataElement::TYPE_BYTES_DESCRIPTION)
+ copy.dest_item->set_memory_allocation(nullptr);
+
+ const DataElement& source_element =
+ copy.source_item->item()->data_element();
+ std::unique_ptr<DataElement> new_element(new DataElement());
+ new_element->SetToFilePathRange(
+ source_element.path(),
+ source_element.offset() + copy.source_item_offset, dest_size,
+ source_element.expected_modification_time());
+ scoped_refptr<BlobDataItem> new_item(new BlobDataItem(
+ std::move(new_element), copy.source_item->item()->data_handle_));
+ copy.dest_item->set_item(std::move(new_item));
+ break;
+ }
case DataElement::TYPE_UNKNOWN:
case DataElement::TYPE_BLOB:
case DataElement::TYPE_BYTES_DESCRIPTION:
@@ -670,8 +765,10 @@ void BlobStorageContext::RequestTransport(
NotifyTransportCompleteInternal(entry);
}
-void BlobStorageContext::OnEnoughSizeForMemory(const std::string& uuid,
- bool success) {
+void BlobStorageContext::OnEnoughSpaceForTransport(
+ const std::string& uuid,
+ std::vector<BlobMemoryController::FileCreationInfo> files,
+ bool success) {
if (!success) {
CancelBuildingBlob(uuid, BlobStatus::ERR_OUT_OF_MEMORY);
return;
@@ -680,15 +777,25 @@ void BlobStorageContext::OnEnoughSizeForMemory(const std::string& uuid,
if (!entry || !entry->building_state_.get())
return;
BlobEntry::BuildingState& building_state = *entry->building_state_;
- DCHECK(!building_state.memory_quota_request);
+ DCHECK(!building_state.transport_quota_request);
+ DCHECK(building_state.transport_items_present);
- if (building_state.transport_items_present) {
- entry->set_status(BlobStatus::PENDING_TRANSPORT);
- RequestTransport(entry,
- std::vector<BlobMemoryController::FileCreationInfo>());
- } else {
- entry->set_status(BlobStatus::PENDING_INTERNALS);
+ entry->set_status(BlobStatus::PENDING_TRANSPORT);
+ RequestTransport(entry, std::move(files));
+
+ if (entry->CanFinishBuilding())
+ FinishBuilding(entry);
+}
+
+void BlobStorageContext::OnEnoughSpaceForCopies(const std::string& uuid,
+ bool success) {
+ if (!success) {
+ CancelBuildingBlob(uuid, BlobStatus::ERR_OUT_OF_MEMORY);
+ return;
}
+ BlobEntry* entry = registry_.GetEntry(uuid);
+ if (!entry)
+ return;
if (entry->CanFinishBuilding())
FinishBuilding(entry);
@@ -716,12 +823,8 @@ void BlobStorageContext::OnDependentBlobFinished(
}
void BlobStorageContext::ClearAndFreeMemory(BlobEntry* entry) {
- if (entry->building_state_) {
- BlobEntry::BuildingState* building_state = entry->building_state_.get();
- if (building_state->memory_quota_request) {
- building_state->memory_quota_request->Cancel();
- }
- }
+ if (entry->building_state_)
+ entry->building_state_->CancelRequests();
entry->ClearItems();
entry->ClearOffsets();
entry->set_size(0);
« no previous file with comments | « storage/browser/blob/blob_storage_context.h ('k') | storage/common/blob_storage/blob_storage_constants.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698