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

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

Issue 895933007: [Storage] Blob items are now shared between blobs. Ready for disk swap. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 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 <algorithm>
8
7 #include "base/bind.h" 9 #include "base/bind.h"
8 #include "base/location.h" 10 #include "base/location.h"
9 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop_proxy.h" 13 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
12 #include "base/stl_util.h" 15 #include "base/stl_util.h"
13 #include "storage/browser/blob/blob_data_builder.h" 16 #include "storage/browser/blob/blob_data_builder.h"
17 #include "storage/browser/blob/blob_data_handle.h"
14 #include "url/gurl.h" 18 #include "url/gurl.h"
15 19
16 namespace storage { 20 namespace storage {
17 21
18 namespace { 22 namespace {
19 23
20 // We can't use GURL directly for these hash fragment manipulations 24 // We can't use GURL directly for these hash fragment manipulations
21 // since it doesn't have specific knowlege of the BlobURL format. GURL 25 // since it doesn't have specific knowlege of the BlobURL format. GURL
22 // treats BlobURLs as if they were PathURLs which don't support hash 26 // treats BlobURLs as if they were PathURLs which don't support hash
23 // fragments. 27 // fragments.
24 28
25 bool BlobUrlHasRef(const GURL& url) { 29 bool BlobUrlHasRef(const GURL& url) {
26 return url.spec().find('#') != std::string::npos; 30 return url.spec().find('#') != std::string::npos;
27 } 31 }
28 32
29 GURL ClearBlobUrlRef(const GURL& url) { 33 GURL ClearBlobUrlRef(const GURL& url) {
30 size_t hash_pos = url.spec().find('#'); 34 size_t hash_pos = url.spec().find('#');
31 if (hash_pos == std::string::npos) 35 if (hash_pos == std::string::npos)
32 return url; 36 return url;
33 return GURL(url.spec().substr(0, hash_pos)); 37 return GURL(url.spec().substr(0, hash_pos));
34 } 38 }
35 39
36 // TODO(michaeln): use base::SysInfo::AmountOfPhysicalMemoryMB() in some 40 // TODO(michaeln): use base::SysInfo::AmountOfPhysicalMemoryMB() in some
37 // way to come up with a better limit. 41 // way to come up with a better limit.
38 static const int64 kMaxMemoryUsage = 500 * 1024 * 1024; // Half a gig. 42 static const int64 kMaxMemoryUsage = 500 * 1024 * 1024; // Half a gig.
39 43
40 } // namespace 44 } // namespace
41 45
42 BlobStorageContext::BlobMapEntry::BlobMapEntry() 46 BlobStorageContext::BlobMapEntry::BlobMapEntry() : refcount(0), flags(0) {
43 : refcount(0), flags(0) {
44 } 47 }
45 48
46 BlobStorageContext::BlobMapEntry::BlobMapEntry(int refcount, 49 BlobStorageContext::BlobMapEntry::BlobMapEntry(int refcount,
47 BlobDataBuilder* data) 50 InternalBlobData::Builder* data)
48 : refcount(refcount), flags(0), data_builder(data) { 51 : refcount(refcount), flags(0), data_builder(data) {
49 } 52 }
50 53
51 BlobStorageContext::BlobMapEntry::~BlobMapEntry() { 54 BlobStorageContext::BlobMapEntry::~BlobMapEntry() {
52 } 55 }
53 56
54 bool BlobStorageContext::BlobMapEntry::IsBeingBuilt() { 57 bool BlobStorageContext::BlobMapEntry::IsBeingBuilt() {
55 return data_builder; 58 return data_builder;
56 } 59 }
57 60
58 BlobStorageContext::BlobStorageContext() 61 BlobStorageContext::BlobStorageContext() : memory_usage_(0) {
59 : memory_usage_(0) {
60 } 62 }
61 63
62 BlobStorageContext::~BlobStorageContext() { 64 BlobStorageContext::~BlobStorageContext() {
63 STLDeleteContainerPairSecondPointers(blob_map_.begin(), blob_map_.end()); 65 STLDeleteContainerPairSecondPointers(blob_map_.begin(), blob_map_.end());
64 } 66 }
65 67
66 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID( 68 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID(
67 const std::string& uuid) { 69 const std::string& uuid) {
68 scoped_ptr<BlobDataHandle> result; 70 scoped_ptr<BlobDataHandle> result;
69 BlobMap::iterator found = blob_map_.find(uuid); 71 BlobMap::iterator found = blob_map_.find(uuid);
70 if (found == blob_map_.end()) 72 if (found == blob_map_.end())
71 return result.Pass(); 73 return result.Pass();
72 auto* entry = found->second; 74 auto* entry = found->second;
73 if (entry->flags & EXCEEDED_MEMORY) 75 if (entry->flags & EXCEEDED_MEMORY)
74 return result.Pass(); 76 return result.Pass();
75 DCHECK(!entry->IsBeingBuilt()); 77 DCHECK(!entry->IsBeingBuilt());
76 result.reset( 78 result.reset(
77 new BlobDataHandle(uuid, this, base::MessageLoopProxy::current().get())); 79 new BlobDataHandle(uuid, this, base::MessageLoopProxy::current().get()));
78 return result.Pass(); 80 return result.Pass();
79 } 81 }
80 82
81 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL( 83 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL(
82 const GURL& url) { 84 const GURL& url) {
83 BlobURLMap::iterator found = public_blob_urls_.find( 85 BlobURLMap::iterator found =
84 BlobUrlHasRef(url) ? ClearBlobUrlRef(url) : url); 86 public_blob_urls_.find(BlobUrlHasRef(url) ? ClearBlobUrlRef(url) : url);
85 if (found == public_blob_urls_.end()) 87 if (found == public_blob_urls_.end())
86 return scoped_ptr<BlobDataHandle>(); 88 return scoped_ptr<BlobDataHandle>();
87 return GetBlobDataFromUUID(found->second); 89 return GetBlobDataFromUUID(found->second);
88 } 90 }
89 91
90 scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob( 92 scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob(
91 const BlobDataBuilder& data) { 93 BlobDataBuilder* builder) {
92 StartBuildingBlob(data.uuid_); 94 StartBuildingBlob(builder->uuid_);
93 for (const auto& blob_item : data.items_) 95 BlobMap::iterator found = blob_map_.find(builder->uuid_);
94 AppendBlobDataItem(data.uuid_, *(blob_item->item_)); 96 DCHECK(found != blob_map_.end());
95 FinishBuildingBlob(data.uuid_, data.content_type_); 97 BlobMapEntry* entry = found->second;
96 scoped_ptr<BlobDataHandle> handle = GetBlobDataFromUUID(data.uuid_); 98 InternalBlobData::Builder* target_blob_builder = entry->data_builder.get();
97 DecrementBlobRefCount(data.uuid_); 99 DCHECK(target_blob_builder);
100
101 for (const auto& blob_item : builder->items_) {
102 if (entry->flags & EXCEEDED_MEMORY)
michaeln 2015/02/05 22:58:47 not sure this test is needed since StartBuildingBl
dmurph 2015/02/06 01:32:30 True, removed.
103 break;
104 if (!AppendAllocatedBlobItem(builder->uuid_, target_blob_builder,
105 blob_item)) {
106 BlobEntryExceededMemory(entry);
107 break;
108 }
109 }
110
111 FinishBuildingBlob(builder->uuid_, builder->content_type_);
112 scoped_ptr<BlobDataHandle> handle = GetBlobDataFromUUID(builder->uuid_);
113 DecrementBlobRefCount(builder->uuid_);
98 return handle.Pass(); 114 return handle.Pass();
99 } 115 }
100 116
101 bool BlobStorageContext::RegisterPublicBlobURL( 117 bool BlobStorageContext::RegisterPublicBlobURL(const GURL& blob_url,
102 const GURL& blob_url, const std::string& uuid) { 118 const std::string& uuid) {
103 DCHECK(!BlobUrlHasRef(blob_url)); 119 DCHECK(!BlobUrlHasRef(blob_url));
104 DCHECK(IsInUse(uuid)); 120 DCHECK(IsInUse(uuid));
105 DCHECK(!IsUrlRegistered(blob_url)); 121 DCHECK(!IsUrlRegistered(blob_url));
106 if (!IsInUse(uuid) || IsUrlRegistered(blob_url)) 122 if (!IsInUse(uuid) || IsUrlRegistered(blob_url))
107 return false; 123 return false;
108 IncrementBlobRefCount(uuid); 124 IncrementBlobRefCount(uuid);
109 public_blob_urls_[blob_url] = uuid; 125 public_blob_urls_[blob_url] = uuid;
110 return true; 126 return true;
111 } 127 }
112 128
113 void BlobStorageContext::RevokePublicBlobURL(const GURL& blob_url) { 129 void BlobStorageContext::RevokePublicBlobURL(const GURL& blob_url) {
114 DCHECK(!BlobUrlHasRef(blob_url)); 130 DCHECK(!BlobUrlHasRef(blob_url));
115 if (!IsUrlRegistered(blob_url)) 131 if (!IsUrlRegistered(blob_url))
116 return; 132 return;
117 DecrementBlobRefCount(public_blob_urls_[blob_url]); 133 DecrementBlobRefCount(public_blob_urls_[blob_url]);
118 public_blob_urls_.erase(blob_url); 134 public_blob_urls_.erase(blob_url);
119 } 135 }
120 136
121 scoped_ptr<BlobDataSnapshot> BlobStorageContext::CreateSnapshot( 137 scoped_ptr<BlobDataSnapshot> BlobStorageContext::CreateSnapshot(
122 const std::string& uuid) { 138 const std::string& uuid) {
123 scoped_ptr<BlobDataSnapshot> result; 139 scoped_ptr<BlobDataSnapshot> result;
124 auto found = blob_map_.find(uuid); 140 auto found = blob_map_.find(uuid);
125 DCHECK(found != blob_map_.end()) 141 DCHECK(found != blob_map_.end())
126 << "Blob should be in map, as the handle is still around"; 142 << "Blob " << uuid << " should be in map, as the handle is still around";
127 BlobMapEntry* entry = found->second; 143 BlobMapEntry* entry = found->second;
128 DCHECK(!entry->IsBeingBuilt()); 144 DCHECK(!entry->IsBeingBuilt());
129 result.reset(new BlobDataSnapshot(*entry->data)); 145 const InternalBlobData& data = *entry->data;
130 return result.Pass(); 146 return CreateSnapshot(uuid, data);
131 } 147 }
132 148
133 void BlobStorageContext::StartBuildingBlob(const std::string& uuid) { 149 void BlobStorageContext::StartBuildingBlob(const std::string& uuid) {
134 DCHECK(!IsInUse(uuid) && !uuid.empty()); 150 DCHECK(!IsInUse(uuid) && !uuid.empty());
135 blob_map_[uuid] = new BlobMapEntry(1, new BlobDataBuilder(uuid)); 151 blob_map_[uuid] = new BlobMapEntry(1, new InternalBlobData::Builder());
136 } 152 }
137 153
138 void BlobStorageContext::AppendBlobDataItem(const std::string& uuid, 154 void BlobStorageContext::AppendBlobDataItem(
139 const DataElement& item) { 155 const std::string& uuid,
156 const storage::DataElement& data_element) {
140 DCHECK(IsBeingBuilt(uuid)); 157 DCHECK(IsBeingBuilt(uuid));
141 BlobMap::iterator found = blob_map_.find(uuid); 158 BlobMap::iterator found = blob_map_.find(uuid);
142 if (found == blob_map_.end()) 159 if (found == blob_map_.end())
143 return; 160 return;
144 BlobMapEntry* entry = found->second; 161 BlobMapEntry* entry = found->second;
145 if (entry->flags & EXCEEDED_MEMORY) 162 if (entry->flags & EXCEEDED_MEMORY)
146 return; 163 return;
147 BlobDataBuilder* target_blob_data = entry->data_builder.get(); 164 InternalBlobData::Builder* target_blob_builder = entry->data_builder.get();
148 DCHECK(target_blob_data); 165 DCHECK(target_blob_builder);
149 166
150 bool exceeded_memory = false; 167 if (!CanFitDataElement(data_element)) {
michaeln 2015/02/05 22:58:47 it might make sense to hoist the one line body of
dmurph 2015/02/06 01:32:30 Done.
151 168 BlobEntryExceededMemory(entry);
152 // The blob data is stored in the canonical way which only contains a 169 return;
153 // list of Data, File, and FileSystem items. Aggregated TYPE_BLOB items
154 // are expanded into the primitive constituent types.
155 // 1) The Data item is denoted by the raw data and length.
156 // 2) The File item is denoted by the file path, the range and the expected
157 // modification time.
158 // 3) The FileSystem File item is denoted by the FileSystem URL, the range
159 // and the expected modification time.
160 // 4) The Blob items are expanded.
161 // TODO(michaeln): Would be nice to avoid copying Data items when expanding.
162
163 uint64 length = item.length();
164 DCHECK_GT(length, 0u);
165 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeBeforeAppend",
166 memory_usage_ / 1024);
167 switch (item.type()) {
168 case DataElement::TYPE_BYTES:
169 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Bytes", length / 1024);
170 DCHECK(!item.offset());
171 exceeded_memory = !AppendBytesItem(target_blob_data, item.bytes(),
172 static_cast<int64>(length));
173 break;
174 case DataElement::TYPE_FILE:
175 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.File", length / 1024);
176 AppendFileItem(target_blob_data, item.path(), item.offset(),
177 item.length(), item.expected_modification_time());
178 break;
179 case DataElement::TYPE_FILE_FILESYSTEM:
180 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.FileSystem", length / 1024);
181 AppendFileSystemFileItem(target_blob_data, item.filesystem_url(),
182 item.offset(), item.length(),
183 item.expected_modification_time());
184 break;
185 case DataElement::TYPE_BLOB: {
186 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Blob", length / 1024);
187 // We grab the handle to ensure it stays around while we copy it.
188 scoped_ptr<BlobDataHandle> src = GetBlobDataFromUUID(item.blob_uuid());
189 if (src) {
190 BlobMapEntry* entry = blob_map_.find(item.blob_uuid())->second;
191 DCHECK(entry->data);
192 exceeded_memory = !ExpandStorageItems(target_blob_data, *entry->data,
193 item.offset(), item.length());
194 }
195 break;
196 }
197 default:
198 NOTREACHED();
199 break;
200 } 170 }
201 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeAfterAppend", 171 scoped_refptr<BlobDataItem> data_item =
202 memory_usage_ / 1024); 172 TransformDataElement(uuid, data_element);
michaeln 2015/02/05 22:58:47 maybe rename this method to AllocateBlobItem(id, e
dmurph 2015/02/06 01:32:30 Done.
203 173 if (!AppendAllocatedBlobItem(uuid, target_blob_builder, data_item)) {
204 // If we're using too much memory, drop this blob's data. 174 BlobEntryExceededMemory(entry);
205 // TODO(michaeln): Blob memory storage does not yet spill over to disk,
206 // as a stop gap, we'll prevent memory usage over a max amount.
207 if (exceeded_memory) {
208 memory_usage_ -= target_blob_data->GetMemoryUsage();
209 entry->flags |= EXCEEDED_MEMORY;
210 entry->data_builder.reset(new BlobDataBuilder(uuid));
211 return;
212 } 175 }
213 } 176 }
214 177
215 void BlobStorageContext::FinishBuildingBlob( 178 void BlobStorageContext::FinishBuildingBlob(const std::string& uuid,
216 const std::string& uuid, const std::string& content_type) { 179 const std::string& content_type) {
217 DCHECK(IsBeingBuilt(uuid)); 180 DCHECK(IsBeingBuilt(uuid));
218 BlobMap::iterator found = blob_map_.find(uuid); 181 BlobMap::iterator found = blob_map_.find(uuid);
219 if (found == blob_map_.end()) 182 if (found == blob_map_.end())
220 return; 183 return;
221 BlobMapEntry* entry = found->second; 184 BlobMapEntry* entry = found->second;
222 entry->data_builder->set_content_type(content_type); 185 entry->data_builder->set_content_type(content_type);
223 entry->data = entry->data_builder->BuildSnapshot().Pass(); 186 scoped_ptr<InternalBlobData::Builder> builder(entry->data_builder.release());
224 entry->data_builder.reset(); 187 entry->data.reset(new InternalBlobData(builder.Pass()));
225 UMA_HISTOGRAM_COUNTS("Storage.Blob.ItemCount", entry->data->items().size()); 188 UMA_HISTOGRAM_COUNTS("Storage.Blob.ItemCount", entry->data->items().size());
226 UMA_HISTOGRAM_BOOLEAN("Storage.Blob.ExceededMemory", 189 UMA_HISTOGRAM_BOOLEAN("Storage.Blob.ExceededMemory",
227 (entry->flags & EXCEEDED_MEMORY) == EXCEEDED_MEMORY); 190 (entry->flags & EXCEEDED_MEMORY) == EXCEEDED_MEMORY);
228 } 191 }
229 192
230 void BlobStorageContext::CancelBuildingBlob(const std::string& uuid) { 193 void BlobStorageContext::CancelBuildingBlob(const std::string& uuid) {
231 DCHECK(IsBeingBuilt(uuid)); 194 DCHECK(IsBeingBuilt(uuid));
232 DecrementBlobRefCount(uuid); 195 DecrementBlobRefCount(uuid);
233 } 196 }
234 197
235 void BlobStorageContext::IncrementBlobRefCount(const std::string& uuid) { 198 void BlobStorageContext::IncrementBlobRefCount(const std::string& uuid) {
236 BlobMap::iterator found = blob_map_.find(uuid); 199 BlobMap::iterator found = blob_map_.find(uuid);
237 if (found == blob_map_.end()) { 200 if (found == blob_map_.end()) {
238 DCHECK(false); 201 DCHECK(false);
239 return; 202 return;
240 } 203 }
241 ++(found->second->refcount); 204 ++(found->second->refcount);
242 } 205 }
243 206
244 void BlobStorageContext::DecrementBlobRefCount(const std::string& uuid) { 207 void BlobStorageContext::DecrementBlobRefCount(const std::string& uuid) {
245 BlobMap::iterator found = blob_map_.find(uuid); 208 BlobMap::iterator found = blob_map_.find(uuid);
246 if (found == blob_map_.end()) 209 if (found == blob_map_.end())
247 return; 210 return;
248 auto* entry = found->second; 211 auto* entry = found->second;
249 if (--(entry->refcount) == 0) { 212 if (--(entry->refcount) == 0) {
213 size_t memory_freeing = 0;
250 if (entry->IsBeingBuilt()) { 214 if (entry->IsBeingBuilt()) {
251 memory_usage_ -= entry->data_builder->GetMemoryUsage(); 215 memory_freeing = entry->data_builder->GetNonsharedMemoryUsage();
216 entry->data_builder->RemoveBlobFromShareableItems(uuid);
252 } else { 217 } else {
253 memory_usage_ -= entry->data->GetMemoryUsage(); 218 memory_freeing = entry->data->GetNonsharedMemoryUsage();
219 entry->data->RemoveBlobFromShareableItems(uuid);
254 } 220 }
221 DCHECK_LE(memory_freeing, memory_usage_);
222 memory_usage_ -= memory_freeing;
255 delete entry; 223 delete entry;
256 blob_map_.erase(found); 224 blob_map_.erase(found);
257 } 225 }
258 } 226 }
259 227
260 bool BlobStorageContext::ExpandStorageItems( 228 bool BlobStorageContext::CanFitDataElement(const DataElement& item) {
261 BlobDataBuilder* target_blob_data, 229 return item.type() == DataElement::TYPE_BYTES &&
262 const BlobDataSnapshot& src_blob_data, 230 memory_usage_ + item.length() <= kMaxMemoryUsage;
263 uint64 offset, 231 }
264 uint64 length) {
265 DCHECK(target_blob_data && length != static_cast<uint64>(-1));
266 232
267 const std::vector<scoped_refptr<BlobDataItem>>& items = src_blob_data.items(); 233 void BlobStorageContext::BlobEntryExceededMemory(BlobMapEntry* entry) {
234 // If we're using too much memory, drop this blob's data.
235 // TODO(michaeln): Blob memory storage does not yet spill over to disk,
236 // as a stop gap, we'll prevent memory usage over a max amount.
237 memory_usage_ -= entry->data_builder->GetNonsharedMemoryUsage();
238 entry->flags |= EXCEEDED_MEMORY;
239 entry->data_builder.reset(new InternalBlobData::Builder());
240 }
241
242 scoped_refptr<BlobDataItem> BlobStorageContext::TransformDataElement(
243 const std::string& uuid,
244 const DataElement& item) {
245 scoped_refptr<BlobDataItem> blob_item;
246
247 size_t length = item.length();
248 DCHECK_GT(length, 0u);
249 scoped_ptr<DataElement> element(new DataElement());
250 switch (item.type()) {
251 case DataElement::TYPE_BYTES:
252 DCHECK(!item.offset());
253 element->SetToBytes(item.bytes(), length);
254 blob_item = new BlobDataItem(element.Pass());
255 break;
256 case DataElement::TYPE_FILE:
257 element->SetToFilePathRange(item.path(), item.offset(), length,
258 item.expected_modification_time());
259 blob_item = new BlobDataItem(element.Pass(),
260 ShareableFileReference::Get(item.path()));
261 break;
262 case DataElement::TYPE_FILE_FILESYSTEM:
263 element->SetToFileSystemUrlRange(item.filesystem_url(), item.offset(),
264 length,
265 item.expected_modification_time());
266 blob_item = new BlobDataItem(element.Pass());
267 break;
268 case DataElement::TYPE_BLOB:
269 // This is a temporary item that will be deconstructed later.
270 element->SetToBlobRange(item.blob_uuid(), item.offset(), item.length());
271 blob_item = new BlobDataItem(element.Pass());
272 break;
273 default:
274 NOTREACHED();
275 break;
276 }
277
278 return blob_item;
279 }
280
281 bool BlobStorageContext::AppendAllocatedBlobItem(
282 const std::string& target_blob_uuid,
283 InternalBlobData::Builder* target_blob_builder,
284 scoped_refptr<BlobDataItem> blob_item) {
285 bool exceeded_memory = false;
286
287 // The blob data is stored in the canonical way which only contains a
288 // list of Data, File, and FileSystem items. Aggregated TYPE_BLOB items
289 // are expanded into the primitive constituent types.
290 // 1) The Data item is denoted by the raw data and length.
291 // 2) The File item is denoted by the file path, the range and the expected
292 // modification time.
293 // 3) The FileSystem File item is denoted by the FileSystem URL, the range
294 // and the expected modification time.
295 // 4) The Blob items are expanded.
296
297 const DataElement& data_element = blob_item->data_element();
298 size_t length = data_element.length();
299 size_t offset = data_element.offset();
michaeln 2015/02/05 22:58:47 these can be len/offsets into files so int64 as th
dmurph 2015/02/06 01:32:30 Done
300 DCHECK_GT(length, 0u);
301 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeBeforeAppend",
302 memory_usage_ / 1024);
303 switch (data_element.type()) {
304 case DataElement::TYPE_BYTES:
305 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Bytes", length / 1024);
306 DCHECK(!offset);
307 if (memory_usage_ + length > kMaxMemoryUsage) {
308 exceeded_memory = true;
309 break;
310 }
311 memory_usage_ += length;
312 target_blob_builder->AppendSharedBlobItem(
313 new ShareableBlobDataItem(target_blob_uuid, blob_item));
314 break;
315 case DataElement::TYPE_FILE:
316 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.File",
317 (length - offset) / 1024);
318 target_blob_builder->AppendSharedBlobItem(
319 new ShareableBlobDataItem(target_blob_uuid, blob_item));
320 break;
321 case DataElement::TYPE_FILE_FILESYSTEM:
322 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.FileSystem",
323 (length - offset) / 1024);
324 target_blob_builder->AppendSharedBlobItem(
325 new ShareableBlobDataItem(target_blob_uuid, blob_item));
326 break;
327 case DataElement::TYPE_BLOB: {
328 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Blob",
329 (length - offset) / 1024);
330 // We grab the handle to ensure it stays around while we copy it.
331 scoped_ptr<BlobDataHandle> src =
332 GetBlobDataFromUUID(data_element.blob_uuid());
333 if (src) {
334 BlobMapEntry* other_entry =
335 blob_map_.find(data_element.blob_uuid())->second;
336 DCHECK(other_entry->data);
337 exceeded_memory = !AppendBlob(target_blob_uuid, target_blob_builder,
338 *other_entry->data, offset, length);
339 }
340 break;
341 }
342 default:
343 NOTREACHED();
344 break;
345 }
346 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeAfterAppend",
347 memory_usage_ / 1024);
348
349 return !exceeded_memory;
350 }
351
352 bool BlobStorageContext::AppendBlob(
353 const std::string& target_blob_uuid,
354 InternalBlobData::Builder* target_blob_builder,
355 const InternalBlobData& blob,
356 size_t offset,
357 size_t length) {
358 DCHECK(length > 0);
359
360 const std::vector<scoped_refptr<ShareableBlobDataItem>>& items = blob.items();
268 auto iter = items.begin(); 361 auto iter = items.begin();
269 if (offset) { 362 if (offset) {
270 for (; iter != items.end(); ++iter) { 363 for (; iter != items.end(); ++iter) {
271 const BlobDataItem& item = *(iter->get()); 364 const BlobDataItem& item = *(iter->get()->item());
272 if (offset >= item.length()) 365 if (offset >= item.length())
273 offset -= item.length(); 366 offset -= item.length();
274 else 367 else
275 break; 368 break;
276 } 369 }
277 } 370 }
278 371
279 for (; iter != items.end() && length > 0; ++iter) { 372 for (; iter != items.end() && length > 0; ++iter) {
280 const BlobDataItem& item = *(iter->get()); 373 scoped_refptr<ShareableBlobDataItem> shareable_item = iter->get();
281 uint64 current_length = item.length() - offset; 374 const BlobDataItem& item = *(shareable_item->item());
282 uint64 new_length = current_length > length ? length : current_length; 375 size_t item_length = item.length();
283 if (iter->get()->type() == DataElement::TYPE_BYTES) { 376 DCHECK_GT(item_length, offset);
284 if (!AppendBytesItem( 377 size_t current_length = item.length() - offset;
285 target_blob_data, 378 size_t new_length = current_length > length ? length : current_length;
286 item.bytes() + static_cast<size_t>(item.offset() + offset), 379
287 static_cast<int64>(new_length))) { 380 bool reusing_blob_item = offset == 0 && new_length == item.length();
288 return false; // exceeded memory 381 UMA_HISTOGRAM_BOOLEAN("Storage.Blob.ReusedItem", reusing_blob_item);
289 } 382 if (reusing_blob_item) {
michaeln 2015/02/05 20:02:09 woohooo!
dmurph 2015/02/06 01:32:30 :)
290 } else if (item.type() == DataElement::TYPE_FILE) { 383 shareable_item->referencing_blobs().insert(target_blob_uuid);
291 AppendFileItem(target_blob_data, item.path(), item.offset() + offset, 384 target_blob_builder->AppendSharedBlobItem(shareable_item);
292 new_length, item.expected_modification_time()); 385 length -= new_length;
293 } else { 386 continue;
294 DCHECK(item.type() == DataElement::TYPE_FILE_FILESYSTEM); 387 }
295 AppendFileSystemFileItem(target_blob_data, item.filesystem_url(), 388
296 item.offset() + offset, new_length, 389 // We need to do copying of the items when we have a different offset or
297 item.expected_modification_time()); 390 // length
391 switch (item.type()) {
392 case DataElement::TYPE_BYTES: {
393 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Blob.Bytes",
394 new_length / 1024);
395 if (memory_usage_ + new_length > kMaxMemoryUsage) {
396 return false;
397 }
398 DCHECK(!item.offset());
399 scoped_ptr<DataElement> element(new DataElement());
400 element->SetToBytes(item.bytes() + offset,
401 static_cast<int64>(new_length));
402 memory_usage_ += new_length;
403 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem(
404 target_blob_uuid, new BlobDataItem(element.Pass())));
405 } break;
406 case DataElement::TYPE_FILE: {
407 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Blob.File",
408 new_length / 1024);
409 scoped_ptr<DataElement> element(new DataElement());
410 element->SetToFilePathRange(item.path(), item.offset() + offset,
411 new_length,
412 item.expected_modification_time());
413 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem(
414 target_blob_uuid,
415 new BlobDataItem(element.Pass(), item.file_handle_)));
416 } break;
417 case DataElement::TYPE_FILE_FILESYSTEM: {
418 UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Blob.FileSystem",
419 new_length / 1024);
420 scoped_ptr<DataElement> element(new DataElement());
421 element->SetToFileSystemUrlRange(item.filesystem_url(),
422 item.offset() + offset, new_length,
423 item.expected_modification_time());
424 target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem(
425 target_blob_uuid, new BlobDataItem(element.Pass())));
426 } break;
427 default:
428 CHECK(false) << "Illegal blob item type: " << item.type();
298 } 429 }
299 length -= new_length; 430 length -= new_length;
300 offset = 0; 431 offset = 0;
301 } 432 }
302 return true; 433 return true;
303 } 434 }
304 435
305 bool BlobStorageContext::AppendBytesItem(BlobDataBuilder* target_blob_data,
306 const char* bytes,
307 int64 length) {
308 if (length < 0) {
309 DCHECK(false);
310 return false;
311 }
312 if (memory_usage_ + length > kMaxMemoryUsage) {
313 return false;
314 }
315 target_blob_data->AppendData(bytes, static_cast<size_t>(length));
316 memory_usage_ += length;
317 return true;
318 }
319
320 void BlobStorageContext::AppendFileItem(
321 BlobDataBuilder* target_blob_data,
322 const base::FilePath& file_path,
323 uint64 offset,
324 uint64 length,
325 const base::Time& expected_modification_time) {
326 // It may be a temporary file that should be deleted when no longer needed.
327 scoped_refptr<ShareableFileReference> shareable_file =
328 ShareableFileReference::Get(file_path);
329
330 target_blob_data->AppendFile(file_path, offset, length,
331 expected_modification_time, shareable_file);
332 }
333
334 void BlobStorageContext::AppendFileSystemFileItem(
335 BlobDataBuilder* target_blob_data,
336 const GURL& filesystem_url,
337 uint64 offset,
338 uint64 length,
339 const base::Time& expected_modification_time) {
340 target_blob_data->AppendFileSystemFile(filesystem_url, offset, length,
341 expected_modification_time);
342 }
343
344 bool BlobStorageContext::IsInUse(const std::string& uuid) { 436 bool BlobStorageContext::IsInUse(const std::string& uuid) {
345 return blob_map_.find(uuid) != blob_map_.end(); 437 return blob_map_.find(uuid) != blob_map_.end();
346 } 438 }
347 439
348 bool BlobStorageContext::IsBeingBuilt(const std::string& uuid) { 440 bool BlobStorageContext::IsBeingBuilt(const std::string& uuid) {
349 BlobMap::iterator found = blob_map_.find(uuid); 441 BlobMap::iterator found = blob_map_.find(uuid);
350 if (found == blob_map_.end()) 442 if (found == blob_map_.end())
351 return false; 443 return false;
352 return found->second->IsBeingBuilt(); 444 return found->second->IsBeingBuilt();
353 } 445 }
354 446
355 bool BlobStorageContext::IsUrlRegistered(const GURL& blob_url) { 447 bool BlobStorageContext::IsUrlRegistered(const GURL& blob_url) {
356 return public_blob_urls_.find(blob_url) != public_blob_urls_.end(); 448 return public_blob_urls_.find(blob_url) != public_blob_urls_.end();
357 } 449 }
358 450
451 scoped_ptr<BlobDataSnapshot> BlobStorageContext::CreateSnapshot(
452 const std::string& uuid,
453 const InternalBlobData& data) {
454 scoped_ptr<BlobDataSnapshot> snapshot(new BlobDataSnapshot(
455 uuid, data.content_type(), data.content_disposition()));
456 snapshot->items_.resize(data.items_.size());
457 std::transform(data.items_.begin(), data.items_.end(),
michaeln 2015/02/05 20:02:09 might be easier to read as a for (const auto& shar
dmurph 2015/02/06 01:32:30 Fine! :)
458 snapshot->items_.begin(),
459 [](const scoped_refptr<ShareableBlobDataItem>& shareableItem) {
michaeln 2015/02/05 20:02:09 shareableItem s/b shareable_item
dmurph 2015/02/06 01:32:30 Done.
460 return shareableItem->item();
461 });
462 return snapshot;
463 }
464
359 } // namespace storage 465 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698