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_request_builder.h" | 11 #include "storage/browser/blob/blob_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<BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest>* | 40 std::vector<BlobTransportRequestBuilder::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 BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest request; | 52 BlobTransportRequestBuilder::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, segment_index); | 64 builder->AppendFutureFile(segment_offset, size, segment_index); |
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<BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest>* | 75 std::vector<BlobTransportRequestBuilder::RendererMemoryItemRequest>* requests; |
76 requests; | |
77 BlobDataBuilder* builder; | 76 BlobDataBuilder* builder; |
78 | 77 |
79 size_t current_item_index; | 78 size_t current_item_index; |
80 }; | 79 }; |
81 | 80 |
82 // This class handles the logic of storing memory that is transported as | 81 // This class handles the logic of storing memory that is transported as |
83 // consolidated shared memory. | 82 // consolidated shared memory. |
84 class SharedMemoryStorageStrategy { | 83 class SharedMemoryStorageStrategy { |
85 public: | 84 public: |
86 SharedMemoryStorageStrategy( | 85 SharedMemoryStorageStrategy( |
87 size_t max_segment_size, | 86 size_t max_segment_size, |
88 std::vector<BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest>* | 87 std::vector<BlobTransportRequestBuilder::RendererMemoryItemRequest>* |
89 requests, | 88 requests, |
90 BlobDataBuilder* builder) | 89 BlobDataBuilder* builder) |
91 : requests(requests), | 90 : requests(requests), |
92 max_segment_size(max_segment_size), | 91 max_segment_size(max_segment_size), |
93 builder(builder), | 92 builder(builder), |
94 current_item_size(0), | 93 current_item_size(0), |
95 current_item_index(0) {} | 94 current_item_index(0) {} |
96 ~SharedMemoryStorageStrategy() {} | 95 ~SharedMemoryStorageStrategy() {} |
97 | 96 |
98 void VisitBytesSegment(size_t element_index, | 97 void VisitBytesSegment(size_t element_index, |
99 uint64_t element_offset, | 98 uint64_t element_offset, |
100 size_t segment_index, | 99 size_t segment_index, |
101 uint64_t segment_offset, | 100 uint64_t segment_offset, |
102 uint64_t size) { | 101 uint64_t size) { |
103 if (current_item_size + size > max_segment_size) { | 102 if (current_item_size + size > max_segment_size) { |
104 builder->AppendFutureData(current_item_size); | 103 builder->AppendFutureData(current_item_size); |
105 current_item_index++; | 104 current_item_index++; |
106 current_item_size = 0; | 105 current_item_size = 0; |
107 } | 106 } |
108 BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest request; | 107 BlobTransportRequestBuilder::RendererMemoryItemRequest request; |
109 request.browser_item_index = current_item_index; | 108 request.browser_item_index = current_item_index; |
110 request.browser_item_offset = current_item_size; | 109 request.browser_item_offset = current_item_size; |
111 request.message.request_number = requests->size(); | 110 request.message.request_number = requests->size(); |
112 request.message.transport_strategy = | 111 request.message.transport_strategy = |
113 IPCBlobItemRequestStrategy::SHARED_MEMORY; | 112 IPCBlobItemRequestStrategy::SHARED_MEMORY; |
114 request.message.renderer_item_index = element_index; | 113 request.message.renderer_item_index = element_index; |
115 request.message.renderer_item_offset = element_offset; | 114 request.message.renderer_item_offset = element_offset; |
116 request.message.size = size; | 115 request.message.size = size; |
117 request.message.handle_index = segment_index; | 116 request.message.handle_index = segment_index; |
118 request.message.handle_offset = segment_offset; | 117 request.message.handle_offset = segment_offset; |
(...skipping 11 matching lines...) Expand all Loading... |
130 current_item_index++; | 129 current_item_index++; |
131 current_item_size = 0; | 130 current_item_size = 0; |
132 } | 131 } |
133 | 132 |
134 void Done() { | 133 void Done() { |
135 if (current_item_size != 0) { | 134 if (current_item_size != 0) { |
136 builder->AppendFutureData(current_item_size); | 135 builder->AppendFutureData(current_item_size); |
137 } | 136 } |
138 } | 137 } |
139 | 138 |
140 std::vector<BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest>* | 139 std::vector<BlobTransportRequestBuilder::RendererMemoryItemRequest>* requests; |
141 requests; | |
142 | 140 |
143 size_t max_segment_size; | 141 size_t max_segment_size; |
144 BlobDataBuilder* builder; | 142 BlobDataBuilder* builder; |
145 size_t current_item_size; | 143 size_t current_item_size; |
146 uint64_t current_item_index; | 144 uint64_t current_item_index; |
147 }; | 145 }; |
148 | 146 |
149 // This iterates of the data elements and segments the 'bytes' data into | 147 // This iterates of the data elements and segments the 'bytes' data into |
150 // the smallest number of segments given the max_segment_size. | 148 // the smallest number of segments given the max_segment_size. |
151 // The callback describes either: | 149 // The callback describes either: |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 segment_offset, memory_writing); | 184 segment_offset, memory_writing); |
187 element_memory_left -= memory_writing; | 185 element_memory_left -= memory_writing; |
188 segment_offset += memory_writing; | 186 segment_offset += memory_writing; |
189 element_offset += memory_writing; | 187 element_offset += memory_writing; |
190 } | 188 } |
191 } | 189 } |
192 visitor->Done(); | 190 visitor->Done(); |
193 } | 191 } |
194 } // namespace | 192 } // namespace |
195 | 193 |
196 BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest:: | 194 BlobTransportRequestBuilder::RendererMemoryItemRequest:: |
197 RendererMemoryItemRequest() | 195 RendererMemoryItemRequest() |
198 : browser_item_index(0), browser_item_offset(0) {} | 196 : browser_item_index(0), browser_item_offset(0) {} |
199 | 197 |
200 BlobAsyncTransportRequestBuilder::BlobAsyncTransportRequestBuilder() | 198 BlobTransportRequestBuilder::BlobTransportRequestBuilder() |
201 : total_bytes_size_(0) {} | 199 : total_bytes_size_(0) {} |
202 | 200 |
203 BlobAsyncTransportRequestBuilder::~BlobAsyncTransportRequestBuilder() {} | 201 BlobTransportRequestBuilder::BlobTransportRequestBuilder( |
| 202 BlobTransportRequestBuilder&&) = default; |
| 203 BlobTransportRequestBuilder& BlobTransportRequestBuilder::operator=( |
| 204 BlobTransportRequestBuilder&&) = default; |
| 205 BlobTransportRequestBuilder::~BlobTransportRequestBuilder() {} |
204 | 206 |
205 // Initializes the transport strategy for file requests. | 207 // Initializes the transport strategy for file requests. |
206 void BlobAsyncTransportRequestBuilder::InitializeForFileRequests( | 208 void BlobTransportRequestBuilder::InitializeForFileRequests( |
207 size_t max_file_size, | 209 size_t max_file_size, |
208 uint64_t blob_total_size, | 210 uint64_t blob_total_size, |
209 const std::vector<DataElement>& elements, | 211 const std::vector<DataElement>& elements, |
210 BlobDataBuilder* builder) { | 212 BlobDataBuilder* builder) { |
211 DCHECK(requests_.empty()); | 213 DCHECK(requests_.empty()); |
212 total_bytes_size_ = blob_total_size; | 214 total_bytes_size_ = blob_total_size; |
213 ComputeHandleSizes(total_bytes_size_, max_file_size, &file_sizes_); | 215 ComputeHandleSizes(total_bytes_size_, max_file_size, &file_sizes_); |
214 FileStorageStrategy strategy(&requests_, builder); | 216 FileStorageStrategy strategy(&requests_, builder); |
215 ForEachWithSegment(elements, static_cast<uint64_t>(max_file_size), &strategy); | 217 ForEachWithSegment(elements, static_cast<uint64_t>(max_file_size), &strategy); |
216 } | 218 } |
217 | 219 |
218 void BlobAsyncTransportRequestBuilder::InitializeForSharedMemoryRequests( | 220 void BlobTransportRequestBuilder::InitializeForSharedMemoryRequests( |
219 size_t max_shared_memory_size, | 221 size_t max_shared_memory_size, |
220 uint64_t blob_total_size, | 222 uint64_t blob_total_size, |
221 const std::vector<DataElement>& elements, | 223 const std::vector<DataElement>& elements, |
222 BlobDataBuilder* builder) { | 224 BlobDataBuilder* builder) { |
223 DCHECK(requests_.empty()); | 225 DCHECK(requests_.empty()); |
224 DCHECK(blob_total_size <= std::numeric_limits<size_t>::max()); | 226 DCHECK(blob_total_size <= std::numeric_limits<size_t>::max()); |
225 total_bytes_size_ = blob_total_size; | 227 total_bytes_size_ = blob_total_size; |
226 ComputeHandleSizes(total_bytes_size_, max_shared_memory_size, | 228 ComputeHandleSizes(total_bytes_size_, max_shared_memory_size, |
227 &shared_memory_sizes_); | 229 &shared_memory_sizes_); |
228 SharedMemoryStorageStrategy strategy(max_shared_memory_size, &requests_, | 230 SharedMemoryStorageStrategy strategy(max_shared_memory_size, &requests_, |
229 builder); | 231 builder); |
230 ForEachWithSegment(elements, static_cast<uint64_t>(max_shared_memory_size), | 232 ForEachWithSegment(elements, static_cast<uint64_t>(max_shared_memory_size), |
231 &strategy); | 233 &strategy); |
232 } | 234 } |
233 | 235 |
234 void BlobAsyncTransportRequestBuilder::InitializeForIPCRequests( | 236 void BlobTransportRequestBuilder::InitializeForIPCRequests( |
235 size_t max_ipc_memory_size, | 237 size_t max_ipc_memory_size, |
236 uint64_t blob_total_size, | 238 uint64_t blob_total_size, |
237 const std::vector<DataElement>& elements, | 239 const std::vector<DataElement>& elements, |
238 BlobDataBuilder* builder) { | 240 BlobDataBuilder* builder) { |
239 DCHECK(requests_.empty()); | 241 DCHECK(requests_.empty()); |
240 // We don't segment anything, and just request the memory items directly | 242 // We don't segment anything, and just request the memory items directly |
241 // in IPC. | 243 // in IPC. |
242 size_t items_length = elements.size(); | 244 size_t items_length = elements.size(); |
243 total_bytes_size_ = blob_total_size; | 245 total_bytes_size_ = blob_total_size; |
244 for (size_t i = 0; i < items_length; i++) { | 246 for (size_t i = 0; i < items_length; i++) { |
245 const auto& info = elements.at(i); | 247 const auto& info = elements.at(i); |
246 if (!IsBytes(info.type())) { | 248 if (!IsBytes(info.type())) { |
247 builder->AppendIPCDataElement(info); | 249 builder->AppendIPCDataElement(info); |
248 continue; | 250 continue; |
249 } | 251 } |
250 BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest request; | 252 BlobTransportRequestBuilder::RendererMemoryItemRequest request; |
251 request.browser_item_index = i; | 253 request.browser_item_index = i; |
252 request.browser_item_offset = 0; | 254 request.browser_item_offset = 0; |
253 request.message.request_number = requests_.size(); | 255 request.message.request_number = requests_.size(); |
254 request.message.transport_strategy = IPCBlobItemRequestStrategy::IPC; | 256 request.message.transport_strategy = IPCBlobItemRequestStrategy::IPC; |
255 request.message.renderer_item_index = i; | 257 request.message.renderer_item_index = i; |
256 request.message.renderer_item_offset = 0; | 258 request.message.renderer_item_offset = 0; |
257 request.message.size = info.length(); | 259 request.message.size = info.length(); |
258 requests_.push_back(request); | 260 requests_.push_back(request); |
259 builder->AppendFutureData(info.length()); | 261 builder->AppendFutureData(info.length()); |
260 } | 262 } |
261 } | 263 } |
262 | 264 |
263 /* static */ | 265 /* static */ |
264 bool BlobAsyncTransportRequestBuilder::ShouldBeShortcut( | 266 void BlobTransportRequestBuilder::ComputeHandleSizes( |
265 const std::vector<DataElement>& elements, | |
266 size_t memory_available) { | |
267 base::CheckedNumeric<size_t> shortcut_bytes = 0; | |
268 for (const auto& element : elements) { | |
269 DataElement::Type type = element.type(); | |
270 if (type == DataElement::TYPE_BYTES_DESCRIPTION) { | |
271 return false; | |
272 } | |
273 if (type == DataElement::TYPE_BYTES) { | |
274 shortcut_bytes += element.length(); | |
275 if (!shortcut_bytes.IsValid()) { | |
276 return false; | |
277 } | |
278 } | |
279 } | |
280 return shortcut_bytes.ValueOrDie() <= memory_available; | |
281 } | |
282 | |
283 /* static */ | |
284 void BlobAsyncTransportRequestBuilder::ComputeHandleSizes( | |
285 uint64_t total_memory_size, | 267 uint64_t total_memory_size, |
286 size_t max_segment_size, | 268 size_t max_segment_size, |
287 std::vector<size_t>* segment_sizes) { | 269 std::vector<size_t>* segment_sizes) { |
288 size_t total_max_segments = | 270 size_t total_max_segments = |
289 static_cast<size_t>(total_memory_size / max_segment_size); | 271 static_cast<size_t>(total_memory_size / max_segment_size); |
290 bool has_extra_segment = (total_memory_size % max_segment_size) > 0; | 272 bool has_extra_segment = (total_memory_size % max_segment_size) > 0; |
291 segment_sizes->reserve(total_max_segments + (has_extra_segment ? 1 : 0)); | 273 segment_sizes->reserve(total_max_segments + (has_extra_segment ? 1 : 0)); |
292 segment_sizes->insert(segment_sizes->begin(), total_max_segments, | 274 segment_sizes->insert(segment_sizes->begin(), total_max_segments, |
293 max_segment_size); | 275 max_segment_size); |
294 if (has_extra_segment) { | 276 if (has_extra_segment) { |
295 segment_sizes->push_back(total_memory_size % max_segment_size); | 277 segment_sizes->push_back(total_memory_size % max_segment_size); |
296 } | 278 } |
297 } | 279 } |
298 | 280 |
299 } // namespace storage | 281 } // namespace storage |
OLD | NEW |