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

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

Powered by Google App Engine
This is Rietveld 408576698