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

Side by Side Diff: sql/connection.cc

Issue 2397753005: [sql] Allow storing mmap status in a VIEW instead of meta table. (Closed)
Patch Set: OK, its an older SQLite on iOS. Created 4 years, 1 month 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
« no previous file with comments | « sql/connection.h ('k') | sql/connection_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "sql/connection.h" 5 #include "sql/connection.h"
6 6
7 #include <limits.h> 7 #include <limits.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 #include <string.h> 10 #include <string.h>
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 Connection::Connection() 311 Connection::Connection()
312 : db_(NULL), 312 : db_(NULL),
313 page_size_(0), 313 page_size_(0),
314 cache_size_(0), 314 cache_size_(0),
315 exclusive_locking_(false), 315 exclusive_locking_(false),
316 restrict_to_user_(false), 316 restrict_to_user_(false),
317 transaction_nesting_(0), 317 transaction_nesting_(0),
318 needs_rollback_(false), 318 needs_rollback_(false),
319 in_memory_(false), 319 in_memory_(false),
320 poisoned_(false), 320 poisoned_(false),
321 mmap_alt_status_(false),
321 mmap_disabled_(false), 322 mmap_disabled_(false),
322 mmap_enabled_(false), 323 mmap_enabled_(false),
323 total_changes_at_last_release_(0), 324 total_changes_at_last_release_(0),
324 stats_histogram_(NULL), 325 stats_histogram_(NULL),
325 commit_time_histogram_(NULL), 326 commit_time_histogram_(NULL),
326 autocommit_time_histogram_(NULL), 327 autocommit_time_histogram_(NULL),
327 update_time_histogram_(NULL), 328 update_time_histogram_(NULL),
328 query_time_histogram_(NULL), 329 query_time_histogram_(NULL),
329 clock_(new TimeSource()) { 330 clock_(new TimeSource()) {
330 } 331 }
(...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after
833 // keep close to the 2000-character size limit for dumping. 834 // keep close to the 2000-character size limit for dumping.
834 const size_t kMaxMessages = 20; 835 const size_t kMaxMessages = 20;
835 for (size_t i = 0; i < kMaxMessages && i < messages.size(); ++i) { 836 for (size_t i = 0; i < kMaxMessages && i < messages.size(); ++i) {
836 base::StringAppendF(&debug_info, "%s\n", messages[i].c_str()); 837 base::StringAppendF(&debug_info, "%s\n", messages[i].c_str());
837 } 838 }
838 } 839 }
839 840
840 return debug_info; 841 return debug_info;
841 } 842 }
842 843
844 bool Connection::GetMmapAltStatus(int64_t* status) {
845 // The [meta] version uses a missing table as a signal for a fresh database.
846 // That will not work for the view, which would not exist in either a new or
847 // an existing database. A new database _should_ be only one page long, so
848 // just don't bother optimizing this case (start at offset 0).
849 // TODO(shess): Could the [meta] case also get simpler, then?
850 if (!DoesViewExist("MmapStatus")) {
851 *status = 0;
852 return true;
853 }
854
855 const char* kMmapStatusSql = "SELECT * FROM MmapStatus";
856 Statement s(GetUniqueStatement(kMmapStatusSql));
857 if (s.Step())
858 *status = s.ColumnInt64(0);
859 return s.Succeeded();
860 }
861
862 bool Connection::SetMmapAltStatus(int64_t status) {
863 if (!BeginTransaction())
864 return false;
865
866 // View may not exist on first run.
867 if (!Execute("DROP VIEW IF EXISTS MmapStatus")) {
868 RollbackTransaction();
869 return false;
870 }
871
872 // Views live in the schema, so they cannot be parameterized. For an integer
873 // value, this construct should be safe from SQL injection, if the value
874 // becomes more complicated use "SELECT quote(?)" to generate a safe quoted
875 // value.
876 const std::string createViewSql =
877 base::StringPrintf("CREATE VIEW MmapStatus (value) AS SELECT %" PRId64,
878 status);
879 if (!Execute(createViewSql.c_str())) {
880 RollbackTransaction();
881 return false;
882 }
883
884 return CommitTransaction();
885 }
886
843 size_t Connection::GetAppropriateMmapSize() { 887 size_t Connection::GetAppropriateMmapSize() {
844 AssertIOAllowed(); 888 AssertIOAllowed();
845 889
846 #if defined(OS_IOS) && defined(USE_SYSTEM_SQLITE) 890 #if defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
847 if (!base::ios::IsRunningOnIOS10OrLater()) { 891 if (!base::ios::IsRunningOnIOS10OrLater()) {
848 // iOS SQLite does not support memory mapping. 892 // iOS SQLite does not support memory mapping.
849 return 0; 893 return 0;
850 } 894 }
851 #endif 895 #endif
852 896
853 // How much to map if no errors are found. 50MB encompasses the 99th 897 // How much to map if no errors are found. 50MB encompasses the 99th
854 // percentile of Chrome databases in the wild, so this should be good. 898 // percentile of Chrome databases in the wild, so this should be good.
855 const size_t kMmapEverything = 256 * 1024 * 1024; 899 const size_t kMmapEverything = 256 * 1024 * 1024;
856 900
857 // If the database doesn't have a place to track progress, assume the best. 901 // Progress information is tracked in the [meta] table for databases which use
858 // This will happen when new databases are created, or if a database doesn't 902 // sql::MetaTable, otherwise it is tracked in a special view.
859 // use a meta table. sql::MetaTable::Init() will preload kMmapSuccess. 903 // TODO(shess): Move all cases to the view implementation.
860 // TODO(shess): Databases not using meta include: 904 int64_t mmap_ofs = 0;
861 // DOMStorageDatabase (localstorage) 905 if (mmap_alt_status_) {
862 // ActivityDatabase (extensions activity log) 906 if (!GetMmapAltStatus(&mmap_ofs)) {
863 // PredictorDatabase (prefetch and autocomplete predictor data) 907 RecordOneEvent(EVENT_MMAP_STATUS_FAILURE_READ);
864 // SyncDirectory (sync metadata storage) 908 return 0;
865 // For now, these all have mmap disabled to allow other databases to get the 909 }
866 // default-enable path. sqlite-diag could be an alternative for all but 910 } else {
867 // DOMStorageDatabase, which creates many small databases. 911 // If [meta] doesn't exist, yet, it's a new database, assume the best.
868 // http://crbug.com/537742 912 // sql::MetaTable::Init() will preload kMmapSuccess.
869 if (!MetaTable::DoesTableExist(this)) { 913 if (!MetaTable::DoesTableExist(this)) {
870 RecordOneEvent(EVENT_MMAP_META_MISSING); 914 RecordOneEvent(EVENT_MMAP_META_MISSING);
871 return kMmapEverything; 915 return kMmapEverything;
872 } 916 }
873 917
874 int64_t mmap_ofs = 0; 918 if (!MetaTable::GetMmapStatus(this, &mmap_ofs)) {
875 if (!MetaTable::GetMmapStatus(this, &mmap_ofs)) { 919 RecordOneEvent(EVENT_MMAP_META_FAILURE_READ);
876 RecordOneEvent(EVENT_MMAP_META_FAILURE_READ); 920 return 0;
877 return 0; 921 }
878 } 922 }
879 923
880 // Database read failed in the past, don't memory map. 924 // Database read failed in the past, don't memory map.
881 if (mmap_ofs == MetaTable::kMmapFailure) { 925 if (mmap_ofs == MetaTable::kMmapFailure) {
882 RecordOneEvent(EVENT_MMAP_FAILED); 926 RecordOneEvent(EVENT_MMAP_FAILED);
883 return 0; 927 return 0;
884 } else if (mmap_ofs != MetaTable::kMmapSuccess) { 928 } else if (mmap_ofs != MetaTable::kMmapSuccess) {
885 // Continue reading from previous offset. 929 // Continue reading from previous offset.
886 DCHECK_GE(mmap_ofs, 0); 930 DCHECK_GE(mmap_ofs, 0);
887 931
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
942 if (mmap_ofs >= db_size) { 986 if (mmap_ofs >= db_size) {
943 mmap_ofs = MetaTable::kMmapSuccess; 987 mmap_ofs = MetaTable::kMmapSuccess;
944 event = EVENT_MMAP_SUCCESS_NEW; 988 event = EVENT_MMAP_SUCCESS_NEW;
945 } else if (mmap_ofs > 0) { 989 } else if (mmap_ofs > 0) {
946 event = EVENT_MMAP_SUCCESS_PARTIAL; 990 event = EVENT_MMAP_SUCCESS_PARTIAL;
947 } else { 991 } else {
948 DCHECK_EQ(MetaTable::kMmapFailure, mmap_ofs); 992 DCHECK_EQ(MetaTable::kMmapFailure, mmap_ofs);
949 event = EVENT_MMAP_FAILED_NEW; 993 event = EVENT_MMAP_FAILED_NEW;
950 } 994 }
951 995
952 if (!MetaTable::SetMmapStatus(this, mmap_ofs)) { 996 if (mmap_alt_status_) {
953 RecordOneEvent(EVENT_MMAP_META_FAILURE_UPDATE); 997 if (!SetMmapAltStatus(mmap_ofs)) {
954 return 0; 998 RecordOneEvent(EVENT_MMAP_STATUS_FAILURE_UPDATE);
999 return 0;
1000 }
1001 } else {
1002 if (!MetaTable::SetMmapStatus(this, mmap_ofs)) {
1003 RecordOneEvent(EVENT_MMAP_META_FAILURE_UPDATE);
1004 return 0;
1005 }
955 } 1006 }
956 1007
957 RecordOneEvent(event); 1008 RecordOneEvent(event);
958 } 1009 }
959 } 1010 }
960 1011
961 if (mmap_ofs == MetaTable::kMmapFailure) 1012 if (mmap_ofs == MetaTable::kMmapFailure)
962 return 0; 1013 return 0;
963 if (mmap_ofs == MetaTable::kMmapSuccess) 1014 if (mmap_ofs == MetaTable::kMmapSuccess)
964 return kMmapEverything; 1015 return kMmapEverything;
(...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after
1496 } 1547 }
1497 1548
1498 sqlite3_stmt* stmt = NULL; 1549 sqlite3_stmt* stmt = NULL;
1499 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) 1550 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK)
1500 return false; 1551 return false;
1501 1552
1502 sqlite3_finalize(stmt); 1553 sqlite3_finalize(stmt);
1503 return true; 1554 return true;
1504 } 1555 }
1505 1556
1506 bool Connection::DoesTableExist(const char* table_name) const { 1557 bool Connection::DoesIndexExist(const char* index_name) const {
1507 return DoesTableOrIndexExist(table_name, "table"); 1558 return DoesSchemaItemExist(index_name, "index");
1508 } 1559 }
1509 1560
1510 bool Connection::DoesIndexExist(const char* index_name) const { 1561 bool Connection::DoesTableExist(const char* table_name) const {
1511 return DoesTableOrIndexExist(index_name, "index"); 1562 return DoesSchemaItemExist(table_name, "table");
1512 } 1563 }
1513 1564
1514 bool Connection::DoesTableOrIndexExist( 1565 bool Connection::DoesViewExist(const char* view_name) const {
1566 return DoesSchemaItemExist(view_name, "view");
1567 }
1568
1569 bool Connection::DoesSchemaItemExist(
1515 const char* name, const char* type) const { 1570 const char* name, const char* type) const {
1516 const char* kSql = 1571 const char* kSql =
1517 "SELECT name FROM sqlite_master WHERE type=? AND name=? COLLATE NOCASE"; 1572 "SELECT name FROM sqlite_master WHERE type=? AND name=? COLLATE NOCASE";
1518 Statement statement(GetUntrackedStatement(kSql)); 1573 Statement statement(GetUntrackedStatement(kSql));
1519 1574
1520 // This can happen if the database is corrupt and the error is a test 1575 // This can happen if the database is corrupt and the error is a test
1521 // expectation. 1576 // expectation.
1522 if (!statement.is_valid()) 1577 if (!statement.is_valid())
1523 return false; 1578 return false;
1524 1579
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
1987 ignore_result(Execute(kNoWritableSchema)); 2042 ignore_result(Execute(kNoWritableSchema));
1988 2043
1989 return ret; 2044 return ret;
1990 } 2045 }
1991 2046
1992 base::TimeTicks TimeSource::Now() { 2047 base::TimeTicks TimeSource::Now() {
1993 return base::TimeTicks::Now(); 2048 return base::TimeTicks::Now();
1994 } 2049 }
1995 2050
1996 } // namespace sql 2051 } // namespace sql
OLDNEW
« no previous file with comments | « sql/connection.h ('k') | sql/connection_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698