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" |
11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
12 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
13 #include "base/format_macros.h" | 13 #include "base/format_macros.h" |
14 #include "base/json/json_file_value_serializer.h" | 14 #include "base/json/json_file_value_serializer.h" |
15 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
18 #include "base/metrics/histogram.h" | 18 #include "base/metrics/histogram.h" |
19 #include "base/metrics/sparse_histogram.h" | 19 #include "base/metrics/sparse_histogram.h" |
20 #include "base/strings/string_split.h" | 20 #include "base/strings/string_split.h" |
21 #include "base/strings/string_util.h" | 21 #include "base/strings/string_util.h" |
22 #include "base/strings/stringprintf.h" | 22 #include "base/strings/stringprintf.h" |
23 #include "base/strings/utf_string_conversions.h" | 23 #include "base/strings/utf_string_conversions.h" |
24 #include "base/synchronization/lock.h" | 24 #include "base/synchronization/lock.h" |
25 #include "base/trace_event/memory_dump_manager.h" | 25 #include "base/trace_event/memory_dump_manager.h" |
26 #include "base/trace_event/process_memory_dump.h" | 26 #include "base/trace_event/process_memory_dump.h" |
27 #include "sql/meta_table.h" | |
27 #include "sql/statement.h" | 28 #include "sql/statement.h" |
28 #include "third_party/sqlite/sqlite3.h" | 29 #include "third_party/sqlite/sqlite3.h" |
29 | 30 |
30 #if defined(OS_IOS) && defined(USE_SYSTEM_SQLITE) | 31 #if defined(OS_IOS) && defined(USE_SYSTEM_SQLITE) |
31 #include "third_party/sqlite/src/ext/icu/sqliteicu.h" | 32 #include "third_party/sqlite/src/ext/icu/sqliteicu.h" |
32 #endif | 33 #endif |
33 | 34 |
34 namespace { | 35 namespace { |
35 | 36 |
36 // Spin for up to a second waiting for the lock to clear when setting | 37 // Spin for up to a second waiting for the lock to clear when setting |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
451 int64_t size_64 = 0; | 452 int64_t size_64 = 0; |
452 if (base::GetFileSize(path, &size_64)) { | 453 if (base::GetFileSize(path, &size_64)) { |
453 size_t sample = static_cast<size_t>(size_64 / 1024); | 454 size_t sample = static_cast<size_t>(size_64 / 1024); |
454 std::string full_histogram_name = "Sqlite.SizeKB." + histogram_tag_; | 455 std::string full_histogram_name = "Sqlite.SizeKB." + histogram_tag_; |
455 base::HistogramBase* histogram = | 456 base::HistogramBase* histogram = |
456 base::Histogram::FactoryGet( | 457 base::Histogram::FactoryGet( |
457 full_histogram_name, 1, 1000000, 50, | 458 full_histogram_name, 1, 1000000, 50, |
458 base::HistogramBase::kUmaTargetedHistogramFlag); | 459 base::HistogramBase::kUmaTargetedHistogramFlag); |
459 if (histogram) | 460 if (histogram) |
460 histogram->Add(sample); | 461 histogram->Add(sample); |
462 UMA_HISTOGRAM_COUNTS("Sqlite.SizeKB", sample); | |
Scott Hess - ex-Googler
2015/12/16 23:09:08
This is sneaking in because when I went to verify
| |
461 } | 463 } |
462 } | 464 } |
463 | 465 |
464 return OpenInternal(AsUTF8ForSQL(path), RETRY_ON_POISON); | 466 return OpenInternal(AsUTF8ForSQL(path), RETRY_ON_POISON); |
465 } | 467 } |
466 | 468 |
467 bool Connection::OpenInMemory() { | 469 bool Connection::OpenInMemory() { |
468 in_memory_ = true; | 470 in_memory_ = true; |
469 return OpenInternal(":memory:", NO_RETRY); | 471 return OpenInternal(":memory:", NO_RETRY); |
470 } | 472 } |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
876 base::StringAppendF(&debug_info, "%s\n", messages[i].c_str()); | 878 base::StringAppendF(&debug_info, "%s\n", messages[i].c_str()); |
877 } | 879 } |
878 } | 880 } |
879 | 881 |
880 return debug_info; | 882 return debug_info; |
881 } | 883 } |
882 | 884 |
883 size_t Connection::GetAppropriateMmapSize() { | 885 size_t Connection::GetAppropriateMmapSize() { |
884 AssertIOAllowed(); | 886 AssertIOAllowed(); |
885 | 887 |
886 // TODO(shess): Using sql::MetaTable seems indicated, but mixing | |
887 // sql::MetaTable and direct access seems error-prone. It might make sense to | |
888 // simply integrate sql::MetaTable functionality into sql::Connection. | |
889 | |
890 #if defined(OS_IOS) | 888 #if defined(OS_IOS) |
891 // iOS SQLite does not support memory mapping. | 889 // iOS SQLite does not support memory mapping. |
892 return 0; | 890 return 0; |
893 #endif | 891 #endif |
894 | 892 |
895 // If the database doesn't have a place to track progress, assume the worst. | 893 // How much to map if no errors are found. 50MB encompasses the 99th |
896 // This will happen when new databases are created. | 894 // percentile of Chrome databases in the wild, so this should be good. |
897 if (!DoesTableExist("meta")) { | 895 const size_t kMmapEverything = 256 * 1024 * 1024; |
896 | |
897 // If the database doesn't have a place to track progress, assume the best. | |
898 // This will happen when new databases are created, or if a database doesn't | |
899 // use a meta table. sql::MetaTable::Init() will preload kMmapSuccess. | |
900 // TODO(shess): Databases not using meta include: | |
901 // DOMStorageDatabase (localstorage) | |
902 // ActivityDatabase (extensions activity log) | |
903 // PredictorDatabase (prefetch and autocomplete predictor data) | |
904 // SyncDirectory (sync metadata storage) | |
905 // For now, these all have mmap disabled to allow other databases to get the | |
906 // default-enable path. sqlite-diag could be an alternative for all but | |
907 // DOMStorageDatabase, which creates many small databases. | |
908 // http://crbug.com/537742 | |
909 if (!MetaTable::DoesTableExist(this)) { | |
898 RecordOneEvent(EVENT_MMAP_META_MISSING); | 910 RecordOneEvent(EVENT_MMAP_META_MISSING); |
911 return kMmapEverything; | |
912 } | |
913 | |
914 int64_t mmap_ofs = 0; | |
915 if (!MetaTable::GetMmapStatus(this, &mmap_ofs)) { | |
916 RecordOneEvent(EVENT_MMAP_META_FAILURE_READ); | |
899 return 0; | 917 return 0; |
900 } | 918 } |
901 | 919 |
902 // Key into meta table to get status from a previous run. The value | |
903 // represents how much data in bytes has successfully been read from the | |
904 // database. |kMmapFailure| indicates that there was a read error and the | |
905 // database should not be memory-mapped, while |kMmapSuccess| indicates that | |
906 // the entire file was read at some point and can be memory-mapped without | |
907 // constraint. | |
908 const char* kMmapStatusKey = "mmap_status"; | |
909 static const sqlite3_int64 kMmapFailure = -2; | |
910 static const sqlite3_int64 kMmapSuccess = -1; | |
911 | |
912 // Start reading from 0 unless status is found in meta table. | |
913 sqlite3_int64 mmap_ofs = 0; | |
914 | |
915 // Retrieve the current status. It is fine for the status to be missing | |
916 // entirely, but any error prevents memory-mapping. | |
917 { | |
918 const char* kMmapStatusSql = "SELECT value FROM meta WHERE key = ?"; | |
919 Statement s(GetUniqueStatement(kMmapStatusSql)); | |
920 s.BindString(0, kMmapStatusKey); | |
921 if (s.Step()) { | |
922 mmap_ofs = s.ColumnInt64(0); | |
923 } else if (!s.Succeeded()) { | |
924 RecordOneEvent(EVENT_MMAP_META_FAILURE_READ); | |
925 return 0; | |
926 } | |
927 } | |
928 | |
929 // Database read failed in the past, don't memory map. | 920 // Database read failed in the past, don't memory map. |
930 if (mmap_ofs == kMmapFailure) { | 921 if (mmap_ofs == MetaTable::kMmapFailure) { |
931 RecordOneEvent(EVENT_MMAP_FAILED); | 922 RecordOneEvent(EVENT_MMAP_FAILED); |
932 return 0; | 923 return 0; |
933 } else if (mmap_ofs != kMmapSuccess) { | 924 } else if (mmap_ofs != MetaTable::kMmapSuccess) { |
934 // Continue reading from previous offset. | 925 // Continue reading from previous offset. |
935 DCHECK_GE(mmap_ofs, 0); | 926 DCHECK_GE(mmap_ofs, 0); |
936 | 927 |
937 // TODO(shess): Could this reading code be shared with Preload()? It would | 928 // TODO(shess): Could this reading code be shared with Preload()? It would |
938 // require locking twice (this code wouldn't be able to access |db_size| so | 929 // require locking twice (this code wouldn't be able to access |db_size| so |
939 // the helper would have to return amount read). | 930 // the helper would have to return amount read). |
940 | 931 |
941 // Read more of the database looking for errors. The VFS interface is used | 932 // Read more of the database looking for errors. The VFS interface is used |
942 // to assure that the reads are valid for SQLite. |g_reads_allowed| is used | 933 // to assure that the reads are valid for SQLite. |g_reads_allowed| is used |
943 // to limit checking to 20MB per run of Chromium. | 934 // to limit checking to 20MB per run of Chromium. |
(...skipping 30 matching lines...) Expand all Loading... | |
974 int rc = file->pMethods->xRead(file, buf, sizeof(buf), mmap_ofs); | 965 int rc = file->pMethods->xRead(file, buf, sizeof(buf), mmap_ofs); |
975 if (rc == SQLITE_OK) { | 966 if (rc == SQLITE_OK) { |
976 mmap_ofs += sizeof(buf); | 967 mmap_ofs += sizeof(buf); |
977 amount -= sizeof(buf); | 968 amount -= sizeof(buf); |
978 } else if (rc == SQLITE_IOERR_SHORT_READ) { | 969 } else if (rc == SQLITE_IOERR_SHORT_READ) { |
979 // Reached EOF for a database with page size < |kPageSize|. | 970 // Reached EOF for a database with page size < |kPageSize|. |
980 mmap_ofs = db_size; | 971 mmap_ofs = db_size; |
981 break; | 972 break; |
982 } else { | 973 } else { |
983 // TODO(shess): Consider calling OnSqliteError(). | 974 // TODO(shess): Consider calling OnSqliteError(). |
984 mmap_ofs = kMmapFailure; | 975 mmap_ofs = MetaTable::kMmapFailure; |
985 break; | 976 break; |
986 } | 977 } |
987 } | 978 } |
988 | 979 |
989 // Log these events after update to distinguish meta update failure. | 980 // Log these events after update to distinguish meta update failure. |
990 Events event; | 981 Events event; |
991 if (mmap_ofs >= db_size) { | 982 if (mmap_ofs >= db_size) { |
992 mmap_ofs = kMmapSuccess; | 983 mmap_ofs = MetaTable::kMmapSuccess; |
993 event = EVENT_MMAP_SUCCESS_NEW; | 984 event = EVENT_MMAP_SUCCESS_NEW; |
994 } else if (mmap_ofs > 0) { | 985 } else if (mmap_ofs > 0) { |
995 event = EVENT_MMAP_SUCCESS_PARTIAL; | 986 event = EVENT_MMAP_SUCCESS_PARTIAL; |
996 } else { | 987 } else { |
997 DCHECK_EQ(kMmapFailure, mmap_ofs); | 988 DCHECK_EQ(MetaTable::kMmapFailure, mmap_ofs); |
998 event = EVENT_MMAP_FAILED_NEW; | 989 event = EVENT_MMAP_FAILED_NEW; |
999 } | 990 } |
1000 | 991 |
1001 const char* kMmapUpdateStatusSql = "REPLACE INTO meta VALUES (?, ?)"; | 992 if (!MetaTable::SetMmapStatus(this, mmap_ofs)) { |
1002 Statement s(GetUniqueStatement(kMmapUpdateStatusSql)); | |
1003 s.BindString(0, kMmapStatusKey); | |
1004 s.BindInt64(1, mmap_ofs); | |
1005 if (!s.Run()) { | |
1006 RecordOneEvent(EVENT_MMAP_META_FAILURE_UPDATE); | 993 RecordOneEvent(EVENT_MMAP_META_FAILURE_UPDATE); |
1007 return 0; | 994 return 0; |
1008 } | 995 } |
1009 | 996 |
1010 RecordOneEvent(event); | 997 RecordOneEvent(event); |
1011 } | 998 } |
1012 } | 999 } |
1013 | 1000 |
1014 if (mmap_ofs == kMmapFailure) | 1001 if (mmap_ofs == MetaTable::kMmapFailure) |
1015 return 0; | 1002 return 0; |
1016 if (mmap_ofs == kMmapSuccess) | 1003 if (mmap_ofs == MetaTable::kMmapSuccess) |
1017 return 256 * 1024 * 1024; | 1004 return kMmapEverything; |
1018 return mmap_ofs; | 1005 return mmap_ofs; |
1019 } | 1006 } |
1020 | 1007 |
1021 void Connection::TrimMemory(bool aggressively) { | 1008 void Connection::TrimMemory(bool aggressively) { |
1022 if (!db_) | 1009 if (!db_) |
1023 return; | 1010 return; |
1024 | 1011 |
1025 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. | 1012 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. |
1026 int original_cache_size; | 1013 int original_cache_size; |
1027 { | 1014 { |
(...skipping 965 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1993 ignore_result(Execute(kNoWritableSchema)); | 1980 ignore_result(Execute(kNoWritableSchema)); |
1994 | 1981 |
1995 return ret; | 1982 return ret; |
1996 } | 1983 } |
1997 | 1984 |
1998 base::TimeTicks TimeSource::Now() { | 1985 base::TimeTicks TimeSource::Now() { |
1999 return base::TimeTicks::Now(); | 1986 return base::TimeTicks::Now(); |
2000 } | 1987 } |
2001 | 1988 |
2002 } // namespace sql | 1989 } // namespace sql |
OLD | NEW |