| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/database/database_tracker.h" | 5 #include "webkit/database/database_tracker.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "app/sql/connection.h" | 9 #include "app/sql/connection.h" |
| 10 #include "app/sql/meta_table.h" | 10 #include "app/sql/meta_table.h" |
| 11 #include "app/sql/statement.h" | 11 #include "app/sql/statement.h" |
| 12 #include "app/sql/transaction.h" |
| 12 #include "base/basictypes.h" | 13 #include "base/basictypes.h" |
| 13 #include "base/file_path.h" | 14 #include "base/file_path.h" |
| 14 #include "base/file_util.h" | 15 #include "base/file_util.h" |
| 15 #include "base/string_util.h" | 16 #include "base/string_util.h" |
| 16 #include "webkit/database/databases_table.h" | 17 #include "webkit/database/databases_table.h" |
| 18 #include "webkit/database/quota_table.h" |
| 17 | 19 |
| 18 namespace webkit_database { | 20 namespace webkit_database { |
| 19 | 21 |
| 20 const FilePath::CharType kDatabaseDirectoryName[] = | 22 const FilePath::CharType kDatabaseDirectoryName[] = |
| 21 FILE_PATH_LITERAL("databases"); | 23 FILE_PATH_LITERAL("databases"); |
| 22 const FilePath::CharType kTrackerDatabaseFileName[] = | 24 const FilePath::CharType kTrackerDatabaseFileName[] = |
| 23 FILE_PATH_LITERAL("Databases.db"); | 25 FILE_PATH_LITERAL("Databases.db"); |
| 24 const int kCurrentVersion = 1; | 26 const int kCurrentVersion = 2; |
| 25 const int kCompatibleVersion = 1; | 27 const int kCompatibleVersion = 1; |
| 26 const int64 kDefaultQuota = 5 * 1024 * 1024; | 28 const int64 kDefaultQuota = 5 * 1024 * 1024; |
| 27 const int64 kDefaultExtensionQuota = 50 * 1024 * 1024; | 29 const int64 kDefaultExtensionQuota = 50 * 1024 * 1024; |
| 28 const char* kExtensionOriginIdentifierPrefix = "chrome-extension_"; | 30 const char* kExtensionOriginIdentifierPrefix = "chrome-extension_"; |
| 29 | 31 |
| 30 DatabaseTracker::DatabaseTracker(const FilePath& profile_path) | 32 DatabaseTracker::DatabaseTracker(const FilePath& profile_path) |
| 31 : initialized_(false), | 33 : initialized_(false), |
| 32 db_dir_(profile_path.Append(FilePath(kDatabaseDirectoryName))), | 34 db_dir_(profile_path.Append(FilePath(kDatabaseDirectoryName))), |
| 33 db_(new sql::Connection()), | 35 db_(new sql::Connection()), |
| 34 databases_table_(NULL), | 36 databases_table_(NULL), |
| (...skipping 11 matching lines...) Expand all Loading... |
| 46 int64* database_size, | 48 int64* database_size, |
| 47 int64* space_available) { | 49 int64* space_available) { |
| 48 if (!LazyInit()) { | 50 if (!LazyInit()) { |
| 49 *database_size = 0; | 51 *database_size = 0; |
| 50 *space_available = 0; | 52 *space_available = 0; |
| 51 return; | 53 return; |
| 52 } | 54 } |
| 53 | 55 |
| 54 InsertOrUpdateDatabaseDetails(origin_identifier, database_name, | 56 InsertOrUpdateDatabaseDetails(origin_identifier, database_name, |
| 55 database_description, estimated_size); | 57 database_description, estimated_size); |
| 58 database_connections_.AddConnection(origin_identifier, database_name); |
| 56 | 59 |
| 57 *database_size = GetCachedDatabaseFileSize(origin_identifier, database_name); | 60 CachedOriginInfo* info = GetCachedOriginInfo(origin_identifier); |
| 61 *database_size = (info ? info->GetDatabaseSize(database_name) : 0); |
| 58 *space_available = GetOriginSpaceAvailable(origin_identifier); | 62 *space_available = GetOriginSpaceAvailable(origin_identifier); |
| 59 } | 63 } |
| 60 | 64 |
| 61 void DatabaseTracker::DatabaseModified(const string16& origin_identifier, | 65 void DatabaseTracker::DatabaseModified(const string16& origin_identifier, |
| 62 const string16& database_name) { | 66 const string16& database_name) { |
| 63 if (!LazyInit()) | 67 if (!LazyInit()) |
| 64 return; | 68 return; |
| 65 | 69 |
| 66 int64 updated_db_size = | 70 int64 updated_db_size = |
| 67 UpdateCachedDatabaseFileSize(origin_identifier, database_name); | 71 UpdateCachedDatabaseFileSize(origin_identifier, database_name); |
| 68 int64 space_available = GetOriginSpaceAvailable(origin_identifier); | 72 int64 space_available = GetOriginSpaceAvailable(origin_identifier); |
| 69 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseSizeChanged( | 73 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseSizeChanged( |
| 70 origin_identifier, database_name, updated_db_size, space_available)); | 74 origin_identifier, database_name, updated_db_size, space_available)); |
| 71 } | 75 } |
| 72 | 76 |
| 73 void DatabaseTracker::DatabaseClosed(const string16& origin_identifier, | 77 void DatabaseTracker::DatabaseClosed(const string16& origin_identifier, |
| 74 const string16& database_name) { | 78 const string16& database_name) { |
| 75 // TODO(dumi): figure out how to use this information at a later time | 79 database_connections_.RemoveConnection(origin_identifier, database_name); |
| 80 } |
| 81 |
| 82 void DatabaseTracker::CloseDatabases(const DatabaseConnections& connections) { |
| 83 database_connections_.RemoveConnections(connections); |
| 76 } | 84 } |
| 77 | 85 |
| 78 void DatabaseTracker::AddObserver(Observer* observer) { | 86 void DatabaseTracker::AddObserver(Observer* observer) { |
| 79 observers_.AddObserver(observer); | 87 observers_.AddObserver(observer); |
| 80 } | 88 } |
| 81 | 89 |
| 82 void DatabaseTracker::RemoveObserver(Observer* observer) { | 90 void DatabaseTracker::RemoveObserver(Observer* observer) { |
| 83 // When we remove a listener, we do not know which cached information | 91 // When we remove a listener, we do not know which cached information |
| 84 // is still needed and which information can be discarded. So we just | 92 // is still needed and which information can be discarded. So we just |
| 85 // clear all caches and re-populate them as needed. | 93 // clear all caches and re-populate them as needed. |
| 86 observers_.RemoveObserver(observer); | 94 observers_.RemoveObserver(observer); |
| 87 ClearAllCachedOriginInfo(); | 95 ClearAllCachedOriginInfo(); |
| 88 } | 96 } |
| 89 | 97 |
| 90 void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() { | 98 void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() { |
| 91 ClearAllCachedOriginInfo(); | 99 ClearAllCachedOriginInfo(); |
| 92 meta_table_.reset(NULL); | 100 meta_table_.reset(NULL); |
| 93 databases_table_.reset(NULL); | 101 databases_table_.reset(NULL); |
| 102 quota_table_.reset(NULL); |
| 94 db_->Close(); | 103 db_->Close(); |
| 95 initialized_ = false; | 104 initialized_ = false; |
| 96 } | 105 } |
| 97 | 106 |
| 98 FilePath DatabaseTracker::GetFullDBFilePath( | 107 FilePath DatabaseTracker::GetFullDBFilePath( |
| 99 const string16& origin_identifier, | 108 const string16& origin_identifier, |
| 100 const string16& database_name) const { | 109 const string16& database_name) const { |
| 101 DCHECK(!origin_identifier.empty()); | 110 DCHECK(!origin_identifier.empty()); |
| 102 DCHECK(!database_name.empty()); | 111 DCHECK(!database_name.empty()); |
| 103 int64 id = databases_table_->GetDatabaseID( | 112 int64 id = databases_table_->GetDatabaseID( |
| 104 origin_identifier, database_name); | 113 origin_identifier, database_name); |
| 105 if (id < 0) | 114 if (id < 0) |
| 106 return FilePath(); | 115 return FilePath(); |
| 107 | 116 |
| 108 FilePath file_name = FilePath::FromWStringHack(Int64ToWString(id)); | 117 FilePath file_name = FilePath::FromWStringHack(Int64ToWString(id)); |
| 109 return db_dir_.Append(FilePath::FromWStringHack( | 118 return db_dir_.Append(FilePath::FromWStringHack( |
| 110 UTF16ToWide(origin_identifier))).Append(file_name); | 119 UTF16ToWide(origin_identifier))).Append(file_name); |
| 111 } | 120 } |
| 112 | 121 |
| 122 bool DatabaseTracker::GetAllOriginsInfo(std::vector<OriginInfo>* origins_info) { |
| 123 DCHECK(origins_info); |
| 124 DCHECK(origins_info->empty()); |
| 125 std::vector<string16> origins; |
| 126 if (!databases_table_->GetAllOrigins(&origins)) |
| 127 return false; |
| 128 |
| 129 for (std::vector<string16>::const_iterator it = origins.begin(); |
| 130 it != origins.end(); it++) { |
| 131 CachedOriginInfo* origin_info = GetCachedOriginInfo(*it); |
| 132 if (!origin_info) { |
| 133 // Restore 'origins_info' to its initial state. |
| 134 origins_info->clear(); |
| 135 return false; |
| 136 } |
| 137 origins_info->push_back(OriginInfo(*origin_info)); |
| 138 } |
| 139 |
| 140 return true; |
| 141 } |
| 142 |
| 143 void DatabaseTracker::SetOriginQuota(const string16& origin_identifier, |
| 144 int64 new_quota) { |
| 145 if (quota_table_->SetOriginQuota(origin_identifier, new_quota) && |
| 146 (origins_info_map_.find(origin_identifier) != origins_info_map_.end())) { |
| 147 origins_info_map_[origin_identifier].SetQuota(new_quota); |
| 148 } |
| 149 } |
| 150 |
| 151 bool DatabaseTracker::DeleteDatabase(const string16& origin_identifier, |
| 152 const string16& database_name) { |
| 153 // Check if the database is opened by any renderer. |
| 154 if (database_connections_.IsDatabaseOpened(origin_identifier, database_name)) |
| 155 return false; |
| 156 |
| 157 // Try to delete the file on the hard drive. |
| 158 FilePath db_file = GetFullDBFilePath(origin_identifier, database_name); |
| 159 if (file_util::PathExists(db_file) && !file_util::Delete(db_file, false)) |
| 160 return false; |
| 161 |
| 162 // Clean up the main database and invalidate the cached record. |
| 163 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name); |
| 164 origins_info_map_.erase(origin_identifier); |
| 165 return true; |
| 166 } |
| 167 |
| 168 bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) { |
| 169 // Check if any database in this origin is opened by any renderer. |
| 170 if (database_connections_.IsOriginUsed(origin_identifier)) |
| 171 return false; |
| 172 |
| 173 // We need to invalidate the cached record whether file_util::Delete() |
| 174 // succeeds or not, because even if it fails, it might still delete some |
| 175 // DB files on the hard drive. |
| 176 origins_info_map_.erase(origin_identifier); |
| 177 FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack( |
| 178 UTF16ToWide(origin_identifier))); |
| 179 if (!file_util::Delete(origin_dir, true)) |
| 180 return false; |
| 181 |
| 182 databases_table_->DeleteOrigin(origin_identifier); |
| 183 return true; |
| 184 } |
| 185 |
| 113 bool DatabaseTracker::LazyInit() { | 186 bool DatabaseTracker::LazyInit() { |
| 114 if (!initialized_) { | 187 if (!initialized_) { |
| 115 DCHECK(!db_->is_open()); | 188 DCHECK(!db_->is_open()); |
| 116 DCHECK(!databases_table_.get()); | 189 DCHECK(!databases_table_.get()); |
| 190 DCHECK(!quota_table_.get()); |
| 117 DCHECK(!meta_table_.get()); | 191 DCHECK(!meta_table_.get()); |
| 118 | 192 |
| 119 // If the tracker database exists, but it's corrupt or doesn't | 193 // If the tracker database exists, but it's corrupt or doesn't |
| 120 // have a meta table, delete the database directory | 194 // have a meta table, delete the database directory. |
| 121 const FilePath kTrackerDatabaseFullPath = | 195 const FilePath kTrackerDatabaseFullPath = |
| 122 db_dir_.Append(FilePath(kTrackerDatabaseFileName)); | 196 db_dir_.Append(FilePath(kTrackerDatabaseFileName)); |
| 123 if (file_util::DirectoryExists(db_dir_) && | 197 if (file_util::DirectoryExists(db_dir_) && |
| 124 file_util::PathExists(kTrackerDatabaseFullPath) && | 198 file_util::PathExists(kTrackerDatabaseFullPath) && |
| 125 (!db_->Open(kTrackerDatabaseFullPath) || | 199 (!db_->Open(kTrackerDatabaseFullPath) || |
| 126 !db_->DoesTableExist("meta"))) { | 200 !sql::MetaTable::DoesTableExist(db_.get()))) { |
| 127 db_->Close(); | 201 db_->Close(); |
| 128 if (!file_util::Delete(db_dir_, true)) | 202 if (!file_util::Delete(db_dir_, true)) |
| 129 return false; | 203 return false; |
| 130 } | 204 } |
| 131 | 205 |
| 132 databases_table_.reset(new DatabasesTable(db_.get())); | 206 databases_table_.reset(new DatabasesTable(db_.get())); |
| 207 quota_table_.reset(new QuotaTable(db_.get())); |
| 133 meta_table_.reset(new sql::MetaTable()); | 208 meta_table_.reset(new sql::MetaTable()); |
| 134 | 209 |
| 135 initialized_ = | 210 initialized_ = |
| 136 file_util::CreateDirectory(db_dir_) && | 211 file_util::CreateDirectory(db_dir_) && |
| 137 (db_->is_open() || db_->Open(kTrackerDatabaseFullPath)) && | 212 (db_->is_open() || db_->Open(kTrackerDatabaseFullPath)) && |
| 138 meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) && | 213 UpgradeToCurrentVersion(); |
| 139 (meta_table_->GetCompatibleVersionNumber() <= kCurrentVersion) && | |
| 140 databases_table_->Init(); | |
| 141 if (!initialized_) { | 214 if (!initialized_) { |
| 142 databases_table_.reset(NULL); | 215 databases_table_.reset(NULL); |
| 216 quota_table_.reset(NULL); |
| 143 meta_table_.reset(NULL); | 217 meta_table_.reset(NULL); |
| 144 db_->Close(); | 218 db_->Close(); |
| 145 } | 219 } |
| 146 } | 220 } |
| 147 return initialized_; | 221 return initialized_; |
| 148 } | 222 } |
| 149 | 223 |
| 224 bool DatabaseTracker::UpgradeToCurrentVersion() { |
| 225 sql::Transaction transaction(db_.get()); |
| 226 if (!transaction.Begin() || |
| 227 !meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) || |
| 228 (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) || |
| 229 !databases_table_->Init() || |
| 230 !quota_table_->Init()) |
| 231 return false; |
| 232 |
| 233 if (meta_table_->GetVersionNumber() < kCurrentVersion) |
| 234 meta_table_->SetVersionNumber(kCurrentVersion); |
| 235 |
| 236 return transaction.Commit(); |
| 237 } |
| 238 |
| 150 void DatabaseTracker::InsertOrUpdateDatabaseDetails( | 239 void DatabaseTracker::InsertOrUpdateDatabaseDetails( |
| 151 const string16& origin_identifier, | 240 const string16& origin_identifier, |
| 152 const string16& database_name, | 241 const string16& database_name, |
| 153 const string16& database_description, | 242 const string16& database_description, |
| 154 int64 estimated_size) { | 243 int64 estimated_size) { |
| 155 DatabaseDetails details; | 244 DatabaseDetails details; |
| 156 if (!databases_table_->GetDatabaseDetails( | 245 if (!databases_table_->GetDatabaseDetails( |
| 157 origin_identifier, database_name, &details)) { | 246 origin_identifier, database_name, &details)) { |
| 158 details.origin_identifier = origin_identifier; | 247 details.origin_identifier = origin_identifier; |
| 159 details.database_name = database_name; | 248 details.database_name = database_name; |
| 160 details.description = database_description; | 249 details.description = database_description; |
| 161 details.estimated_size = estimated_size; | 250 details.estimated_size = estimated_size; |
| 162 databases_table_->InsertDatabaseDetails(details); | 251 databases_table_->InsertDatabaseDetails(details); |
| 163 } else if ((details.description != database_description) || | 252 } else if ((details.description != database_description) || |
| 164 (details.estimated_size != estimated_size)) { | 253 (details.estimated_size != estimated_size)) { |
| 165 details.description = database_description; | 254 details.description = database_description; |
| 166 details.estimated_size = estimated_size; | 255 details.estimated_size = estimated_size; |
| 167 databases_table_->UpdateDatabaseDetails(details); | 256 databases_table_->UpdateDatabaseDetails(details); |
| 168 } | 257 } |
| 169 } | 258 } |
| 170 | 259 |
| 171 int64 DatabaseTracker::GetDBFileSize(const string16& origin_identifier, | |
| 172 const string16& database_name) const { | |
| 173 FilePath db_file_name = GetFullDBFilePath(origin_identifier, database_name); | |
| 174 int64 db_file_size = 0; | |
| 175 if (!file_util::GetFileSize(db_file_name, &db_file_size)) | |
| 176 db_file_size = 0; | |
| 177 return db_file_size; | |
| 178 } | |
| 179 | |
| 180 void DatabaseTracker::ClearAllCachedOriginInfo() { | 260 void DatabaseTracker::ClearAllCachedOriginInfo() { |
| 181 origins_info_map_.clear(); | 261 origins_info_map_.clear(); |
| 182 } | 262 } |
| 183 | 263 |
| 184 DatabaseTracker::CachedOriginInfo* DatabaseTracker::GetCachedOriginInfo( | 264 DatabaseTracker::CachedOriginInfo* DatabaseTracker::GetCachedOriginInfo( |
| 185 const string16& origin_identifier) { | 265 const string16& origin_identifier) { |
| 266 if (!LazyInit()) |
| 267 return NULL; |
| 268 |
| 186 // Populate the cache with data for this origin if needed. | 269 // Populate the cache with data for this origin if needed. |
| 187 if (origins_info_map_.find(origin_identifier) == origins_info_map_.end()) { | 270 if (origins_info_map_.find(origin_identifier) == origins_info_map_.end()) { |
| 188 std::vector<DatabaseDetails> details; | 271 std::vector<DatabaseDetails> details; |
| 189 if (!databases_table_->GetAllDatabaseDetailsForOrigin( | 272 if (!databases_table_->GetAllDatabaseDetailsForOrigin( |
| 190 origin_identifier, &details)) { | 273 origin_identifier, &details)) { |
| 191 return NULL; | 274 return NULL; |
| 192 } | 275 } |
| 193 | 276 |
| 194 CachedOriginInfo& origin_info = origins_info_map_[origin_identifier]; | 277 CachedOriginInfo& origin_info = origins_info_map_[origin_identifier]; |
| 278 origin_info.SetOrigin(origin_identifier); |
| 195 for (std::vector<DatabaseDetails>::const_iterator it = details.begin(); | 279 for (std::vector<DatabaseDetails>::const_iterator it = details.begin(); |
| 196 it != details.end(); it++) { | 280 it != details.end(); it++) { |
| 197 int64 db_file_size = | 281 int64 db_file_size = |
| 198 GetDBFileSize(it->origin_identifier, it->database_name); | 282 GetDBFileSize(origin_identifier, it->database_name); |
| 199 origin_info.SetCachedDatabaseSize(it->database_name, db_file_size); | 283 origin_info.SetDatabaseSize(it->database_name, db_file_size); |
| 284 } |
| 285 |
| 286 int64 origin_quota = quota_table_->GetOriginQuota(origin_identifier); |
| 287 if (origin_quota > 0) { |
| 288 origin_info.SetQuota(origin_quota); |
| 289 } else if (StartsWith(origin_identifier, |
| 290 ASCIIToUTF16(kExtensionOriginIdentifierPrefix), |
| 291 true)) { |
| 292 origin_info.SetQuota(kDefaultExtensionQuota); |
| 293 } else { |
| 294 origin_info.SetQuota(kDefaultQuota); |
| 200 } | 295 } |
| 201 } | 296 } |
| 202 | 297 |
| 203 return &origins_info_map_[origin_identifier]; | 298 return &origins_info_map_[origin_identifier]; |
| 204 } | 299 } |
| 205 | 300 |
| 206 int64 DatabaseTracker::GetCachedDatabaseFileSize( | 301 int64 DatabaseTracker::GetDBFileSize(const string16& origin_identifier, |
| 207 const string16& origin_identifier, | 302 const string16& database_name) const { |
| 208 const string16& database_name) { | 303 FilePath db_file_name = GetFullDBFilePath(origin_identifier, database_name); |
| 304 int64 db_file_size = 0; |
| 305 if (!file_util::GetFileSize(db_file_name, &db_file_size)) |
| 306 db_file_size = 0; |
| 307 return db_file_size; |
| 308 } |
| 309 |
| 310 int64 DatabaseTracker::GetOriginSpaceAvailable( |
| 311 const string16& origin_identifier) { |
| 209 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); | 312 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); |
| 210 if (!origin_info) | 313 if (!origin_info) |
| 211 return 0; | 314 return 0; |
| 212 return origin_info->GetCachedDatabaseSize(database_name); | 315 int64 space_available = origin_info->Quota() - origin_info->TotalSize(); |
| 316 return (space_available < 0 ? 0 : space_available); |
| 213 } | 317 } |
| 214 | 318 |
| 215 int64 DatabaseTracker::UpdateCachedDatabaseFileSize( | 319 int64 DatabaseTracker::UpdateCachedDatabaseFileSize( |
| 216 const string16& origin_identifier, | 320 const string16& origin_identifier, |
| 217 const string16& database_name) { | 321 const string16& database_name) { |
| 218 int64 new_size = GetDBFileSize(origin_identifier, database_name); | 322 int64 new_size = GetDBFileSize(origin_identifier, database_name); |
| 219 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); | 323 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); |
| 220 if (origin_info) | 324 if (origin_info) |
| 221 origin_info->SetCachedDatabaseSize(database_name, new_size); | 325 origin_info->SetDatabaseSize(database_name, new_size); |
| 222 return new_size; | 326 return new_size; |
| 223 } | 327 } |
| 224 | 328 |
| 225 int64 DatabaseTracker::GetOriginUsage(const string16& origin_identifier) { | |
| 226 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); | |
| 227 if (!origin_info) | |
| 228 return kint64max; | |
| 229 return origin_info->TotalSize(); | |
| 230 } | |
| 231 | |
| 232 int64 DatabaseTracker::GetOriginQuota( | |
| 233 const string16& origin_identifier) const { | |
| 234 if (StartsWith(origin_identifier, | |
| 235 ASCIIToUTF16(kExtensionOriginIdentifierPrefix), true)) { | |
| 236 return kDefaultExtensionQuota; | |
| 237 } | |
| 238 | |
| 239 return kDefaultQuota; | |
| 240 } | |
| 241 | |
| 242 int64 DatabaseTracker::GetOriginSpaceAvailable( | |
| 243 const string16& origin_identifier) { | |
| 244 int64 space_available = GetOriginQuota(origin_identifier) - | |
| 245 GetOriginUsage(origin_identifier); | |
| 246 return (space_available < 0 ? 0 : space_available); | |
| 247 } | |
| 248 | |
| 249 } // namespace webkit_database | 329 } // namespace webkit_database |
| OLD | NEW |