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

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

Issue 2055053003: [BlobAsync] Disk support for blob storage (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Combined BlobSlice & BlobFlattener files, more comments, a little cleanup. Created 4 years, 4 months 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 2016 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_flattener.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <set>
10 #include <utility>
11
12 #include "storage/browser/blob/blob_async_transport_request_builder.h"
13 #include "storage/browser/blob/blob_data_builder.h"
14 #include "storage/browser/blob/blob_data_item.h"
15 #include "storage/browser/blob/blob_storage_context.h"
16 #include "storage/browser/blob/blob_storage_registry.h"
17 #include "storage/browser/blob/internal_blob_data.h"
18 #include "storage/browser/blob/shareable_blob_data_item.h"
19 #include "storage/common/data_element.h"
20
21 namespace storage {
22 namespace {
23 using ItemCopyEntry = InternalBlobData::ItemCopyEntry;
24
25 bool IsBytes(DataElement::Type type) {
26 return type == DataElement::TYPE_BYTES ||
27 type == DataElement::TYPE_BYTES_DESCRIPTION;
28 }
29 } // namespace
30
31 // static
32 BlobFlattener::BlobFlattener(const BlobDataBuilder& input_builder,
33 InternalBlobData* output_blob,
34 BlobStorageRegistry* registry) {
35 const std::string& uuid = input_builder.uuid_;
36 std::set<std::string> dependent_blob_uuids;
37 bool contains_pending_content = false;
38
39 size_t num_files_with_unknown_size = 0;
40
41 for (scoped_refptr<BlobDataItem> input_item : input_builder.items_) {
42 const DataElement& input_element = input_item->data_element();
43 DataElement::Type type = input_element.type();
44 uint64_t length = input_element.length();
45 contains_pending_content |= type == DataElement::TYPE_BYTES_DESCRIPTION;
46
47 if (IsBytes(type)) {
48 DCHECK_NE(0 + DataElement::kUnknownSize, input_element.length());
49 transport_quota_needed += length;
50 total_size += length;
51 scoped_refptr<ShareableBlobDataItem> item = new ShareableBlobDataItem(
52 std::move(input_item), ShareableBlobDataItem::QUOTA_NEEDED);
53 transport_pending_items.push_back(item.get());
54 output_blob->AppendSharedBlobItem(uuid, std::move(item));
55 continue;
56 }
57 if (type == DataElement::TYPE_BLOB) {
58 InternalBlobData* ref_entry =
59 registry->GetEntry(input_element.blob_uuid());
60
61 if (!ref_entry || input_element.blob_uuid() == uuid) {
62 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
63 return;
64 }
65
66 if (BlobStatusIsError(ref_entry->status())) {
67 status = BlobStatus::ERR_REFERENCED_BLOB_BROKEN;
68 return;
69 }
70
71 if (ref_entry->total_size() == DataElement::kUnknownSize) {
72 // We can't reference a blob with unknown size.
73 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
74 return;
75 }
76
77 if (dependent_blob_uuids.find(input_element.blob_uuid()) ==
78 dependent_blob_uuids.end()) {
79 dependent_blobs.push_back(
80 std::make_pair(input_element.blob_uuid(), ref_entry));
81 dependent_blob_uuids.insert(input_element.blob_uuid());
82 }
83
84 length = length == DataElement::kUnknownSize ? ref_entry->total_size()
85 : input_element.length();
86 total_size += length;
87
88 // If we're referencing the whole blob, then we don't need to slice.
89 if (input_element.offset() == 0 && length == ref_entry->total_size()) {
90 for (const auto& shareable_item : ref_entry->items()) {
91 output_blob->AppendSharedBlobItem(uuid, shareable_item);
92 }
93 continue;
94 }
95
96 // Validate our reference has good offset & length.
97 if (input_element.offset() + input_element.length() >
98 ref_entry->total_size()) {
99 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
100 return;
101 }
102
103 BlobSlice slice(*ref_entry, input_element.offset(),
104 input_element.length());
Marijn Kruisselbrink 2016/08/05 23:23:54 Should this use input_element.length() (which can
dmurph 2016/08/19 00:18:32 Good idea. Thanks.
105
106 if (slice.first_source_item) {
107 copies.push_back(ItemCopyEntry(slice.first_source_item,
108 slice.first_item_slice_offset,
109 slice.dest_items.front()));
110 copy_pending_items.push_back(slice.dest_items.front().get());
111 }
112 if (slice.last_source_item) {
113 copies.push_back(
114 ItemCopyEntry(slice.last_source_item, 0, slice.dest_items.back()));
115 copy_pending_items.push_back(slice.dest_items.back().get());
116 }
117 copy_quota_needed += slice.copying_memory_size;
118
119 for (auto& shareable_item : slice.dest_items) {
120 output_blob->AppendSharedBlobItem(uuid, std::move(shareable_item));
121 }
122 continue;
123 }
124
125 // If the source item is a temporary file item, then we need to keep track
126 // of that and mark is as needing quota.
127 scoped_refptr<ShareableBlobDataItem> item;
128 if (type == DataElement::TYPE_FILE &&
129 BlobDataBuilder::IsTemporaryFileItem(input_element)) {
130 item = new ShareableBlobDataItem(std::move(input_item),
131 ShareableBlobDataItem::QUOTA_NEEDED);
132 contains_pending_content = true;
133 transport_pending_items.push_back(item.get());
134 transport_quota_needed += length;
135 } else {
136 item = new ShareableBlobDataItem(
137 std::move(input_item),
138 ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA);
139 }
140 if (length == DataElement::kUnknownSize)
141 num_files_with_unknown_size++;
142
143 total_size += length;
Marijn Kruisselbrink 2016/08/05 23:23:54 It seems a bit odd to sometimes be adding kUnknown
dmurph 2016/08/19 00:18:32 Yeah, since total_size is a safe math variable any
144 output_blob->AppendSharedBlobItem(uuid, std::move(item));
145 }
146
147 if (num_files_with_unknown_size > 1 && input_builder.items_.size() > 1) {
148 LOG(ERROR) << "We only allow an unknown size when it's a single file item";
149 status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
150 return;
151 }
152 status = contains_pending_content ? BlobStatus::PENDING : BlobStatus::DONE;
Marijn Kruisselbrink 2016/08/05 23:23:54 Currently you have whoever called BlobFlattener ch
dmurph 2016/08/19 00:18:33 Done.
153 }
154
155 BlobFlattener::~BlobFlattener() {}
156
157 BlobSlice::BlobSlice(const InternalBlobData& source,
158 uint64_t slice_offset,
159 uint64_t slice_size) {
160 const auto& source_items = source.items();
161 const auto& offsets = source.offsets();
162 LOG(ERROR) << "doing a slice at " << slice_offset << " with size "
163 << slice_size;
164 DCHECK_LE(slice_offset + slice_size, source.total_size());
165 size_t item_index =
166 std::upper_bound(offsets.begin(), offsets.end(), slice_offset) -
167 offsets.begin();
168 uint64_t item_offset =
169 item_index == 0 ? slice_offset : slice_offset - offsets[item_index - 1];
170 size_t num_items = source_items.size();
171
172 size_t first_item_index = item_index;
173 copying_memory_size = 0;
174
175 // Read starting from 'first_item_index' and 'item_offset'.
176 for (uint64_t total_sliced = 0;
177 item_index < num_items && total_sliced < slice_size; item_index++) {
178 const scoped_refptr<BlobDataItem>& source_item =
179 source_items[item_index]->item();
180 uint64_t source_length = source_item->length();
181 DCHECK_NE(source_length, std::numeric_limits<uint64_t>::max());
182 DCHECK_NE(source_length, 0ull);
183
184 uint64_t read_size =
185 std::min(source_length - item_offset, slice_size - total_sliced);
186 total_sliced += read_size;
187
188 if (read_size == source_length) {
189 // We can share the entire item.
190 LOG(ERROR) << "we can share";
191 dest_items.push_back(source_items[item_index]);
192 continue;
193 }
194
195 scoped_refptr<BlobDataItem> data_item;
196 ShareableBlobDataItem::State state =
197 ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA;
198 switch (source_item->type()) {
199 case DataElement::TYPE_BYTES_DESCRIPTION:
200 case DataElement::TYPE_BYTES: {
201 if (item_index == first_item_index) {
202 first_item_slice_offset = item_offset;
203 first_source_item = source_items[item_index];
204 } else {
205 last_source_item = source_items[item_index];
206 }
207 LOG(ERROR) << "we're slicing a bytes item!";
208 copying_memory_size += read_size;
209 // Since we don't have quota yet for memory, we create temporary items
210 // for this data. When our blob is finished constructing, all dependent
211 // blobs are done, and we have enough memory quota, we'll copy the data
212 // over.
213 std::unique_ptr<DataElement> element(new DataElement());
214 element->SetToBytesDescription(base::checked_cast<size_t>(read_size));
215 data_item = new BlobDataItem(std::move(element));
216 state = ShareableBlobDataItem::QUOTA_NEEDED;
217 break;
218 }
219 case DataElement::TYPE_FILE: {
220 std::unique_ptr<DataElement> element(new DataElement());
221 element->SetToFilePathRange(
222 source_item->path(), source_item->offset() + item_offset, read_size,
223 source_item->expected_modification_time());
224 data_item =
225 new BlobDataItem(std::move(element), source_item->data_handle_);
226
227 if (BlobDataBuilder::IsTemporaryFileItem(source_item->data_element())) {
228 // Since we don't have file path / reference for our future file, we
229 // create another file item with this temporary file name. When our
230 // blob is finished constructing, all dependent blobs are done, and we
231 // can copy the handle over.
232 LOG(ERROR) << "we're slicing a temp file item!";
233 if (item_index == first_item_index) {
234 first_item_slice_offset = item_offset;
235 first_source_item = source_items[item_index];
236 } else {
237 last_source_item = source_items[item_index];
238 }
239 state = ShareableBlobDataItem::QUOTA_NEEDED;
240 }
241 break;
242 }
243 case DataElement::TYPE_FILE_FILESYSTEM: {
244 std::unique_ptr<DataElement> element(new DataElement());
245 element->SetToFileSystemUrlRange(
246 source_item->filesystem_url(), source_item->offset() + item_offset,
247 read_size, source_item->expected_modification_time());
248 data_item = new BlobDataItem(std::move(element));
249 break;
250 }
251 case DataElement::TYPE_DISK_CACHE_ENTRY: {
252 std::unique_ptr<DataElement> element(new DataElement());
253 element->SetToDiskCacheEntryRange(source_item->offset() + item_offset,
254 read_size);
255 data_item =
256 new BlobDataItem(std::move(element), source_item->data_handle_,
257 source_item->disk_cache_entry(),
258 source_item->disk_cache_stream_index(),
259 source_item->disk_cache_side_stream_index());
260 break;
261 }
262 case DataElement::TYPE_BLOB:
263 case DataElement::TYPE_UNKNOWN:
264 CHECK(false) << "Illegal blob item type: " << source_item->type();
265 }
266 dest_items.push_back(
267 new ShareableBlobDataItem(std::move(data_item), state));
268 item_offset = 0;
269 }
270 }
271
272 BlobSlice::~BlobSlice() {}
273
274 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698