Chromium Code Reviews| 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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 93 } | 96 } |
| 94 | 97 |
| 95 FilePath IndexedDBContext::GetIndexedDBFilePath( | 98 FilePath IndexedDBContext::GetIndexedDBFilePath( |
| 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) { |
|
michaeln
2011/08/04 00:23:27
I don't see any external callers of this method, i
dgrogan
2011/08/04 19:47:50
Done.
| |
| 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::EvictOriginIfNotInUse(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 } | |
|
michaeln
2011/08/04 00:23:27
I think a call to quota->NotifyStorageModified(ori
dgrogan
2011/08/04 19:47:50
Good idea.
| |
| 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); | |
| 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]--; | |
| 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]++; | |
| 186 QueryAvailableQuota(origin_url); | |
| 187 } | |
| 188 | |
| 189 bool IndexedDBContext::WouldBeOverQuota(const GURL& origin_url, | |
| 190 int64 additional_bytes) { | |
| 191 if (space_available_map_.find(origin_url) == space_available_map_.end()) { | |
| 192 // We haven't heard back from the QuotaManager yet, just let it through. | |
| 193 return false; | |
| 194 } | |
| 195 bool over_quota = additional_bytes > space_available_map_[origin_url]; | |
| 196 return over_quota; | |
|
michaeln
2011/08/04 00:23:27
nit: could return the comparison result w/o the lo
| |
| 197 } | |
| 198 | |
| 199 bool IndexedDBContext::IsOverQuota(const GURL& origin_url) { | |
| 200 // Can we store an additional byte? | |
| 201 return WouldBeOverQuota(origin_url, 1 /*additional_bytes*/); | |
|
michaeln
2011/08/04 00:23:27
nit: instead of comments, consider self-documentin
dgrogan
2011/08/04 19:47:50
Done.
| |
| 202 } | |
| 203 | |
| 204 void IndexedDBContext::TransactionComplete(const GURL& origin_url) { | |
| 205 QueryDiskAndUpdateQuotaUsage(origin_url); | |
| 206 QueryAvailableQuota(origin_url); | |
| 207 } | |
| 208 | |
| 209 void IndexedDBContext::QueryDiskAndUpdateQuotaUsage(const GURL& origin_url) { | |
| 210 int64 former_disk_usage = origin_size_map_[origin_url]; | |
| 211 int64 current_disk_usage = ReadUsageFromDisk(origin_url); | |
| 212 int64 difference = current_disk_usage - former_disk_usage; | |
| 213 if (difference) { | |
| 214 quota_manager_proxy()->NotifyStorageModified( | |
| 215 quota::QuotaClient::kIndexedDatabase, | |
| 216 origin_url, | |
| 217 quota::kStorageTypeTemporary, | |
| 218 difference); | |
| 219 origin_size_map_[origin_url] = current_disk_usage; | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 void IndexedDBContext::GotUpdatedQuota(const GURL& origin_url, int64 usage, | |
| 224 int64 quota) { | |
| 225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
| 226 space_available_map_[origin_url] = quota - usage; | |
| 227 } | |
| 228 | |
| 229 class IndexedDBGetUsageAndQuotaCallback : | |
|
michaeln
2011/08/04 00:23:27
can this be in the anon namespace too, or maybe we
dgrogan
2011/08/04 19:47:50
I made it a nested class.
| |
| 230 public quota::QuotaManager::GetUsageAndQuotaCallback { | |
| 231 public: | |
| 232 IndexedDBGetUsageAndQuotaCallback(IndexedDBContext* context, | |
| 233 const GURL& origin_url) | |
| 234 : context_(context), | |
| 235 origin_url_(origin_url) { | |
| 236 } | |
| 237 | |
| 238 void Run(quota::QuotaStatusCode status, int64 usage, int64 quota) { | |
| 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 240 DCHECK(status == quota::kQuotaStatusOk || status == quota::kQuotaErrorAbort) | |
| 241 << "status was " << status; | |
| 242 if (status == quota::kQuotaErrorAbort) { | |
| 243 // We seem to no longer care to wait around for the answer. | |
| 244 return; | |
| 245 } | |
| 246 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, | |
| 247 NewRunnableMethod(context_.get(), | |
| 248 &IndexedDBContext::GotUpdatedQuota, | |
| 249 origin_url_, | |
| 250 usage, | |
| 251 quota)); | |
| 252 } | |
| 253 | |
| 254 virtual void RunWithParams( | |
| 255 const Tuple3<quota::QuotaStatusCode, int64, int64>& params) { | |
| 256 Run(params.a, params.b, params.c); | |
| 257 } | |
| 258 | |
| 259 private: | |
| 260 scoped_refptr<IndexedDBContext> context_; | |
| 261 const GURL origin_url_; | |
| 262 }; | |
| 263 | |
| 264 namespace { | |
| 265 | |
| 266 void RequestQuota( | |
|
michaeln
2011/08/04 00:23:27
I think some of this can be simplified by posting
dgrogan
2011/08/04 19:47:50
I got rid of this RequestQuota method by following
| |
| 267 scoped_refptr<quota::QuotaManagerProxy> proxy, const GURL& gurl, | |
| 268 IndexedDBGetUsageAndQuotaCallback* idb_quota_callback) { | |
| 269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 270 if (!proxy->quota_manager()) { | |
| 271 // QuotaManager was deleted on the IO thread just before this RequestQuota | |
| 272 // task was run. | |
| 273 return; | |
| 274 } | |
| 275 proxy->quota_manager()->GetUsageAndQuota( | |
| 276 gurl, | |
| 277 quota::kStorageTypeTemporary, | |
| 278 idb_quota_callback); | |
| 279 } | |
| 280 | |
| 281 } | |
| 282 | |
| 283 void IndexedDBContext::QueryAvailableQuota(const GURL& origin_url) { | |
| 284 IndexedDBGetUsageAndQuotaCallback* callback = | |
| 285 new IndexedDBGetUsageAndQuotaCallback(this, origin_url); | |
| 286 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 287 NewRunnableFunction(&RequestQuota, | |
| 288 make_scoped_refptr(quota_manager_proxy()), | |
| 289 origin_url, | |
| 290 callback)); | |
| 291 } | |
| 292 | |
| 140 quota::QuotaManagerProxy* IndexedDBContext::quota_manager_proxy() { | 293 quota::QuotaManagerProxy* IndexedDBContext::quota_manager_proxy() { |
| 141 return quota_manager_proxy_; | 294 return quota_manager_proxy_; |
| 142 } | 295 } |
| OLD | NEW |