| 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() {} |
| 204 | 202 |
| 205 // Initializes the transport strategy for file requests. | 203 // Initializes the transport strategy for file requests. |
| 206 void BlobAsyncTransportRequestBuilder::InitializeForFileRequests( | 204 void BlobTransportRequestBuilder::InitializeForFileRequests( |
| 207 size_t max_file_size, | 205 size_t max_file_size, |
| 208 uint64_t blob_total_size, | 206 uint64_t blob_total_size, |
| 209 const std::vector<DataElement>& elements, | 207 const std::vector<DataElement>& elements, |
| 210 BlobDataBuilder* builder) { | 208 BlobDataBuilder* builder) { |
| 211 DCHECK(requests_.empty()); | 209 DCHECK(requests_.empty()); |
| 212 total_bytes_size_ = blob_total_size; | 210 total_bytes_size_ = blob_total_size; |
| 213 ComputeHandleSizes(total_bytes_size_, max_file_size, &file_sizes_); | 211 ComputeHandleSizes(total_bytes_size_, max_file_size, &file_sizes_); |
| 214 FileStorageStrategy strategy(&requests_, builder); | 212 FileStorageStrategy strategy(&requests_, builder); |
| 215 ForEachWithSegment(elements, static_cast<uint64_t>(max_file_size), &strategy); | 213 ForEachWithSegment(elements, static_cast<uint64_t>(max_file_size), &strategy); |
| 216 } | 214 } |
| 217 | 215 |
| 218 void BlobAsyncTransportRequestBuilder::InitializeForSharedMemoryRequests( | 216 void BlobTransportRequestBuilder::InitializeForSharedMemoryRequests( |
| 219 size_t max_shared_memory_size, | 217 size_t max_shared_memory_size, |
| 220 uint64_t blob_total_size, | 218 uint64_t blob_total_size, |
| 221 const std::vector<DataElement>& elements, | 219 const std::vector<DataElement>& elements, |
| 222 BlobDataBuilder* builder) { | 220 BlobDataBuilder* builder) { |
| 223 DCHECK(requests_.empty()); | 221 DCHECK(requests_.empty()); |
| 224 DCHECK(blob_total_size <= std::numeric_limits<size_t>::max()); | 222 DCHECK(blob_total_size <= std::numeric_limits<size_t>::max()); |
| 225 total_bytes_size_ = blob_total_size; | 223 total_bytes_size_ = blob_total_size; |
| 226 ComputeHandleSizes(total_bytes_size_, max_shared_memory_size, | 224 ComputeHandleSizes(total_bytes_size_, max_shared_memory_size, |
| 227 &shared_memory_sizes_); | 225 &shared_memory_sizes_); |
| 228 SharedMemoryStorageStrategy strategy(max_shared_memory_size, &requests_, | 226 SharedMemoryStorageStrategy strategy(max_shared_memory_size, &requests_, |
| 229 builder); | 227 builder); |
| 230 ForEachWithSegment(elements, static_cast<uint64_t>(max_shared_memory_size), | 228 ForEachWithSegment(elements, static_cast<uint64_t>(max_shared_memory_size), |
| 231 &strategy); | 229 &strategy); |
| 232 } | 230 } |
| 233 | 231 |
| 234 void BlobAsyncTransportRequestBuilder::InitializeForIPCRequests( | 232 void BlobTransportRequestBuilder::InitializeForIPCRequests( |
| 235 size_t max_ipc_memory_size, | 233 size_t max_ipc_memory_size, |
| 236 uint64_t blob_total_size, | 234 uint64_t blob_total_size, |
| 237 const std::vector<DataElement>& elements, | 235 const std::vector<DataElement>& elements, |
| 238 BlobDataBuilder* builder) { | 236 BlobDataBuilder* builder) { |
| 239 DCHECK(requests_.empty()); | 237 DCHECK(requests_.empty()); |
| 240 // We don't segment anything, and just request the memory items directly | 238 // We don't segment anything, and just request the memory items directly |
| 241 // in IPC. | 239 // in IPC. |
| 242 size_t items_length = elements.size(); | 240 size_t items_length = elements.size(); |
| 243 total_bytes_size_ = blob_total_size; | 241 total_bytes_size_ = blob_total_size; |
| 244 for (size_t i = 0; i < items_length; i++) { | 242 for (size_t i = 0; i < items_length; i++) { |
| 245 const auto& info = elements.at(i); | 243 const auto& info = elements.at(i); |
| 246 if (!IsBytes(info.type())) { | 244 if (!IsBytes(info.type())) { |
| 247 builder->AppendIPCDataElement(info); | 245 builder->AppendIPCDataElement(info); |
| 248 continue; | 246 continue; |
| 249 } | 247 } |
| 250 BlobAsyncTransportRequestBuilder::RendererMemoryItemRequest request; | 248 BlobTransportRequestBuilder::RendererMemoryItemRequest request; |
| 251 request.browser_item_index = i; | 249 request.browser_item_index = i; |
| 252 request.browser_item_offset = 0; | 250 request.browser_item_offset = 0; |
| 253 request.message.request_number = requests_.size(); | 251 request.message.request_number = requests_.size(); |
| 254 request.message.transport_strategy = IPCBlobItemRequestStrategy::IPC; | 252 request.message.transport_strategy = IPCBlobItemRequestStrategy::IPC; |
| 255 request.message.renderer_item_index = i; | 253 request.message.renderer_item_index = i; |
| 256 request.message.renderer_item_offset = 0; | 254 request.message.renderer_item_offset = 0; |
| 257 request.message.size = info.length(); | 255 request.message.size = info.length(); |
| 258 requests_.push_back(request); | 256 requests_.push_back(request); |
| 259 builder->AppendFutureData(info.length()); | 257 builder->AppendFutureData(info.length()); |
| 260 } | 258 } |
| 261 } | 259 } |
| 262 | 260 |
| 263 /* static */ | 261 /* static */ |
| 264 bool BlobAsyncTransportRequestBuilder::ShouldBeShortcut( | 262 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, | 263 uint64_t total_memory_size, |
| 286 size_t max_segment_size, | 264 size_t max_segment_size, |
| 287 std::vector<size_t>* segment_sizes) { | 265 std::vector<size_t>* segment_sizes) { |
| 288 size_t total_max_segments = | 266 size_t total_max_segments = |
| 289 static_cast<size_t>(total_memory_size / max_segment_size); | 267 static_cast<size_t>(total_memory_size / max_segment_size); |
| 290 bool has_extra_segment = (total_memory_size % max_segment_size) > 0; | 268 bool has_extra_segment = (total_memory_size % max_segment_size) > 0; |
| 291 segment_sizes->reserve(total_max_segments + (has_extra_segment ? 1 : 0)); | 269 segment_sizes->reserve(total_max_segments + (has_extra_segment ? 1 : 0)); |
| 292 segment_sizes->insert(segment_sizes->begin(), total_max_segments, | 270 segment_sizes->insert(segment_sizes->begin(), total_max_segments, |
| 293 max_segment_size); | 271 max_segment_size); |
| 294 if (has_extra_segment) { | 272 if (has_extra_segment) { |
| 295 segment_sizes->push_back(total_memory_size % max_segment_size); | 273 segment_sizes->push_back(total_memory_size % max_segment_size); |
| 296 } | 274 } |
| 297 } | 275 } |
| 298 | 276 |
| 299 } // namespace storage | 277 } // namespace storage |
| OLD | NEW |