Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: storage/browser/blob/blob_async_transport_strategy.cc

Issue 1098853003: [BlobAsync] Patch 4: Browser Classes & Logic. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments, and simplification Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 <algorithm>
6
7 #include "storage/browser/blob/blob_async_transport_strategy.h"
8 #include "storage/common/blob_storage/blob_storage_constants.h"
9
10 namespace storage {
11 namespace {
12 const char* kTemporaryFileName = "TODO(dmurph) Replace with real filename";
13
14 bool IsBytes(DataElement::Type type) {
15 return type == DataElement::TYPE_BYTES ||
16 type == DataElement::TYPE_BYTES_DESCRIPTION;
17 }
18 } // namespace
19
20 // This class handles the logic of how transported memory is going to be
21 // represented as storage in the browser. The main idea is that all the memory
22 // is now packed into file chunks, and the browser items will just reference
23 // the file with offsets and sizes.
24 class FileStorageStrategy
25 : public BlobAsyncTransportStrategy::BlobSegmentVisitor<uint64_t> {
26 public:
27 typedef uint64_t SizeType;
28
29 FileStorageStrategy(
30 std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>*
31 requests,
32 BlobDataBuilder* builder)
33 : requests(requests), builder(builder), current_storage_item(0) {}
34
35 ~FileStorageStrategy() override {}
36
37 void VisitBytesSegment(size_t element_index,
38 SizeType element_offset,
39 size_t segment_index,
40 SizeType segment_offset,
41 SizeType size) override {
42 BlobAsyncTransportStrategy::RendererMemoryItemRequest request;
43 request.browser_item_index = current_storage_item;
44 request.browser_item_offset = 0;
45 request.message.request_number = requests->size();
46 request.message.transport_strategy = IPCBlobItemRequestStrategy::FILE;
47 request.message.renderer_item_index = element_index;
48 request.message.renderer_item_offset = element_offset;
49 request.message.size = size;
50 request.message.handle_index = segment_index;
51 request.message.handle_offset = segment_offset;
52
53 requests->push_back(request);
54 builder->AppendFile(
55 base::FilePath::FromUTF8Unsafe(std::string(kTemporaryFileName)),
56 segment_offset, size, base::Time::FromDoubleT(0));
57 current_storage_item++;
58 }
59
60 void VisitNonBytesSegment(const DataElement& element,
61 size_t element_index) override {
62 builder->AppendIPCDataElement(element);
63 current_storage_item++;
64 }
65
66 void Done() override {}
67
68 std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* requests;
69 BlobDataBuilder* builder;
70
71 size_t current_storage_item;
72 };
73
74 // This class handles the logic of storing memory that is transported as
75 // consolidated shared memory. The main hurdle is to re-separate memory blocks
76 // that cross file or blob boundaries.
77 class SharedMemoryStorageStrategy
78 : public BlobAsyncTransportStrategy::BlobSegmentVisitor<size_t> {
79 public:
80 typedef size_t SizeType;
81
82 SharedMemoryStorageStrategy(
83 SizeType max_segment_size,
84 std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>*
85 requests,
86 BlobDataBuilder* builder)
87 : requests(requests),
88 max_segment_size(max_segment_size),
89 storage_element_offset(0),
90 builder(builder),
91 current_item_size(0),
92 current_storage_item(0) {}
93 ~SharedMemoryStorageStrategy() override {}
94
95 void VisitBytesSegment(size_t element_index,
96 SizeType element_offset,
97 size_t segment_index,
98 SizeType segment_offset,
99 SizeType size) override {
100 if (storage_element_offset + size > max_segment_size) {
101 builder->AppendFutureData(current_item_size);
102 current_storage_item++;
103 current_item_size = 0;
104 storage_element_offset = 0;
105 }
106 BlobAsyncTransportStrategy::RendererMemoryItemRequest request;
107 request.browser_item_index = current_storage_item;
108 request.browser_item_offset = storage_element_offset;
109 request.message.request_number = requests->size();
110 request.message.transport_strategy =
111 IPCBlobItemRequestStrategy::SHARED_MEMORY;
112 request.message.renderer_item_index = element_index;
113 request.message.renderer_item_offset = element_offset;
114 request.message.size = size;
115 request.message.handle_index = segment_index;
116 request.message.handle_offset = segment_offset;
117
118 requests->push_back(request);
119 storage_element_offset += size;
120 current_item_size += size;
121 };
122
123 void VisitNonBytesSegment(const DataElement& element,
124 size_t element_index) override {
125 builder->AppendFutureData(current_item_size);
126 current_storage_item++;
127 builder->AppendIPCDataElement(element);
128 current_storage_item++;
129 storage_element_offset = 0;
130 current_item_size = 0;
131 }
132
133 void Done() override {
134 if (current_item_size != 0) {
135 builder->AppendFutureData(current_item_size);
136 }
137 }
138
139 std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* requests;
140
141 SizeType max_segment_size;
142 SizeType storage_element_offset;
143 BlobDataBuilder* builder;
144 SizeType current_item_size;
145 size_t current_storage_item;
146 };
147
148 BlobAsyncTransportStrategy::RendererMemoryItemRequest::
149 RendererMemoryItemRequest()
150 : browser_item_index(0), browser_item_offset(0), received(false) {}
151
152 BlobAsyncTransportStrategy::BlobAsyncTransportStrategy()
153 : error_(BlobAsyncTransportStrategy::ERROR_NONE), total_bytes_size_(0) {}
154
155 BlobAsyncTransportStrategy::~BlobAsyncTransportStrategy() {}
156
157 // if total_blob_size > kMaxBlobSize (say 400MB)
158 // Request all data in files
159 // (Segment all of the existing data into
160 // file blocks, of <= kMaxFileSize)
161 // else if total_blob_size > kMaxIPCSize (this is 150KB)
162 // Request all data in shared memory
163 // (Segment all of the existing data into
164 // shared memory blocks, of <= kMaxSharedMemorySize)
165 // else
166 // Request all data to be sent over IPC
167 void BlobAsyncTransportStrategy::Initialize(
168 size_t max_ipc_memory_size,
169 size_t max_shared_memory_size,
170 uint64_t max_file_size,
171 uint64_t disk_space_left,
172 size_t memory_available,
173 const std::string& uuid,
174 const std::vector<DataElement>& blob_item_infos) {
175 file_handle_sizes_.clear();
176 shared_memory_handle_sizes_.clear();
177 requests_.clear();
178 builder_.reset(new BlobDataBuilder(uuid));
179 error_ = BlobAsyncTransportStrategy::ERROR_NONE;
180
181 size_t memory_items = 0;
182 total_bytes_size_ = 0;
183 for (const auto& info : blob_item_infos) {
184 if (!IsBytes(info.type())) {
185 continue;
186 }
187 total_bytes_size_ += info.length();
188 ++memory_items;
189 }
190
191 // See if we have enough memory
192 if (total_bytes_size_ >
193 disk_space_left + static_cast<uint64_t>(memory_available)) {
194 error_ = BlobAsyncTransportStrategy::ERROR_TOO_LARGE;
195 return;
196 }
197
198 // If we're more than the available memory, then we're going straight to disk.
199 if (total_bytes_size_ > memory_available) {
200 // First, handle the case where we go to disk.
201 if (total_bytes_size_ < disk_space_left) {
202 ComputeHandleSizes(total_bytes_size_, max_file_size, &file_handle_sizes_);
203 FileStorageStrategy strategy(&requests_, builder_.get());
204 ForEachWithSegment(blob_item_infos, max_file_size, &strategy);
205 return;
206 }
207 error_ = BlobAsyncTransportStrategy::ERROR_TOO_LARGE;
208 return;
209 }
210
211 if (total_bytes_size_ > max_ipc_memory_size) {
212 CHECK_LE(total_bytes_size_, std::numeric_limits<size_t>::max());
213 ComputeHandleSizes(static_cast<size_t>(total_bytes_size_),
214 max_shared_memory_size, &shared_memory_handle_sizes_);
215 SharedMemoryStorageStrategy strategy(max_shared_memory_size, &requests_,
216 builder_.get());
217 ForEachWithSegment(blob_item_infos, max_shared_memory_size, &strategy);
218 return;
219 }
220 // Since they can all fit in IPC memory, we don't need to segment anything,
221 // and just request them straight in IPC.
222 size_t items_length = blob_item_infos.size();
223 for (size_t i = 0; i < items_length; i++) {
224 const auto& info = blob_item_infos.at(i);
225 if (!IsBytes(info.type())) {
226 builder_->AppendIPCDataElement(info);
227 continue;
228 }
229 BlobAsyncTransportStrategy::RendererMemoryItemRequest request;
230 request.browser_item_index = i;
231 request.browser_item_offset = 0;
232 request.message.request_number = requests_.size();
233 request.message.transport_strategy = IPCBlobItemRequestStrategy::IPC;
234 request.message.renderer_item_index = i;
235 request.message.renderer_item_offset = 0;
236 request.message.size = info.length();
237 requests_.push_back(request);
238 builder_->AppendFutureData(info.length());
239 }
240 }
241
242 // Splits each |element| into one or more |segments| of a max_size, invokes the
243 // strategy to determine the request to make for each |segment| produced. A
244 // |segment| can also span multiple |elements|.
245 /* static */
246 template <typename SizeType>
247 void BlobAsyncTransportStrategy::ForEachWithSegment(
248 const std::vector<DataElement>& elements,
249 SizeType max_segment_size,
250 BlobSegmentVisitor<SizeType>* visitor) {
251 DCHECK_GT(max_segment_size, 0ull);
252 size_t segment_index = 0;
253 SizeType segment_offset = 0;
254 size_t elements_length = elements.size();
255 for (size_t element_index = 0; element_index < elements_length;
256 ++element_index) {
257 const auto& element = elements.at(element_index);
258 DataElement::Type type = element.type();
259 if (!IsBytes(type)) {
260 visitor->VisitNonBytesSegment(element, element_index);
261 continue;
262 }
263 SizeType element_memory_left = element.length();
264 SizeType element_offset = 0;
265 while (element_memory_left > 0) {
266 if (segment_offset == max_segment_size) {
267 ++segment_index;
268 segment_offset = 0;
269 }
270 SizeType memory_writing =
271 std::min(max_segment_size - segment_offset, element_memory_left);
272 visitor->VisitBytesSegment(element_index, element_offset, segment_index,
273 segment_offset, memory_writing);
274 element_memory_left -= memory_writing;
275 segment_offset += memory_writing;
276 element_offset += memory_writing;
277 }
278 }
279 visitor->Done();
280 }
281
282 /* static */
283 bool BlobAsyncTransportStrategy::ShouldBeShortcut(
284 const std::vector<DataElement>& elements,
285 size_t memory_available) {
286 size_t shortcut_bytes = 0;
287 for (const auto& element : elements) {
288 DataElement::Type type = element.type();
289 if (type == DataElement::TYPE_BYTES_DESCRIPTION) {
290 return false;
291 }
292 if (type == DataElement::TYPE_BYTES) {
293 shortcut_bytes += element.length();
294 }
295 }
296 return shortcut_bytes <= memory_available;
297 }
298
299 /* static */
300 template <typename SizeType>
301 void BlobAsyncTransportStrategy::ComputeHandleSizes(
302 SizeType total_memory_size,
303 SizeType max_segment_size,
304 std::vector<SizeType>* segment_sizes) {
305 SizeType memory_left = total_memory_size;
306 SizeType segment_size;
307 segment_sizes->insert(segment_sizes->begin(),
308 total_memory_size / max_segment_size, max_segment_size);
309 segment_sizes->push_back(total_memory_size % max_segment_size);
310 }
311
312 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698