OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |