Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "storage/browser/quota/quota_database.h" | 5 #include "storage/browser/quota/quota_database.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
| 13 #include "sql/connection.h" | 13 #include "sql/connection.h" |
| 14 #include "sql/meta_table.h" | 14 #include "sql/meta_table.h" |
| 15 #include "sql/statement.h" | 15 #include "sql/statement.h" |
| 16 #include "sql/transaction.h" | 16 #include "sql/transaction.h" |
| 17 #include "storage/browser/quota/special_storage_policy.h" | 17 #include "storage/browser/quota/special_storage_policy.h" |
| 18 | 18 |
| 19 namespace storage { | 19 namespace storage { |
| 20 namespace { | 20 namespace { |
| 21 | 21 |
| 22 // Definitions for database schema. | 22 // Definitions for database schema. |
| 23 | 23 |
| 24 const int kCurrentVersion = 4; | 24 const int kCurrentVersion = 5; |
| 25 const int kCompatibleVersion = 2; | 25 const int kCompatibleVersion = 2; |
| 26 | 26 |
| 27 const char kHostQuotaTable[] = "HostQuotaTable"; | 27 const char kHostQuotaTable[] = "HostQuotaTable"; |
| 28 const char kOriginInfoTable[] = "OriginInfoTable"; | 28 const char kOriginInfoTable[] = "OriginInfoTable"; |
| 29 const char kEvictionInfoTable[] = "EvictionInfoTable"; | |
| 29 const char kIsOriginTableBootstrapped[] = "IsOriginTableBootstrapped"; | 30 const char kIsOriginTableBootstrapped[] = "IsOriginTableBootstrapped"; |
| 30 | 31 |
| 31 bool VerifyValidQuotaConfig(const char* key) { | 32 bool VerifyValidQuotaConfig(const char* key) { |
| 32 return (key != NULL && | 33 return (key != NULL && |
| 33 (!strcmp(key, QuotaDatabase::kDesiredAvailableSpaceKey) || | 34 (!strcmp(key, QuotaDatabase::kDesiredAvailableSpaceKey) || |
| 34 !strcmp(key, QuotaDatabase::kTemporaryQuotaOverrideKey))); | 35 !strcmp(key, QuotaDatabase::kTemporaryQuotaOverrideKey))); |
| 35 } | 36 } |
| 36 | 37 |
| 37 const int kCommitIntervalMs = 30000; | 38 const int kCommitIntervalMs = 30000; |
| 38 | 39 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 55 } | 56 } |
| 56 | 57 |
| 57 } // anonymous namespace | 58 } // anonymous namespace |
| 58 | 59 |
| 59 // static | 60 // static |
| 60 const char QuotaDatabase::kDesiredAvailableSpaceKey[] = "DesiredAvailableSpace"; | 61 const char QuotaDatabase::kDesiredAvailableSpaceKey[] = "DesiredAvailableSpace"; |
| 61 const char QuotaDatabase::kTemporaryQuotaOverrideKey[] = | 62 const char QuotaDatabase::kTemporaryQuotaOverrideKey[] = |
| 62 "TemporaryQuotaOverride"; | 63 "TemporaryQuotaOverride"; |
| 63 | 64 |
| 64 const QuotaDatabase::TableSchema QuotaDatabase::kTables[] = { | 65 const QuotaDatabase::TableSchema QuotaDatabase::kTables[] = { |
| 65 { kHostQuotaTable, | 66 {kHostQuotaTable, |
| 66 "(host TEXT NOT NULL," | 67 "(host TEXT NOT NULL," |
| 67 " type INTEGER NOT NULL," | 68 " type INTEGER NOT NULL," |
| 68 " quota INTEGER DEFAULT 0," | 69 " quota INTEGER DEFAULT 0," |
| 69 " UNIQUE(host, type))" }, | 70 " UNIQUE(host, type))"}, |
| 70 { kOriginInfoTable, | 71 {kOriginInfoTable, |
| 71 "(origin TEXT NOT NULL," | 72 "(origin TEXT NOT NULL," |
| 72 " type INTEGER NOT NULL," | 73 " type INTEGER NOT NULL," |
| 73 " used_count INTEGER DEFAULT 0," | 74 " used_count INTEGER DEFAULT 0," |
| 74 " last_access_time INTEGER DEFAULT 0," | 75 " last_access_time INTEGER DEFAULT 0," |
| 75 " last_modified_time INTEGER DEFAULT 0," | 76 " last_modified_time INTEGER DEFAULT 0," |
| 76 " UNIQUE(origin, type))" }, | 77 " UNIQUE(origin, type))"}, |
| 77 }; | 78 {kEvictionInfoTable, |
| 79 "(origin TEXT NOT NULL," | |
| 80 " type INTEGER NOT NULL," | |
| 81 " last_eviction_time INTEGER DEFAULT 0," | |
| 82 " UNIQUE(origin, type))"}}; | |
| 78 | 83 |
| 79 // static | 84 // static |
| 80 const QuotaDatabase::IndexSchema QuotaDatabase::kIndexes[] = { | 85 const QuotaDatabase::IndexSchema QuotaDatabase::kIndexes[] = { |
| 81 { "HostIndex", | 86 { "HostIndex", |
| 82 kHostQuotaTable, | 87 kHostQuotaTable, |
| 83 "(host)", | 88 "(host)", |
| 84 false }, | 89 false }, |
| 85 { "OriginInfoIndex", | 90 { "OriginInfoIndex", |
| 86 kOriginInfoTable, | 91 kOriginInfoTable, |
| 87 "(origin)", | 92 "(origin)", |
| 88 false }, | 93 false }, |
| 89 { "OriginLastAccessTimeIndex", | 94 { "OriginLastAccessTimeIndex", |
| 90 kOriginInfoTable, | 95 kOriginInfoTable, |
| 91 "(last_access_time)", | 96 "(last_access_time)", |
| 92 false }, | 97 false }, |
| 93 { "OriginLastModifiedTimeIndex", | 98 { "OriginLastModifiedTimeIndex", |
| 94 kOriginInfoTable, | 99 kOriginInfoTable, |
| 95 "(last_modified_time)", | 100 "(last_modified_time)", |
| 96 false }, | 101 false }, |
|
michaeln
2015/10/13 21:35:36
do you want an index on the origin column?
calamity
2015/10/15 07:56:43
Hmm. I don't think it will be necessary. We're not
| |
| 97 }; | 102 }; |
| 98 | 103 |
| 99 struct QuotaDatabase::QuotaTableImporter { | 104 struct QuotaDatabase::QuotaTableImporter { |
| 100 bool Append(const QuotaTableEntry& entry) { | 105 bool Append(const QuotaTableEntry& entry) { |
| 101 entries.push_back(entry); | 106 entries.push_back(entry); |
| 102 return true; | 107 return true; |
| 103 } | 108 } |
| 104 std::vector<QuotaTableEntry> entries; | 109 std::vector<QuotaTableEntry> entries; |
| 105 }; | 110 }; |
| 106 | 111 |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 statement.BindString(1, origin.spec()); | 262 statement.BindString(1, origin.spec()); |
| 258 statement.BindInt(2, static_cast<int>(type)); | 263 statement.BindInt(2, static_cast<int>(type)); |
| 259 | 264 |
| 260 if (!statement.Run()) | 265 if (!statement.Run()) |
| 261 return false; | 266 return false; |
| 262 | 267 |
| 263 ScheduleCommit(); | 268 ScheduleCommit(); |
| 264 return true; | 269 return true; |
| 265 } | 270 } |
| 266 | 271 |
| 272 bool QuotaDatabase::GetOriginLastEvictionTime(const GURL& origin, | |
| 273 StorageType type, | |
| 274 base::Time* last_modified_time) { | |
| 275 DCHECK(last_modified_time); | |
| 276 if (!LazyOpen(false)) | |
| 277 return false; | |
| 278 | |
| 279 const char* kSql = | |
| 280 "SELECT last_eviction_time" | |
| 281 " FROM EvictionInfoTable" | |
| 282 " WHERE origin = ? AND type = ?"; | |
| 283 | |
| 284 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
| 285 statement.BindString(0, origin.spec()); | |
| 286 statement.BindInt(1, static_cast<int>(type)); | |
| 287 | |
| 288 if (!statement.Step()) | |
| 289 return statement.Succeeded(); | |
| 290 | |
| 291 *last_modified_time = base::Time::FromInternalValue(statement.ColumnInt64(0)); | |
| 292 return true; | |
| 293 } | |
| 294 | |
| 295 bool QuotaDatabase::SetOriginLastEvictionTime(const GURL& origin, | |
| 296 StorageType type, | |
| 297 base::Time last_modified_time) { | |
| 298 if (!LazyOpen(true)) | |
| 299 return false; | |
| 300 | |
| 301 const char* kSql = | |
| 302 "INSERT OR REPLACE INTO EvictionInfoTable" | |
| 303 " (last_eviction_time, origin, type)" | |
| 304 " VALUES (?, ?, ?)"; | |
| 305 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
| 306 statement.BindInt64(0, last_modified_time.ToInternalValue()); | |
| 307 statement.BindString(1, origin.spec()); | |
| 308 statement.BindInt(2, static_cast<int>(type)); | |
| 309 | |
| 310 if (!statement.Run()) | |
| 311 return false; | |
| 312 | |
| 313 ScheduleCommit(); | |
| 314 return true; | |
| 315 } | |
| 316 | |
| 317 bool QuotaDatabase::DeleteOriginLastEvictionTime(const GURL& origin, | |
| 318 StorageType type) { | |
| 319 if (!LazyOpen(false)) | |
| 320 return false; | |
| 321 | |
| 322 const char* kSql = | |
| 323 "DELETE FROM EvictionInfoTable" | |
| 324 " WHERE origin = ? AND type = ?"; | |
| 325 | |
| 326 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | |
| 327 statement.BindString(0, origin.spec()); | |
| 328 statement.BindInt(1, static_cast<int>(type)); | |
| 329 | |
| 330 if (!statement.Run()) | |
| 331 return false; | |
| 332 | |
| 333 ScheduleCommit(); | |
| 334 return true; | |
| 335 } | |
| 336 | |
| 267 bool QuotaDatabase::RegisterInitialOriginInfo( | 337 bool QuotaDatabase::RegisterInitialOriginInfo( |
| 268 const std::set<GURL>& origins, StorageType type) { | 338 const std::set<GURL>& origins, StorageType type) { |
| 269 if (!LazyOpen(true)) | 339 if (!LazyOpen(true)) |
| 270 return false; | 340 return false; |
| 271 | 341 |
| 272 typedef std::set<GURL>::const_iterator itr_type; | 342 typedef std::set<GURL>::const_iterator itr_type; |
| 273 for (itr_type itr = origins.begin(), end = origins.end(); | 343 for (itr_type itr = origins.begin(), end = origins.end(); |
| 274 itr != end; ++itr) { | 344 itr != end; ++itr) { |
| 275 const char* kSql = | 345 const char* kSql = |
| 276 "INSERT OR IGNORE INTO OriginInfoTable" | 346 "INSERT OR IGNORE INTO OriginInfoTable" |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 596 | 666 |
| 597 // So we can't go recursive. | 667 // So we can't go recursive. |
| 598 if (is_recreating_) | 668 if (is_recreating_) |
| 599 return false; | 669 return false; |
| 600 | 670 |
| 601 base::AutoReset<bool> auto_reset(&is_recreating_, true); | 671 base::AutoReset<bool> auto_reset(&is_recreating_, true); |
| 602 return LazyOpen(true); | 672 return LazyOpen(true); |
| 603 } | 673 } |
| 604 | 674 |
| 605 bool QuotaDatabase::UpgradeSchema(int current_version) { | 675 bool QuotaDatabase::UpgradeSchema(int current_version) { |
| 676 bool upgraded = false; | |
| 606 if (current_version == 2) { | 677 if (current_version == 2) { |
| 607 QuotaTableImporter importer; | 678 QuotaTableImporter importer; |
| 608 typedef std::vector<QuotaTableEntry> QuotaTableEntries; | 679 typedef std::vector<QuotaTableEntry> QuotaTableEntries; |
| 609 if (!DumpQuotaTable(base::Bind(&QuotaTableImporter::Append, | 680 if (!DumpQuotaTable(base::Bind(&QuotaTableImporter::Append, |
| 610 base::Unretained(&importer)))) { | 681 base::Unretained(&importer)))) { |
| 611 return false; | 682 return false; |
| 612 } | 683 } |
| 613 ResetSchema(); | 684 ResetSchema(); |
| 614 for (QuotaTableEntries::const_iterator iter = importer.entries.begin(); | 685 for (QuotaTableEntries::const_iterator iter = importer.entries.begin(); |
| 615 iter != importer.entries.end(); ++iter) { | 686 iter != importer.entries.end(); ++iter) { |
| 616 if (!SetHostQuota(iter->host, iter->type, iter->quota)) | 687 if (!SetHostQuota(iter->host, iter->type, iter->quota)) |
| 617 return false; | 688 return false; |
| 618 } | 689 } |
| 619 Commit(); | 690 Commit(); |
| 620 return true; | 691 upgraded = true; |
| 692 } else if (current_version < 5) { | |
| 693 const QuotaDatabase::TableSchema& eviction_table_schema = kTables[2]; | |
| 694 DCHECK_EQ(strcmp(kEvictionInfoTable, eviction_table_schema.table_name), 0); | |
| 695 | |
| 696 std::string sql("CREATE TABLE "); | |
| 697 sql += eviction_table_schema.table_name; | |
| 698 sql += eviction_table_schema.columns; | |
| 699 if (!db_->Execute(sql.c_str())) { | |
| 700 VLOG(1) << "Failed to execute " << sql; | |
| 701 return false; | |
| 702 } | |
|
michaeln
2015/10/13 21:35:36
do you want an index on the origin column?
calamity
2015/10/15 07:56:43
See above.
| |
| 703 | |
| 704 meta_table_->SetVersionNumber(5); | |
|
michaeln
2015/10/13 21:35:36
i think you want to to Commit() here
calamity
2015/10/15 07:56:43
Done.
calamity
2015/10/15 11:11:06
Oops, missed this one. Will do it tomorrow.
| |
| 705 upgraded = true; | |
| 621 } | 706 } |
| 622 return false; | 707 return upgraded; |
| 623 } | 708 } |
| 624 | 709 |
| 625 bool QuotaDatabase::DumpQuotaTable(const QuotaTableCallback& callback) { | 710 bool QuotaDatabase::DumpQuotaTable(const QuotaTableCallback& callback) { |
| 626 if (!LazyOpen(true)) | 711 if (!LazyOpen(true)) |
| 627 return false; | 712 return false; |
| 628 | 713 |
| 629 const char* kSql = "SELECT * FROM HostQuotaTable"; | 714 const char* kSql = "SELECT * FROM HostQuotaTable"; |
| 630 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); | 715 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); |
| 631 | 716 |
| 632 while (statement.Step()) { | 717 while (statement.Step()) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 680 if (lhs.origin < rhs.origin) return true; | 765 if (lhs.origin < rhs.origin) return true; |
| 681 if (rhs.origin < lhs.origin) return false; | 766 if (rhs.origin < lhs.origin) return false; |
| 682 if (lhs.type < rhs.type) return true; | 767 if (lhs.type < rhs.type) return true; |
| 683 if (rhs.type < lhs.type) return false; | 768 if (rhs.type < lhs.type) return false; |
| 684 if (lhs.used_count < rhs.used_count) return true; | 769 if (lhs.used_count < rhs.used_count) return true; |
| 685 if (rhs.used_count < lhs.used_count) return false; | 770 if (rhs.used_count < lhs.used_count) return false; |
| 686 return lhs.last_access_time < rhs.last_access_time; | 771 return lhs.last_access_time < rhs.last_access_time; |
| 687 } | 772 } |
| 688 | 773 |
| 689 } // namespace storage | 774 } // namespace storage |
| OLD | NEW |