Chromium Code Reviews| OLD | NEW |
|---|---|
| (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_transport_strategy.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 namespace storage { | |
| 10 | |
| 11 namespace { | |
| 12 | |
| 13 // This class handles the logic of how transported memory is going to be | |
| 14 // represented as storage in the browser. The main idea is that all the memory | |
| 15 // is now packed into file chunks, and the browser items will just reference | |
| 16 // the file with offsets and sizes. | |
| 17 struct FileStorageStrategy { | |
| 18 typedef uint64_t SizeType; | |
| 19 | |
| 20 FileStorageStrategy( | |
| 21 std::vector<BlobTransportStrategy::MemoryItemRequest>* requests) | |
| 22 : requests(requests), storage_element_index(0) {} | |
| 23 | |
| 24 void operator()(DataElement::Type type, | |
| 25 size_t element_index, | |
| 26 SizeType element_offset, | |
| 27 size_t segment_index, | |
| 28 SizeType segment_offset, | |
| 29 SizeType size) { | |
| 30 if (type != DataElement::TYPE_BYTES) { | |
| 31 storage_element_index++; | |
| 32 return; | |
| 33 } | |
| 34 BlobTransportStrategy::MemoryItemRequest request; | |
| 35 request.browser_item_index = storage_element_index; | |
| 36 request.browser_item_offset = 0; | |
| 37 request.message.request_number = requests->size(); | |
| 38 request.message.transport_strategy = IPC_BLOB_ITEM_REQUEST_STRATEGY_FILE; | |
| 39 request.message.renderer_item_index = element_index; | |
| 40 request.message.renderer_item_offset = element_offset; | |
| 41 request.message.size = size; | |
| 42 request.message.handle_index = segment_index; | |
| 43 request.message.handle_offset = segment_offset; | |
| 44 | |
| 45 requests->push_back(request); | |
| 46 storage_element_index++; | |
| 47 }; | |
| 48 | |
| 49 std::vector<BlobTransportStrategy::MemoryItemRequest>* requests; | |
| 50 | |
| 51 size_t storage_element_index; | |
| 52 }; | |
| 53 | |
| 54 // This class handles the logic of storing memory that is transported as | |
| 55 // consolidated shared memory. The main hurdle is to re-separate memory blocks | |
| 56 // that cross file or blob boundaries. | |
| 57 struct SharedMemoryStorageStrategy { | |
| 58 typedef size_t SizeType; | |
| 59 | |
| 60 SharedMemoryStorageStrategy( | |
| 61 SizeType max_segment_size, | |
| 62 std::vector<BlobTransportStrategy::MemoryItemRequest>* requests) | |
| 63 : requests(requests), | |
| 64 max_segment_size(max_segment_size), | |
| 65 storage_element_index(0), | |
| 66 storage_element_offset(0) {} | |
| 67 | |
| 68 void operator()(DataElement::Type type, | |
| 69 size_t element_index, | |
| 70 SizeType element_offset, | |
| 71 size_t segment_index, | |
| 72 SizeType segment_offset, | |
| 73 SizeType size) { | |
| 74 if (type != DataElement::TYPE_BYTES) { | |
| 75 // We add 1 to skip the non-bytes storage element, and we add 1 again | |
| 76 // because we need to start a new request (requests don't span blob | |
| 77 // or file boundaries). Thus, +2. | |
| 78 storage_element_index += 2; | |
| 79 storage_element_offset = 0; | |
| 80 return; | |
| 81 } | |
| 82 if (storage_element_offset + size > max_segment_size) { | |
| 83 storage_element_index++; | |
| 84 storage_element_offset = 0; | |
| 85 } | |
| 86 BlobTransportStrategy::MemoryItemRequest request; | |
| 87 request.browser_item_index = storage_element_index; | |
| 88 request.browser_item_offset = storage_element_offset; | |
| 89 request.message.request_number = requests->size(); | |
| 90 request.message.transport_strategy = | |
| 91 IPC_BLOB_ITEM_REQUEST_STRATEGY_SHARED_MEMORY; | |
| 92 request.message.renderer_item_index = element_index; | |
| 93 request.message.renderer_item_offset = element_offset; | |
| 94 request.message.size = size; | |
| 95 request.message.handle_index = segment_index; | |
| 96 request.message.handle_offset = segment_offset; | |
| 97 | |
| 98 requests->push_back(request); | |
| 99 storage_element_offset += size; | |
| 100 }; | |
| 101 | |
| 102 std::vector<BlobTransportStrategy::MemoryItemRequest>* requests; | |
| 103 | |
| 104 SizeType max_segment_size; | |
| 105 size_t storage_element_index; | |
| 106 SizeType storage_element_offset; | |
| 107 }; | |
| 108 } // namespace | |
| 109 | |
| 110 BlobTransportStrategy::BlobTransportStrategy() | |
| 111 : error_(BlobTransportStrategy::ERROR_NONE) {} | |
| 112 | |
| 113 BlobTransportStrategy::~BlobTransportStrategy() {} | |
| 114 | |
| 115 void BlobTransportStrategy::Initialize( | |
| 116 BlobTransportStrategy::Mode mode, | |
| 117 size_t max_ipc_memory_size, | |
| 118 size_t max_shared_memory_size, | |
| 119 uint64_t max_file_size, | |
| 120 size_t max_blob_in_memory_size, | |
| 121 uint64_t disk_space_left, | |
| 122 size_t memory_left, | |
| 123 const std::vector<DataElement>& blob_item_infos) { | |
| 124 file_handles_.clear(); | |
| 125 shared_memory_handles_.clear(); | |
| 126 requests_.clear(); | |
| 127 error_ = BlobTransportStrategy::ERROR_NONE; | |
| 128 | |
| 129 uint64_t total_memory_size = 0; | |
| 130 for (const auto& info : blob_item_infos) { | |
| 131 if (info.type() != DataElement::TYPE_BYTES) { | |
| 132 continue; | |
| 133 } | |
|
kinuko
2015/05/25 08:32:02
nit: no { } required for single-line body in chrom
dmurph
2015/06/13 00:13:10
Done.
| |
| 134 total_memory_size += info.length(); | |
| 135 } | |
| 136 | |
| 137 switch (mode) { | |
| 138 case BlobTransportStrategy::MODE_DISK: | |
| 139 if (total_memory_size > | |
| 140 disk_space_left + static_cast<uint64_t>(memory_left)) { | |
| 141 error_ = BlobTransportStrategy::ERROR_TOO_LARGE; | |
| 142 return; | |
| 143 } | |
| 144 if (total_memory_size > max_blob_in_memory_size) { | |
| 145 if (total_memory_size > disk_space_left) { | |
| 146 error_ = BlobTransportStrategy::ERROR_TOO_LARGE; | |
| 147 return; | |
| 148 } | |
| 149 CreateHandleSizes(total_memory_size, max_file_size, &file_handles_); | |
| 150 FileStorageStrategy strategy(&requests_); | |
| 151 BlobTransportStrategy::ForEachWithSegment(blob_item_infos, | |
|
kinuko
2015/05/25 08:32:02
nit: we probably don't need BlobTransportStorategy
dmurph
2015/06/13 00:13:10
Done.
| |
| 152 max_file_size, strategy); | |
| 153 return; | |
| 154 } | |
| 155 break; | |
| 156 case BlobTransportStrategy::MODE_NO_DISK: | |
| 157 if (total_memory_size > memory_left) { | |
| 158 error_ = BlobTransportStrategy::ERROR_TOO_LARGE; | |
| 159 return; | |
| 160 } | |
| 161 break; | |
| 162 default: | |
| 163 NOTREACHED() << "Invalid mode " << mode; | |
| 164 error_ = BlobTransportStrategy::ERROR_INVALID_PARAMS; | |
| 165 return; | |
| 166 } | |
| 167 if (total_memory_size > max_ipc_memory_size) { | |
| 168 CHECK_LE(total_memory_size, std::numeric_limits<size_t>::max()); | |
| 169 CreateHandleSizes(static_cast<size_t>(total_memory_size), | |
| 170 max_shared_memory_size, &shared_memory_handles_); | |
| 171 SharedMemoryStorageStrategy strategy(max_shared_memory_size, &requests_); | |
| 172 BlobTransportStrategy::ForEachWithSegment(blob_item_infos, | |
| 173 max_shared_memory_size, strategy); | |
| 174 return; | |
| 175 } | |
| 176 size_t items_length = blob_item_infos.size(); | |
| 177 for (size_t i = 0; i < items_length; i++) { | |
| 178 const auto& info = blob_item_infos.at(i); | |
| 179 if (info.type() != DataElement::TYPE_BYTES) { | |
| 180 continue; | |
| 181 } | |
| 182 BlobTransportStrategy::MemoryItemRequest request; | |
| 183 request.browser_item_index = i; | |
| 184 request.browser_item_offset = 0; | |
| 185 request.message.request_number = requests_.size(); | |
| 186 request.message.transport_strategy = | |
| 187 storage::IPC_BLOB_ITEM_REQUEST_STRATEGY_IPC; | |
| 188 request.message.renderer_item_index = i; | |
| 189 request.message.renderer_item_offset = 0; | |
| 190 request.message.size = info.length(); | |
| 191 requests_.push_back(request); | |
|
kinuko
2015/05/25 08:32:03
So in the current design the decision is basically
dmurph
2015/06/13 00:13:10
Yes.
| |
| 192 } | |
| 193 } | |
| 194 | |
| 195 template <typename ForEachFunctor, typename SizeType> | |
| 196 /* static */ void BlobTransportStrategy::ForEachWithSegment( | |
| 197 const std::vector<DataElement>& items, | |
| 198 SizeType max_segment_size, | |
| 199 ForEachFunctor function) { | |
| 200 DCHECK_GT(max_segment_size, 0ull); | |
| 201 size_t segment_index = 0; | |
| 202 SizeType segment_offset = 0; | |
| 203 size_t items_length = items.size(); | |
| 204 for (size_t element_index = 0; element_index < items_length; | |
| 205 ++element_index) { | |
| 206 const auto& element = items.at(element_index); | |
| 207 if (element.type() != DataElement::TYPE_BYTES) { | |
| 208 function(element.type(), element_index, 0, 0, 0, 0); | |
| 209 continue; | |
| 210 } | |
| 211 SizeType element_memory_left = element.length(); | |
| 212 SizeType element_offset = 0; | |
| 213 while (element_memory_left > 0) { | |
| 214 if (segment_offset == max_segment_size) { | |
| 215 ++segment_index; | |
| 216 segment_offset = 0; | |
| 217 } | |
| 218 SizeType memory_writing = | |
| 219 std::min(max_segment_size - segment_offset, element_memory_left); | |
| 220 function(DataElement::TYPE_BYTES, element_index, element_offset, | |
| 221 segment_index, segment_offset, memory_writing); | |
| 222 element_memory_left -= memory_writing; | |
| 223 segment_offset += memory_writing; | |
| 224 element_offset += memory_writing; | |
| 225 } | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 template <typename SizeType> | |
| 230 /* static */ void BlobTransportStrategy::CreateHandleSizes( | |
| 231 SizeType total_memory_size, | |
| 232 SizeType max_segment_size, | |
| 233 std::vector<SizeType>* segment_sizes) { | |
| 234 SizeType memory_left = total_memory_size; | |
| 235 SizeType segment_size; | |
| 236 for (; memory_left > 0; memory_left -= segment_size) { | |
| 237 segment_size = std::min(max_segment_size, memory_left); | |
| 238 segment_sizes->push_back(segment_size); | |
| 239 } | |
|
kinuko
2015/05/25 08:32:03
I have a feeling that this is a bit verbose and co
dmurph
2015/06/13 00:13:10
I'm scared that it will make that function too com
| |
| 240 } | |
| 241 | |
| 242 } // namespace storage | |
| OLD | NEW |