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

Side by Side Diff: content/browser/in_process_webkit/indexed_db_context.cc

Issue 7470008: Improve IndexedDB's quota support (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: finally responded to everything Created 9 years, 4 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
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "content/browser/in_process_webkit/indexed_db_context.h" 5 #include "content/browser/in_process_webkit/indexed_db_context.h"
6 6
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/message_loop_proxy.h" 9 #include "base/message_loop_proxy.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "base/task.h"
11 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
12 #include "content/browser/browser_thread.h" 13 #include "content/browser/browser_thread.h"
13 #include "content/browser/in_process_webkit/indexed_db_quota_client.h" 14 #include "content/browser/in_process_webkit/indexed_db_quota_client.h"
14 #include "content/browser/in_process_webkit/webkit_context.h" 15 #include "content/browser/in_process_webkit/webkit_context.h"
15 #include "googleurl/src/gurl.h" 16 #include "googleurl/src/gurl.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h" 17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBDatabase.h" 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBDatabase.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBFactory.h" 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBFactory.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" 21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
22 #include "webkit/database/database_util.h"
21 #include "webkit/glue/webkit_glue.h" 23 #include "webkit/glue/webkit_glue.h"
22 #include "webkit/quota/quota_manager.h" 24 #include "webkit/quota/quota_manager.h"
23 #include "webkit/quota/special_storage_policy.h" 25 #include "webkit/quota/special_storage_policy.h"
24 26
27 using webkit_database::DatabaseUtil;
25 using WebKit::WebIDBDatabase; 28 using WebKit::WebIDBDatabase;
26 using WebKit::WebIDBFactory; 29 using WebKit::WebIDBFactory;
27 using WebKit::WebSecurityOrigin; 30 using WebKit::WebSecurityOrigin;
28 31
29 namespace { 32 namespace {
30 33
31 void ClearLocalState( 34 void ClearLocalState(
32 const FilePath& indexeddb_path, 35 const FilePath& indexeddb_path,
33 scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy) { 36 scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy) {
34 file_util::FileEnumerator file_enumerator( 37 file_util::FileEnumerator file_enumerator(
(...skipping 14 matching lines...) Expand all
49 } 52 }
50 53
51 } // namespace 54 } // namespace
52 55
53 const FilePath::CharType IndexedDBContext::kIndexedDBDirectory[] = 56 const FilePath::CharType IndexedDBContext::kIndexedDBDirectory[] =
54 FILE_PATH_LITERAL("IndexedDB"); 57 FILE_PATH_LITERAL("IndexedDB");
55 58
56 const FilePath::CharType IndexedDBContext::kIndexedDBExtension[] = 59 const FilePath::CharType IndexedDBContext::kIndexedDBExtension[] =
57 FILE_PATH_LITERAL(".leveldb"); 60 FILE_PATH_LITERAL(".leveldb");
58 61
62 class IndexedDBContext::IndexedDBGetUsageAndQuotaCallback :
dgrogan 2011/08/04 23:44:56 I recall seeing something that said nested class i
63 public quota::QuotaManager::GetUsageAndQuotaCallback {
64 public:
65 IndexedDBGetUsageAndQuotaCallback(IndexedDBContext* context,
66 const GURL& origin_url)
67 : context_(context),
68 origin_url_(origin_url) {
69 }
70
71 void Run(quota::QuotaStatusCode status, int64 usage, int64 quota) {
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
73 DCHECK(status == quota::kQuotaStatusOk || status == quota::kQuotaErrorAbort)
74 << "status was " << status;
75 if (status == quota::kQuotaErrorAbort) {
76 // We seem to no longer care to wait around for the answer.
77 return;
78 }
79 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE,
80 NewRunnableMethod(context_.get(),
81 &IndexedDBContext::GotUpdatedQuota,
82 origin_url_,
83 usage,
84 quota));
85 }
86
87 virtual void RunWithParams(
88 const Tuple3<quota::QuotaStatusCode, int64, int64>& params) {
89 Run(params.a, params.b, params.c);
90 }
91
92 private:
93 scoped_refptr<IndexedDBContext> context_;
94 const GURL origin_url_;
95 };
96
59 IndexedDBContext::IndexedDBContext( 97 IndexedDBContext::IndexedDBContext(
60 WebKitContext* webkit_context, 98 WebKitContext* webkit_context,
61 quota::SpecialStoragePolicy* special_storage_policy, 99 quota::SpecialStoragePolicy* special_storage_policy,
62 quota::QuotaManagerProxy* quota_manager_proxy, 100 quota::QuotaManagerProxy* quota_manager_proxy,
63 base::MessageLoopProxy* webkit_thread_loop) 101 base::MessageLoopProxy* webkit_thread_loop)
64 : clear_local_state_on_exit_(false), 102 : clear_local_state_on_exit_(false),
65 special_storage_policy_(special_storage_policy), 103 special_storage_policy_(special_storage_policy),
66 quota_manager_proxy_(quota_manager_proxy) { 104 quota_manager_proxy_(quota_manager_proxy) {
67 data_path_ = webkit_context->data_path().Append(kIndexedDBDirectory); 105 data_path_ = webkit_context->data_path().Append(kIndexedDBDirectory);
68 if (quota_manager_proxy) { 106 if (quota_manager_proxy) {
(...skipping 24 matching lines...) Expand all
93 } 131 }
94 132
95 FilePath IndexedDBContext::GetIndexedDBFilePath( 133 FilePath IndexedDBContext::GetIndexedDBFilePath(
96 const string16& origin_id) const { 134 const string16& origin_id) const {
97 FilePath::StringType id = 135 FilePath::StringType id =
98 webkit_glue::WebStringToFilePathString(origin_id).append( 136 webkit_glue::WebStringToFilePathString(origin_id).append(
99 FILE_PATH_LITERAL(".indexeddb")); 137 FILE_PATH_LITERAL(".indexeddb"));
100 return data_path_.Append(id.append(kIndexedDBExtension)); 138 return data_path_.Append(id.append(kIndexedDBExtension));
101 } 139 }
102 140
103 void IndexedDBContext::DeleteIndexedDBFile(const FilePath& file_path) { 141 // Note: This is not called in response to a UI action in Content Settings. Only
142 // extension data deleter and quota manager currently call this.
143 void IndexedDBContext::DeleteIndexedDBForOrigin(const GURL& origin_url) {
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); 144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
105 // TODO(pastarmovj): Close all database connections that use that file. 145 string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url);
106 file_util::Delete(file_path, false); 146 FilePath idb_directory = GetIndexedDBFilePath(origin_id);
107 } 147 if (idb_directory.BaseName().value().substr(0, strlen("chrome-extension")) ==
108 148 FILE_PATH_LITERAL("chrome-extension") ||
109 void IndexedDBContext::DeleteIndexedDBForOrigin(const string16& origin_id) { 149 connection_count_.find(origin_url) == connection_count_.end()) {
110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); 150 file_util::Delete(idb_directory, true /*recursive*/);
111 // TODO(pastarmovj): Remove this check once we are safe to delete any time. 151 QueryDiskAndUpdateQuotaUsage(origin_url);
112 FilePath idb_file = GetIndexedDBFilePath(origin_id); 152 }
113 DCHECK_EQ(idb_file.BaseName().value().substr(0, strlen("chrome-extension")),
114 FILE_PATH_LITERAL("chrome-extension"));
115 DeleteIndexedDBFile(GetIndexedDBFilePath(origin_id));
116 } 153 }
117 154
118 bool IndexedDBContext::IsUnlimitedStorageGranted( 155 bool IndexedDBContext::IsUnlimitedStorageGranted(
119 const GURL& origin) const { 156 const GURL& origin) const {
120 return special_storage_policy_->IsStorageUnlimited(origin); 157 return special_storage_policy_->IsStorageUnlimited(origin);
121 } 158 }
122 159
123 // TODO(dgrogan): Merge this code with the similar loop in 160 // TODO(dgrogan): Merge this code with the similar loop in
124 // BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread. 161 // BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread.
125 void IndexedDBContext::GetAllOriginIdentifiers( 162 void IndexedDBContext::GetAllOriginIdentifiers(
126 std::vector<string16>* origin_ids) { 163 std::vector<string16>* origin_ids) {
127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
128 file_util::FileEnumerator file_enumerator(data_path_, 165 file_util::FileEnumerator file_enumerator(data_path_,
129 false, file_util::FileEnumerator::DIRECTORIES); 166 false, file_util::FileEnumerator::DIRECTORIES);
130 for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); 167 for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
131 file_path = file_enumerator.Next()) { 168 file_path = file_enumerator.Next()) {
132 if (file_path.Extension() == IndexedDBContext::kIndexedDBExtension) { 169 if (file_path.Extension() == IndexedDBContext::kIndexedDBExtension) {
133 WebKit::WebString origin_id_webstring = 170 WebKit::WebString origin_id_webstring =
134 webkit_glue::FilePathToWebString(file_path.BaseName()); 171 webkit_glue::FilePathToWebString(file_path.BaseName());
135 origin_ids->push_back(origin_id_webstring); 172 origin_ids->push_back(origin_id_webstring);
136 } 173 }
137 } 174 }
138 } 175 }
139 176
177 int64 IndexedDBContext::GetOriginDiskUsage(const GURL& origin_url) {
178 return ResetDiskUsageCache(origin_url);
179 }
180
181 void IndexedDBContext::ConnectionOpened(const GURL& origin_url) {
182 if (quota_manager_proxy()) {
183 quota_manager_proxy()->NotifyStorageAccessed(
184 quota::QuotaClient::kIndexedDatabase, origin_url,
185 quota::kStorageTypeTemporary);
186 }
187 connection_count_[origin_url]++;
188 QueryAvailableQuota(origin_url);
189 EnsureDiskUsageCacheInitialized(origin_url);
190 }
191
192 void IndexedDBContext::ConnectionClosed(const GURL& origin_url) {
193 if (quota_manager_proxy()) {
194 quota_manager_proxy()->NotifyStorageAccessed(
195 quota::QuotaClient::kIndexedDatabase, origin_url,
196 quota::kStorageTypeTemporary);
197 }
198 connection_count_[origin_url]--;
199 if (connection_count_[origin_url] == 0) {
200 QueryDiskAndUpdateQuotaUsage(origin_url);
201 connection_count_.erase(origin_url);
202 }
203 }
204
205 void IndexedDBContext::TransactionComplete(const GURL& origin_url) {
206 QueryDiskAndUpdateQuotaUsage(origin_url);
207 QueryAvailableQuota(origin_url);
208 }
209
210 bool IndexedDBContext::WouldBeOverQuota(const GURL& origin_url,
211 int64 additional_bytes) {
212 if (space_available_map_.find(origin_url) == space_available_map_.end()) {
213 // We haven't heard back from the QuotaManager yet, just let it through.
214 return false;
215 }
216 bool over_quota = additional_bytes > space_available_map_[origin_url];
217 return over_quota;
218 }
219
220 bool IndexedDBContext::IsOverQuota(const GURL& origin_url) {
221 const int kOneAdditionalByte = 1;
222 return WouldBeOverQuota(origin_url, kOneAdditionalByte);
223 }
224
140 quota::QuotaManagerProxy* IndexedDBContext::quota_manager_proxy() { 225 quota::QuotaManagerProxy* IndexedDBContext::quota_manager_proxy() {
141 return quota_manager_proxy_; 226 return quota_manager_proxy_;
142 } 227 }
228
229 int64 IndexedDBContext::ReadUsageFromDisk(const GURL& origin_url) const {
230 string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url);
231 FilePath file_path = GetIndexedDBFilePath(origin_id);
232 return file_util::ComputeDirectorySize(file_path);
233 }
234
235 void IndexedDBContext::EnsureDiskUsageCacheInitialized(const GURL& origin_url) {
236 if (origin_size_map_.find(origin_url) == origin_size_map_.end())
237 ResetDiskUsageCache(origin_url);
238 }
239
240 void IndexedDBContext::QueryDiskAndUpdateQuotaUsage(const GURL& origin_url) {
241 EnsureDiskUsageCacheInitialized(origin_url);
242 int64 former_disk_usage = origin_size_map_[origin_url];
243 int64 current_disk_usage = ReadUsageFromDisk(origin_url);
244 int64 difference = current_disk_usage - former_disk_usage;
245 if (difference) {
246 origin_size_map_[origin_url] = current_disk_usage;
247 // quota_manager_proxy() is NULL in unit tests.
248 if (quota_manager_proxy())
249 quota_manager_proxy()->NotifyStorageModified(
250 quota::QuotaClient::kIndexedDatabase,
251 origin_url,
252 quota::kStorageTypeTemporary,
253 difference);
254 }
255 }
256
257 void IndexedDBContext::GotUpdatedQuota(const GURL& origin_url, int64 usage,
258 int64 quota) {
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
260 space_available_map_[origin_url] = quota - usage;
261 }
262
263 void IndexedDBContext::QueryAvailableQuota(const GURL& origin_url) {
264 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
266 if (quota_manager_proxy())
267 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
268 NewRunnableMethod(this, &IndexedDBContext::QueryAvailableQuota,
269 origin_url));
270 return;
271 }
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
273 if (!quota_manager_proxy()->quota_manager())
274 return;
275 IndexedDBGetUsageAndQuotaCallback* callback =
276 new IndexedDBGetUsageAndQuotaCallback(this, origin_url);
277 quota_manager_proxy()->quota_manager()->GetUsageAndQuota(
278 origin_url,
279 quota::kStorageTypeTemporary,
280 callback);
281 }
282
283 int64 IndexedDBContext::ResetDiskUsageCache(const GURL& origin_url) {
dgrogan 2011/08/04 23:44:56 The guts of the old "InitializeDiskUsage" are here
284 origin_size_map_[origin_url] = ReadUsageFromDisk(origin_url);
285 return origin_size_map_[origin_url];
286 }
OLDNEW
« no previous file with comments | « content/browser/in_process_webkit/indexed_db_context.h ('k') | content/browser/in_process_webkit/indexed_db_dispatcher_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698