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

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

Issue 1528233004: [Blob] Blob paging to disk patch. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@blob-disk1
Patch Set: Created 5 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
Index: storage/browser/blob/blob_async_builder_host.cc
diff --git a/storage/browser/blob/blob_async_builder_host.cc b/storage/browser/blob/blob_async_builder_host.cc
index 1cd2e7779e1a071d7d77c4d82d28ad2eea00dc45..460c65837eefaf1ee549f293cc6852108f602a0f 100644
--- a/storage/browser/blob/blob_async_builder_host.cc
+++ b/storage/browser/blob/blob_async_builder_host.cc
@@ -6,21 +6,25 @@
#include <utility>
+#include "base/bind.h"
+#include "base/files/file.h"
#include "base/memory/shared_memory.h"
+#include "storage/browser/blob/blob_memory_controller.h"
+#include "storage/browser/blob/shareable_file_reference.h"
namespace storage {
-
+using BlobTrasportationMemoryStrategyResult =
+ BlobMemoryController::BlobTrasportationMemoryStrategyResult;
+using FileCreationInfo = BlobMemoryController::FileCreationInfo;
using MemoryItemRequest = BlobAsyncTransportStrategy::RendererMemoryItemRequest;
-BlobAsyncBuilderHost::BlobBuildingState::BlobBuildingState()
- : next_request(0),
- num_fulfilled_requests(0),
- num_shared_memory_requests(0),
- current_shared_memory_handle_index(0) {}
+BlobAsyncBuilderHost::BlobBuildingState::BlobBuildingState(
+ const std::string& uuid)
+ : builder(uuid) {}
BlobAsyncBuilderHost::BlobBuildingState::~BlobBuildingState() {}
-BlobAsyncBuilderHost::BlobAsyncBuilderHost() {}
+BlobAsyncBuilderHost::BlobAsyncBuilderHost() : weak_ptr_factory_(this) {}
BlobAsyncBuilderHost::~BlobAsyncBuilderHost() {}
@@ -28,28 +32,47 @@ bool BlobAsyncBuilderHost::StartBuildingBlob(
const std::string& uuid,
const std::string& type,
const std::vector<DataElement>& descriptions,
- size_t memory_available,
+ storage::BlobMemoryController* memory_controller,
const base::Callback<void(const std::vector<storage::BlobItemBytesRequest>&,
const std::vector<base::SharedMemoryHandle>&,
const std::vector<uint64_t>&)>& request_memory,
const base::Callback<void(const BlobDataBuilder&)>& done,
const base::Callback<void(IPCBlobCreationCancelCode)>& cancel) {
+ DCHECK(memory_controller);
if (async_blob_map_.find(uuid) != async_blob_map_.end())
return false;
- if (BlobAsyncTransportStrategy::ShouldBeShortcut(descriptions,
- memory_available)) {
- // We have enough memory, and all the data is here, so we use the shortcut
- // method and populate the old way.
- BlobDataBuilder builder(uuid);
- builder.set_content_type(type);
- for (const DataElement& element : descriptions) {
- builder.AppendIPCDataElement(element);
+
+ uint64_t total_memory_size_bytes;
+ BlobMemoryController::BlobTrasportationMemoryStrategyResult strategy;
+ if (!memory_controller->DecideBlobTransportationMemoryStrategy(
+ descriptions, &total_memory_size_bytes, &strategy)) {
+ return false;
+ }
+
+ switch (strategy) {
+ case BlobTrasportationMemoryStrategyResult::TOO_LARGE:
+ cancel.Run(IPCBlobCreationCancelCode::OUT_OF_MEMORY);
+ return true;
+ case BlobTrasportationMemoryStrategyResult::NONE_NEEDED:
+ case BlobTrasportationMemoryStrategyResult::SHORTCUT: {
+ // We either have enough memory & the data is populated, or we don't have
+ // any data to populate.
+ BlobDataBuilder builder(uuid);
+ builder.set_content_type(type);
+ for (const DataElement& element : descriptions) {
+ builder.AppendIPCDataElement(element);
+ }
+ done.Run(builder);
+ return true;
}
- done.Run(builder);
- return true;
+ case BlobTrasportationMemoryStrategyResult::IPC:
+ case BlobTrasportationMemoryStrategyResult::SHARED_MEMORY:
+ case BlobTrasportationMemoryStrategyResult::FILE:
+ // Handle these in next switch, as we need to create our state first.
+ break;
}
- scoped_ptr<BlobBuildingState> state(new BlobBuildingState());
+ scoped_ptr<BlobBuildingState> state(new BlobBuildingState(uuid));
BlobBuildingState* state_ptr = state.get();
async_blob_map_[uuid] = std::move(state);
state_ptr->type = type;
@@ -57,29 +80,38 @@ bool BlobAsyncBuilderHost::StartBuildingBlob(
state_ptr->done_callback = done;
state_ptr->cancel_callback = cancel;
- // We are currently only operating in 'no disk' mode. This will change in
- // future patches to enable disk storage.
- // Since we don't have a disk yet, we put 0 for disk_space_left.
- state_ptr->transport_strategy.Initialize(
- max_ipc_memory_size_, max_shared_memory_size_, max_file_size_,
- 0 /* disk_space_left */, memory_available, uuid, descriptions);
-
- switch (state_ptr->transport_strategy.error()) {
- case BlobAsyncTransportStrategy::ERROR_TOO_LARGE:
- // Cancel cleanly, we're out of memory.
- CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY);
- return true;
- case BlobAsyncTransportStrategy::ERROR_INVALID_PARAMS:
- // Bad IPC, so we ignore and clean up.
- VLOG(1) << "Error initializing transport strategy: "
- << state_ptr->transport_strategy.error();
- async_blob_map_.erase(async_blob_map_.find(uuid));
- return false;
- case BlobAsyncTransportStrategy::ERROR_NONE:
- ContinueBlobMemoryRequests(uuid);
- return true;
+ switch (strategy) {
+ case BlobTrasportationMemoryStrategyResult::IPC:
+ state_ptr->transport_strategy.InitializeForIPCTransportation(
+ max_ipc_memory_size_, uuid, total_memory_size_bytes, descriptions,
+ &(state_ptr->builder));
+ break;
+ case BlobTrasportationMemoryStrategyResult::SHARED_MEMORY:
+ state_ptr->transport_strategy.InitializeForSharedMemoryRequests(
+ max_shared_memory_size_, uuid, total_memory_size_bytes, descriptions,
+ &(state_ptr->builder));
+ break;
+ case BlobTrasportationMemoryStrategyResult::FILE:
+ state_ptr->transport_strategy.InitializeForFileRequests(
+ max_file_size_, uuid, total_memory_size_bytes, descriptions,
+ &(state_ptr->builder));
+ break;
+ case BlobTrasportationMemoryStrategyResult::TOO_LARGE:
+ case BlobTrasportationMemoryStrategyResult::NONE_NEEDED:
+ case BlobTrasportationMemoryStrategyResult::SHORTCUT:
+ // These cases should be handled above.
+ CHECK(false);
+ break;
}
- return false;
+ state_ptr->request_received.resize(
+ state_ptr->transport_strategy.requests().size(), false);
+
+ memory_controller->NotifyWhenBlobCanBeRequested(
+ total_memory_size_bytes,
+ base::Bind(&BlobAsyncBuilderHost::StartRequestingBlobAndCreateFileHandles,
+ weak_ptr_factory_.GetWeakPtr(), uuid,
+ memory_controller->AsWeakPtr()));
+ return true;
}
bool BlobAsyncBuilderHost::OnMemoryResponses(
@@ -108,13 +140,13 @@ bool BlobAsyncBuilderHost::OnMemoryResponses(
return false;
}
const MemoryItemRequest& request = requests[response.request_number];
- if (request.received) {
+ if (state->request_received[response.request_number]) {
// Bad IPC, so we delete our record.
DVLOG(1) << "Already received response for that request.";
async_blob_map_.erase(state_it);
return false;
}
- strategy.MarkRequestAsReceived(response.request_number);
+ state->request_received[response.request_number] = true;
switch (request.message.transport_strategy) {
case IPCBlobItemRequestStrategy::IPC:
if (response.inline_data.size() < request.message.size) {
@@ -123,7 +155,7 @@ bool BlobAsyncBuilderHost::OnMemoryResponses(
invalid_ipc = true;
break;
}
- invalid_ipc = !strategy.blob_builder()->PopulateFutureData(
+ invalid_ipc = !state->builder.PopulateFutureData(
request.browser_item_index, &response.inline_data[0],
request.browser_item_offset, request.message.size);
break;
@@ -139,7 +171,7 @@ bool BlobAsyncBuilderHost::OnMemoryResponses(
// whole thing in this group of responses. Another option is to use
// MapAt, remove the mapped boolean, and then exclude the
// handle_offset below.
- size_t handle_size = strategy.handle_sizes().at(
+ size_t handle_size = strategy.shared_memory_handle_sizes().at(
state->current_shared_memory_handle_index);
if (!state->shared_memory_block->Map(handle_size)) {
DVLOG(1) << "Unable to map memory to size " << handle_size;
@@ -148,13 +180,24 @@ bool BlobAsyncBuilderHost::OnMemoryResponses(
}
}
- invalid_ipc = !strategy.blob_builder()->PopulateFutureData(
+ invalid_ipc = !state->builder.PopulateFutureData(
request.browser_item_index,
static_cast<const char*>(state->shared_memory_block->memory()) +
request.message.handle_offset,
request.browser_item_offset, request.message.size);
break;
- case IPCBlobItemRequestStrategy::FILE:
+ case IPCBlobItemRequestStrategy::FILE: {
+ const FileCreationInfo& file_info =
+ state->files_created[request.message.handle_offset];
+ if (!file_info.file_reference.get() ||
+ file_info.error != base::File::FILE_OK) {
+ invalid_ipc = true;
+ break;
+ }
+ invalid_ipc = !state->builder.PopulateFutureFile(
+ request.browser_item_index, file_info.file_reference,
+ response.time_modified);
+ }
case IPCBlobItemRequestStrategy::UNKNOWN:
DVLOG(1) << "Not implemented.";
invalid_ipc = true;
@@ -180,10 +223,44 @@ void BlobAsyncBuilderHost::StopBuildingBlob(const std::string& uuid) {
async_blob_map_.erase(async_blob_map_.find(uuid));
}
+void BlobAsyncBuilderHost::StartRequestingBlobAndCreateFileHandles(
+ const std::string& uuid,
+ base::WeakPtr<BlobMemoryController> memory_controller,
+ bool can_request) {
+ if (!can_request) {
+ CancelAndCleanup(uuid, IPCBlobCreationCancelCode::UNKNOWN);
+ return;
+ }
+ BlobAsyncBuilderHost::BlobBuildingState* state = async_blob_map_[uuid].get();
+ DCHECK(state);
+ DCHECK(!state->requests_started);
+ if (!memory_controller.get()) {
+ async_blob_map_.erase(uuid);
+ return;
+ }
+
+ size_t file_handles_count =
+ state->transport_strategy.file_handle_sizes().size();
+ if (file_handles_count != 0) {
+ state->files_created.resize(file_handles_count, FileCreationInfo());
+ // Create file handles.
+ for (int i = 0; i < file_handles_count; ++i) {
+ size_t file_handle_size =
+ state->transport_strategy.file_handle_sizes()[i];
+ memory_controller->CreateTemporaryFileForRenderer(
+ file_handle_size,
+ base::Bind(&BlobAsyncBuilderHost::FileCreatedForBlob,
+ weak_ptr_factory_.GetWeakPtr(), uuid, i));
+ }
+ }
+
+ ContinueBlobMemoryRequests(uuid);
+}
+
void BlobAsyncBuilderHost::ContinueBlobMemoryRequests(const std::string& uuid) {
- AsyncBlobMap::const_iterator state_it = async_blob_map_.find(uuid);
- DCHECK(state_it != async_blob_map_.end());
- BlobAsyncBuilderHost::BlobBuildingState* state = state_it->second.get();
+ BlobAsyncBuilderHost::BlobBuildingState* state = async_blob_map_[uuid].get();
+ DCHECK(state);
+ DCHECK(state->requests_started);
const std::vector<MemoryItemRequest>& requests =
state->transport_strategy.requests();
@@ -201,7 +278,6 @@ void BlobAsyncBuilderHost::ContinueBlobMemoryRequests(const std::string& uuid) {
std::vector<BlobItemBytesRequest> byte_requests;
std::vector<base::SharedMemoryHandle> shared_memory;
- std::vector<uint64_t> files;
for (; state->next_request < num_requests; ++state->next_request) {
const MemoryItemRequest& request = requests[state->next_request];
@@ -227,7 +303,9 @@ void BlobAsyncBuilderHost::ContinueBlobMemoryRequests(const std::string& uuid) {
if (!state->shared_memory_block) {
state->shared_memory_block.reset(new base::SharedMemory());
- size_t size = strategy.handle_sizes()[request.message.handle_index];
+ size_t size =
+ strategy
+ .shared_memory_handle_sizes()[request.message.handle_index];
if (!state->shared_memory_block->CreateAnonymous(size)) {
DVLOG(1) << "Unable to allocate shared memory for blob transfer.";
CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY);
@@ -241,6 +319,9 @@ void BlobAsyncBuilderHost::ContinueBlobMemoryRequests(const std::string& uuid) {
byte_requests.back().handle_index = 0;
break;
case IPCBlobItemRequestStrategy::FILE:
+ // We ignore file requests because we send them in our
+ // FileCreatedForBlob callback after the file is created.
+ break;
case IPCBlobItemRequestStrategy::UNKNOWN:
NOTREACHED() << "Not implemented yet.";
break;
@@ -250,9 +331,51 @@ void BlobAsyncBuilderHost::ContinueBlobMemoryRequests(const std::string& uuid) {
}
}
- DCHECK(!requests.empty());
+ if (byte_requests.empty()) {
+ return;
+ }
+
+ state->request_memory_callback.Run(
+ byte_requests, shared_memory,
+ std::vector<scoped_refptr<ShareableFileReference>>());
+}
+
+void BlobAsyncBuilderHost::FileCreatedForBlob(
+ const std::string& uuid,
+ size_t handle_index,
+ const BlobMemoryController::FileCreationInfo& creation_info) {
+ auto it = async_blob_map_.find(uuid);
+ if (it == async_blob_map_.end()) {
+ // We must have killed the blob. Returning should kill the file, as it is
+ // managed by the ShareableFileReference in the creation info.
+ return;
+ }
+ BlobAsyncBuilderHost::BlobBuildingState* state = it->second.get();
+ DCHECK(state);
+ DCHECK(state->requests_started);
+ if (creation_info.error != base::File::FILE_OK) {
+ CancelAndCleanup(uuid, IPCBlobCreationCancelCode::UNKNOWN);
+ return;
+ }
+ state->files_created[handle_index] = creation_info;
+
+ std::vector<BlobItemBytesRequest> byte_requests;
+ std::vector<scoped_refptr<ShareableFileReference>> file_handles = {
+ creation_info.file_reference};
+
+ // We send all requests that use this handle.
+ for (const auto& request : state->transport_strategy.requests()) {
+ const BlobItemBytesRequest& message = request.message;
+ if (message.transport_strategy != IPCBlobItemRequestStrategy::FILE ||
+ message.handle_index != handle_index) {
+ continue;
+ }
+ byte_requests.push_back(request.message);
+ byte_requests.back().handle_index = 0;
+ }
- state->request_memory_callback.Run(byte_requests, shared_memory, files);
+ state->request_memory_callback.Run(
+ byte_requests, std::vector<base::SharedMemoryHandle>(), file_handles);
}
void BlobAsyncBuilderHost::CancelAndCleanup(const std::string& uuid,
@@ -265,9 +388,8 @@ void BlobAsyncBuilderHost::CancelAndCleanup(const std::string& uuid,
void BlobAsyncBuilderHost::DoneAndCleanup(const std::string& uuid) {
scoped_ptr<BlobBuildingState> state = std::move(async_blob_map_[uuid]);
async_blob_map_.erase(uuid);
- BlobDataBuilder* builder = state->transport_strategy.blob_builder();
- builder->set_content_type(state->type);
- state->done_callback.Run(*builder);
+ state->builder.set_content_type(state->type);
+ state->done_callback.Run(state->builder);
}
} // namespace storage
« no previous file with comments | « storage/browser/blob/blob_async_builder_host.h ('k') | storage/browser/blob/blob_async_transport_strategy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698