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

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

Issue 11410019: ********** Chromium Blob hacking (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 7 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 | Annotate | Revision Log
« no previous file with comments | « webkit/blob/blob_storage_context.h ('k') | webkit/blob/blob_storage_controller.h » ('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) 2012 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"
10 13
11 namespace webkit_blob { 14 namespace webkit_blob {
12 15
13 namespace { 16 namespace {
14 17
15 // We can't use GURL directly for these hash fragment manipulations 18 // We can't use GURL directly for these hash fragment manipulations
16 // since it doesn't have specific knowlege of the BlobURL format. GURL 19 // 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 20 // treats BlobURLs as if they were PathURLs which don't support hash
18 // fragments. 21 // fragments.
19 22
20 bool BlobUrlHasRef(const GURL& url) { 23 bool BlobUrlHasRef(const GURL& url) {
21 return url.spec().find('#') != std::string::npos; 24 return url.spec().find('#') != std::string::npos;
22 } 25 }
23 26
24 GURL ClearBlobUrlRef(const GURL& url) { 27 GURL ClearBlobUrlRef(const GURL& url) {
25 size_t hash_pos = url.spec().find('#'); 28 size_t hash_pos = url.spec().find('#');
26 if (hash_pos == std::string::npos) 29 if (hash_pos == std::string::npos)
27 return url; 30 return url;
28 return GURL(url.spec().substr(0, hash_pos)); 31 return GURL(url.spec().substr(0, hash_pos));
29 } 32 }
30 33
31 static const int64 kMaxMemoryUsage = 1024 * 1024 * 1024; // 1G 34 static const int64 kMaxMemoryUsage = 1024 * 1024 * 1024; // 1G
32 35
33 } // namespace 36 } // namespace
34 37
35 BlobStorageController::BlobStorageController() 38 //-----------------------------------------------------------------------
39 // BlobDataHandle
40 //-----------------------------------------------------------------------
41
42 BlobDataHandle::BlobDataHandle(BlobData* blob_data, BlobStorageContext* context,
43 base::SequencedTaskRunner* task_runner)
44 : blob_data_(blob_data),
45 context_(new base::WeakPtr<BlobStorageContext>(context->AsWeakPtr())),
46 io_task_runner_(task_runner) {
47 // Ensures the uuid remains registered and the underlying data is not deleted.
48 context_->get()->IncrementBlobRefCount(blob_data->uuid());
49 }
50
51 BlobDataHandle::~BlobDataHandle() {
52 if (io_task_runner_->RunsTasksOnCurrentThread()) {
53 if (context_->get())
54 context_->get()->DecrementBlobRefCount(blob_data_->uuid());
55 return;
56 }
57 io_task_runner_->PostTask(
58 FROM_HERE,
59 base::Bind(&DeleteHelper, base::Passed(&context_), blob_data_));
60 }
61
62 BlobData* BlobDataHandle::data() const {
63 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
64 return blob_data_.get();
65 }
66
67 // static
68 void BlobDataHandle::DeleteHelper(
69 scoped_ptr<base::WeakPtr<BlobStorageContext> > context,
70 scoped_refptr<BlobData> blob_data) {
71 if (context->get())
72 context->get()->DecrementBlobRefCount(blob_data->uuid());
73 }
74
75 //-----------------------------------------------------------------------
76 // BlobStorageConsumer
77 //-----------------------------------------------------------------------
78
79 // TODO(michaeln): I need to tighten this up, some assertions and better
80 // map usage (aka use ->find more). Do something reasonable given bad inputs
81 // like addref'ing a id that does not exist.
82
83 BlobStorageConsumer::BlobStorageConsumer(BlobStorageContext* context)
84 : context_(context->AsWeakPtr()) {
85 }
86
87 BlobStorageConsumer::~BlobStorageConsumer() {
88 if (!context_)
89 return;
90 for (BlobReferenceMap::iterator iter = blobs_inuse_map_.begin();
91 iter != blobs_inuse_map_.end(); ++iter) {
92 for (int i = 0; i < iter->second; ++i)
93 context_->DecrementBlobRefCount(iter->first);
94 }
95
96 for (std::set<GURL>::iterator iter = public_blob_urls_.begin();
97 iter != public_blob_urls_.end(); ++iter) {
98 context_->RevokePublicBlobURL(*iter);
99 }
100 }
101
102 void BlobStorageConsumer::StartBuildingBlob(const std::string& uuid) {
103 if (!context_)
104 return;
105 DCHECK(blobs_inuse_map_.find(uuid) == blobs_inuse_map_.end());
106 blobs_inuse_map_[uuid] = 1;
107 context_->StartBuildingBlob(uuid);
108 }
109
110 void BlobStorageConsumer::AppendBlobDataItem(
111 const std::string& uuid, const BlobData::Item& data_item) {
112 if (!context_)
113 return;
114 DCHECK_EQ(blobs_inuse_map_[uuid], 1);
115 context_->AppendBlobDataItem(uuid, data_item);
116 }
117
118 void BlobStorageConsumer::CancelBuildingBlob(const std::string& uuid) {
119 if (!context_)
120 return;
121 DCHECK_EQ(blobs_inuse_map_[uuid], 1);
122 blobs_inuse_map_.erase(uuid);
123 context_->CancelBuildingBlob(uuid);
124 }
125
126 void BlobStorageConsumer::FinishBuildingBlob(
127 const std::string& uuid, const std::string& content_type) {
128 if (!context_)
129 return;
130 DCHECK_EQ(blobs_inuse_map_[uuid], 1);
131 context_->FinishBuildingBlob(uuid, content_type);
132 }
133
134 void BlobStorageConsumer::IncrementBlobRefCount(const std::string& uuid) {
135 if (!context_)
136 return;
137 blobs_inuse_map_[uuid] += 1;
138 context_->IncrementBlobRefCount(uuid);
139 }
140
141 void BlobStorageConsumer::DecrementBlobRefCount(const std::string& uuid) {
142 if (!context_)
143 return;
144 DCHECK_GT(blobs_inuse_map_[uuid], 0);
145 blobs_inuse_map_[uuid] -= 1;
146 if (blobs_inuse_map_[uuid] == 0)
147 blobs_inuse_map_.erase(uuid);
148 context_->DecrementBlobRefCount(uuid);
149 }
150
151 void BlobStorageConsumer::RegisterPublicBlobURL(
152 const GURL& blob_url, const std::string& uuid) {
153 if (!context_)
154 return;
155 DCHECK_GT(blobs_inuse_map_[uuid], 0);
156 public_blob_urls_.insert(blob_url);
157 context_->RegisterPublicBlobURL(blob_url, uuid);
158 }
159
160 void BlobStorageConsumer::RevokePublicBlobURL(const GURL& blob_url) {
161 if (!context_)
162 return;
163 public_blob_urls_.erase(blob_url);
164 context_->RevokePublicBlobURL(blob_url);
165 }
166
167 //-----------------------------------------------------------------------
168 // BlobStorageContext
169 //-----------------------------------------------------------------------
170
171 BlobStorageContext::BlobStorageContext()
36 : memory_usage_(0) { 172 : memory_usage_(0) {
37 } 173 }
38 174
39 BlobStorageController::~BlobStorageController() { 175 BlobStorageContext::~BlobStorageContext() {
40 } 176 }
41 177
42 void BlobStorageController::StartBuildingBlob(const GURL& url) { 178 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID(
43 DCHECK(url.SchemeIs("blob")); 179 const std::string& uuid) {
44 DCHECK(!BlobUrlHasRef(url)); 180 scoped_ptr<BlobDataHandle> result;
45 BlobData* blob_data = new BlobData; 181 BlobMap::iterator found = blob_map_.find(uuid);
46 unfinalized_blob_map_[url.spec()] = blob_data; 182 if (found == blob_map_.end())
47 IncrementBlobDataUsage(blob_data); 183 return result.Pass();
184 result.reset(new BlobDataHandle(found->second.second, this,
185 base::MessageLoopProxy::current()));
186 return result.Pass();
48 } 187 }
49 188
50 void BlobStorageController::AppendBlobDataItem( 189 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicUrl(
51 const GURL& url, const BlobData::Item& item) { 190 const GURL& url) {
52 DCHECK(url.SchemeIs("blob")); 191 BlobURLMap::iterator found = public_blob_urls_.find(
53 DCHECK(!BlobUrlHasRef(url)); 192 BlobUrlHasRef(url) ? ClearBlobUrlRef(url) : url);
54 BlobMap::iterator found = unfinalized_blob_map_.find(url.spec()); 193 if (found == public_blob_urls_.end())
194 return scoped_ptr<BlobDataHandle>();
195 return GetBlobDataFromUUID(found->second);
196 }
197
198 void BlobStorageContext::StartBuildingBlob(const std::string& uuid) {
199 DCHECK(unfinalized_blob_map_.find(uuid) == unfinalized_blob_map_.end());
200 unfinalized_blob_map_[uuid] = std::make_pair(1 , new BlobData(uuid));
201 }
202
203 void BlobStorageContext::AppendBlobDataItem(
204 const std::string& uuid, const BlobData::Item& item) {
205 BlobMap::iterator found = unfinalized_blob_map_.find(uuid);
55 if (found == unfinalized_blob_map_.end()) 206 if (found == unfinalized_blob_map_.end())
56 return; 207 return;
57 BlobData* target_blob_data = found->second; 208 BlobData* target_blob_data = found->second.second;
58 DCHECK(target_blob_data); 209 DCHECK(target_blob_data);
59 210
60 memory_usage_ -= target_blob_data->GetMemoryUsage(); 211 memory_usage_ -= target_blob_data->GetMemoryUsage();
61 212
62 // The blob data is stored in the "canonical" way. That is, it only contains a 213 // The blob data is stored in the "canonical" way. That is, it only contains a
63 // list of Data and File items. 214 // list of Data and File items.
64 // 1) The Data item is denoted by the raw data and the range. 215 // 1) The Data item is denoted by the raw data and the range.
65 // 2) The File item is denoted by the file path, the range and the expected 216 // 2) The File item is denoted by the file path, the range and the expected
66 // modification time. 217 // modification time.
67 // 3) The FileSystem File item is denoted by the FileSystem URL, the range
68 // and the expected modification time.
69 // All the Blob items in the passing blob data are resolved and expanded into 218 // All the Blob items in the passing blob data are resolved and expanded into
70 // a set of Data and File items. 219 // a set of Data, File, and FileSystemFile items.
71 220
72 DCHECK(item.length() > 0); 221 DCHECK(item.length() > 0);
73 switch (item.type()) { 222 switch (item.type()) {
74 case BlobData::Item::TYPE_BYTES: 223 case BlobData::Item::TYPE_BYTES:
75 DCHECK(!item.offset()); 224 DCHECK(!item.offset());
76 target_blob_data->AppendData(item.bytes(), item.length()); 225 target_blob_data->AppendData(item.bytes(), item.length());
77 break; 226 break;
78 case BlobData::Item::TYPE_FILE: 227 case BlobData::Item::TYPE_FILE:
79 AppendFileItem(target_blob_data, 228 AppendFileItem(target_blob_data,
80 item.path(), 229 item.path(),
81 item.offset(), 230 item.offset(),
82 item.length(), 231 item.length(),
83 item.expected_modification_time()); 232 item.expected_modification_time());
84 break; 233 break;
85 case BlobData::Item::TYPE_FILE_FILESYSTEM: 234 case BlobData::Item::TYPE_FILE_FILESYSTEM:
86 AppendFileSystemFileItem(target_blob_data, 235 AppendFileSystemFileItem(target_blob_data,
87 item.url(), 236 item.filesystem_url(),
88 item.offset(), 237 item.offset(),
89 item.length(), 238 item.length(),
90 item.expected_modification_time()); 239 item.expected_modification_time());
91 break; 240 break;
92 case BlobData::Item::TYPE_BLOB: { 241 case BlobData::Item::TYPE_BLOB: {
93 BlobData* src_blob_data = GetBlobDataFromUrl(item.url()); 242 scoped_ptr<BlobDataHandle> src = GetBlobDataFromUUID(item.blob_uuid());
94 DCHECK(src_blob_data); 243 DCHECK(src.get());
95 if (src_blob_data) 244 if (src.get())
96 AppendStorageItems(target_blob_data, 245 AppendStorageItems(target_blob_data,
97 src_blob_data, 246 src->data(),
98 item.offset(), 247 item.offset(),
99 item.length()); 248 item.length());
100 break; 249 break;
101 } 250 }
102 default: 251 default:
103 NOTREACHED(); 252 NOTREACHED();
104 break; 253 break;
105 } 254 }
106 255
107 memory_usage_ += target_blob_data->GetMemoryUsage(); 256 memory_usage_ += target_blob_data->GetMemoryUsage();
108 257
109 // If we're using too much memory, drop this blob. 258 // If we're using too much memory, drop this blob.
110 // TODO(michaeln): Blob memory storage does not yet spill over to disk, 259 // 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. 260 // until it does, we'll prevent memory usage over a max amount.
112 if (memory_usage_ > kMaxMemoryUsage) 261 if (memory_usage_ > kMaxMemoryUsage) {
113 RemoveBlob(url); 262 DCHECK_EQ(1, found->second.first);
263 memory_usage_ -= target_blob_data->GetMemoryUsage();
264 unfinalized_blob_map_.erase(found);
265 }
114 } 266 }
115 267
116 void BlobStorageController::FinishBuildingBlob( 268 void BlobStorageContext::FinishBuildingBlob(
117 const GURL& url, const std::string& content_type) { 269 const std::string& uuid, const std::string& content_type) {
118 DCHECK(url.SchemeIs("blob")); 270 BlobMap::iterator found = unfinalized_blob_map_.find(uuid);
119 DCHECK(!BlobUrlHasRef(url)); 271 if (found == unfinalized_blob_map_.end()) {
120 BlobMap::iterator found = unfinalized_blob_map_.find(url.spec()); 272 DCHECK(false);
121 if (found == unfinalized_blob_map_.end())
122 return; 273 return;
123 found->second->set_content_type(content_type); 274 }
124 blob_map_[url.spec()] = found->second; 275 found->second.second->set_content_type(content_type);
276 blob_map_[uuid] = std::make_pair(1, found->second.second);
125 unfinalized_blob_map_.erase(found); 277 unfinalized_blob_map_.erase(found);
126 } 278 }
127 279
128 void BlobStorageController::AddFinishedBlob(const GURL& url, 280 void BlobStorageContext::CancelBuildingBlob(const std::string& uuid) {
129 const BlobData* data) { 281 DCHECK(unfinalized_blob_map_.find(uuid) != unfinalized_blob_map_.end());
130 StartBuildingBlob(url); 282 DecrementBlobRefCountHelper(&unfinalized_blob_map_, uuid);
283 DCHECK(unfinalized_blob_map_.find(uuid) == unfinalized_blob_map_.end());
284 }
285
286 void BlobStorageContext::AddFinishedBlob(const BlobData* data) {
287 StartBuildingBlob(data->uuid());
131 for (std::vector<BlobData::Item>::const_iterator iter = 288 for (std::vector<BlobData::Item>::const_iterator iter =
132 data->items().begin(); 289 data->items().begin();
133 iter != data->items().end(); ++iter) { 290 iter != data->items().end(); ++iter) {
134 AppendBlobDataItem(url, *iter); 291 AppendBlobDataItem(data->uuid(), *iter);
135 } 292 }
136 FinishBuildingBlob(url, data->content_type()); 293 FinishBuildingBlob(data->uuid(), data->content_type());
137 } 294 }
138 295
139 void BlobStorageController::CloneBlob( 296 void BlobStorageContext::IncrementBlobRefCount(const std::string& uuid) {
140 const GURL& url, const GURL& src_url) { 297 BlobMap::iterator found = blob_map_.find(uuid);
141 DCHECK(url.SchemeIs("blob")); 298 if (found == blob_map_.end()) {
142 DCHECK(!BlobUrlHasRef(url)); 299 DCHECK(false);
143
144 BlobData* blob_data = GetBlobDataFromUrl(src_url);
145 DCHECK(blob_data);
146 if (!blob_data)
147 return; 300 return;
148 301 }
149 blob_map_[url.spec()] = blob_data; 302 ++(found->second.first);
150 IncrementBlobDataUsage(blob_data);
151 } 303 }
152 304
153 void BlobStorageController::RemoveBlob(const GURL& url) { 305 void BlobStorageContext::DecrementBlobRefCount(const std::string& uuid) {
154 DCHECK(url.SchemeIs("blob")); 306 if (!DecrementBlobRefCountHelper(&unfinalized_blob_map_, uuid))
155 DCHECK(!BlobUrlHasRef(url)); 307 DecrementBlobRefCountHelper(&blob_map_, uuid);
156
157 if (!RemoveFromMapHelper(&unfinalized_blob_map_, url))
158 RemoveFromMapHelper(&blob_map_, url);
159 } 308 }
160 309
161 bool BlobStorageController::RemoveFromMapHelper( 310 bool BlobStorageContext::DecrementBlobRefCountHelper(
162 BlobMap* map, const GURL& url) { 311 BlobMap* map, const std::string& uuid) {
163 BlobMap::iterator found = map->find(url.spec()); 312 BlobMap::iterator found = map->find(uuid);
164 if (found == map->end()) 313 if (found == map->end())
165 return false; 314 return false;
166 if (DecrementBlobDataUsage(found->second)) 315 if (--(found->second.first) == 0) {
167 memory_usage_ -= found->second->GetMemoryUsage(); 316 if (found->second.second->uuid() == uuid) {
168 map->erase(found); 317 memory_usage_ -= found->second.second->GetMemoryUsage();
318 } else {
319 // TODO(michaeln): Remove this once HackCloneBlob is removed,
320 // barring that hack, uuid's should always match.
321 //DecrementBlobRefCount(found->second.second->uuid());
322 DCHECK(false);
323 }
324 map->erase(found);
325 }
169 return true; 326 return true;
170 } 327 }
171 328
172 329 void BlobStorageContext::RegisterPublicBlobURL(
173 BlobData* BlobStorageController::GetBlobDataFromUrl(const GURL& url) { 330 const GURL& blob_url, const std::string& uuid) {
174 BlobMap::iterator found = blob_map_.find( 331 DCHECK(!BlobUrlHasRef(blob_url));
175 BlobUrlHasRef(url) ? ClearBlobUrlRef(url).spec() : url.spec()); 332 IncrementBlobRefCount(uuid);
176 return (found != blob_map_.end()) ? found->second : NULL; 333 public_blob_urls_[blob_url] = uuid;
177 } 334 }
178 335
179 void BlobStorageController::AppendStorageItems( 336 void BlobStorageContext::RevokePublicBlobURL(const GURL& blob_url) {
337 DCHECK(!BlobUrlHasRef(blob_url));
338 DecrementBlobRefCount(public_blob_urls_[blob_url]);
339 public_blob_urls_.erase(blob_url);
340 }
341
342 void BlobStorageContext::AppendStorageItems(
180 BlobData* target_blob_data, BlobData* src_blob_data, 343 BlobData* target_blob_data, BlobData* src_blob_data,
181 uint64 offset, uint64 length) { 344 uint64 offset, uint64 length) {
182 DCHECK(target_blob_data && src_blob_data && 345 DCHECK(target_blob_data && src_blob_data &&
183 length != static_cast<uint64>(-1)); 346 length != static_cast<uint64>(-1));
184 347
185 std::vector<BlobData::Item>::const_iterator iter = 348 std::vector<BlobData::Item>::const_iterator iter =
186 src_blob_data->items().begin(); 349 src_blob_data->items().begin();
187 if (offset) { 350 if (offset) {
188 for (; iter != src_blob_data->items().end(); ++iter) { 351 for (; iter != src_blob_data->items().end(); ++iter) {
189 if (offset >= iter->length()) 352 if (offset >= iter->length())
(...skipping 16 matching lines...) Expand all
206 iter->path(), 369 iter->path(),
207 iter->offset() + offset, 370 iter->offset() + offset,
208 new_length, 371 new_length,
209 iter->expected_modification_time()); 372 iter->expected_modification_time());
210 } 373 }
211 length -= new_length; 374 length -= new_length;
212 offset = 0; 375 offset = 0;
213 } 376 }
214 } 377 }
215 378
216 void BlobStorageController::AppendFileItem( 379 void BlobStorageContext::AppendFileItem(
217 BlobData* target_blob_data, 380 BlobData* target_blob_data,
218 const FilePath& file_path, uint64 offset, uint64 length, 381 const base::FilePath& file_path, uint64 offset, uint64 length,
219 const base::Time& expected_modification_time) { 382 const base::Time& expected_modification_time) {
220 target_blob_data->AppendFile(file_path, offset, length, 383 target_blob_data->AppendFile(file_path, offset, length,
221 expected_modification_time); 384 expected_modification_time);
222 385
223 // It may be a temporary file that should be deleted when no longer needed. 386 // It may be a temporary file that should be deleted when no longer needed.
224 scoped_refptr<ShareableFileReference> shareable_file = 387 scoped_refptr<ShareableFileReference> shareable_file =
225 ShareableFileReference::Get(file_path); 388 ShareableFileReference::Get(file_path);
226 if (shareable_file) 389 if (shareable_file)
227 target_blob_data->AttachShareableFileReference(shareable_file); 390 target_blob_data->AttachShareableFileReference(shareable_file);
228 } 391 }
229 392
230 void BlobStorageController::AppendFileSystemFileItem( 393 void BlobStorageContext::AppendFileSystemFileItem(
231 BlobData* target_blob_data, 394 BlobData* target_blob_data,
232 const GURL& url, uint64 offset, uint64 length, 395 const GURL& fileSystemUrl, uint64 offset, uint64 length,
233 const base::Time& expected_modification_time) { 396 const base::Time& expected_modification_time) {
234 target_blob_data->AppendFileSystemFile(url, offset, length, 397 target_blob_data->AppendFileSystemFile(fileSystemUrl, offset, length,
235 expected_modification_time); 398 expected_modification_time);
236 } 399 }
237 400
238 void BlobStorageController::IncrementBlobDataUsage(BlobData* blob_data) {
239 blob_data_usage_count_[blob_data] += 1;
240 }
241
242 bool BlobStorageController::DecrementBlobDataUsage(BlobData* blob_data) {
243 BlobDataUsageMap::iterator found = blob_data_usage_count_.find(blob_data);
244 DCHECK(found != blob_data_usage_count_.end());
245 if (--(found->second))
246 return false; // Still in use
247 blob_data_usage_count_.erase(found);
248 return true;
249 }
250
251 } // namespace webkit_blob 401 } // namespace webkit_blob
OLDNEW
« no previous file with comments | « webkit/blob/blob_storage_context.h ('k') | webkit/blob/blob_storage_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698