OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stddef.h> | 5 #include <stddef.h> |
6 #include <stdint.h> | 6 #include <stdint.h> |
7 | 7 |
8 #include <algorithm> | 8 #include <algorithm> |
9 | 9 |
10 #include "base/numerics/safe_math.h" | 10 #include "base/numerics/safe_math.h" |
11 #include "storage/browser/blob/blob_async_transport_strategy.h" | 11 #include "storage/browser/blob/blob_async_transport_request_builder.h" |
12 #include "storage/common/blob_storage/blob_storage_constants.h" | 12 #include "storage/common/blob_storage/blob_storage_constants.h" |
13 | 13 |
14 namespace storage { | 14 namespace storage { |
15 namespace { | 15 namespace { |
16 bool IsBytes(DataElement::Type type) { | 16 bool IsBytes(DataElement::Type type) { |
17 return type == DataElement::TYPE_BYTES || | 17 return type == DataElement::TYPE_BYTES || |
18 type == DataElement::TYPE_BYTES_DESCRIPTION; | 18 type == DataElement::TYPE_BYTES_DESCRIPTION; |
19 } | 19 } |
20 | 20 |
21 // This is the general template that each strategy below implements. See the | 21 // This is the general template that each strategy below implements. See the |
22 // ForEachWithSegment method for a description of how these are called. | 22 // ForEachWithSegment method for a description of how these are called. |
23 // class BlobSegmentVisitor { | 23 // class BlobSegmentVisitor { |
24 // public: | 24 // public: |
25 // typedef ___ SizeType; | 25 // typedef ___ SizeType; |
26 // void VisitBytesSegment(size_t element_index, uint64_t element_offset, | 26 // void VisitBytesSegment(size_t element_index, uint64_t element_offset, |
27 // size_t segment_index, uint64_t segment_offset, | 27 // size_t segment_index, uint64_t segment_offset, |
28 // uint64_t size); | 28 // uint64_t size); |
29 // void VisitNonBytesSegment(const DataElement& element, size_t element_idx); | 29 // void VisitNonBytesSegment(const DataElement& element, size_t element_idx); |
30 // void Done(); | 30 // void Done(); |
31 // }; | 31 // }; |
32 | 32 |
33 // This class handles the logic of how transported memory is going to be | 33 // This class handles the logic of how transported memory is going to be |
34 // represented as storage in the browser. The main idea is that all the memory | 34 // represented as storage in the browser. The main idea is that all the memory |
35 // is now packed into file chunks, and the browser items will just reference | 35 // is now packed into file chunks, and the browser items will just reference |
36 // the file with offsets and sizes. | 36 // the file with offsets and sizes. |
37 class FileStorageStrategy { | 37 class FileStorageStrategy { |
38 public: | 38 public: |
39 FileStorageStrategy( | 39 FileStorageStrategy( |
40 std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* | 40 std::vector<BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest>* |
41 requests, | 41 requests, |
42 BlobDataBuilder* builder) | 42 BlobDataBuilder* builder) |
43 : requests(requests), builder(builder), current_item_index(0) {} | 43 : requests(requests), builder(builder), current_item_index(0) {} |
44 | 44 |
45 ~FileStorageStrategy() {} | 45 ~FileStorageStrategy() {} |
46 | 46 |
47 void VisitBytesSegment(size_t element_index, | 47 void VisitBytesSegment(size_t element_index, |
48 uint64_t element_offset, | 48 uint64_t element_offset, |
49 size_t segment_index, | 49 size_t segment_index, |
50 uint64_t segment_offset, | 50 uint64_t segment_offset, |
51 uint64_t size) { | 51 uint64_t size) { |
52 BlobAsyncTransportStrategy::RendererMemoryItemRequest request; | 52 BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest request; |
53 request.browser_item_index = current_item_index; | 53 request.browser_item_index = current_item_index; |
54 request.browser_item_offset = 0; | 54 request.browser_item_offset = 0; |
55 request.message.request_number = requests->size(); | 55 request.message.request_number = requests->size(); |
56 request.message.transport_strategy = IPCBlobItemRequestStrategy::FILE; | 56 request.message.transport_strategy = IPCBlobItemRequestStrategy::FILE; |
57 request.message.renderer_item_index = element_index; | 57 request.message.renderer_item_index = element_index; |
58 request.message.renderer_item_offset = element_offset; | 58 request.message.renderer_item_offset = element_offset; |
59 request.message.size = size; | 59 request.message.size = size; |
60 request.message.handle_index = segment_index; | 60 request.message.handle_index = segment_index; |
61 request.message.handle_offset = segment_offset; | 61 request.message.handle_offset = segment_offset; |
62 | 62 |
63 requests->push_back(request); | 63 requests->push_back(request); |
64 builder->AppendFutureFile(segment_offset, size); | 64 builder->AppendFutureFile(segment_offset, size); |
65 current_item_index++; | 65 current_item_index++; |
66 } | 66 } |
67 | 67 |
68 void VisitNonBytesSegment(const DataElement& element, size_t element_index) { | 68 void VisitNonBytesSegment(const DataElement& element, size_t element_index) { |
69 builder->AppendIPCDataElement(element); | 69 builder->AppendIPCDataElement(element); |
70 current_item_index++; | 70 current_item_index++; |
71 } | 71 } |
72 | 72 |
73 void Done() {} | 73 void Done() {} |
74 | 74 |
75 std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* requests; | 75 std::vector<BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest>* |
| 76 requests; |
76 BlobDataBuilder* builder; | 77 BlobDataBuilder* builder; |
77 | 78 |
78 size_t current_item_index; | 79 size_t current_item_index; |
79 }; | 80 }; |
80 | 81 |
81 // This class handles the logic of storing memory that is transported as | 82 // This class handles the logic of storing memory that is transported as |
82 // consolidated shared memory. | 83 // consolidated shared memory. |
83 class SharedMemoryStorageStrategy { | 84 class SharedMemoryStorageStrategy { |
84 public: | 85 public: |
85 SharedMemoryStorageStrategy( | 86 SharedMemoryStorageStrategy( |
86 size_t max_segment_size, | 87 size_t max_segment_size, |
87 std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* | 88 std::vector<BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest>* |
88 requests, | 89 requests, |
89 BlobDataBuilder* builder) | 90 BlobDataBuilder* builder) |
90 : requests(requests), | 91 : requests(requests), |
91 max_segment_size(max_segment_size), | 92 max_segment_size(max_segment_size), |
92 builder(builder), | 93 builder(builder), |
93 current_item_size(0), | 94 current_item_size(0), |
94 current_item_index(0) {} | 95 current_item_index(0) {} |
95 ~SharedMemoryStorageStrategy() {} | 96 ~SharedMemoryStorageStrategy() {} |
96 | 97 |
97 void VisitBytesSegment(size_t element_index, | 98 void VisitBytesSegment(size_t element_index, |
98 uint64_t element_offset, | 99 uint64_t element_offset, |
99 size_t segment_index, | 100 size_t segment_index, |
100 uint64_t segment_offset, | 101 uint64_t segment_offset, |
101 uint64_t size) { | 102 uint64_t size) { |
102 if (current_item_size + size > max_segment_size) { | 103 if (current_item_size + size > max_segment_size) { |
103 builder->AppendFutureData(current_item_size); | 104 builder->AppendFutureData(current_item_size); |
104 current_item_index++; | 105 current_item_index++; |
105 current_item_size = 0; | 106 current_item_size = 0; |
106 } | 107 } |
107 BlobAsyncTransportStrategy::RendererMemoryItemRequest request; | 108 BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest request; |
108 request.browser_item_index = current_item_index; | 109 request.browser_item_index = current_item_index; |
109 request.browser_item_offset = current_item_size; | 110 request.browser_item_offset = current_item_size; |
110 request.message.request_number = requests->size(); | 111 request.message.request_number = requests->size(); |
111 request.message.transport_strategy = | 112 request.message.transport_strategy = |
112 IPCBlobItemRequestStrategy::SHARED_MEMORY; | 113 IPCBlobItemRequestStrategy::SHARED_MEMORY; |
113 request.message.renderer_item_index = element_index; | 114 request.message.renderer_item_index = element_index; |
114 request.message.renderer_item_offset = element_offset; | 115 request.message.renderer_item_offset = element_offset; |
115 request.message.size = size; | 116 request.message.size = size; |
116 request.message.handle_index = segment_index; | 117 request.message.handle_index = segment_index; |
117 request.message.handle_offset = segment_offset; | 118 request.message.handle_offset = segment_offset; |
(...skipping 11 matching lines...) Expand all Loading... |
129 current_item_index++; | 130 current_item_index++; |
130 current_item_size = 0; | 131 current_item_size = 0; |
131 } | 132 } |
132 | 133 |
133 void Done() { | 134 void Done() { |
134 if (current_item_size != 0) { | 135 if (current_item_size != 0) { |
135 builder->AppendFutureData(current_item_size); | 136 builder->AppendFutureData(current_item_size); |
136 } | 137 } |
137 } | 138 } |
138 | 139 |
139 std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* requests; | 140 std::vector<BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest>* |
| 141 requests; |
140 | 142 |
141 size_t max_segment_size; | 143 size_t max_segment_size; |
142 BlobDataBuilder* builder; | 144 BlobDataBuilder* builder; |
143 size_t current_item_size; | 145 size_t current_item_size; |
144 uint64_t current_item_index; | 146 uint64_t current_item_index; |
145 }; | 147 }; |
146 | 148 |
147 // This iterates of the data elements and segments the 'bytes' data into | 149 // This iterates of the data elements and segments the 'bytes' data into |
148 // the smallest number of segments given the max_segment_size. | 150 // the smallest number of segments given the max_segment_size. |
149 // The callback describes either: | 151 // The callback describes either: |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 segment_offset, memory_writing); | 186 segment_offset, memory_writing); |
185 element_memory_left -= memory_writing; | 187 element_memory_left -= memory_writing; |
186 segment_offset += memory_writing; | 188 segment_offset += memory_writing; |
187 element_offset += memory_writing; | 189 element_offset += memory_writing; |
188 } | 190 } |
189 } | 191 } |
190 visitor->Done(); | 192 visitor->Done(); |
191 } | 193 } |
192 } // namespace | 194 } // namespace |
193 | 195 |
194 BlobAsyncTransportStrategy::RendererMemoryItemRequest:: | 196 BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest:: |
195 RendererMemoryItemRequest() | 197 RendererMemoryItemRequest() |
196 : browser_item_index(0), browser_item_offset(0), received(false) {} | 198 : browser_item_index(0), browser_item_offset(0) {} |
197 | 199 |
198 BlobAsyncTransportStrategy::BlobAsyncTransportStrategy() | 200 BlobAsyncTransportRequestBuilder::BlobAsyncTransportRequestBuilder() |
199 : error_(BlobAsyncTransportStrategy::ERROR_NONE), total_bytes_size_(0) {} | 201 : total_bytes_size_(0) {} |
200 | 202 |
201 BlobAsyncTransportStrategy::~BlobAsyncTransportStrategy() {} | 203 BlobAsyncTransportRequestBuilder::~BlobAsyncTransportRequestBuilder() {} |
202 | 204 |
203 // if total_blob_size > |memory_available| (say 400MB) | 205 // Initializes the transport strategy for file requests. |
204 // Request all data in files | 206 void BlobAsyncTransportRequestBuilder::InitializeForFileRequests( |
205 // (Segment all of the existing data into | 207 size_t max_file_size, |
206 // file blocks, of <= |max_file_size|) | 208 uint64_t blob_total_size, |
207 // else if total_blob_size > |max_ipc_memory_size| (say 150KB) | 209 const std::vector<DataElement>& elements, |
208 // Request all data in shared memory | 210 BlobDataBuilder* builder) { |
209 // (Segment all of the existing data into | 211 DCHECK(requests_.empty()); |
210 // shared memory blocks, of <= |max_shared_memory_size|) | 212 total_bytes_size_ = blob_total_size; |
211 // else | 213 ComputeHandleSizes(total_bytes_size_, max_file_size, &file_sizes_); |
212 // Request all data to be sent over IPC | 214 FileStorageStrategy strategy(&requests_, builder); |
213 void BlobAsyncTransportStrategy::Initialize( | 215 ForEachWithSegment(elements, static_cast<uint64_t>(max_file_size), &strategy); |
| 216 } |
| 217 |
| 218 void BlobAsyncTransportRequestBuilder::InitializeForSharedMemoryRequests( |
| 219 size_t max_shared_memory_size, |
| 220 uint64_t blob_total_size, |
| 221 const std::vector<DataElement>& elements, |
| 222 BlobDataBuilder* builder) { |
| 223 DCHECK(requests_.empty()); |
| 224 DCHECK(blob_total_size <= std::numeric_limits<size_t>::max()); |
| 225 total_bytes_size_ = blob_total_size; |
| 226 ComputeHandleSizes(total_bytes_size_, max_shared_memory_size, |
| 227 &shared_memory_sizes_); |
| 228 SharedMemoryStorageStrategy strategy(max_shared_memory_size, &requests_, |
| 229 builder); |
| 230 ForEachWithSegment(elements, static_cast<uint64_t>(max_shared_memory_size), |
| 231 &strategy); |
| 232 } |
| 233 |
| 234 void BlobAsyncTransportRequestBuilder::InitializeForIPCRequests( |
214 size_t max_ipc_memory_size, | 235 size_t max_ipc_memory_size, |
215 size_t max_shared_memory_size, | 236 uint64_t blob_total_size, |
216 size_t max_file_size, | 237 const std::vector<DataElement>& elements, |
217 uint64_t disk_space_left, | 238 BlobDataBuilder* builder) { |
218 size_t memory_available, | |
219 const std::string& uuid, | |
220 const std::vector<DataElement>& blob_item_infos) { | |
221 DCHECK(handle_sizes_.empty()); | |
222 DCHECK(requests_.empty()); | 239 DCHECK(requests_.empty()); |
223 DCHECK(!builder_.get()); | 240 // We don't segment anything, and just request the memory items directly |
224 builder_.reset(new BlobDataBuilder(uuid)); | 241 // in IPC. |
225 error_ = BlobAsyncTransportStrategy::ERROR_NONE; | 242 size_t items_length = elements.size(); |
226 | 243 total_bytes_size_ = blob_total_size; |
227 size_t memory_items = 0; | 244 for (size_t i = 0; i < items_length; i++) { |
228 base::CheckedNumeric<uint64_t> total_size_checked = 0; | 245 const auto& info = elements.at(i); |
229 for (const auto& info : blob_item_infos) { | |
230 if (!IsBytes(info.type())) { | 246 if (!IsBytes(info.type())) { |
| 247 builder->AppendIPCDataElement(info); |
231 continue; | 248 continue; |
232 } | 249 } |
233 total_size_checked += info.length(); | 250 BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest request; |
234 ++memory_items; | |
235 } | |
236 | |
237 if (!total_size_checked.IsValid()) { | |
238 DVLOG(1) << "Impossible total size of all memory elements."; | |
239 error_ = BlobAsyncTransportStrategy::ERROR_INVALID_PARAMS; | |
240 return; | |
241 } | |
242 | |
243 total_bytes_size_ = total_size_checked.ValueOrDie(); | |
244 | |
245 // See if we have enough memory. | |
246 if (total_bytes_size_ > | |
247 disk_space_left + static_cast<uint64_t>(memory_available)) { | |
248 error_ = BlobAsyncTransportStrategy::ERROR_TOO_LARGE; | |
249 return; | |
250 } | |
251 | |
252 // If we're more than the available memory, then we're going straight to disk. | |
253 if (total_bytes_size_ > memory_available) { | |
254 if (total_bytes_size_ > disk_space_left) { | |
255 error_ = BlobAsyncTransportStrategy::ERROR_TOO_LARGE; | |
256 return; | |
257 } | |
258 ComputeHandleSizes(total_bytes_size_, max_file_size, &handle_sizes_); | |
259 FileStorageStrategy strategy(&requests_, builder_.get()); | |
260 ForEachWithSegment(blob_item_infos, static_cast<uint64_t>(max_file_size), | |
261 &strategy); | |
262 return; | |
263 } | |
264 | |
265 if (total_bytes_size_ > max_ipc_memory_size) { | |
266 // Note: The size must be <= std::numeric_limits<size_t>::max(). Otherwise | |
267 // we are guarenteed to be caught by the if statement above, | |
268 // |total_bytes_size_ > memory_available|. | |
269 ComputeHandleSizes(total_bytes_size_, max_shared_memory_size, | |
270 &handle_sizes_); | |
271 SharedMemoryStorageStrategy strategy(max_shared_memory_size, &requests_, | |
272 builder_.get()); | |
273 ForEachWithSegment(blob_item_infos, | |
274 static_cast<uint64_t>(max_shared_memory_size), | |
275 &strategy); | |
276 return; | |
277 } | |
278 | |
279 // Since they can all fit in IPC memory, we don't need to segment anything, | |
280 // and just request them straight in IPC. | |
281 size_t items_length = blob_item_infos.size(); | |
282 for (size_t i = 0; i < items_length; i++) { | |
283 const auto& info = blob_item_infos.at(i); | |
284 if (!IsBytes(info.type())) { | |
285 builder_->AppendIPCDataElement(info); | |
286 continue; | |
287 } | |
288 BlobAsyncTransportStrategy::RendererMemoryItemRequest request; | |
289 request.browser_item_index = i; | 251 request.browser_item_index = i; |
290 request.browser_item_offset = 0; | 252 request.browser_item_offset = 0; |
291 request.message.request_number = requests_.size(); | 253 request.message.request_number = requests_.size(); |
292 request.message.transport_strategy = IPCBlobItemRequestStrategy::IPC; | 254 request.message.transport_strategy = IPCBlobItemRequestStrategy::IPC; |
293 request.message.renderer_item_index = i; | 255 request.message.renderer_item_index = i; |
294 request.message.renderer_item_offset = 0; | 256 request.message.renderer_item_offset = 0; |
295 request.message.size = info.length(); | 257 request.message.size = info.length(); |
296 requests_.push_back(request); | 258 requests_.push_back(request); |
297 builder_->AppendFutureData(info.length()); | 259 builder->AppendFutureData(info.length()); |
298 } | 260 } |
299 } | 261 } |
300 | 262 |
301 /* static */ | 263 /* static */ |
302 bool BlobAsyncTransportStrategy::ShouldBeShortcut( | 264 bool BlobAsyncTransportRequestBuilder::ShouldBeShortcut( |
303 const std::vector<DataElement>& elements, | 265 const std::vector<DataElement>& elements, |
304 size_t memory_available) { | 266 size_t memory_available) { |
305 base::CheckedNumeric<size_t> shortcut_bytes = 0; | 267 base::CheckedNumeric<size_t> shortcut_bytes = 0; |
306 for (const auto& element : elements) { | 268 for (const auto& element : elements) { |
307 DataElement::Type type = element.type(); | 269 DataElement::Type type = element.type(); |
308 if (type == DataElement::TYPE_BYTES_DESCRIPTION) { | 270 if (type == DataElement::TYPE_BYTES_DESCRIPTION) { |
309 return false; | 271 return false; |
310 } | 272 } |
311 if (type == DataElement::TYPE_BYTES) { | 273 if (type == DataElement::TYPE_BYTES) { |
312 shortcut_bytes += element.length(); | 274 shortcut_bytes += element.length(); |
313 if (!shortcut_bytes.IsValid()) { | 275 if (!shortcut_bytes.IsValid()) { |
314 return false; | 276 return false; |
315 } | 277 } |
316 } | 278 } |
317 } | 279 } |
318 return shortcut_bytes.ValueOrDie() <= memory_available; | 280 return shortcut_bytes.ValueOrDie() <= memory_available; |
319 } | 281 } |
320 | 282 |
321 /* static */ | 283 /* static */ |
322 void BlobAsyncTransportStrategy::ComputeHandleSizes( | 284 void BlobAsyncTransportRequestBuilder::ComputeHandleSizes( |
323 uint64_t total_memory_size, | 285 uint64_t total_memory_size, |
324 size_t max_segment_size, | 286 size_t max_segment_size, |
325 std::vector<size_t>* segment_sizes) { | 287 std::vector<size_t>* segment_sizes) { |
326 size_t total_max_segments = | 288 size_t total_max_segments = |
327 static_cast<size_t>(total_memory_size / max_segment_size); | 289 static_cast<size_t>(total_memory_size / max_segment_size); |
328 bool has_extra_segment = (total_memory_size % max_segment_size) > 0; | 290 bool has_extra_segment = (total_memory_size % max_segment_size) > 0; |
329 segment_sizes->reserve(total_max_segments + (has_extra_segment ? 1 : 0)); | 291 segment_sizes->reserve(total_max_segments + (has_extra_segment ? 1 : 0)); |
330 segment_sizes->insert(segment_sizes->begin(), total_max_segments, | 292 segment_sizes->insert(segment_sizes->begin(), total_max_segments, |
331 max_segment_size); | 293 max_segment_size); |
332 if (has_extra_segment) { | 294 if (has_extra_segment) { |
333 segment_sizes->push_back(total_memory_size % max_segment_size); | 295 segment_sizes->push_back(total_memory_size % max_segment_size); |
334 } | 296 } |
335 } | 297 } |
336 | 298 |
337 } // namespace storage | 299 } // namespace storage |
OLD | NEW |