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

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 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 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 <utility>
8
9 #include "base/memory/shared_memory.h"
10
11 namespace storage {
12
13 using MemoryItemRequest = BlobAsyncTransportStrategy::RendererMemoryItemRequest;
14
15 BlobAsyncBuilderHost::BlobBuildingState::BlobBuildingState()
16 : next_request(0),
17 num_fulfilled_requests(0),
18 num_shared_memory_requests(0),
19 current_shared_memory_handle_index(0) {}
20
21 BlobAsyncBuilderHost::BlobBuildingState::~BlobBuildingState() {}
22
23 BlobAsyncBuilderHost::BlobAsyncBuilderHost() {}
24
25 BlobAsyncBuilderHost::~BlobAsyncBuilderHost() {}
26
27 bool BlobAsyncBuilderHost::StartBuildingBlob(
28 const std::string& uuid,
29 const std::string& type,
30 const std::vector<DataElement>& descriptions,
31 size_t memory_available,
32 const base::Callback<void(const std::vector<storage::BlobItemBytesRequest>&,
33 const std::vector<base::SharedMemoryHandle>&,
34 const std::vector<uint64_t>&)>& request_memory,
35 const base::Callback<void(const BlobDataBuilder&)>& done,
36 const 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 true;
48 }
49
50 if (async_blob_map_.find(uuid) != async_blob_map_.end())
51 return false;
kinuko 2015/11/25 16:08:17 nit: is it not necessary to do this check before l
dmurph 2015/11/25 21:16:30 Good catch.
52 scoped_ptr<BlobBuildingState> state(new BlobBuildingState());
53 BlobBuildingState* state_ptr = state.get();
54 async_blob_map_[uuid] = std::move(state);
michaeln 2015/11/24 23:19:40 fancy :)
dmurph 2015/11/25 21:16:30 :)
55 state_ptr->type = type;
56 state_ptr->request_memory_callback = request_memory;
57 state_ptr->done_callback = done;
58 state_ptr->cancel_callback = cancel;
59
60 // We are currently only operating in 'no disk' mode. This will change in
61 // future patches to enable disk storage.
62 // Since we don't have a disk yet, we put 0 for disk_space_left.
63 state_ptr->transport_strategy.Initialize(
64 max_ipc_memory_size_, max_shared_memory_size_, max_file_size_,
65 0 /* disk_space_left */, memory_available, uuid, descriptions);
66
67 switch (state_ptr->transport_strategy.error()) {
68 case BlobAsyncTransportStrategy::ERROR_NONE:
69 ContinueBlobMemoryRequests(uuid);
70 return true;
71 case BlobAsyncTransportStrategy::ERROR_TOO_LARGE:
72 // Cancel cleanly, we're out of memory.
73 CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY);
74 return true;
75 case BlobAsyncTransportStrategy::ERROR_INVALID_PARAMS:
76 // Bad IPC, so we ignore and clean up.
77 async_blob_map_.erase(async_blob_map_.find(uuid));
78 VLOG(1) << "Error initializing transport strategy: "
79 << state_ptr->transport_strategy.error();
80 return false;
81 }
82 }
83
84 bool BlobAsyncBuilderHost::OnMemoryResponses(
85 const std::string& uuid,
86 const std::vector<BlobItemBytesResponse>& responses) {
87 AsyncBlobMap::const_iterator state_it = async_blob_map_.find(uuid);
88 if (state_it == async_blob_map_.end())
89 return false;
michaeln 2015/11/24 23:19:40 I'm not sure this one is always indicative of a ba
dmurph 2015/11/25 21:16:30 Done.
90 BlobAsyncBuilderHost::BlobBuildingState* state = state_it->second.get();
91 BlobAsyncTransportStrategy& strategy = state->transport_strategy;
92 bool invalid_ipc = false;
93 bool memory_error = false;
94 const auto& requests = strategy.requests();
95 for (const BlobItemBytesResponse& response : responses) {
96 if (response.request_number >= requests.size()) {
97 // Bad IPC, so we delete our record and ignore.
98 DVLOG(1) << "Invalid request number " << response.request_number;
99 async_blob_map_.erase(state_it);
100 return false;
101 }
102 const MemoryItemRequest& request = requests[response.request_number];
103 if (request.received) {
104 // Bad IPC, so we delete our record.
105 DVLOG(1) << "Already received response for that request.";
106 async_blob_map_.erase(state_it);
107 return false;
108 }
109 switch (request.message.transport_strategy) {
110 case IPCBlobItemRequestStrategy::IPC:
111 if (response.inline_data.size() < request.message.size) {
112 DVLOG(1) << "Invalid data size " << response.inline_data.size()
113 << " vs requested size of " << request.message.size;
114 invalid_ipc = true;
115 break;
116 }
117 invalid_ipc = !strategy.blob_builder()->PopulateFutureData(
118 request.browser_item_index, &response.inline_data[0],
119 request.browser_item_offset, request.message.size);
120 break;
121 case IPCBlobItemRequestStrategy::SHARED_MEMORY:
122 if (state->num_shared_memory_requests == 0) {
123 DVLOG(1) << "Received too many responses for shared memory.";
124 invalid_ipc = true;
125 break;
126 }
127 state->num_shared_memory_requests--;
128 if (!state->shared_memory_block->memory()) {
129 // We just map the whole block, as we'll probably be accessing the
130 // whole thing in this group of responses. Another option is to use
131 // MapAt, remove the mapped boolean, and then exclude the
132 // handle_offset below.
133 size_t handle_size = strategy.shared_memory_handle_sizes().at(
134 state->current_shared_memory_handle_index);
135 if (!state->shared_memory_block->Map(handle_size)) {
136 DVLOG(1) << "Unable to map memory to size " << handle_size;
137 memory_error = true;
138 break;
139 }
140 }
141
142 invalid_ipc = !strategy.blob_builder()->PopulateFutureData(
143 request.browser_item_index,
144 static_cast<const char*>(state->shared_memory_block->memory()) +
145 request.message.handle_offset,
146 request.browser_item_offset, request.message.size);
147 break;
148 case IPCBlobItemRequestStrategy::FILE:
149 case IPCBlobItemRequestStrategy::UNKNOWN:
150 DVLOG(1) << "Not implemented.";
151 invalid_ipc = true;
152 break;
153 }
154 if (invalid_ipc) {
155 // Bad IPC, so we delete our record and return false.
156 async_blob_map_.erase(state_it);
157 return false;
158 }
159 if (memory_error) {
160 DVLOG(1) << "Shared memory error.";
161 CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY);
162 return true;
163 }
164 state->num_fulfilled_requests++;
165 }
166 ContinueBlobMemoryRequests(uuid);
167 return true;
168 }
169
170 void BlobAsyncBuilderHost::StopBuildingBlob(const std::string& uuid) {
171 async_blob_map_.erase(async_blob_map_.find(uuid));
172 }
173
174 void BlobAsyncBuilderHost::ContinueBlobMemoryRequests(const std::string& uuid) {
175 AsyncBlobMap::const_iterator state_it = async_blob_map_.find(uuid);
176 DCHECK(state_it != async_blob_map_.end());
177 BlobAsyncBuilderHost::BlobBuildingState* state = state_it->second.get();
178
179 const std::vector<MemoryItemRequest>& requests =
180 state->transport_strategy.requests();
181 BlobAsyncTransportStrategy& strategy = state->transport_strategy;
182 size_t num_requests = requests.size();
183 if (state->num_fulfilled_requests == num_requests) {
184 DoneAndCleanup(uuid);
185 return;
186 }
187 DCHECK_LT(state->num_fulfilled_requests, num_requests);
188 if (state->next_request == num_requests) {
189 // We are still waiting on other requests to come back.
190 return;
191 }
192
193 std::vector<BlobItemBytesRequest> byte_requests;
194 std::vector<base::SharedMemoryHandle> shared_memory;
195 std::vector<uint64_t> files;
196
197 for (; state->next_request < num_requests; ++state->next_request) {
198 const MemoryItemRequest& request = requests[state->next_request];
199
200 bool stop_accumulating = false;
201 bool using_shared_memory_handle = state->num_shared_memory_requests > 0;
202 switch (request.message.transport_strategy) {
203 case IPCBlobItemRequestStrategy::IPC:
204 byte_requests.push_back(request.message);
205 break;
206 case IPCBlobItemRequestStrategy::SHARED_MEMORY:
207 if (using_shared_memory_handle &&
208 state->current_shared_memory_handle_index !=
209 request.message.handle_index) {
210 // We only want one shared memory per requesting blob.
211 stop_accumulating = true;
212 break;
213 }
214 using_shared_memory_handle = true;
215 state->current_shared_memory_handle_index =
216 request.message.handle_index;
217 state->num_shared_memory_requests++;
218
219 if (!state->shared_memory_block) {
220 state->shared_memory_block.reset(new base::SharedMemory());
221 size_t size =
222 strategy
223 .shared_memory_handle_sizes()[request.message.handle_index];
224 if (!state->shared_memory_block->CreateAnonymous(size)) {
225 DVLOG(1) << "Unable to allocate shared memory for blob transfer.";
226 CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY);
227 return;
228 }
229 }
230 shared_memory.push_back(state->shared_memory_block->handle());
231 byte_requests.push_back(request.message);
232 // Since we are only using one handle at a time, transform our handle
233 // index correctly back to 0.
234 byte_requests.back().handle_index = 0;
235 break;
236 case IPCBlobItemRequestStrategy::FILE:
237 case IPCBlobItemRequestStrategy::UNKNOWN:
238 NOTREACHED() << "Not implemented yet.";
239 break;
240 }
241 if (stop_accumulating) {
242 break;
243 }
244 }
245
246 DCHECK(!requests.empty());
247
248 state->request_memory_callback.Run(byte_requests, shared_memory, files);
249 }
250
251 void BlobAsyncBuilderHost::CancelAndCleanup(const std::string& uuid,
252 IPCBlobCreationCancelCode code) {
253 scoped_ptr<BlobBuildingState> state = std::move(async_blob_map_[uuid]);
254 async_blob_map_.erase(uuid);
255 DCHECK(state.get());
kinuko 2015/11/25 16:08:17 nit: this DCHECK and similar ones on line 262, 264
dmurph 2015/11/25 21:16:30 makes sense. Done.
256 state->cancel_callback.Run(code);
257 }
258
259 void BlobAsyncBuilderHost::DoneAndCleanup(const std::string& uuid) {
260 scoped_ptr<BlobBuildingState> state = std::move(async_blob_map_[uuid]);
261 async_blob_map_.erase(uuid);
262 DCHECK(state.get());
263 BlobDataBuilder* builder = state->transport_strategy.blob_builder();
264 DCHECK(builder);
265 builder->set_content_type(state->type);
266 state->done_callback.Run(*builder);
267 }
268
269 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698