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 <string.h> | 7 #include <string.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/debug/dump_without_crashing.h" | 10 #include "base/debug/dump_without_crashing.h" |
(...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 if (rc != SQLITE_OK) | 530 if (rc != SQLITE_OK) |
531 return; | 531 return; |
532 | 532 |
533 // Don't preload more than the file contains. | 533 // Don't preload more than the file contains. |
534 if (preload_size > file_size) | 534 if (preload_size > file_size) |
535 preload_size = file_size; | 535 preload_size = file_size; |
536 | 536 |
537 scoped_ptr<char[]> buf(new char[page_size]); | 537 scoped_ptr<char[]> buf(new char[page_size]); |
538 for (sqlite3_int64 pos = 0; pos < preload_size; pos += page_size) { | 538 for (sqlite3_int64 pos = 0; pos < preload_size; pos += page_size) { |
539 rc = file->pMethods->xRead(file, buf.get(), page_size, pos); | 539 rc = file->pMethods->xRead(file, buf.get(), page_size, pos); |
540 | |
541 // TODO(shess): Consider calling OnSqliteError(). | |
542 if (rc != SQLITE_OK) | 540 if (rc != SQLITE_OK) |
543 return; | 541 return; |
544 } | 542 } |
545 } | 543 } |
546 | 544 |
547 // SQLite keeps unused pages associated with a connection in a cache. It asks | 545 // SQLite keeps unused pages associated with a connection in a cache. It asks |
548 // the cache for pages by an id, and if the page is present and the database is | 546 // the cache for pages by an id, and if the page is present and the database is |
549 // unchanged, it considers the content of the page valid and doesn't read it | 547 // unchanged, it considers the content of the page valid and doesn't read it |
550 // from disk. When memory-mapped I/O is enabled, on read SQLite uses page | 548 // from disk. When memory-mapped I/O is enabled, on read SQLite uses page |
551 // structures created from the memory map data before consulting the cache. On | 549 // structures created from the memory map data before consulting the cache. On |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
856 // keep close to the 2000-character size limit for dumping. | 854 // keep close to the 2000-character size limit for dumping. |
857 const size_t kMaxMessages = 20; | 855 const size_t kMaxMessages = 20; |
858 for (size_t i = 0; i < kMaxMessages && i < messages.size(); ++i) { | 856 for (size_t i = 0; i < kMaxMessages && i < messages.size(); ++i) { |
859 base::StringAppendF(&debug_info, "%s\n", messages[i].c_str()); | 857 base::StringAppendF(&debug_info, "%s\n", messages[i].c_str()); |
860 } | 858 } |
861 } | 859 } |
862 | 860 |
863 return debug_info; | 861 return debug_info; |
864 } | 862 } |
865 | 863 |
866 size_t Connection::GetAppropriateMmapSize() { | |
867 AssertIOAllowed(); | |
868 | |
869 // TODO(shess): Using sql::MetaTable seems indicated, but mixing | |
870 // sql::MetaTable and direct access seems error-prone. It might make sense to | |
871 // simply integrate sql::MetaTable functionality into sql::Connection. | |
872 | |
873 #if defined(OS_IOS) | |
874 // iOS SQLite does not support memory mapping. | |
875 return 0; | |
876 #endif | |
877 | |
878 // If the database doesn't have a place to track progress, assume the worst. | |
879 // This will happen when new databases are created. | |
880 if (!DoesTableExist("meta")) { | |
881 RecordOneEvent(EVENT_MMAP_META_MISSING); | |
882 return 0; | |
883 } | |
884 | |
885 // Key into meta table to get status from a previous run. The value | |
886 // represents how much data in bytes has successfully been read from the | |
887 // database. |kMmapFailure| indicates that there was a read error and the | |
888 // database should not be memory-mapped, while |kMmapSuccess| indicates that | |
889 // the entire file was read at some point and can be memory-mapped without | |
890 // constraint. | |
891 const char* kMmapStatusKey = "mmap_status"; | |
892 static const sqlite3_int64 kMmapFailure = -2; | |
893 static const sqlite3_int64 kMmapSuccess = -1; | |
894 | |
895 // Start reading from 0 unless status is found in meta table. | |
896 sqlite3_int64 mmap_ofs = 0; | |
897 | |
898 // Retrieve the current status. It is fine for the status to be missing | |
899 // entirely, but any error prevents memory-mapping. | |
900 { | |
901 const char* kMmapStatusSql = "SELECT value FROM meta WHERE key = ?"; | |
902 Statement s(GetUniqueStatement(kMmapStatusSql)); | |
903 s.BindString(0, kMmapStatusKey); | |
904 if (s.Step()) { | |
905 mmap_ofs = s.ColumnInt64(0); | |
906 } else if (!s.Succeeded()) { | |
907 RecordOneEvent(EVENT_MMAP_META_FAILURE_READ); | |
908 return 0; | |
909 } | |
910 } | |
911 | |
912 // Database read failed in the past, don't memory map. | |
913 if (mmap_ofs == kMmapFailure) { | |
914 RecordOneEvent(EVENT_MMAP_FAILED); | |
915 return 0; | |
916 } else if (mmap_ofs != kMmapSuccess) { | |
917 // Continue reading from previous offset. | |
918 DCHECK_GE(mmap_ofs, 0); | |
919 | |
920 // TODO(shess): Could this reading code be shared with Preload()? It would | |
921 // require locking twice (this code wouldn't be able to access |db_size| so | |
922 // the helper would have to return amount read). | |
923 | |
924 // Read more of the database looking for errors. The VFS interface is used | |
925 // to assure that the reads are valid for SQLite. |g_reads_allowed| is used | |
926 // to limit checking to 20MB per run of Chromium. | |
927 sqlite3_file* file = NULL; | |
928 sqlite3_int64 db_size = 0; | |
929 if (SQLITE_OK != GetSqlite3FileAndSize(db_, &file, &db_size)) { | |
930 RecordOneEvent(EVENT_MMAP_VFS_FAILURE); | |
931 return 0; | |
932 } | |
933 | |
934 // Read the data left, or |g_reads_allowed|, whichever is smaller. | |
935 // |g_reads_allowed| limits the total amount of I/O to spend verifying data | |
936 // in a single Chromium run. | |
937 sqlite3_int64 amount = db_size - mmap_ofs; | |
938 if (amount < 0) | |
939 amount = 0; | |
940 if (amount > 0) { | |
941 base::AutoLock lock(g_sqlite_init_lock.Get()); | |
942 static sqlite3_int64 g_reads_allowed = 20 * 1024 * 1024; | |
943 if (g_reads_allowed < amount) | |
944 amount = g_reads_allowed; | |
945 g_reads_allowed -= amount; | |
946 } | |
947 | |
948 // |amount| can be <= 0 if |g_reads_allowed| ran out of quota, or if the | |
949 // database was truncated after a previous pass. | |
950 if (amount <= 0 && mmap_ofs < db_size) { | |
951 DCHECK_EQ(0, amount); | |
952 RecordOneEvent(EVENT_MMAP_SUCCESS_NO_PROGRESS); | |
953 } else { | |
954 static const int kPageSize = 4096; | |
955 char buf[kPageSize]; | |
956 while (amount > 0) { | |
957 int rc = file->pMethods->xRead(file, buf, sizeof(buf), mmap_ofs); | |
958 if (rc == SQLITE_OK) { | |
959 mmap_ofs += sizeof(buf); | |
960 amount -= sizeof(buf); | |
961 } else if (rc == SQLITE_IOERR_SHORT_READ) { | |
962 // Reached EOF for a database with page size < |kPageSize|. | |
963 mmap_ofs = db_size; | |
964 break; | |
965 } else { | |
966 // TODO(shess): Consider calling OnSqliteError(). | |
967 mmap_ofs = kMmapFailure; | |
968 break; | |
969 } | |
970 } | |
971 | |
972 // Log these events after update to distinguish meta update failure. | |
973 Events event; | |
974 if (mmap_ofs >= db_size) { | |
975 mmap_ofs = kMmapSuccess; | |
976 event = EVENT_MMAP_SUCCESS_NEW; | |
977 } else if (mmap_ofs > 0) { | |
978 event = EVENT_MMAP_SUCCESS_PARTIAL; | |
979 } else { | |
980 DCHECK_EQ(kMmapFailure, mmap_ofs); | |
981 event = EVENT_MMAP_FAILED_NEW; | |
982 } | |
983 | |
984 const char* kMmapUpdateStatusSql = "REPLACE INTO meta VALUES (?, ?)"; | |
985 Statement s(GetUniqueStatement(kMmapUpdateStatusSql)); | |
986 s.BindString(0, kMmapStatusKey); | |
987 s.BindInt64(1, mmap_ofs); | |
988 if (!s.Run()) { | |
989 RecordOneEvent(EVENT_MMAP_META_FAILURE_UPDATE); | |
990 return 0; | |
991 } | |
992 | |
993 RecordOneEvent(event); | |
994 } | |
995 } | |
996 | |
997 if (mmap_ofs == kMmapFailure) | |
998 return 0; | |
999 if (mmap_ofs == kMmapSuccess) | |
1000 return 256 * 1024 * 1024; | |
1001 return mmap_ofs; | |
1002 } | |
1003 | |
1004 void Connection::TrimMemory(bool aggressively) { | 864 void Connection::TrimMemory(bool aggressively) { |
1005 if (!db_) | 865 if (!db_) |
1006 return; | 866 return; |
1007 | 867 |
1008 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. | 868 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. |
1009 int original_cache_size; | 869 int original_cache_size; |
1010 { | 870 { |
1011 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); | 871 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); |
1012 if (!sql_get_original.Step()) { | 872 if (!sql_get_original.Step()) { |
1013 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); | 873 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); |
(...skipping 799 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1813 sqlite3_int64 db_size = 0; | 1673 sqlite3_int64 db_size = 0; |
1814 int rc = GetSqlite3FileAndSize(db_, &file, &db_size); | 1674 int rc = GetSqlite3FileAndSize(db_, &file, &db_size); |
1815 if (rc == SQLITE_OK && db_size > 16 * 1024) { | 1675 if (rc == SQLITE_OK && db_size > 16 * 1024) { |
1816 int chunk_size = 4 * 1024; | 1676 int chunk_size = 4 * 1024; |
1817 if (db_size > 128 * 1024) | 1677 if (db_size > 128 * 1024) |
1818 chunk_size = 32 * 1024; | 1678 chunk_size = 32 * 1024; |
1819 sqlite3_file_control(db_, NULL, SQLITE_FCNTL_CHUNK_SIZE, &chunk_size); | 1679 sqlite3_file_control(db_, NULL, SQLITE_FCNTL_CHUNK_SIZE, &chunk_size); |
1820 } | 1680 } |
1821 | 1681 |
1822 // Enable memory-mapped access. The explicit-disable case is because SQLite | 1682 // Enable memory-mapped access. The explicit-disable case is because SQLite |
1823 // can be built to default-enable mmap. GetAppropriateMmapSize() calculates a | 1683 // can be built to default-enable mmap. This value will be capped by |
1824 // safe range to memory-map based on past regular I/O. This value will be | 1684 // SQLITE_MAX_MMAP_SIZE, which could be different between 32-bit and 64-bit |
1825 // capped by SQLITE_MAX_MMAP_SIZE, which could be different between 32-bit and | 1685 // platforms. |
1826 // 64-bit platforms. | 1686 if (mmap_disabled_) { |
1827 size_t mmap_size = mmap_disabled_ ? 0 : GetAppropriateMmapSize(); | 1687 ignore_result(Execute("PRAGMA mmap_size = 0")); |
1828 std::string mmap_sql = | 1688 } else { |
1829 base::StringPrintf("PRAGMA mmap_size = %" PRIuS, mmap_size); | 1689 ignore_result(Execute("PRAGMA mmap_size = 268435456")); // 256MB. |
1830 ignore_result(Execute(mmap_sql.c_str())); | 1690 } |
1831 | 1691 |
1832 // Determine if memory-mapping has actually been enabled. The Execute() above | 1692 // Determine if memory-mapping has actually been enabled. The Execute() above |
1833 // can succeed without changing the amount mapped. | 1693 // can succeed without changing the amount mapped. |
1834 mmap_enabled_ = false; | 1694 mmap_enabled_ = false; |
1835 { | 1695 { |
1836 Statement s(GetUniqueStatement("PRAGMA mmap_size")); | 1696 Statement s(GetUniqueStatement("PRAGMA mmap_size")); |
1837 if (s.Step() && s.ColumnInt64(0) > 0) | 1697 if (s.Step() && s.ColumnInt64(0) > 0) |
1838 mmap_enabled_ = true; | 1698 mmap_enabled_ = true; |
1839 } | 1699 } |
1840 | 1700 |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1970 ignore_result(Execute(kNoWritableSchema)); | 1830 ignore_result(Execute(kNoWritableSchema)); |
1971 | 1831 |
1972 return ret; | 1832 return ret; |
1973 } | 1833 } |
1974 | 1834 |
1975 base::TimeTicks TimeSource::Now() { | 1835 base::TimeTicks TimeSource::Now() { |
1976 return base::TimeTicks::Now(); | 1836 return base::TimeTicks::Now(); |
1977 } | 1837 } |
1978 | 1838 |
1979 } // namespace sql | 1839 } // namespace sql |
OLD | NEW |