| 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); |
| 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 |