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

Side by Side Diff: webkit/blob/blob_storage_context.cc

Issue 14139026: New blobstoragecontext for use in the main browser process, not plugged in yet. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 7 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « webkit/blob/blob_storage_context.h ('k') | webkit/blob/blob_storage_context_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 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 "webkit/blob/blob_storage_controller.h" 5 #include "webkit/blob/blob_storage_context.h"
6 6
7 #include "base/bind.h"
8 #include "base/location.h"
7 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop_proxy.h"
8 #include "googleurl/src/gurl.h" 11 #include "googleurl/src/gurl.h"
9 #include "webkit/blob/blob_data.h" 12 #include "webkit/blob/blob_data.h"
13 #include "webkit/blob/blob_data_handle.h"
10 14
11 namespace webkit_blob { 15 namespace webkit_blob {
12 16
13 namespace { 17 namespace {
14 18
15 // We can't use GURL directly for these hash fragment manipulations 19 // We can't use GURL directly for these hash fragment manipulations
16 // since it doesn't have specific knowlege of the BlobURL format. GURL 20 // since it doesn't have specific knowlege of the BlobURL format. GURL
17 // treats BlobURLs as if they were PathURLs which don't support hash 21 // treats BlobURLs as if they were PathURLs which don't support hash
18 // fragments. 22 // fragments.
19 23
20 bool BlobUrlHasRef(const GURL& url) { 24 bool BlobUrlHasRef(const GURL& url) {
21 return url.spec().find('#') != std::string::npos; 25 return url.spec().find('#') != std::string::npos;
22 } 26 }
23 27
24 GURL ClearBlobUrlRef(const GURL& url) { 28 GURL ClearBlobUrlRef(const GURL& url) {
25 size_t hash_pos = url.spec().find('#'); 29 size_t hash_pos = url.spec().find('#');
26 if (hash_pos == std::string::npos) 30 if (hash_pos == std::string::npos)
27 return url; 31 return url;
28 return GURL(url.spec().substr(0, hash_pos)); 32 return GURL(url.spec().substr(0, hash_pos));
29 } 33 }
30 34
31 static const int64 kMaxMemoryUsage = 1024 * 1024 * 1024; // 1G 35 // TODO(michaeln): use base::SysInfo::AmountOfPhysicalMemoryMB() in some
36 // way to come up with a better limit.
37 static const int64 kMaxMemoryUsage = 500 * 1024 * 1024; // Half a gig.
32 38
33 } // namespace 39 } // namespace
34 40
35 BlobStorageController::BlobStorageController() 41 BlobStorageContext::BlobMapEntry::BlobMapEntry()
42 : refcount(0), flags(0) {
43 }
44
45 BlobStorageContext::BlobMapEntry::BlobMapEntry(
46 int refcount, int flags, BlobData* data)
47 : refcount(refcount), flags(flags), data(data) {
48 }
49
50 BlobStorageContext::BlobMapEntry::~BlobMapEntry() {
51 }
52
53 BlobStorageContext::BlobStorageContext()
36 : memory_usage_(0) { 54 : memory_usage_(0) {
37 } 55 }
38 56
39 BlobStorageController::~BlobStorageController() { 57 BlobStorageContext::~BlobStorageContext() {
40 } 58 }
41 59
42 void BlobStorageController::StartBuildingBlob(const GURL& url) { 60 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID(
43 DCHECK(url.SchemeIs("blob")); 61 const std::string& uuid) {
44 DCHECK(!BlobUrlHasRef(url)); 62 scoped_ptr<BlobDataHandle> result;
45 BlobData* blob_data = new BlobData; 63 BlobMap::iterator found = blob_map_.find(uuid);
46 unfinalized_blob_map_[url.spec()] = blob_data; 64 if (found == blob_map_.end())
47 IncrementBlobDataUsage(blob_data); 65 return result.Pass();
66 if (found->second.flags & EXCEEDED_MEMORY)
67 return result.Pass();
68 DCHECK(!(found->second.flags & BEING_BUILT));
69 result.reset(new BlobDataHandle(found->second.data, this,
70 base::MessageLoopProxy::current()));
71 return result.Pass();
48 } 72 }
49 73
50 void BlobStorageController::AppendBlobDataItem( 74 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL(
51 const GURL& url, const BlobData::Item& item) { 75 const GURL& url) {
52 DCHECK(url.SchemeIs("blob")); 76 BlobURLMap::iterator found = public_blob_urls_.find(
53 DCHECK(!BlobUrlHasRef(url)); 77 BlobUrlHasRef(url) ? ClearBlobUrlRef(url) : url);
54 BlobMap::iterator found = unfinalized_blob_map_.find(url.spec()); 78 if (found == public_blob_urls_.end())
55 if (found == unfinalized_blob_map_.end()) 79 return scoped_ptr<BlobDataHandle>();
80 return GetBlobDataFromUUID(found->second);
81 }
82
83 scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob(
84 const BlobData* data) {
85 StartBuildingBlob(data->uuid());
86 for (std::vector<BlobData::Item>::const_iterator iter =
87 data->items().begin();
88 iter != data->items().end(); ++iter) {
89 AppendBlobDataItem(data->uuid(), *iter);
90 }
91 FinishBuildingBlob(data->uuid(), data->content_type());
92 scoped_ptr<BlobDataHandle> handle = GetBlobDataFromUUID(data->uuid());
93 DecrementBlobRefCount(data->uuid());
94 return handle.Pass();
95 }
96
97 void BlobStorageContext::StartBuildingBlob(const std::string& uuid) {
98 DCHECK(!IsInUse(uuid) && !uuid.empty());
99 blob_map_[uuid] = BlobMapEntry(1, BEING_BUILT, new BlobData(uuid));
100 }
101
102 void BlobStorageContext::AppendBlobDataItem(
103 const std::string& uuid, const BlobData::Item& item) {
104 DCHECK(IsBeingBuilt(uuid));
105 BlobMap::iterator found = blob_map_.find(uuid);
106 if (found == blob_map_.end())
56 return; 107 return;
57 BlobData* target_blob_data = found->second; 108 if (found->second.flags & EXCEEDED_MEMORY)
109 return;
110 BlobData* target_blob_data = found->second.data;
58 DCHECK(target_blob_data); 111 DCHECK(target_blob_data);
59 112
60 memory_usage_ -= target_blob_data->GetMemoryUsage(); 113 bool exceeded_memory = false;
61 114
62 // The blob data is stored in the "canonical" way. That is, it only contains a 115 // The blob data is stored in the canonical way which only contains a
63 // list of Data and File items. 116 // list of Data, File, and FileSystem items. Aggregated TYPE_BLOB items
64 // 1) The Data item is denoted by the raw data and the range. 117 // are expanded into the primitive constituent types.
118 // 1) The Data item is denoted by the raw data and length.
65 // 2) The File item is denoted by the file path, the range and the expected 119 // 2) The File item is denoted by the file path, the range and the expected
66 // modification time. 120 // modification time.
67 // 3) The FileSystem File item is denoted by the FileSystem URL, the range 121 // 3) The FileSystem File item is denoted by the FileSystem URL, the range
68 // and the expected modification time. 122 // and the expected modification time.
69 // All the Blob items in the passing blob data are resolved and expanded into 123 // 4) The Blob items are expanded.
70 // a set of Data and File items. 124 // TODO(michaeln): Would be nice to avoid copying Data items when expanding.
71 125
72 DCHECK(item.length() > 0); 126 DCHECK(item.length() > 0);
73 switch (item.type()) { 127 switch (item.type()) {
74 case BlobData::Item::TYPE_BYTES: 128 case BlobData::Item::TYPE_BYTES:
75 DCHECK(!item.offset()); 129 DCHECK(!item.offset());
76 target_blob_data->AppendData(item.bytes(), item.length()); 130 exceeded_memory = !AppendBytesItem(target_blob_data,
131 item.bytes(),
132 static_cast<int64>(item.length()));
77 break; 133 break;
78 case BlobData::Item::TYPE_FILE: 134 case BlobData::Item::TYPE_FILE:
79 AppendFileItem(target_blob_data, 135 AppendFileItem(target_blob_data,
80 item.path(), 136 item.path(),
81 item.offset(), 137 item.offset(),
82 item.length(), 138 item.length(),
83 item.expected_modification_time()); 139 item.expected_modification_time());
84 break; 140 break;
85 case BlobData::Item::TYPE_FILE_FILESYSTEM: 141 case BlobData::Item::TYPE_FILE_FILESYSTEM:
86 AppendFileSystemFileItem(target_blob_data, 142 AppendFileSystemFileItem(target_blob_data,
87 item.url(), 143 item.filesystem_url(),
88 item.offset(), 144 item.offset(),
89 item.length(), 145 item.length(),
90 item.expected_modification_time()); 146 item.expected_modification_time());
91 break; 147 break;
92 case BlobData::Item::TYPE_BLOB: { 148 case BlobData::Item::TYPE_BLOB: {
93 BlobData* src_blob_data = GetBlobDataFromUrl(item.url()); 149 scoped_ptr<BlobDataHandle> src = GetBlobDataFromUUID(item.blob_uuid());
94 DCHECK(src_blob_data); 150 if (src.get())
95 if (src_blob_data) 151 exceeded_memory = !ExpandStorageItems(target_blob_data,
96 AppendStorageItems(target_blob_data, 152 src->data(),
97 src_blob_data, 153 item.offset(),
98 item.offset(), 154 item.length());
99 item.length());
100 break; 155 break;
101 } 156 }
102 default: 157 default:
103 NOTREACHED(); 158 NOTREACHED();
104 break; 159 break;
105 } 160 }
106 161
107 memory_usage_ += target_blob_data->GetMemoryUsage(); 162 // If we're using too much memory, drop this blob's data.
108
109 // If we're using too much memory, drop this blob.
110 // TODO(michaeln): Blob memory storage does not yet spill over to disk, 163 // TODO(michaeln): Blob memory storage does not yet spill over to disk,
111 // until it does, we'll prevent memory usage over a max amount. 164 // as a stop gap, we'll prevent memory usage over a max amount.
112 if (memory_usage_ > kMaxMemoryUsage) 165 if (exceeded_memory) {
113 RemoveBlob(url); 166 memory_usage_ -= target_blob_data->GetMemoryUsage();
167 found->second.flags |= EXCEEDED_MEMORY;
168 found->second.data = new BlobData(uuid);
169 return;
170 }
114 } 171 }
115 172
116 void BlobStorageController::FinishBuildingBlob( 173 void BlobStorageContext::FinishBuildingBlob(
117 const GURL& url, const std::string& content_type) { 174 const std::string& uuid, const std::string& content_type) {
118 DCHECK(url.SchemeIs("blob")); 175 DCHECK(IsBeingBuilt(uuid));
119 DCHECK(!BlobUrlHasRef(url)); 176 BlobMap::iterator found = blob_map_.find(uuid);
120 BlobMap::iterator found = unfinalized_blob_map_.find(url.spec()); 177 if (found == blob_map_.end())
121 if (found == unfinalized_blob_map_.end())
122 return; 178 return;
123 found->second->set_content_type(content_type); 179 found->second.data->set_content_type(content_type);
124 blob_map_[url.spec()] = found->second; 180 found->second.flags &= ~BEING_BUILT;
125 unfinalized_blob_map_.erase(found);
126 } 181 }
127 182
128 void BlobStorageController::AddFinishedBlob(const GURL& url, 183 void BlobStorageContext::CancelBuildingBlob(const std::string& uuid) {
129 const BlobData* data) { 184 DCHECK(IsBeingBuilt(uuid));
130 StartBuildingBlob(url); 185 DecrementBlobRefCount(uuid);
131 for (std::vector<BlobData::Item>::const_iterator iter =
132 data->items().begin();
133 iter != data->items().end(); ++iter) {
134 AppendBlobDataItem(url, *iter);
135 }
136 FinishBuildingBlob(url, data->content_type());
137 } 186 }
138 187
139 void BlobStorageController::CloneBlob( 188 void BlobStorageContext::IncrementBlobRefCount(const std::string& uuid) {
140 const GURL& url, const GURL& src_url) { 189 BlobMap::iterator found = blob_map_.find(uuid);
141 DCHECK(url.SchemeIs("blob")); 190 if (found == blob_map_.end()) {
142 DCHECK(!BlobUrlHasRef(url)); 191 DCHECK(false);
143
144 BlobData* blob_data = GetBlobDataFromUrl(src_url);
145 DCHECK(blob_data);
146 if (!blob_data)
147 return; 192 return;
148 193 }
149 blob_map_[url.spec()] = blob_data; 194 ++(found->second.refcount);
150 IncrementBlobDataUsage(blob_data);
151 } 195 }
152 196
153 void BlobStorageController::RemoveBlob(const GURL& url) { 197 void BlobStorageContext::DecrementBlobRefCount(const std::string& uuid) {
154 DCHECK(url.SchemeIs("blob")); 198 BlobMap::iterator found = blob_map_.find(uuid);
155 DCHECK(!BlobUrlHasRef(url)); 199 if (found == blob_map_.end())
156 200 return;
157 if (!RemoveFromMapHelper(&unfinalized_blob_map_, url)) 201 DCHECK_EQ(found->second.data->uuid(), uuid);
158 RemoveFromMapHelper(&blob_map_, url); 202 if (--(found->second.refcount) == 0) {
203 memory_usage_ -= found->second.data->GetMemoryUsage();
204 blob_map_.erase(found);
205 }
159 } 206 }
160 207
161 bool BlobStorageController::RemoveFromMapHelper( 208 void BlobStorageContext::RegisterPublicBlobURL(
162 BlobMap* map, const GURL& url) { 209 const GURL& blob_url, const std::string& uuid) {
163 BlobMap::iterator found = map->find(url.spec()); 210 DCHECK(!BlobUrlHasRef(blob_url));
164 if (found == map->end()) 211 DCHECK(IsInUse(uuid));
165 return false; 212 DCHECK(!IsUrlRegistered(blob_url));
166 if (DecrementBlobDataUsage(found->second)) 213 IncrementBlobRefCount(uuid);
167 memory_usage_ -= found->second->GetMemoryUsage(); 214 public_blob_urls_[blob_url] = uuid;
168 map->erase(found);
169 return true;
170 } 215 }
171 216
172 217 void BlobStorageContext::RevokePublicBlobURL(const GURL& blob_url) {
173 BlobData* BlobStorageController::GetBlobDataFromUrl(const GURL& url) { 218 DCHECK(!BlobUrlHasRef(blob_url));
174 BlobMap::iterator found = blob_map_.find( 219 if (!IsUrlRegistered(blob_url))
175 BlobUrlHasRef(url) ? ClearBlobUrlRef(url).spec() : url.spec()); 220 return;
176 return (found != blob_map_.end()) ? found->second : NULL; 221 DecrementBlobRefCount(public_blob_urls_[blob_url]);
222 public_blob_urls_.erase(blob_url);
177 } 223 }
178 224
179 void BlobStorageController::AppendStorageItems( 225 bool BlobStorageContext::ExpandStorageItems(
180 BlobData* target_blob_data, BlobData* src_blob_data, 226 BlobData* target_blob_data, BlobData* src_blob_data,
181 uint64 offset, uint64 length) { 227 uint64 offset, uint64 length) {
182 DCHECK(target_blob_data && src_blob_data && 228 DCHECK(target_blob_data && src_blob_data &&
183 length != static_cast<uint64>(-1)); 229 length != static_cast<uint64>(-1));
184 230
185 std::vector<BlobData::Item>::const_iterator iter = 231 std::vector<BlobData::Item>::const_iterator iter =
186 src_blob_data->items().begin(); 232 src_blob_data->items().begin();
187 if (offset) { 233 if (offset) {
188 for (; iter != src_blob_data->items().end(); ++iter) { 234 for (; iter != src_blob_data->items().end(); ++iter) {
189 if (offset >= iter->length()) 235 if (offset >= iter->length())
190 offset -= iter->length(); 236 offset -= iter->length();
191 else 237 else
192 break; 238 break;
193 } 239 }
194 } 240 }
195 241
196 for (; iter != src_blob_data->items().end() && length > 0; ++iter) { 242 for (; iter != src_blob_data->items().end() && length > 0; ++iter) {
197 uint64 current_length = iter->length() - offset; 243 uint64 current_length = iter->length() - offset;
198 uint64 new_length = current_length > length ? length : current_length; 244 uint64 new_length = current_length > length ? length : current_length;
199 if (iter->type() == BlobData::Item::TYPE_BYTES) { 245 if (iter->type() == BlobData::Item::TYPE_BYTES) {
200 target_blob_data->AppendData( 246 if (!AppendBytesItem(
201 iter->bytes() + static_cast<size_t>(iter->offset() + offset), 247 target_blob_data,
202 static_cast<uint32>(new_length)); 248 iter->bytes() + static_cast<size_t>(iter->offset() + offset),
249 static_cast<int64>(new_length))) {
250 return false; // exceeded memory
251 }
203 } else if (iter->type() == BlobData::Item::TYPE_FILE) { 252 } else if (iter->type() == BlobData::Item::TYPE_FILE) {
204 AppendFileItem(target_blob_data, 253 AppendFileItem(target_blob_data,
205 iter->path(), 254 iter->path(),
206 iter->offset() + offset, 255 iter->offset() + offset,
207 new_length, 256 new_length,
208 iter->expected_modification_time()); 257 iter->expected_modification_time());
209 } else { 258 } else {
210 DCHECK(iter->type() == BlobData::Item::TYPE_FILE_FILESYSTEM); 259 DCHECK(iter->type() == BlobData::Item::TYPE_FILE_FILESYSTEM);
211 AppendFileSystemFileItem(target_blob_data, 260 AppendFileSystemFileItem(target_blob_data,
212 iter->url(), 261 iter->filesystem_url(),
213 iter->offset() + offset, 262 iter->offset() + offset,
214 new_length, 263 new_length,
215 iter->expected_modification_time()); 264 iter->expected_modification_time());
216 } 265 }
217 length -= new_length; 266 length -= new_length;
218 offset = 0; 267 offset = 0;
219 } 268 }
269 return true;
220 } 270 }
221 271
222 void BlobStorageController::AppendFileItem( 272 bool BlobStorageContext::AppendBytesItem(
273 BlobData* target_blob_data, const char* bytes, int64 length) {
274 if (length < 0) {
275 DCHECK(false);
276 return false;
277 }
278 if (memory_usage_ + length > kMaxMemoryUsage)
279 return false;
280 target_blob_data->AppendData(bytes, static_cast<size_t>(length));
281 memory_usage_ += length;
282 return true;
283 }
284
285 void BlobStorageContext::AppendFileItem(
223 BlobData* target_blob_data, 286 BlobData* target_blob_data,
224 const base::FilePath& file_path, uint64 offset, uint64 length, 287 const base::FilePath& file_path, uint64 offset, uint64 length,
225 const base::Time& expected_modification_time) { 288 const base::Time& expected_modification_time) {
226 target_blob_data->AppendFile(file_path, offset, length, 289 target_blob_data->AppendFile(file_path, offset, length,
227 expected_modification_time); 290 expected_modification_time);
228 291
229 // It may be a temporary file that should be deleted when no longer needed. 292 // It may be a temporary file that should be deleted when no longer needed.
230 scoped_refptr<ShareableFileReference> shareable_file = 293 scoped_refptr<ShareableFileReference> shareable_file =
231 ShareableFileReference::Get(file_path); 294 ShareableFileReference::Get(file_path);
232 if (shareable_file) 295 if (shareable_file)
233 target_blob_data->AttachShareableFileReference(shareable_file); 296 target_blob_data->AttachShareableFileReference(shareable_file);
234 } 297 }
235 298
236 void BlobStorageController::AppendFileSystemFileItem( 299 void BlobStorageContext::AppendFileSystemFileItem(
237 BlobData* target_blob_data, 300 BlobData* target_blob_data,
238 const GURL& url, uint64 offset, uint64 length, 301 const GURL& filesystem_url, uint64 offset, uint64 length,
239 const base::Time& expected_modification_time) { 302 const base::Time& expected_modification_time) {
240 target_blob_data->AppendFileSystemFile(url, offset, length, 303 target_blob_data->AppendFileSystemFile(filesystem_url, offset, length,
241 expected_modification_time); 304 expected_modification_time);
242 } 305 }
243 306
244 void BlobStorageController::IncrementBlobDataUsage(BlobData* blob_data) { 307 bool BlobStorageContext::IsInUse(const std::string& uuid) {
245 blob_data_usage_count_[blob_data] += 1; 308 return blob_map_.find(uuid) != blob_map_.end();
246 } 309 }
247 310
248 bool BlobStorageController::DecrementBlobDataUsage(BlobData* blob_data) { 311 bool BlobStorageContext::IsBeingBuilt(const std::string& uuid) {
249 BlobDataUsageMap::iterator found = blob_data_usage_count_.find(blob_data); 312 BlobMap::iterator found = blob_map_.find(uuid);
250 DCHECK(found != blob_data_usage_count_.end()); 313 if (found == blob_map_.end())
251 if (--(found->second)) 314 return false;
252 return false; // Still in use 315 return found->second.flags & BEING_BUILT;
253 blob_data_usage_count_.erase(found); 316 }
254 return true; 317
318 bool BlobStorageContext::IsUrlRegistered(const GURL& blob_url) {
319 return public_blob_urls_.find(blob_url) != public_blob_urls_.end();
255 } 320 }
256 321
257 } // namespace webkit_blob 322 } // namespace webkit_blob
OLDNEW
« no previous file with comments | « webkit/blob/blob_storage_context.h ('k') | webkit/blob/blob_storage_context_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698