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 SizeType total_memory_size, SizeType max_segment_size, | |
| 22 std::vector<SizeType>* segment_sizes, | |
| 23 std::vector<BlobTransportStrategy::MemoryItemRequest>* requests) | |
|
kinuko
2015/04/30 15:04:21
nit: one parameter on each line (here and below)
dmurph
2015/05/07 02:07:39
Done.
| |
| 24 : segment_sizes(segment_sizes), | |
| 25 requests(requests), | |
| 26 storage_element_index(0) { | |
| 27 SizeType memory_left = total_memory_size; | |
| 28 SizeType segment_size = 0; | |
| 29 for (; memory_left > 0; memory_left -= segment_size) { | |
| 30 segment_size = std::min(max_segment_size, memory_left); | |
| 31 segment_sizes->push_back(segment_size); | |
| 32 } | |
|
kinuko
2015/04/30 15:04:21
What is this segment_sizes for? (Not used?) In the
kinuko
2015/04/30 15:04:21
nit: I'd keep segment_size within the loop (reads
dmurph
2015/05/07 02:07:38
Done.
| |
| 33 } | |
| 34 | |
| 35 void operator()(DataElement::Type type, size_t element_index, | |
|
kinuko
2015/04/30 15:04:21
nit: in chromium code I've hardly seen operator()
dmurph
2015/05/07 02:07:38
I could turn these into lambdas as well. All the
| |
| 36 SizeType element_offset, size_t segment_index, | |
| 37 SizeType segment_offset, SizeType size) { | |
| 38 if (type != DataElement::TYPE_BYTES) { | |
| 39 storage_element_index++; | |
| 40 return; | |
| 41 } | |
| 42 BlobTransportStrategy::MemoryItemRequest request; | |
| 43 request.browser_item_index = storage_element_index; | |
|
kinuko
2015/04/30 15:04:21
is storage_element_index == element_index always t
dmurph
2015/05/07 02:07:39
No, as the element index can stay the same for mul
| |
| 44 request.browser_item_offset = 0; | |
| 45 request.message.request_number = requests->size(); | |
| 46 request.message.transport_strategy = IPC_BLOB_ITEM_REQUEST_STRATEGY_FILE; | |
| 47 request.message.renderer_item_index = element_index; | |
| 48 request.message.renderer_item_offset = element_offset; | |
| 49 request.message.size = size; | |
|
kinuko
2015/04/30 15:04:21
nit: why the order of indices/sizes different in f
dmurph
2015/05/07 02:07:38
No reason, which way do you prefer?
| |
| 50 request.message.handle_index = segment_index; | |
| 51 request.message.handle_offset = segment_offset; | |
|
kinuko
2015/04/30 15:04:21
nit: Intentionally not using BlobItemBytesRequest:
dmurph
2015/05/07 02:07:38
Yes, it's a little more readable, as you can read
| |
| 52 | |
| 53 requests->push_back(request); | |
| 54 storage_element_index++; | |
| 55 }; | |
| 56 | |
| 57 std::vector<SizeType>* segment_sizes; | |
| 58 std::vector<BlobTransportStrategy::MemoryItemRequest>* requests; | |
| 59 | |
| 60 size_t storage_element_index; | |
| 61 }; | |
| 62 | |
| 63 // This class handles the logic of storing memory that is transported as | |
| 64 // consolidated shared memory. The main hurdle is to re-separate memory blocks | |
| 65 // that cross file or blob boundaries. | |
| 66 struct SharedMemoryStorageStrategy { | |
| 67 typedef size_t SizeType; | |
| 68 | |
| 69 SharedMemoryStorageStrategy( | |
| 70 SizeType total_memory_size, SizeType max_segment_size, | |
| 71 std::vector<SizeType>* segment_sizes, | |
| 72 std::vector<BlobTransportStrategy::MemoryItemRequest>* requests) | |
| 73 : segment_sizes(segment_sizes), | |
| 74 requests(requests), | |
| 75 max_segment_size(max_segment_size), | |
| 76 storage_element_index(0), | |
| 77 storage_element_offset(0) { | |
| 78 SizeType memory_left = total_memory_size; | |
| 79 SizeType segment_size = 0; | |
| 80 for (; memory_left > 0; memory_left -= segment_size) { | |
| 81 segment_size = std::min(max_segment_size, memory_left); | |
| 82 segment_sizes->push_back(segment_size); | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 void operator()(DataElement::Type type, size_t element_index, | |
| 87 SizeType element_offset, size_t segment_index, | |
| 88 SizeType segment_offset, SizeType size) { | |
| 89 if (type != DataElement::TYPE_BYTES) { | |
| 90 storage_element_index += 2; | |
|
kinuko
2015/04/30 15:04:21
I think I'm lost here; why do we add 2?
dmurph
2015/05/07 02:07:38
Added comment.
| |
| 91 storage_element_offset = 0; | |
| 92 return; | |
| 93 } | |
| 94 if (storage_element_offset + size > max_segment_size) { | |
| 95 storage_element_index++; | |
| 96 storage_element_offset = 0; | |
| 97 } | |
| 98 BlobTransportStrategy::MemoryItemRequest request; | |
| 99 request.browser_item_index = storage_element_index; | |
| 100 request.browser_item_offset = storage_element_offset; | |
| 101 request.message.request_number = requests->size(); | |
| 102 request.message.transport_strategy = | |
| 103 IPC_BLOB_ITEM_REQUEST_STRATEGY_SHARED_MEMORY; | |
| 104 request.message.renderer_item_index = element_index; | |
| 105 request.message.renderer_item_offset = element_offset; | |
| 106 request.message.size = size; | |
| 107 request.message.handle_index = segment_index; | |
| 108 request.message.handle_offset = segment_offset; | |
| 109 | |
| 110 requests->push_back(request); | |
| 111 storage_element_offset += size; | |
| 112 }; | |
| 113 | |
| 114 std::vector<SizeType>* segment_sizes; | |
| 115 std::vector<BlobTransportStrategy::MemoryItemRequest>* requests; | |
| 116 | |
| 117 SizeType max_segment_size; | |
| 118 size_t storage_element_index; | |
| 119 SizeType storage_element_offset; | |
| 120 }; | |
| 121 } // namespace | |
| 122 | |
| 123 template <typename ForEachFunctor, typename SizeType> | |
| 124 /* static */ void BlobTransportStrategy::ForEachWithSegment( | |
|
kinuko
2015/04/30 15:04:21
nit: same method order in .h and in .cc
dmurph
2015/05/07 02:07:38
Done.
| |
| 125 const std::vector<DataElement> items, SizeType max_segment_size, | |
| 126 ForEachFunctor function) { | |
| 127 DCHECK_GT(max_segment_size, 0ull); | |
| 128 size_t segment_index = 0; | |
| 129 SizeType segment_offset = 0; | |
| 130 size_t items_length = items.size(); | |
| 131 for (size_t element_index = 0; element_index < items_length; | |
| 132 ++element_index) { | |
| 133 const auto& element = items.at(element_index); | |
| 134 if (element.type() != DataElement::TYPE_BYTES) { | |
| 135 function(element.type(), element_index, 0, 0, 0, 0); | |
| 136 continue; | |
| 137 } | |
| 138 SizeType element_memory_left = element.length(); | |
| 139 SizeType element_offset = 0; | |
| 140 while (element_memory_left > 0) { | |
| 141 if (segment_offset == max_segment_size) { | |
| 142 ++segment_index; | |
| 143 segment_offset = 0; | |
| 144 } | |
| 145 SizeType memory_writing = | |
| 146 std::min(max_segment_size - segment_offset, element_memory_left); | |
| 147 function(DataElement::TYPE_BYTES, element_index, element_offset, | |
| 148 segment_index, segment_offset, memory_writing); | |
| 149 element_memory_left -= memory_writing; | |
| 150 segment_offset += memory_writing; | |
| 151 element_offset += memory_writing; | |
| 152 } | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 BlobTransportStrategy::BlobTransportStrategy() | |
| 157 : error_(BlobTransportStrategy::ERROR_NONE) {} | |
| 158 | |
| 159 BlobTransportStrategy::~BlobTransportStrategy() {} | |
| 160 | |
| 161 void BlobTransportStrategy::Initialize( | |
| 162 BlobTransportStrategy::Mode mode, size_t max_ipc_memory_size, | |
| 163 size_t max_shared_memory_size, uint64_t max_file_size, | |
| 164 size_t max_blob_in_memory_size, uint64_t disk_space_left, | |
| 165 size_t memory_left, const std::vector<DataElement> blob_item_infos) { | |
| 166 file_handles_.clear(); | |
| 167 shared_memory_handles_.clear(); | |
| 168 requests_.clear(); | |
| 169 error_ = BlobTransportStrategy::ERROR_NONE; | |
|
kinuko
2015/04/30 15:04:21
Could Initialize() be called multiple times? Is th
dmurph
2015/05/07 02:07:38
Yes it can, it's reusable.
| |
| 170 | |
| 171 uint64_t total_memory_size = 0; | |
| 172 size_t memory_items = 0; | |
|
kinuko
2015/04/30 15:04:21
Not used after line 177?
If it's for the # of mem
dmurph
2015/05/07 02:07:39
Removed.
| |
| 173 for (const auto& info : blob_item_infos) { | |
| 174 if (info.type() != DataElement::TYPE_BYTES) { | |
| 175 continue; | |
| 176 } | |
| 177 ++memory_items; | |
| 178 total_memory_size += info.length(); | |
| 179 } | |
| 180 | |
| 181 switch (mode) { | |
| 182 case BlobTransportStrategy::MODE_DISK: | |
| 183 if (total_memory_size > | |
| 184 disk_space_left + static_cast<uint64_t>(memory_left)) { | |
| 185 error_ = BlobTransportStrategy::ERROR_TOO_LARGE; | |
| 186 return; | |
| 187 } | |
| 188 if (total_memory_size > max_blob_in_memory_size) { | |
|
kinuko
2015/04/30 15:04:21
max_blob_in_memory_size == kMaxBlobSize (e.g. 400M
dmurph
2015/05/07 02:07:39
Yes, here we know that we need to save to disk.
| |
| 189 if (total_memory_size > disk_space_left) { | |
| 190 error_ = BlobTransportStrategy::ERROR_TOO_LARGE; | |
| 191 return; | |
| 192 } | |
| 193 FileStorageStrategy strategy(total_memory_size, max_file_size, | |
| 194 &file_handles_, &requests_); | |
| 195 BlobTransportStrategy::ForEachWithSegment(blob_item_infos, | |
| 196 max_file_size, strategy); | |
| 197 return; | |
| 198 } | |
| 199 break; | |
| 200 case BlobTransportStrategy::MODE_NO_DISK: | |
| 201 if (total_memory_size > memory_left) { | |
| 202 error_ = BlobTransportStrategy::ERROR_TOO_LARGE; | |
| 203 return; | |
| 204 } | |
| 205 break; | |
| 206 default: | |
| 207 NOTREACHED() << "Invalid mode " << mode; | |
| 208 error_ = BlobTransportStrategy::ERROR_INVALID_PARAMS; | |
| 209 return; | |
| 210 } | |
| 211 if (total_memory_size > max_ipc_memory_size) { | |
| 212 DCHECK_LE(total_memory_size, std::numeric_limits<size_t>::max()); | |
|
kinuko
2015/04/30 15:04:21
If blob_item_infos comes over IPC this cannot be g
dmurph
2015/05/07 02:07:38
Good catch, changed to CHECK. This should still n
| |
| 213 SharedMemoryStorageStrategy strategy(total_memory_size, | |
| 214 max_shared_memory_size, | |
| 215 &shared_memory_handles_, &requests_); | |
| 216 BlobTransportStrategy::ForEachWithSegment(blob_item_infos, | |
| 217 max_shared_memory_size, strategy); | |
| 218 return; | |
| 219 } | |
| 220 size_t items_length = blob_item_infos.size(); | |
| 221 for (size_t i = 0; i < items_length; i++) { | |
| 222 const auto& info = blob_item_infos.at(i); | |
| 223 if (info.type() != DataElement::TYPE_BYTES) { | |
| 224 continue; | |
| 225 } | |
| 226 BlobTransportStrategy::MemoryItemRequest request; | |
| 227 request.browser_item_index = i; | |
| 228 request.browser_item_offset = 0; | |
| 229 request.message.request_number = requests_.size(); | |
| 230 request.message.transport_strategy = | |
| 231 storage::IPC_BLOB_ITEM_REQUEST_STRATEGY_IPC; | |
| 232 request.message.renderer_item_index = i; | |
| 233 request.message.renderer_item_offset = 0; | |
| 234 request.message.size = info.length(); | |
| 235 requests_.push_back(request); | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 } // namespace storage | |
| OLD | NEW |