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

Side by Side Diff: storage/browser/blob/blob_async_builder_host.cc

Issue 1098853003: [BlobAsync] Patch 4: Browser Classes & Logic. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments, and simplification Created 5 years, 1 month 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "storage/browser/blob/blob_async_builder_host.h"
6
7 #include "base/memory/shared_memory.h"
8 #include "base/stl_util.h"
9
10 namespace storage {
11
12 using MemoryItemRequest = BlobAsyncTransportStrategy::RendererMemoryItemRequest;
13
14 BlobAsyncBuilderHost::BlobBuildingState::BlobBuildingState()
15 : next_request(0),
16 num_fulfilled_requests(0),
17 num_shared_memory_requests(0),
18 current_shared_memory_handle_index(0) {}
19
20 BlobAsyncBuilderHost::BlobBuildingState::~BlobBuildingState() {}
21
22 BlobAsyncBuilderHost::BlobAsyncBuilderHost() {}
23
24 BlobAsyncBuilderHost::~BlobAsyncBuilderHost() {}
25
26 void BlobAsyncBuilderHost::StartBuildingBlob(
27 const std::string& uuid,
28 const std::string& type,
29 const std::vector<DataElement>& descriptions,
30 size_t memory_available,
31 base::Callback<void(const std::vector<storage::BlobItemBytesRequest>&,
32 const std::vector<base::SharedMemoryHandle>&,
33 const std::vector<IPC::PlatformFileForTransit>&)>
34 request_memory,
35 base::Callback<void(BlobDataBuilder*)> done,
36 base::Callback<void(IPCBlobCreationCancelCode)> cancel) {
37 if (BlobAsyncTransportStrategy::ShouldBeShortcut(descriptions,
38 memory_available)) {
39 // We have enough memory, and all the data is here, so we use the shortcut
40 // method and populate the old way.
41 BlobDataBuilder builder(uuid);
42 builder.set_content_type(type);
43 for (const DataElement& element : descriptions) {
44 builder.AppendIPCDataElement(element);
45 }
46 done.Run(&builder);
47 return;
48 }
49
50 DCHECK(async_blob_map_.find(uuid) == async_blob_map_.end());
51 BlobBuildingState* state_ptr = new BlobBuildingState();
52 async_blob_map_.insert(uuid, make_scoped_ptr(state_ptr).Pass());
53 state_ptr->type = type;
54 state_ptr->request_memory_callback = request_memory;
55 state_ptr->done_callback = done;
56 state_ptr->cancel_callback = cancel;
57
58 // We are currently only operating in 'no disk' mode. This will change in
59 // future patches to enable disk storage.
60 // Since we don't have a disk yet, we put 0 for disk_space_left.
61 state_ptr->transport_strategy.Initialize(
62 max_ipc_memory_size_, max_shared_memory_size_, max_file_size_,
63 /* disk_space_left */ 0, memory_available, uuid, descriptions);
64
65 switch (state_ptr->transport_strategy.error()) {
66 case BlobAsyncTransportStrategy::ERROR_NONE:
67 ContinueBlobMemoryRequests(uuid);
68 return;
69 case BlobAsyncTransportStrategy::ERROR_TOO_LARGE:
70 // Cancel cleanly, we're out of memory.
71 CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY);
72 return;
73 case BlobAsyncTransportStrategy::ERROR_INVALID_PARAMS:
74 // Bad IPC, so we ignore and clean up.
75 async_blob_map_.erase(async_blob_map_.find(uuid));
76 NOTREACHED() << "Error initializing transport strategy: "
77 << state_ptr->transport_strategy.error();
78 return;
79 }
80 }
81
82 void BlobAsyncBuilderHost::OnMemoryResponses(
83 const std::string& uuid,
84 const std::vector<BlobItemBytesResponse>& responses) {
85 AsyncBlobMap::const_iterator state_it = async_blob_map_.find(uuid);
86 DCHECK(state_it != async_blob_map_.end());
87 BlobAsyncBuilderHost::BlobBuildingState* state = state_it->second;
88 BlobAsyncTransportStrategy& strategy = state->transport_strategy;
89 bool populate_success = false;
90 const auto& requests = strategy.requests();
91 for (const BlobItemBytesResponse& response : responses) {
92 if (response.request_number >= requests.size()) {
93 // Bad IPC, so we delete our record and ignore.
94 DVLOG(1) << "Invalid request number " << response.request_number;
95 async_blob_map_.erase(state_it);
96 return;
97 }
98 const MemoryItemRequest& request = requests[response.request_number];
99 if (request.received) {
100 // Bad IPC, so we delete our record and ignore.
101 async_blob_map_.erase(state_it);
102 NOTREACHED() << "Already received response for that request.";
103 return;
104 }
105 switch (request.message.transport_strategy) {
106 case IPCBlobItemRequestStrategy::IPC:
107 if (response.inline_data.size() < request.message.size) {
108 // Bad IPC, so we delete our record and ignore.
109 async_blob_map_.erase(state_it);
110 NOTREACHED() << "Invalid data size " << response.inline_data.size()
111 << " vs requested size of " << request.message.size;
112 return;
113 }
114 populate_success = strategy.blob_builder()->PopulateFutureData(
115 request.browser_item_index, &response.inline_data[0],
116 request.browser_item_offset, request.message.size);
117 break;
118 case IPCBlobItemRequestStrategy::SHARED_MEMORY:
119 if (state->num_shared_memory_requests == 0) {
120 // Bad IPC, so we delete our record and ignore.
121 async_blob_map_.erase(state_it);
122 NOTREACHED() << "Received too many responses for shared memory.";
123 return;
124 }
125 state->num_shared_memory_requests--;
126 if (!state->shared_memory_block->memory()) {
127 // We just map the whole block, as we'll probably be accessing the
128 // whole thing in this group of responses. Another option is to use
129 // MapAt, remove the mapped boolean, and then exclude the
130 // handle_offset below.
131 size_t handle_size = strategy.shared_memory_handle_sizes().at(
132 state->current_shared_memory_handle_index);
133 if (!state->shared_memory_block->Map(handle_size)) {
134 DVLOG(1) << "Unable to map memory to size " << handle_size;
135 populate_success = false;
136 break;
137 }
138 }
139
140 populate_success = strategy.blob_builder()->PopulateFutureData(
141 request.browser_item_index,
142 static_cast<const char*>(state->shared_memory_block->memory()) +
143 request.message.handle_offset,
144 request.browser_item_offset, request.message.size);
145 break;
146 case IPCBlobItemRequestStrategy::FILE:
147 case IPCBlobItemRequestStrategy::UNKNOWN:
148 NOTREACHED() << "Not implemented yet.";
149 break;
150 }
151 if (!populate_success) {
152 DVLOG(1) << "Unable to populate blob data.";
153 CancelAndCleanup(uuid, IPCBlobCreationCancelCode::UNKNOWN);
154 return;
155 }
156 state->num_fulfilled_requests++;
157 }
158 ContinueBlobMemoryRequests(uuid);
159 }
160
161 void BlobAsyncBuilderHost::StopBuildingBlob(const std::string& uuid) {
162 async_blob_map_.erase(async_blob_map_.find(uuid));
163 }
164
165 void BlobAsyncBuilderHost::ContinueBlobMemoryRequests(const std::string& uuid) {
166 AsyncBlobMap::const_iterator state_it = async_blob_map_.find(uuid);
167 DCHECK(state_it != async_blob_map_.end());
168 BlobAsyncBuilderHost::BlobBuildingState* state = state_it->second;
169
170 const std::vector<MemoryItemRequest>& requests =
171 state->transport_strategy.requests();
172 BlobAsyncTransportStrategy& strategy = state->transport_strategy;
173 size_t num_requests = requests.size();
174 if (state->num_fulfilled_requests == num_requests) {
175 DoneAndCleanup(uuid);
176 return;
177 }
178 DCHECK_LT(state->num_fulfilled_requests, num_requests);
179 if (state->next_request == num_requests) {
180 // We are still waiting on other requests to come back.
181 return;
182 }
183
184 std::vector<BlobItemBytesRequest> byte_requests;
185 std::vector<base::SharedMemoryHandle> shared_memory;
186 std::vector<IPC::PlatformFileForTransit> files;
187
188 for (; state->next_request < num_requests; ++state->next_request) {
189 const MemoryItemRequest& request = requests[state->next_request];
190
191 bool stop_accumulating = false;
192 bool using_shared_memory_handle = state->num_shared_memory_requests > 0;
193 switch (request.message.transport_strategy) {
194 case IPCBlobItemRequestStrategy::IPC:
195 byte_requests.push_back(request.message);
196 break;
197 case IPCBlobItemRequestStrategy::SHARED_MEMORY:
198 if (using_shared_memory_handle &&
199 state->current_shared_memory_handle_index !=
200 request.message.handle_index) {
201 // We only want one shared memory per requesting blob.
202 stop_accumulating = true;
203 break;
204 }
205 using_shared_memory_handle = true;
206 state->current_shared_memory_handle_index =
207 request.message.handle_index;
208 state->num_shared_memory_requests++;
209
210 if (!state->shared_memory_block) {
211 state->shared_memory_block.reset(new base::SharedMemory());
212 size_t size =
213 strategy
214 .shared_memory_handle_sizes()[request.message.handle_index];
215 if (!state->shared_memory_block->CreateAnonymous(size)) {
216 DVLOG(1) << "Unable to allocate shared memory for blob transfer.";
217 CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY);
218 return;
219 }
220 }
221 shared_memory.push_back(state->shared_memory_block->handle());
222 byte_requests.push_back(request.message);
223 // Since we are only using one handle at a time, transform our handle
224 // index correctly back to 0.
225 byte_requests.back().handle_index = 0;
226 break;
227 case IPCBlobItemRequestStrategy::FILE:
228 case IPCBlobItemRequestStrategy::UNKNOWN:
229 NOTREACHED() << "Not implemented yet.";
230 break;
231 }
232 if (stop_accumulating) {
233 break;
234 }
235 }
236
237 DCHECK(!requests.empty());
238
239 state->request_memory_callback.Run(byte_requests, shared_memory, files);
240 }
241
242 void BlobAsyncBuilderHost::CancelAndCleanup(const std::string& uuid,
243 IPCBlobCreationCancelCode code) {
244 scoped_ptr<BlobBuildingState> state = async_blob_map_.take_and_erase(uuid);
245 DCHECK(state.get());
246 state->cancel_callback.Run(code);
247 }
248
249 void BlobAsyncBuilderHost::DoneAndCleanup(const std::string& uuid) {
250 scoped_ptr<BlobBuildingState> state = async_blob_map_.take_and_erase(uuid);
251 DCHECK(state.get());
252 BlobDataBuilder* builder = state->transport_strategy.blob_builder();
253 builder->set_content_type(state->type);
254 DCHECK(builder);
255 state->done_callback.Run(builder);
256 }
257
258 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698