OLD | NEW |
---|---|
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 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
96 const string16& origin_id) const { | 99 const string16& origin_id) const { |
97 FilePath::StringType id = | 100 FilePath::StringType id = |
98 webkit_glue::WebStringToFilePathString(origin_id).append( | 101 webkit_glue::WebStringToFilePathString(origin_id).append( |
99 FILE_PATH_LITERAL(".indexeddb")); | 102 FILE_PATH_LITERAL(".indexeddb")); |
100 return data_path_.Append(id.append(kIndexedDBExtension)); | 103 return data_path_.Append(id.append(kIndexedDBExtension)); |
101 } | 104 } |
102 | 105 |
103 void IndexedDBContext::DeleteIndexedDBFile(const FilePath& file_path) { | 106 void IndexedDBContext::DeleteIndexedDBFile(const FilePath& file_path) { |
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | 107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); |
105 // TODO(pastarmovj): Close all database connections that use that file. | 108 // TODO(pastarmovj): Close all database connections that use that file. |
106 file_util::Delete(file_path, false); | 109 file_util::Delete(file_path, true /*recursive*/); |
107 } | 110 } |
108 | 111 |
109 void IndexedDBContext::DeleteIndexedDBForOrigin(const string16& origin_id) { | 112 void IndexedDBContext::DeleteIndexedDBForOrigin(const string16& origin_id) { |
110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); |
111 // TODO(pastarmovj): Remove this check once we are safe to delete any time. | 114 // TODO(pastarmovj): Remove this check once we are safe to delete any time. |
112 FilePath idb_file = GetIndexedDBFilePath(origin_id); | 115 FilePath idb_file = GetIndexedDBFilePath(origin_id); |
113 DCHECK_EQ(idb_file.BaseName().value().substr(0, strlen("chrome-extension")), | 116 DCHECK_EQ(idb_file.BaseName().value().substr(0, strlen("chrome-extension")), |
114 FILE_PATH_LITERAL("chrome-extension")); | 117 FILE_PATH_LITERAL("chrome-extension")); |
115 DeleteIndexedDBFile(GetIndexedDBFilePath(origin_id)); | 118 DeleteIndexedDBFile(GetIndexedDBFilePath(origin_id)); |
116 } | 119 } |
117 | 120 |
121 // TODO(dgrogan): Once we can delete IndexedDB directories out from underneath | |
122 // open webkit instances, merge this and DeleteIndexedDBForOrigin. | |
123 void IndexedDBContext::EvictOrigin(const GURL& origin_url) { | |
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
125 if (connection_count_.find(origin_url) == connection_count_.end()) { | |
126 string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url); | |
127 FilePath idb_directory = GetIndexedDBFilePath(origin_id); | |
128 DeleteIndexedDBFile(idb_directory); | |
129 } | |
130 } | |
131 | |
118 bool IndexedDBContext::IsUnlimitedStorageGranted( | 132 bool IndexedDBContext::IsUnlimitedStorageGranted( |
119 const GURL& origin) const { | 133 const GURL& origin) const { |
120 return special_storage_policy_->IsStorageUnlimited(origin); | 134 return special_storage_policy_->IsStorageUnlimited(origin); |
121 } | 135 } |
122 | 136 |
123 // TODO(dgrogan): Merge this code with the similar loop in | 137 // TODO(dgrogan): Merge this code with the similar loop in |
124 // BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread. | 138 // BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread. |
125 void IndexedDBContext::GetAllOriginIdentifiers( | 139 void IndexedDBContext::GetAllOriginIdentifiers( |
126 std::vector<string16>* origin_ids) { | 140 std::vector<string16>* origin_ids) { |
127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); |
128 file_util::FileEnumerator file_enumerator(data_path_, | 142 file_util::FileEnumerator file_enumerator(data_path_, |
129 false, file_util::FileEnumerator::DIRECTORIES); | 143 false, file_util::FileEnumerator::DIRECTORIES); |
130 for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); | 144 for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); |
131 file_path = file_enumerator.Next()) { | 145 file_path = file_enumerator.Next()) { |
132 if (file_path.Extension() == IndexedDBContext::kIndexedDBExtension) { | 146 if (file_path.Extension() == IndexedDBContext::kIndexedDBExtension) { |
133 WebKit::WebString origin_id_webstring = | 147 WebKit::WebString origin_id_webstring = |
134 webkit_glue::FilePathToWebString(file_path.BaseName()); | 148 webkit_glue::FilePathToWebString(file_path.BaseName()); |
135 origin_ids->push_back(origin_id_webstring); | 149 origin_ids->push_back(origin_id_webstring); |
136 } | 150 } |
137 } | 151 } |
138 } | 152 } |
139 | 153 |
154 int64 IndexedDBContext::InitializeDiskUsage(const GURL& origin_url) { | |
155 int64 disk_usage = ReadUsageFromDisk(origin_url); | |
dgrogan
2011/08/03 01:41:29
This deviates from "the Michael design." This fun
michaeln
2011/08/03 03:40:40
Seems reasonable, although if you do have a cached
kinuko
2011/08/03 09:12:22
(fwiw: I'm planning to make QM purge its cache per
dgrogan
2011/08/04 23:44:55
I remember why this deviated. The test code write
| |
156 origin_size_map_[origin_url] = disk_usage; | |
157 return disk_usage; | |
158 } | |
159 | |
160 int64 IndexedDBContext::ReadUsageFromDisk(const GURL& origin_url) const { | |
161 string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url); | |
162 FilePath file_path = GetIndexedDBFilePath(origin_id); | |
163 return file_util::ComputeDirectorySize(file_path); | |
164 } | |
165 | |
166 void IndexedDBContext::ConnectionClosed(const GURL& origin_url) { | |
167 if (quota_manager_proxy()) { | |
168 quota_manager_proxy()->NotifyStorageAccessed( | |
169 quota::QuotaClient::kIndexedDatabase, origin_url, | |
170 quota::kStorageTypeTemporary); | |
171 } | |
172 connection_count_[origin_url] --; | |
kinuko
2011/08/03 09:12:22
nit: extra space before -- (here and at line 185)
dgrogan
2011/08/03 21:45:47
Done.
| |
173 if (connection_count_[origin_url] == 0) { | |
174 QueryDiskAndUpdateQuotaUsage(origin_url); | |
175 connection_count_.erase(origin_url); | |
176 } | |
177 } | |
178 | |
179 void IndexedDBContext::NewConnection(const GURL& origin_url) { | |
180 if (quota_manager_proxy()) { | |
181 quota_manager_proxy()->NotifyStorageAccessed( | |
182 quota::QuotaClient::kIndexedDatabase, origin_url, | |
183 quota::kStorageTypeTemporary); | |
184 } | |
185 connection_count_[origin_url] ++; | |
michaeln
2011/08/03 03:40:40
Seems like you may want to ensure you have a cache
dgrogan
2011/08/04 23:44:55
Done.
| |
186 QueryAvailableQuota(origin_url); | |
187 } | |
188 | |
189 bool IndexedDBContext::WouldBeOverQuota(const GURL& origin_url, | |
190 int64 additional_bytes) { | |
191 if (origin_allocated_quota_map_.find(origin_url) == | |
192 origin_allocated_quota_map_.end()) { | |
193 // We haven't heard back from the QuotaManager yet, just let it through. | |
dgrogan
2011/08/03 01:41:29
This happened a few times in the existing browser
| |
194 return false; | |
195 } | |
196 bool over_quota = additional_bytes + origin_size_map_[origin_url] > | |
michaeln
2011/08/03 03:40:40
Is this comparing apples to oranges?
The lhs is i
dgrogan
2011/08/03 21:45:47
No. I'm glad you noticed this.
| |
197 origin_allocated_quota_map_[origin_url]; | |
198 return over_quota; | |
199 } | |
200 | |
201 bool IndexedDBContext::IsOverQuota(const GURL& origin_url) { | |
202 return WouldBeOverQuota(origin_url, 0 /*additional_bytes*/); | |
michaeln
2011/08/03 03:40:40
return space_available <= 0;
dgrogan
2011/08/03 21:45:47
I did space_available < 1
| |
203 } | |
204 | |
205 void IndexedDBContext::TransactionComplete(const GURL& origin_url) { | |
206 QueryDiskAndUpdateQuotaUsage(origin_url); | |
207 QueryAvailableQuota(origin_url); | |
208 } | |
209 | |
210 void IndexedDBContext::QueryDiskAndUpdateQuotaUsage(const GURL& origin_url) { | |
211 int64 former_disk_usage = origin_size_map_[origin_url]; | |
212 int64 current_disk_usage = ReadUsageFromDisk(origin_url); | |
213 int64 difference = current_disk_usage - former_disk_usage; | |
214 if (difference) { | |
215 quota_manager_proxy()->NotifyStorageModified( | |
216 quota::QuotaClient::kIndexedDatabase, | |
217 origin_url, | |
218 quota::kStorageTypeTemporary, | |
219 difference); | |
220 origin_size_map_[origin_url] = current_disk_usage; | |
221 } | |
222 } | |
223 | |
224 void IndexedDBContext::GotUpdatedQuota(const GURL& origin_url, int64 usage, | |
225 int64 quota) { | |
226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
227 origin_allocated_quota_map_[origin_url] = quota; | |
michaeln
2011/08/03 03:40:40
do u really want space_available_map_[origin_url]
dgrogan
2011/08/03 21:45:47
Yes I do.
| |
228 } | |
229 | |
230 void GotUpdatedQuota(IndexedDBContext* context, const GURL& origin_url, | |
michaeln
2011/08/03 03:40:40
this should be static or in an anon namespace if i
dgrogan
2011/08/03 21:45:47
deleted
| |
231 int64 usage, int64 quota) { | |
232 context->GotUpdatedQuota(origin_url, usage, quota); | |
233 } | |
234 | |
235 class IndexedDBGetUsageAndQuotaCallback : | |
236 public quota::QuotaManager::GetUsageAndQuotaCallback { | |
237 public: | |
238 IndexedDBGetUsageAndQuotaCallback(IndexedDBContext* context, | |
239 const GURL& origin_url) | |
240 : context_(context), | |
241 origin_url_(origin_url) { | |
242 } | |
243 | |
244 void Run(quota::QuotaStatusCode status, int64 usage, int64 quota) { | |
245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
246 DCHECK(status == quota::kQuotaStatusOk || status == quota::kQuotaErrorAbort) | |
247 << "status was " << status; | |
248 if (status == quota::kQuotaErrorAbort) { | |
249 // We seem to no longer care to wait around for the answer. | |
250 return; | |
251 } | |
252 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, | |
253 NewRunnableFunction(&GotUpdatedQuota, | |
michaeln
2011/08/03 03:40:40
would a runnable object method work here inplace o
dgrogan
2011/08/03 21:45:47
Done.
| |
254 context_, | |
255 origin_url_, | |
256 usage, | |
257 quota)); | |
258 } | |
259 | |
260 virtual void RunWithParams( | |
261 const Tuple3<quota::QuotaStatusCode, int64, int64>& params) { | |
262 Run(params.a, params.b, params.c); | |
263 } | |
264 | |
265 private: | |
266 scoped_refptr<IndexedDBContext> context_; | |
267 const GURL origin_url_; | |
268 }; | |
269 | |
270 void RequestQuota( | |
michaeln
2011/08/03 03:40:40
ditto comment about static or anon namespace
dgrogan
2011/08/03 21:45:47
Now in an anon namespace.
| |
271 scoped_refptr<quota::QuotaManagerProxy> proxy, const GURL& gurl, | |
272 IndexedDBGetUsageAndQuotaCallback* idb_quota_callback) { | |
273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
274 if (!proxy->quota_manager()) { | |
dgrogan
2011/08/03 21:45:47
If I switched to NewRunnableMethod, I'm worried ab
| |
275 // QuotaManager was deleted on the IO thread just before this RequestQuota | |
276 // task was run. | |
277 return; | |
278 } | |
279 proxy->quota_manager()->GetUsageAndQuota( | |
280 gurl, | |
281 quota::kStorageTypeTemporary, | |
282 idb_quota_callback); | |
283 } | |
284 | |
285 void IndexedDBContext::QueryAvailableQuota(const GURL& origin_url) { | |
286 IndexedDBGetUsageAndQuotaCallback* callback = | |
287 new IndexedDBGetUsageAndQuotaCallback(this, origin_url); | |
288 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
289 NewRunnableFunction(&RequestQuota, | |
michaeln
2011/08/03 03:40:40
ditto question about runnable object method
dgrogan
2011/08/03 21:45:47
It seems like I'd want to post a RunnableMethod(qu
| |
290 scoped_refptr<quota::QuotaManagerProxy>( | |
291 quota_manager_proxy()), | |
292 origin_url, | |
293 callback)); | |
294 } | |
295 | |
140 quota::QuotaManagerProxy* IndexedDBContext::quota_manager_proxy() { | 296 quota::QuotaManagerProxy* IndexedDBContext::quota_manager_proxy() { |
141 return quota_manager_proxy_; | 297 return quota_manager_proxy_; |
142 } | 298 } |
OLD | NEW |