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

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 8 years 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
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_(context),
46 io_task_runner_(task_runner) {
47 // Ensures the uuid remains registered and the underlying data is not deleted.
48 context_->IncrementBlobRefCount(blob_data->uuid());
49 }
50
51 BlobDataHandle::~BlobDataHandle() {
52 if (io_task_runner_->RunsTasksOnCurrentThread()) {
53 context_->DecrementBlobRefCount(blob_data_->uuid());
54 return;
55 }
56 io_task_runner_->PostTask(
57 FROM_HERE,
58 base::Bind(&BlobStorageContext::DecrementBlobRefCount,
59 base::Unretained(context_), blob_data_->uuid()));
60 io_task_runner_->ReleaseSoon(FROM_HERE, blob_data_.release());
61 }
62
63 BlobData* BlobDataHandle::data() const {
64 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
65 return blob_data_.get();
66 }
67
68
69 //-----------------------------------------------------------------------
70 // BlobStorageConsumer
71 //-----------------------------------------------------------------------
72
73 // TODO(michaeln): I need to tighten this up, some assertions and better
74 // map usage (aka use ->find more). Do something reasonable given bad inputs
75 // like addref'ing a id that does not exist.
76
77 BlobStorageConsumer::BlobStorageConsumer(BlobStorageContext* context)
78 : context_(context) {
79 }
80
81 BlobStorageConsumer::~BlobStorageConsumer() {
82 for (BlobReferenceMap::iterator iter = blobs_inuse_map_.begin();
83 iter != blobs_inuse_map_.end(); ++iter) {
84 for (int i = 0; i < iter->second; ++i)
85 context_->DecrementBlobRefCount(iter->first);
86 }
87
88 for (std::set<GURL>::iterator iter = public_blob_urls_.begin();
89 iter != public_blob_urls_.end(); ++iter) {
90 context_->RevokePublicBlobURL(*iter);
91 }
92 }
93
94 void BlobStorageConsumer::StartBuildingBlob(const std::string& uuid) {
95 blobs_inuse_map_[uuid] = 1;
96 context_->StartBuildingBlob(uuid);
97 }
98
99 void BlobStorageConsumer::AppendBlobDataItem(
100 const std::string& uuid, const BlobData::Item& data_item) {
101 context_->AppendBlobDataItem(uuid, data_item);
102 }
103
104 void BlobStorageConsumer::CancelBuildingBlob(const std::string& uuid) {
105 blobs_inuse_map_.erase(uuid);
106 context_->CancelBuildingBlob(uuid);
107 }
108
109 void BlobStorageConsumer::FinishBuildingBlob(
110 const std::string& uuid, const std::string& content_type) {
111 context_->FinishBuildingBlob(uuid, content_type);
112 }
113
114 void BlobStorageConsumer::IncrementBlobRefCount(const std::string& uuid) {
115 blobs_inuse_map_[uuid] += 1;
116 context_->IncrementBlobRefCount(uuid);
117 }
118
119 void BlobStorageConsumer::DecrementBlobRefCount(const std::string& uuid) {
120 blobs_inuse_map_[uuid] -= 1;
121 if (blobs_inuse_map_[uuid] == 0)
122 blobs_inuse_map_.erase(uuid);
123 context_->DecrementBlobRefCount(uuid);
124 }
125
126 void BlobStorageConsumer::RegisterPublicBlobURL(
127 const GURL& blob_url, const std::string& uuid) {
128 public_blob_urls_.insert(blob_url);
129 context_->RegisterPublicBlobURL(blob_url, uuid);
130 }
131
132 void BlobStorageConsumer::RevokePublicBlobURL(const GURL& blob_url) {
133 public_blob_urls_.erase(blob_url);
134 context_->RevokePublicBlobURL(blob_url);
135 }
136
137 //-----------------------------------------------------------------------
138 // BlobStorageContext
139 //-----------------------------------------------------------------------
140
141 BlobStorageContext::BlobStorageContext()
36 : memory_usage_(0) { 142 : memory_usage_(0) {
37 } 143 }
38 144
39 BlobStorageController::~BlobStorageController() { 145 BlobStorageContext::~BlobStorageContext() {
40 } 146 }
41 147
42 void BlobStorageController::StartBuildingBlob(const GURL& url) { 148 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID(
43 DCHECK(url.SchemeIs("blob")); 149 const std::string& uuid) {
44 DCHECK(!BlobUrlHasRef(url)); 150 scoped_ptr<BlobDataHandle> result;
45 BlobData* blob_data = new BlobData; 151 BlobMap::iterator found = blob_map_.find(uuid);
46 unfinalized_blob_map_[url.spec()] = blob_data; 152 if (found == blob_map_.end())
47 IncrementBlobDataUsage(blob_data); 153 return result.Pass();
154 result.reset(new BlobDataHandle(found->second.second, this,
155 base::MessageLoopProxy::current()));
156 return result.Pass();
48 } 157 }
49 158
50 void BlobStorageController::AppendBlobDataItem( 159 scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicUrl(
51 const GURL& url, const BlobData::Item& item) { 160 const GURL& url) {
52 DCHECK(url.SchemeIs("blob")); 161 BlobURLMap::iterator found = public_blob_urls_.find(
53 DCHECK(!BlobUrlHasRef(url)); 162 BlobUrlHasRef(url) ? ClearBlobUrlRef(url) : url);
54 BlobMap::iterator found = unfinalized_blob_map_.find(url.spec()); 163 if (found == public_blob_urls_.end())
164 return scoped_ptr<BlobDataHandle>();
165 return GetBlobDataFromUUID(found->second);
166 }
167
168 void BlobStorageContext::StartBuildingBlob(const std::string& uuid) {
169 DCHECK(unfinalized_blob_map_.find(uuid) == unfinalized_blob_map_.end());
170 unfinalized_blob_map_[uuid] = std::make_pair(1 , new BlobData(uuid));
171 }
172
173 void BlobStorageContext::AppendBlobDataItem(
174 const std::string& uuid, const BlobData::Item& item) {
175 BlobMap::iterator found = unfinalized_blob_map_.find(uuid);
55 if (found == unfinalized_blob_map_.end()) 176 if (found == unfinalized_blob_map_.end())
56 return; 177 return;
57 BlobData* target_blob_data = found->second; 178 BlobData* target_blob_data = found->second.second;
58 DCHECK(target_blob_data); 179 DCHECK(target_blob_data);
59 180
60 memory_usage_ -= target_blob_data->GetMemoryUsage(); 181 memory_usage_ -= target_blob_data->GetMemoryUsage();
61 182
62 // The blob data is stored in the "canonical" way. That is, it only contains a 183 // The blob data is stored in the "canonical" way. That is, it only contains a
63 // list of Data and File items. 184 // list of Data and File items.
64 // 1) The Data item is denoted by the raw data and the range. 185 // 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 186 // 2) The File item is denoted by the file path, the range and the expected
66 // modification time. 187 // 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 188 // All the Blob items in the passing blob data are resolved and expanded into
70 // a set of Data and File items. 189 // a set of Data, File, and FileSystemFile items.
71 190
72 DCHECK(item.length() > 0); 191 DCHECK(item.length() > 0);
73 switch (item.type()) { 192 switch (item.type()) {
74 case BlobData::Item::TYPE_BYTES: 193 case BlobData::Item::TYPE_BYTES:
75 DCHECK(!item.offset()); 194 DCHECK(!item.offset());
76 target_blob_data->AppendData(item.bytes(), item.length()); 195 target_blob_data->AppendData(item.bytes(), item.length());
77 break; 196 break;
78 case BlobData::Item::TYPE_FILE: 197 case BlobData::Item::TYPE_FILE:
79 AppendFileItem(target_blob_data, 198 AppendFileItem(target_blob_data,
80 item.path(), 199 item.path(),
81 item.offset(), 200 item.offset(),
82 item.length(), 201 item.length(),
83 item.expected_modification_time()); 202 item.expected_modification_time());
84 break; 203 break;
85 case BlobData::Item::TYPE_FILE_FILESYSTEM: 204 case BlobData::Item::TYPE_FILE_FILESYSTEM:
86 AppendFileSystemFileItem(target_blob_data, 205 AppendFileSystemFileItem(target_blob_data,
87 item.url(), 206 item.filesystem_url(),
88 item.offset(), 207 item.offset(),
89 item.length(), 208 item.length(),
90 item.expected_modification_time()); 209 item.expected_modification_time());
91 break; 210 break;
92 case BlobData::Item::TYPE_BLOB: { 211 case BlobData::Item::TYPE_BLOB: {
93 BlobData* src_blob_data = GetBlobDataFromUrl(item.url()); 212 scoped_ptr<BlobDataHandle> src = GetBlobDataFromUUID(item.blob_uuid());
94 DCHECK(src_blob_data); 213 DCHECK(src.get());
95 if (src_blob_data) 214 if (src.get())
96 AppendStorageItems(target_blob_data, 215 AppendStorageItems(target_blob_data,
97 src_blob_data, 216 src->data(),
98 item.offset(), 217 item.offset(),
99 item.length()); 218 item.length());
100 break; 219 break;
101 } 220 }
102 default: 221 default:
103 NOTREACHED(); 222 NOTREACHED();
104 break; 223 break;
105 } 224 }
106 225
107 memory_usage_ += target_blob_data->GetMemoryUsage(); 226 memory_usage_ += target_blob_data->GetMemoryUsage();
108 227
109 // If we're using too much memory, drop this blob. 228 // If we're using too much memory, drop this blob.
110 // TODO(michaeln): Blob memory storage does not yet spill over to disk, 229 // 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. 230 // until it does, we'll prevent memory usage over a max amount.
112 if (memory_usage_ > kMaxMemoryUsage) 231 if (memory_usage_ > kMaxMemoryUsage) {
113 RemoveBlob(url); 232 DCHECK_EQ(1, found->second.first);
233 memory_usage_ -= target_blob_data->GetMemoryUsage();
234 unfinalized_blob_map_.erase(found);
235 }
114 } 236 }
115 237
116 void BlobStorageController::FinishBuildingBlob( 238 void BlobStorageContext::FinishBuildingBlob(
117 const GURL& url, const std::string& content_type) { 239 const std::string& uuid, const std::string& content_type) {
118 DCHECK(url.SchemeIs("blob")); 240 BlobMap::iterator found = unfinalized_blob_map_.find(uuid);
119 DCHECK(!BlobUrlHasRef(url)); 241 if (found == unfinalized_blob_map_.end()) {
120 BlobMap::iterator found = unfinalized_blob_map_.find(url.spec()); 242 DCHECK(false);
121 if (found == unfinalized_blob_map_.end())
122 return; 243 return;
123 found->second->set_content_type(content_type); 244 }
124 blob_map_[url.spec()] = found->second; 245 found->second.second->set_content_type(content_type);
246 blob_map_[uuid] = std::make_pair(1, found->second.second);
125 unfinalized_blob_map_.erase(found); 247 unfinalized_blob_map_.erase(found);
126 } 248 }
127 249
128 void BlobStorageController::AddFinishedBlob(const GURL& url, 250 void BlobStorageContext::CancelBuildingBlob(const std::string& uuid) {
129 const BlobData* data) { 251 DCHECK(unfinalized_blob_map_.find(uuid) != unfinalized_blob_map_.end());
130 StartBuildingBlob(url); 252 DecrementBlobRefCountHelper(&unfinalized_blob_map_, uuid);
253 DCHECK(unfinalized_blob_map_.find(uuid) == unfinalized_blob_map_.end());
254 }
255
256 void BlobStorageContext::AddFinishedBlob(const BlobData* data) {
257 StartBuildingBlob(data->uuid());
131 for (std::vector<BlobData::Item>::const_iterator iter = 258 for (std::vector<BlobData::Item>::const_iterator iter =
132 data->items().begin(); 259 data->items().begin();
133 iter != data->items().end(); ++iter) { 260 iter != data->items().end(); ++iter) {
134 AppendBlobDataItem(url, *iter); 261 AppendBlobDataItem(data->uuid(), *iter);
135 } 262 }
136 FinishBuildingBlob(url, data->content_type()); 263 FinishBuildingBlob(data->uuid(), data->content_type());
137 } 264 }
138 265
139 void BlobStorageController::CloneBlob( 266 void BlobStorageContext::IncrementBlobRefCount(const std::string& uuid) {
140 const GURL& url, const GURL& src_url) { 267 BlobMap::iterator found = blob_map_.find(uuid);
141 DCHECK(url.SchemeIs("blob")); 268 if (found == blob_map_.end()) {
142 DCHECK(!BlobUrlHasRef(url)); 269 DCHECK(false);
143
144 BlobData* blob_data = GetBlobDataFromUrl(src_url);
145 DCHECK(blob_data);
146 if (!blob_data)
147 return; 270 return;
148 271 }
149 blob_map_[url.spec()] = blob_data; 272 ++(found->second.first);
150 IncrementBlobDataUsage(blob_data);
151 } 273 }
152 274
153 void BlobStorageController::RemoveBlob(const GURL& url) { 275 void BlobStorageContext::DecrementBlobRefCount(const std::string& uuid) {
154 DCHECK(url.SchemeIs("blob")); 276 if (!DecrementBlobRefCountHelper(&unfinalized_blob_map_, uuid))
155 DCHECK(!BlobUrlHasRef(url)); 277 DecrementBlobRefCountHelper(&blob_map_, uuid);
156
157 if (!RemoveFromMapHelper(&unfinalized_blob_map_, url))
158 RemoveFromMapHelper(&blob_map_, url);
159 } 278 }
160 279
161 bool BlobStorageController::RemoveFromMapHelper( 280 bool BlobStorageContext::DecrementBlobRefCountHelper(
162 BlobMap* map, const GURL& url) { 281 BlobMap* map, const std::string& uuid) {
163 BlobMap::iterator found = map->find(url.spec()); 282 BlobMap::iterator found = map->find(uuid);
164 if (found == map->end()) 283 if (found == map->end())
165 return false; 284 return false;
166 if (DecrementBlobDataUsage(found->second)) 285 if (--(found->second.first) == 0) {
167 memory_usage_ -= found->second->GetMemoryUsage(); 286 if (found->second.second->uuid() == uuid) {
168 map->erase(found); 287 memory_usage_ -= found->second.second->GetMemoryUsage();
288 } else {
289 // TODO(michaeln): Remove this once HackCloneBlob is removed,
290 // barring that hack, uuid's should always match.
291 DecrementBlobRefCount(found->second.second->uuid());
292 }
293 map->erase(found);
294 }
169 return true; 295 return true;
170 } 296 }
171 297
172 298 void BlobStorageContext::RegisterPublicBlobURL(
173 BlobData* BlobStorageController::GetBlobDataFromUrl(const GURL& url) { 299 const GURL& blob_url, const std::string& uuid) {
174 BlobMap::iterator found = blob_map_.find( 300 DCHECK(!BlobUrlHasRef(blob_url));
175 BlobUrlHasRef(url) ? ClearBlobUrlRef(url).spec() : url.spec()); 301 IncrementBlobRefCount(uuid);
176 return (found != blob_map_.end()) ? found->second : NULL; 302 public_blob_urls_[blob_url] = uuid;
177 } 303 }
178 304
179 void BlobStorageController::AppendStorageItems( 305 void BlobStorageContext::RevokePublicBlobURL(const GURL& blob_url) {
306 DCHECK(!BlobUrlHasRef(blob_url));
307 DecrementBlobRefCount(public_blob_urls_[blob_url]);
308 public_blob_urls_.erase(blob_url);
309 }
310
311 void BlobStorageContext::AppendStorageItems(
180 BlobData* target_blob_data, BlobData* src_blob_data, 312 BlobData* target_blob_data, BlobData* src_blob_data,
181 uint64 offset, uint64 length) { 313 uint64 offset, uint64 length) {
182 DCHECK(target_blob_data && src_blob_data && 314 DCHECK(target_blob_data && src_blob_data &&
183 length != static_cast<uint64>(-1)); 315 length != static_cast<uint64>(-1));
184 316
185 std::vector<BlobData::Item>::const_iterator iter = 317 std::vector<BlobData::Item>::const_iterator iter =
186 src_blob_data->items().begin(); 318 src_blob_data->items().begin();
187 if (offset) { 319 if (offset) {
188 for (; iter != src_blob_data->items().end(); ++iter) { 320 for (; iter != src_blob_data->items().end(); ++iter) {
189 if (offset >= iter->length()) 321 if (offset >= iter->length())
(...skipping 16 matching lines...) Expand all
206 iter->path(), 338 iter->path(),
207 iter->offset() + offset, 339 iter->offset() + offset,
208 new_length, 340 new_length,
209 iter->expected_modification_time()); 341 iter->expected_modification_time());
210 } 342 }
211 length -= new_length; 343 length -= new_length;
212 offset = 0; 344 offset = 0;
213 } 345 }
214 } 346 }
215 347
216 void BlobStorageController::AppendFileItem( 348 void BlobStorageContext::AppendFileItem(
217 BlobData* target_blob_data, 349 BlobData* target_blob_data,
218 const FilePath& file_path, uint64 offset, uint64 length, 350 const FilePath& file_path, uint64 offset, uint64 length,
219 const base::Time& expected_modification_time) { 351 const base::Time& expected_modification_time) {
220 target_blob_data->AppendFile(file_path, offset, length, 352 target_blob_data->AppendFile(file_path, offset, length,
221 expected_modification_time); 353 expected_modification_time);
222 354
223 // It may be a temporary file that should be deleted when no longer needed. 355 // It may be a temporary file that should be deleted when no longer needed.
224 scoped_refptr<ShareableFileReference> shareable_file = 356 scoped_refptr<ShareableFileReference> shareable_file =
225 ShareableFileReference::Get(file_path); 357 ShareableFileReference::Get(file_path);
226 if (shareable_file) 358 if (shareable_file)
227 target_blob_data->AttachShareableFileReference(shareable_file); 359 target_blob_data->AttachShareableFileReference(shareable_file);
228 } 360 }
229 361
230 void BlobStorageController::AppendFileSystemFileItem( 362 void BlobStorageContext::AppendFileSystemFileItem(
231 BlobData* target_blob_data, 363 BlobData* target_blob_data,
232 const GURL& url, uint64 offset, uint64 length, 364 const GURL& fileSystemUrl, uint64 offset, uint64 length,
233 const base::Time& expected_modification_time) { 365 const base::Time& expected_modification_time) {
234 target_blob_data->AppendFileSystemFile(url, offset, length, 366 target_blob_data->AppendFileSystemFile(fileSystemUrl, offset, length,
235 expected_modification_time); 367 expected_modification_time);
236 } 368 }
237 369
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 370 } // namespace webkit_blob
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698