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_storage_context.cc

Issue 1234813004: [BlobAsync] Asynchronous Blob Construction Final Patch (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@blob-protocol-change
Patch Set: Comments Created 4 years, 9 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
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "storage/browser/blob/blob_storage_context.h" 5 #include "storage/browser/blob/blob_storage_context.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 #include <algorithm> 9 #include <algorithm>
10 #include <limits> 10 #include <limits>
11 #include <utility> 11 #include <utility>
12 12
13 #include "base/bind.h" 13 #include "base/bind.h"
14 #include "base/callback.h"
14 #include "base/location.h" 15 #include "base/location.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "base/memory/scoped_ptr.h" 17 #include "base/memory/scoped_ptr.h"
18 #include "base/message_loop/message_loop.h"
17 #include "base/metrics/histogram.h" 19 #include "base/metrics/histogram.h"
18 #include "base/stl_util.h"
19 #include "base/thread_task_runner_handle.h" 20 #include "base/thread_task_runner_handle.h"
20 #include "base/trace_event/trace_event.h" 21 #include "base/trace_event/trace_event.h"
21 #include "storage/browser/blob/blob_data_builder.h" 22 #include "storage/browser/blob/blob_data_builder.h"
22 #include "storage/browser/blob/shareable_file_reference.h" 23 #include "storage/browser/blob/blob_data_handle.h"
24 #include "storage/browser/blob/blob_data_item.h"
25 #include "storage/browser/blob/blob_data_snapshot.h"
26 #include "storage/browser/blob/shareable_blob_data_item.h"
23 #include "url/gurl.h" 27 #include "url/gurl.h"
24 28
25 namespace storage { 29 namespace storage {
30 using BlobRegistryEntry = BlobStorageRegistry::Entry;
31 using BlobState = BlobStorageRegistry::BlobState;
26 32
27 namespace { 33 BlobStorageContext::BlobStorageContext() : memory_usage_(0) {}
28
29 // We can't use GURL directly for these hash fragment manipulations
30 // since it doesn't have specific knowlege of the BlobURL format. GURL
31 // treats BlobURLs as if they were PathURLs which don't support hash
32 // fragments.
33
34 bool BlobUrlHasRef(const GURL& url) {
35 return url.spec().find('#') != std::string::npos;
36 }
37
38 GURL ClearBlobUrlRef(const GURL& url) {
39 size_t hash_pos = url.spec().find('#');
40 if (hash_pos == std::string::npos)
41 return url;
42 return GURL(url.spec().substr(0, hash_pos));
43 }
44
45 // TODO(michaeln): use base::SysInfo::AmountOfPhysicalMemoryMB() in some
46 // way to come up with a better limit.
47 static const int64_t kMaxMemoryUsage = 500 * 1024 * 1024; // Half a gig.
48
49 } // namespace
50
51 BlobStorageContext::BlobMapEntry::BlobMapEntry() : refcount(0), flags(0) {
52 }
53
54 BlobStorageContext::BlobMapEntry::BlobMapEntry(int refcount,
55 InternalBlobData::Builder* data)
56 : refcount(refcount), flags(0), data_builder(data) {
57 }
58
59 BlobStorageContext::BlobMapEntry::~BlobMapEntry() {
60 }
61
62 bool BlobStorageContext::BlobMapEntry::IsBeingBuilt() {
63 return !!data_builder;
64 }
65
66 BlobStorageContext::BlobStorageContext() : memory_usage_(0) {
67 }
68 34
69 BlobStorageContext::~BlobStorageContext() { 35 BlobStorageContext::~BlobStorageContext() {
70 STLDeleteContainerPairSecondPointers(blob_map_.begin(), blob_map_.end());
71 } 36 }
72 37
73 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID( 38 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID(
74 const std::string& uuid) { 39 const std::string& uuid) {
75 scoped_ptr<BlobDataHandle> result; 40 BlobRegistryEntry* entry = registry_.GetEntry(uuid);
76 BlobMap::iterator found = blob_map_.find(uuid); 41 if (!entry) {
77 if (found == blob_map_.end()) 42 return nullptr;
78 return result; 43 }
79 auto* entry = found->second; 44 return make_scoped_ptr(
80 if (entry->flags & EXCEEDED_MEMORY) 45 new BlobDataHandle(uuid, entry->content_type, entry->content_disposition,
81 return result; 46 this, base::ThreadTaskRunnerHandle::Get().get()));
82 DCHECK(!entry->IsBeingBuilt());
83 result.reset(new BlobDataHandle(uuid, entry->data->content_type(),
84 entry->data->content_disposition(), this,
85 base::ThreadTaskRunnerHandle::Get().get()));
86 return result;
87 } 47 }
88 48
89 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL( 49 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL(
90 const GURL& url) { 50 const GURL& url) {
91 BlobURLMap::iterator found = 51 std::string uuid;
92 public_blob_urls_.find(BlobUrlHasRef(url) ? ClearBlobUrlRef(url) : url); 52 BlobRegistryEntry* entry = registry_.GetEntryFromURL(url, &uuid);
93 if (found == public_blob_urls_.end()) 53 if (!entry) {
94 return scoped_ptr<BlobDataHandle>(); 54 return nullptr;
95 return GetBlobDataFromUUID(found->second); 55 }
56 return make_scoped_ptr(
57 new BlobDataHandle(uuid, entry->content_type, entry->content_disposition,
58 this, base::ThreadTaskRunnerHandle::Get().get()));
96 } 59 }
97 60
98 scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob( 61 scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob(
99 const BlobDataBuilder& external_builder) { 62 const BlobDataBuilder& external_builder) {
100 TRACE_EVENT0("Blob", "Context::AddFinishedBlob"); 63 TRACE_EVENT0("Blob", "Context::AddFinishedBlob");
101 StartBuildingBlob(external_builder.uuid_); 64 CreatePendingBlob(external_builder.uuid(), external_builder.content_type_,
102 BlobMap::iterator found = blob_map_.find(external_builder.uuid_); 65 external_builder.content_disposition_);
103 DCHECK(found != blob_map_.end()); 66 CompletePendingBlob(external_builder);
104 BlobMapEntry* entry = found->second;
105 InternalBlobData::Builder* target_blob_builder = entry->data_builder.get();
106 DCHECK(target_blob_builder);
107
108 target_blob_builder->set_content_disposition(
109 external_builder.content_disposition_);
110 for (const auto& blob_item : external_builder.items_) {
111 if (!AppendAllocatedBlobItem(external_builder.uuid_, blob_item,
112 target_blob_builder)) {
113 BlobEntryExceededMemory(entry);
114 break;
115 }
116 }
117
118 FinishBuildingBlob(external_builder.uuid_, external_builder.content_type_);
119 scoped_ptr<BlobDataHandle> handle = 67 scoped_ptr<BlobDataHandle> handle =
120 GetBlobDataFromUUID(external_builder.uuid_); 68 GetBlobDataFromUUID(external_builder.uuid_);
121 DecrementBlobRefCount(external_builder.uuid_); 69 DecrementBlobRefCount(external_builder.uuid_);
122 return handle; 70 return handle;
123 } 71 }
124 72
125 scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob( 73 scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob(
126 const BlobDataBuilder* builder) { 74 const BlobDataBuilder* builder) {
127 DCHECK(builder); 75 DCHECK(builder);
128 return AddFinishedBlob(*builder); 76 return AddFinishedBlob(*builder);
129 } 77 }
130 78
131 bool BlobStorageContext::RegisterPublicBlobURL(const GURL& blob_url, 79 bool BlobStorageContext::RegisterPublicBlobURL(const GURL& blob_url,
132 const std::string& uuid) { 80 const std::string& uuid) {
133 DCHECK(!BlobUrlHasRef(blob_url)); 81 if (!registry_.CreateUrlMapping(blob_url, uuid)) {
134 DCHECK(IsInUse(uuid));
135 DCHECK(!IsUrlRegistered(blob_url));
136 if (!IsInUse(uuid) || IsUrlRegistered(blob_url))
137 return false; 82 return false;
83 }
138 IncrementBlobRefCount(uuid); 84 IncrementBlobRefCount(uuid);
139 public_blob_urls_[blob_url] = uuid;
140 return true; 85 return true;
141 } 86 }
142 87
143 void BlobStorageContext::RevokePublicBlobURL(const GURL& blob_url) { 88 void BlobStorageContext::RevokePublicBlobURL(const GURL& blob_url) {
144 DCHECK(!BlobUrlHasRef(blob_url)); 89 std::string uuid;
145 if (!IsUrlRegistered(blob_url)) 90 if (!registry_.DeleteURLMapping(blob_url, &uuid)) {
146 return; 91 return;
147 DecrementBlobRefCount(public_blob_urls_[blob_url]); 92 }
148 public_blob_urls_.erase(blob_url); 93 DecrementBlobRefCount(uuid);
94 }
95
96 void BlobStorageContext::CreatePendingBlob(
97 const std::string& uuid,
98 const std::string& content_type,
99 const std::string& content_disposition) {
100 DCHECK(!registry_.GetEntry(uuid) && !uuid.empty());
101 registry_.CreateEntry(uuid, content_type, content_disposition);
102 }
103
104 void BlobStorageContext::CompletePendingBlob(
105 const BlobDataBuilder& external_builder) {
106 BlobRegistryEntry* entry = registry_.GetEntry(external_builder.uuid());
107 DCHECK(entry);
108 DCHECK(!entry->data.get()) << "Blob already constructed: "
109 << external_builder.uuid();
110 // We want to handle storing our broken blob as well.
111 switch (entry->state) {
112 case BlobState::PENDING: {
113 entry->data_builder.reset(new InternalBlobData::Builder());
114 InternalBlobData::Builder* internal_data_builder =
115 entry->data_builder.get();
116
117 bool broken = false;
118 for (const auto& blob_item : external_builder.items_) {
119 IPCBlobCreationCancelCode error_code;
120 if (!AppendAllocatedBlobItem(external_builder.uuid_, blob_item,
121 internal_data_builder, &error_code)) {
122 broken = true;
123 memory_usage_ -= entry->data_builder->GetNonsharedMemoryUsage();
124 entry->state = BlobState::BROKEN;
125 entry->broken_reason = error_code;
126 entry->data_builder.reset(new InternalBlobData::Builder());
127 break;
128 }
129 }
130 entry->data = entry->data_builder->Build();
131 entry->data_builder.reset();
132 entry->state = broken ? BlobState::BROKEN : BlobState::COMPLETE;
133 break;
134 }
135 case BlobState::BROKEN: {
136 InternalBlobData::Builder builder;
137 entry->data = builder.Build();
138 break;
139 }
140 case BlobState::COMPLETE:
141 DCHECK(false) << "Blob already constructed: " << external_builder.uuid();
142 return;
143 }
144
145 UMA_HISTOGRAM_COUNTS("Storage.Blob.ItemCount", entry->data->items().size());
146 UMA_HISTOGRAM_BOOLEAN("Storage.Blob.Broken",
147 entry->state == BlobState::BROKEN);
148 if (entry->state == BlobState::BROKEN) {
149 UMA_HISTOGRAM_ENUMERATION(
150 "Storage.Blob.BrokenReason", static_cast<int>(entry->broken_reason),
151 (static_cast<int>(IPCBlobCreationCancelCode::LAST) + 1));
152 }
153 size_t total_memory = 0, nonshared_memory = 0;
154 entry->data->GetMemoryUsage(&total_memory, &nonshared_memory);
155 UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalSize", total_memory / 1024);
156 UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalUnsharedSize",
157 nonshared_memory / 1024);
158 TRACE_COUNTER1("Blob", "MemoryStoreUsageBytes", memory_usage_);
159
160 auto runner = base::ThreadTaskRunnerHandle::Get();
161 for (const auto& callback : entry->build_completion_callbacks) {
162 runner->PostTask(FROM_HERE,
163 base::Bind(callback, entry->state == BlobState::COMPLETE));
164 }
165 entry->build_completion_callbacks.clear();
166 }
167
168 void BlobStorageContext::CancelPendingBlob(const std::string& uuid,
169 IPCBlobCreationCancelCode reason) {
170 BlobRegistryEntry* entry = registry_.GetEntry(uuid);
171 DCHECK(entry && entry->state == BlobState::PENDING);
172 entry->state = BlobState::BROKEN;
173 entry->broken_reason = reason;
174 CompletePendingBlob(BlobDataBuilder(uuid));
175 }
176
177 void BlobStorageContext::IncrementBlobRefCount(const std::string& uuid) {
178 BlobRegistryEntry* entry = registry_.GetEntry(uuid);
179 DCHECK(entry);
180 ++(entry->refcount);
181 }
182
183 void BlobStorageContext::DecrementBlobRefCount(const std::string& uuid) {
184 BlobRegistryEntry* entry = registry_.GetEntry(uuid);
185 DCHECK(entry);
186 DCHECK_GT(entry->refcount, 0u);
187 if (--(entry->refcount) == 0) {
188 size_t memory_freeing = 0;
189 if (entry->state == BlobState::COMPLETE) {
190 memory_freeing = entry->data->GetUnsharedMemoryUsage();
191 entry->data->RemoveBlobFromShareableItems(uuid);
192 }
193 DCHECK_LE(memory_freeing, memory_usage_);
194 memory_usage_ -= memory_freeing;
195 registry_.DeleteEntry(uuid);
196 }
149 } 197 }
150 198
151 scoped_ptr<BlobDataSnapshot> BlobStorageContext::CreateSnapshot( 199 scoped_ptr<BlobDataSnapshot> BlobStorageContext::CreateSnapshot(
152 const std::string& uuid) { 200 const std::string& uuid) {
153 scoped_ptr<BlobDataSnapshot> result; 201 scoped_ptr<BlobDataSnapshot> result;
154 auto found = blob_map_.find(uuid); 202 BlobRegistryEntry* entry = registry_.GetEntry(uuid);
155 DCHECK(found != blob_map_.end()) 203 if (entry->state != BlobState::COMPLETE) {
156 << "Blob " << uuid << " should be in map, as the handle is still around"; 204 return result;
157 BlobMapEntry* entry = found->second; 205 }
158 DCHECK(!entry->IsBeingBuilt()); 206
159 const InternalBlobData& data = *entry->data; 207 const InternalBlobData& data = *entry->data;
160
161 scoped_ptr<BlobDataSnapshot> snapshot(new BlobDataSnapshot( 208 scoped_ptr<BlobDataSnapshot> snapshot(new BlobDataSnapshot(
162 uuid, data.content_type(), data.content_disposition())); 209 uuid, entry->content_type, entry->content_disposition));
163 snapshot->items_.reserve(data.items().size()); 210 snapshot->items_.reserve(data.items().size());
164 for (const auto& shareable_item : data.items()) { 211 for (const auto& shareable_item : data.items()) {
165 snapshot->items_.push_back(shareable_item->item()); 212 snapshot->items_.push_back(shareable_item->item());
166 } 213 }
167 return snapshot; 214 return snapshot;
168 } 215 }
169 216
170 void BlobStorageContext::StartBuildingBlob(const std::string& uuid) { 217 bool BlobStorageContext::IsBroken(const std::string& uuid) const {
171 DCHECK(!IsInUse(uuid) && !uuid.empty()); 218 const BlobRegistryEntry* entry = registry_.GetEntry(uuid);
172 blob_map_[uuid] = new BlobMapEntry(1, new InternalBlobData::Builder()); 219 if (!entry) {
220 return true;
221 }
222 return entry->state == BlobState::BROKEN;
173 } 223 }
174 224
175 void BlobStorageContext::AppendBlobDataItem( 225 bool BlobStorageContext::IsBeingBuilt(const std::string& uuid) const {
176 const std::string& uuid, 226 const BlobRegistryEntry* entry = registry_.GetEntry(uuid);
177 const storage::DataElement& ipc_data_element) { 227 if (!entry) {
178 TRACE_EVENT0("Blob", "Context::AppendBlobDataItem"); 228 return false;
179 DCHECK(IsBeingBuilt(uuid));
180 BlobMap::iterator found = blob_map_.find(uuid);
181 if (found == blob_map_.end())
182 return;
183 BlobMapEntry* entry = found->second;
184 if (entry->flags & EXCEEDED_MEMORY)
185 return;
186 InternalBlobData::Builder* target_blob_builder = entry->data_builder.get();
187 DCHECK(target_blob_builder);
188
189 if (ipc_data_element.type() == DataElement::TYPE_BYTES &&
190 memory_usage_ + ipc_data_element.length() > kMaxMemoryUsage) {
191 BlobEntryExceededMemory(entry);
192 return;
193 } 229 }
194 if (!AppendAllocatedBlobItem(uuid, AllocateBlobItem(uuid, ipc_data_element), 230 return entry->state == BlobState::PENDING;
195 target_blob_builder)) {
196 BlobEntryExceededMemory(entry);
197 }
198 } 231 }
199 232
200 void BlobStorageContext::FinishBuildingBlob(const std::string& uuid, 233 void BlobStorageContext::RunOnConstructionComplete(
201 const std::string& content_type) { 234 const std::string& uuid,
202 DCHECK(IsBeingBuilt(uuid)); 235 const base::Callback<void(bool)>& done) {
203 BlobMap::iterator found = blob_map_.find(uuid); 236 BlobRegistryEntry* entry = registry_.GetEntry(uuid);
204 if (found == blob_map_.end()) 237 DCHECK(entry);
205 return; 238 switch (entry->state) {
206 BlobMapEntry* entry = found->second; 239 case BlobState::COMPLETE:
207 entry->data_builder->set_content_type(content_type); 240 done.Run(true);
208 entry->data = entry->data_builder->Build(); 241 return;
209 entry->data_builder.reset(); 242 case BlobState::BROKEN:
210 UMA_HISTOGRAM_COUNTS("Storage.Blob.ItemCount", entry->data->items().size()); 243 done.Run(false);
211 UMA_HISTOGRAM_BOOLEAN("Storage.Blob.ExceededMemory", 244 return;
212 (entry->flags & EXCEEDED_MEMORY) == EXCEEDED_MEMORY); 245 case BlobState::PENDING:
213 size_t total_memory = 0, nonshared_memory = 0; 246 entry->build_completion_callbacks.push_back(done);
214 entry->data->GetMemoryUsage(&total_memory, &nonshared_memory); 247 return;
215 UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalSize", total_memory / 1024);
216 UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalUnsharedSize",
217 nonshared_memory / 1024);
218 TRACE_COUNTER1("Blob", "MemoryStoreUsageBytes", memory_usage_);
219 }
220
221 void BlobStorageContext::CancelBuildingBlob(const std::string& uuid) {
222 DCHECK(IsBeingBuilt(uuid));
223 DecrementBlobRefCount(uuid);
224 }
225
226 void BlobStorageContext::IncrementBlobRefCount(const std::string& uuid) {
227 BlobMap::iterator found = blob_map_.find(uuid);
228 if (found == blob_map_.end()) {
229 DCHECK(false);
230 return;
231 } 248 }
232 ++(found->second->refcount); 249 NOTREACHED();
233 }
234
235 void BlobStorageContext::DecrementBlobRefCount(const std::string& uuid) {
236 BlobMap::iterator found = blob_map_.find(uuid);
237 if (found == blob_map_.end())
238 return;
239 auto* entry = found->second;
240 if (--(entry->refcount) == 0) {
241 size_t memory_freeing = 0;
242 if (entry->IsBeingBuilt()) {
243 memory_freeing = entry->data_builder->GetNonsharedMemoryUsage();
244 entry->data_builder->RemoveBlobFromShareableItems(uuid);
245 } else {
246 memory_freeing = entry->data->GetUnsharedMemoryUsage();
247 entry->data->RemoveBlobFromShareableItems(uuid);
248 }
249 DCHECK_LE(memory_freeing, memory_usage_);
250 memory_usage_ -= memory_freeing;
251 delete entry;
252 blob_map_.erase(found);
253 }
254 }
255
256 void BlobStorageContext::BlobEntryExceededMemory(BlobMapEntry* entry) {
257 // If we're using too much memory, drop this blob's data.
258 // TODO(michaeln): Blob memory storage does not yet spill over to disk,
259 // as a stop gap, we'll prevent memory usage over a max amount.
260 memory_usage_ -= entry->data_builder->GetNonsharedMemoryUsage();
261 entry->flags |= EXCEEDED_MEMORY;
262 entry->data_builder.reset(new InternalBlobData::Builder());
263 }
264
265 scoped_refptr<BlobDataItem> BlobStorageContext::AllocateBlobItem(
266 const std::string& uuid,
267 const DataElement& ipc_data) {
268 scoped_refptr<BlobDataItem> blob_item;
269
270 uint64_t length = ipc_data.length();
271 scoped_ptr<DataElement> element(new DataElement());
272 switch (ipc_data.type()) {
273 case DataElement::TYPE_BYTES:
274 DCHECK(!ipc_data.offset());
275 element->SetToBytes(ipc_data.bytes(), length);
276 blob_item = new BlobDataItem(std::move(element));
277 break;
278 case DataElement::TYPE_FILE:
279 element->SetToFilePathRange(ipc_data.path(), ipc_data.offset(), length,
280 ipc_data.expected_modification_time());
281 blob_item = new BlobDataItem(
282 std::move(element), ShareableFileReference::Get(ipc_data.path()));
283 break;
284 case DataElement::TYPE_FILE_FILESYSTEM:
285 element->SetToFileSystemUrlRange(ipc_data.filesystem_url(),
286 ipc_data.offset(), length,
287 ipc_data.expected_modification_time());
288 blob_item = new BlobDataItem(std::move(element));
289 break;
290 case DataElement::TYPE_BLOB:
291 // This is a temporary item that will be deconstructed later.
292 element->SetToBlobRange(ipc_data.blob_uuid(), ipc_data.offset(),
293 ipc_data.length());
294 blob_item = new BlobDataItem(std::move(element));
295 break;
296 case DataElement::TYPE_DISK_CACHE_ENTRY: // This type can't be sent by IPC.
297 NOTREACHED();
298 break;
299 default:
300 NOTREACHED();
301 break;
302 }
303
304 return blob_item;
305 } 250 }
306 251
307 bool BlobStorageContext::AppendAllocatedBlobItem( 252 bool BlobStorageContext::AppendAllocatedBlobItem(
308 const std::string& target_blob_uuid, 253 const std::string& target_blob_uuid,
309 scoped_refptr<BlobDataItem> blob_item, 254 scoped_refptr<BlobDataItem> blob_item,
310 InternalBlobData::Builder* target_blob_builder) { 255 InternalBlobData::Builder* target_blob_builder,
311 bool exceeded_memory = false; 256 IPCBlobCreationCancelCode* error_code) {
257 DCHECK(error_code);
258 *error_code = IPCBlobCreationCancelCode::UNKNOWN;
259 bool error = false;
312 260
313 // The blob data is stored in the canonical way which only contains a 261 // The blob data is stored in the canonical way which only contains a
314 // list of Data, File, and FileSystem items. Aggregated TYPE_BLOB items 262 // list of Data, File, and FileSystem items. Aggregated TYPE_BLOB items
315 // are expanded into the primitive constituent types and reused if possible. 263 // are expanded into the primitive constituent types and reused if possible.
316 // 1) The Data item is denoted by the raw data and length. 264 // 1) The Data item is denoted by the raw data and length.
317 // 2) The File item is denoted by the file path, the range and the expected 265 // 2) The File item is denoted by the file path, the range and the expected
318 // modification time. 266 // modification time.
319 // 3) The FileSystem File item is denoted by the FileSystem URL, the range 267 // 3) The FileSystem File item is denoted by the FileSystem URL, the range
320 // and the expected modification time. 268 // and the expected modification time.
321 // 4) The Blob item is denoted by the source blob and an offset and size. 269 // 4) The Blob item is denoted by the source blob and an offset and size.
322 // Internal items that are fully used by the new blob (not cut by the 270 // Internal items that are fully used by the new blob (not cut by the
323 // offset or size) are shared between the blobs. Otherwise, the relevant 271 // offset or size) are shared between the blobs. Otherwise, the relevant
324 // portion of the item is copied. 272 // portion of the item is copied.
325 273
274 DCHECK(blob_item->data_element_ptr());
326 const DataElement& data_element = blob_item->data_element(); 275 const DataElement& data_element = blob_item->data_element();
327 uint64_t length = data_element.length(); 276 uint64_t length = data_element.length();
328 uint64_t offset = data_element.offset(); 277 uint64_t offset = data_element.offset();
329 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeBeforeAppend", 278 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeBeforeAppend",
330 memory_usage_ / 1024); 279 memory_usage_ / 1024);
331 switch (data_element.type()) { 280 switch (data_element.type()) {
332 case DataElement::TYPE_BYTES: 281 case DataElement::TYPE_BYTES:
333 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Bytes", length / 1024); 282 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Bytes", length / 1024);
334 DCHECK(!offset); 283 DCHECK(!offset);
335 if (memory_usage_ + length > kMaxMemoryUsage) { 284 if (memory_usage_ + length > kBlobStorageMaxMemoryUsage) {
336 exceeded_memory = true; 285 error = true;
286 *error_code = IPCBlobCreationCancelCode::OUT_OF_MEMORY;
337 break; 287 break;
338 } 288 }
339 memory_usage_ += length; 289 memory_usage_ += length;
340 target_blob_builder->AppendSharedBlobItem( 290 target_blob_builder->AppendSharedBlobItem(
341 new ShareableBlobDataItem(target_blob_uuid, blob_item)); 291 new ShareableBlobDataItem(target_blob_uuid, blob_item));
342 break; 292 break;
343 case DataElement::TYPE_FILE: { 293 case DataElement::TYPE_FILE: {
344 bool full_file = (length == std::numeric_limits<uint64_t>::max()); 294 bool full_file = (length == std::numeric_limits<uint64_t>::max());
345 UMA_HISTOGRAM_BOOLEAN("Storage.BlobItemSize.File.Unknown", full_file); 295 UMA_HISTOGRAM_BOOLEAN("Storage.BlobItemSize.File.Unknown", full_file);
346 if (!full_file) { 296 if (!full_file) {
(...skipping 15 matching lines...) Expand all
362 target_blob_builder->AppendSharedBlobItem( 312 target_blob_builder->AppendSharedBlobItem(
363 new ShareableBlobDataItem(target_blob_uuid, blob_item)); 313 new ShareableBlobDataItem(target_blob_uuid, blob_item));
364 break; 314 break;
365 } 315 }
366 case DataElement::TYPE_BLOB: { 316 case DataElement::TYPE_BLOB: {
367 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Blob", 317 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Blob",
368 (length - offset) / 1024); 318 (length - offset) / 1024);
369 // We grab the handle to ensure it stays around while we copy it. 319 // We grab the handle to ensure it stays around while we copy it.
370 scoped_ptr<BlobDataHandle> src = 320 scoped_ptr<BlobDataHandle> src =
371 GetBlobDataFromUUID(data_element.blob_uuid()); 321 GetBlobDataFromUUID(data_element.blob_uuid());
372 if (src) { 322 if (!src || src->IsBroken() || src->IsBeingBuilt()) {
373 BlobMapEntry* other_entry = 323 error = true;
374 blob_map_.find(data_element.blob_uuid())->second; 324 *error_code = IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN;
375 DCHECK(other_entry->data); 325 break;
376 exceeded_memory = !AppendBlob(target_blob_uuid, *other_entry->data, 326 }
377 offset, length, target_blob_builder); 327 BlobRegistryEntry* other_entry =
328 registry_.GetEntry(data_element.blob_uuid());
329 DCHECK(other_entry->data);
330 if (!AppendBlob(target_blob_uuid, *other_entry->data, offset, length,
331 target_blob_builder)) {
332 error = true;
333 *error_code = IPCBlobCreationCancelCode::OUT_OF_MEMORY;
378 } 334 }
379 break; 335 break;
380 } 336 }
381 case DataElement::TYPE_DISK_CACHE_ENTRY: { 337 case DataElement::TYPE_DISK_CACHE_ENTRY: {
382 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.CacheEntry", 338 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.CacheEntry",
383 (length - offset) / 1024); 339 (length - offset) / 1024);
384 target_blob_builder->AppendSharedBlobItem( 340 target_blob_builder->AppendSharedBlobItem(
385 new ShareableBlobDataItem(target_blob_uuid, blob_item)); 341 new ShareableBlobDataItem(target_blob_uuid, blob_item));
386 break; 342 break;
387 } 343 }
388 default: 344 case DataElement::TYPE_BYTES_DESCRIPTION:
345 case DataElement::TYPE_UNKNOWN:
389 NOTREACHED(); 346 NOTREACHED();
390 break; 347 break;
391 } 348 }
392 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeAfterAppend", 349 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeAfterAppend",
393 memory_usage_ / 1024); 350 memory_usage_ / 1024);
394 351 return !error;
395 return !exceeded_memory;
396 } 352 }
397 353
398 bool BlobStorageContext::AppendBlob( 354 bool BlobStorageContext::AppendBlob(
399 const std::string& target_blob_uuid, 355 const std::string& target_blob_uuid,
400 const InternalBlobData& blob, 356 const InternalBlobData& blob,
401 uint64_t offset, 357 uint64_t offset,
402 uint64_t length, 358 uint64_t length,
403 InternalBlobData::Builder* target_blob_builder) { 359 InternalBlobData::Builder* target_blob_builder) {
404 DCHECK(length > 0); 360 DCHECK_GT(length, 0ull);
405 361
406 const std::vector<scoped_refptr<ShareableBlobDataItem>>& items = blob.items(); 362 const std::vector<scoped_refptr<ShareableBlobDataItem>>& items = blob.items();
407 auto iter = items.begin(); 363 auto iter = items.begin();
408 if (offset) { 364 if (offset) {
409 for (; iter != items.end(); ++iter) { 365 for (; iter != items.end(); ++iter) {
410 const BlobDataItem& item = *(iter->get()->item()); 366 const BlobDataItem& item = *(iter->get()->item());
411 if (offset >= item.length()) 367 if (offset >= item.length())
412 offset -= item.length(); 368 offset -= item.length();
413 else 369 else
414 break; 370 break;
(...skipping 16 matching lines...) Expand all
431 length -= new_length; 387 length -= new_length;
432 continue; 388 continue;
433 } 389 }
434 390
435 // We need to do copying of the items when we have a different offset or 391 // We need to do copying of the items when we have a different offset or
436 // length 392 // length
437 switch (item.type()) { 393 switch (item.type()) {
438 case DataElement::TYPE_BYTES: { 394 case DataElement::TYPE_BYTES: {
439 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.Bytes", 395 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.Bytes",
440 new_length / 1024); 396 new_length / 1024);
441 if (memory_usage_ + new_length > kMaxMemoryUsage) { 397 if (memory_usage_ + new_length > kBlobStorageMaxMemoryUsage) {
442 return false; 398 return false;
443 } 399 }
444 DCHECK(!item.offset()); 400 DCHECK(!item.offset());
445 scoped_ptr<DataElement> element(new DataElement()); 401 scoped_ptr<DataElement> element(new DataElement());
446 element->SetToBytes(item.bytes() + offset, 402 element->SetToBytes(item.bytes() + offset,
447 static_cast<int64_t>(new_length)); 403 static_cast<int64_t>(new_length));
448 memory_usage_ += new_length; 404 memory_usage_ += new_length;
449 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( 405 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem(
450 target_blob_uuid, new BlobDataItem(std::move(element)))); 406 target_blob_uuid, new BlobDataItem(std::move(element))));
451 } break; 407 } break;
(...skipping 23 matching lines...) Expand all
475 case DataElement::TYPE_DISK_CACHE_ENTRY: { 431 case DataElement::TYPE_DISK_CACHE_ENTRY: {
476 scoped_ptr<DataElement> element(new DataElement()); 432 scoped_ptr<DataElement> element(new DataElement());
477 element->SetToDiskCacheEntryRange(item.offset() + offset, 433 element->SetToDiskCacheEntryRange(item.offset() + offset,
478 new_length); 434 new_length);
479 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( 435 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem(
480 target_blob_uuid, 436 target_blob_uuid,
481 new BlobDataItem(std::move(element), item.data_handle_, 437 new BlobDataItem(std::move(element), item.data_handle_,
482 item.disk_cache_entry(), 438 item.disk_cache_entry(),
483 item.disk_cache_stream_index()))); 439 item.disk_cache_stream_index())));
484 } break; 440 } break;
485 default: 441 case DataElement::TYPE_BYTES_DESCRIPTION:
442 case DataElement::TYPE_BLOB:
443 case DataElement::TYPE_UNKNOWN:
486 CHECK(false) << "Illegal blob item type: " << item.type(); 444 CHECK(false) << "Illegal blob item type: " << item.type();
487 } 445 }
488 length -= new_length; 446 length -= new_length;
489 offset = 0; 447 offset = 0;
490 } 448 }
491 return true; 449 return true;
492 } 450 }
493 451
494 bool BlobStorageContext::IsInUse(const std::string& uuid) {
495 return blob_map_.find(uuid) != blob_map_.end();
496 }
497
498 bool BlobStorageContext::IsBeingBuilt(const std::string& uuid) {
499 BlobMap::iterator found = blob_map_.find(uuid);
500 if (found == blob_map_.end())
501 return false;
502 return found->second->IsBeingBuilt();
503 }
504
505 bool BlobStorageContext::IsUrlRegistered(const GURL& blob_url) {
506 return public_blob_urls_.find(blob_url) != public_blob_urls_.end();
507 }
508
509 } // namespace storage 452 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698