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/files/file_path.h" | 11 #include "base/files/file_path.h" |
11 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
| 13 #include "base/format_macros.h" |
| 14 #include "base/json/json_file_value_serializer.h" |
12 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
13 #include "base/logging.h" | 16 #include "base/logging.h" |
14 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
15 #include "base/metrics/histogram.h" | 18 #include "base/metrics/histogram.h" |
16 #include "base/metrics/sparse_histogram.h" | 19 #include "base/metrics/sparse_histogram.h" |
17 #include "base/strings/string_split.h" | 20 #include "base/strings/string_split.h" |
18 #include "base/strings/string_util.h" | 21 #include "base/strings/string_util.h" |
19 #include "base/strings/stringprintf.h" | 22 #include "base/strings/stringprintf.h" |
20 #include "base/strings/utf_string_conversions.h" | 23 #include "base/strings/utf_string_conversions.h" |
21 #include "base/synchronization/lock.h" | 24 #include "base/synchronization/lock.h" |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 cache_size); | 253 cache_size); |
251 dump->AddScalar("schema_size", | 254 dump->AddScalar("schema_size", |
252 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | 255 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
253 schema_size); | 256 schema_size); |
254 dump->AddScalar("statement_size", | 257 dump->AddScalar("statement_size", |
255 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | 258 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
256 statement_size); | 259 statement_size); |
257 return true; | 260 return true; |
258 } | 261 } |
259 | 262 |
| 263 void Connection::ReportDiagnosticInfo(int extended_error, Statement* stmt) { |
| 264 AssertIOAllowed(); |
| 265 |
| 266 std::string debug_info; |
| 267 const int error = (extended_error & 0xFF); |
| 268 if (error == SQLITE_CORRUPT) { |
| 269 debug_info = CollectCorruptionInfo(); |
| 270 } else { |
| 271 debug_info = CollectErrorInfo(extended_error, stmt); |
| 272 } |
| 273 |
| 274 if (!debug_info.empty() && RegisterIntentToUpload()) { |
| 275 char debug_buf[2000]; |
| 276 base::strlcpy(debug_buf, debug_info.c_str(), arraysize(debug_buf)); |
| 277 base::debug::Alias(&debug_buf); |
| 278 |
| 279 base::debug::DumpWithoutCrashing(); |
| 280 } |
| 281 } |
| 282 |
260 // static | 283 // static |
261 void Connection::SetErrorIgnorer(Connection::ErrorIgnorerCallback* cb) { | 284 void Connection::SetErrorIgnorer(Connection::ErrorIgnorerCallback* cb) { |
262 CHECK(current_ignorer_cb_ == NULL); | 285 CHECK(current_ignorer_cb_ == NULL); |
263 current_ignorer_cb_ = cb; | 286 current_ignorer_cb_ = cb; |
264 } | 287 } |
265 | 288 |
266 // static | 289 // static |
267 void Connection::ResetErrorIgnorer() { | 290 void Connection::ResetErrorIgnorer() { |
268 CHECK(current_ignorer_cb_); | 291 CHECK(current_ignorer_cb_); |
269 current_ignorer_cb_ = NULL; | 292 current_ignorer_cb_ = NULL; |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 // If no changes have been made, skip flushing. This allows the first page of | 598 // If no changes have been made, skip flushing. This allows the first page of |
576 // the database to remain in cache across multiple reads. | 599 // the database to remain in cache across multiple reads. |
577 const int total_changes = sqlite3_total_changes(db_); | 600 const int total_changes = sqlite3_total_changes(db_); |
578 if (total_changes == total_changes_at_last_release_) | 601 if (total_changes == total_changes_at_last_release_) |
579 return; | 602 return; |
580 | 603 |
581 total_changes_at_last_release_ = total_changes; | 604 total_changes_at_last_release_ = total_changes; |
582 sqlite3_db_release_memory(db_); | 605 sqlite3_db_release_memory(db_); |
583 } | 606 } |
584 | 607 |
| 608 base::FilePath Connection::DbPath() const { |
| 609 if (!is_open()) |
| 610 return base::FilePath(); |
| 611 |
| 612 const char* path = sqlite3_db_filename(db_, "main"); |
| 613 const base::StringPiece db_path(path); |
| 614 #if defined(OS_WIN) |
| 615 return base::FilePath(base::UTF8ToWide(db_path)); |
| 616 #elif defined(OS_POSIX) |
| 617 return base::FilePath(db_path); |
| 618 #else |
| 619 NOTREACHED(); |
| 620 return base::FilePath(); |
| 621 #endif |
| 622 } |
| 623 |
| 624 // Data is persisted in a file shared between databases in the same directory. |
| 625 // The "sqlite-diag" file contains a dictionary with the version number, and an |
| 626 // array of histogram tags for databases which have been dumped. |
| 627 bool Connection::RegisterIntentToUpload() const { |
| 628 static const char* kVersionKey = "version"; |
| 629 static const char* kDiagnosticDumpsKey = "DiagnosticDumps"; |
| 630 static int kVersion = 1; |
| 631 |
| 632 AssertIOAllowed(); |
| 633 |
| 634 if (histogram_tag_.empty()) |
| 635 return false; |
| 636 |
| 637 if (!is_open()) |
| 638 return false; |
| 639 |
| 640 if (in_memory_) |
| 641 return false; |
| 642 |
| 643 const base::FilePath db_path = DbPath(); |
| 644 if (db_path.empty()) |
| 645 return false; |
| 646 |
| 647 // Put the collection of diagnostic data next to the databases. In most |
| 648 // cases, this is the profile directory, but safe-browsing stores a Cookies |
| 649 // file in the directory above the profile directory. |
| 650 base::FilePath breadcrumb_path( |
| 651 db_path.DirName().Append(FILE_PATH_LITERAL("sqlite-diag"))); |
| 652 |
| 653 // Lock against multiple updates to the diagnostics file. This code should |
| 654 // seldom be called in the first place, and when called it should seldom be |
| 655 // called for multiple databases, and when called for multiple databases there |
| 656 // is _probably_ something systemic wrong with the user's system. So the lock |
| 657 // should never be contended, but when it is the database experience is |
| 658 // already bad. |
| 659 base::AutoLock lock(g_sqlite_init_lock.Get()); |
| 660 |
| 661 scoped_ptr<base::Value> root; |
| 662 if (!base::PathExists(breadcrumb_path)) { |
| 663 scoped_ptr<base::DictionaryValue> root_dict(new base::DictionaryValue()); |
| 664 root_dict->SetInteger(kVersionKey, kVersion); |
| 665 |
| 666 scoped_ptr<base::ListValue> dumps(new base::ListValue); |
| 667 dumps->AppendString(histogram_tag_); |
| 668 root_dict->Set(kDiagnosticDumpsKey, dumps.Pass()); |
| 669 |
| 670 root = root_dict.Pass(); |
| 671 } else { |
| 672 // Failure to read a valid dictionary implies that something is going wrong |
| 673 // on the system. |
| 674 JSONFileValueDeserializer deserializer(breadcrumb_path); |
| 675 scoped_ptr<base::Value> read_root( |
| 676 deserializer.Deserialize(nullptr, nullptr)); |
| 677 if (!read_root.get()) |
| 678 return false; |
| 679 scoped_ptr<base::DictionaryValue> root_dict = |
| 680 base::DictionaryValue::From(read_root.Pass()); |
| 681 if (!root_dict) |
| 682 return false; |
| 683 |
| 684 // Don't upload if the version is missing or newer. |
| 685 int version = 0; |
| 686 if (!root_dict->GetInteger(kVersionKey, &version) || version > kVersion) |
| 687 return false; |
| 688 |
| 689 base::ListValue* dumps = nullptr; |
| 690 if (!root_dict->GetList(kDiagnosticDumpsKey, &dumps)) |
| 691 return false; |
| 692 |
| 693 const size_t size = dumps->GetSize(); |
| 694 for (size_t i = 0; i < size; ++i) { |
| 695 std::string s; |
| 696 |
| 697 // Don't upload if the value isn't a string, or indicates a prior upload. |
| 698 if (!dumps->GetString(i, &s) || s == histogram_tag_) |
| 699 return false; |
| 700 } |
| 701 |
| 702 // Record intention to proceed with upload. |
| 703 dumps->AppendString(histogram_tag_); |
| 704 root = root_dict.Pass(); |
| 705 } |
| 706 |
| 707 const base::FilePath breadcrumb_new = |
| 708 breadcrumb_path.AddExtension(FILE_PATH_LITERAL("new")); |
| 709 base::DeleteFile(breadcrumb_new, false); |
| 710 |
| 711 // No upload if the breadcrumb file cannot be updated. |
| 712 // TODO(shess): Consider ImportantFileWriter::WriteFileAtomically() to land |
| 713 // the data on disk. For now, losing the data is not a big problem, so the |
| 714 // sync overhead would probably not be worth it. |
| 715 JSONFileValueSerializer serializer(breadcrumb_new); |
| 716 if (!serializer.Serialize(*root)) |
| 717 return false; |
| 718 if (!base::PathExists(breadcrumb_new)) |
| 719 return false; |
| 720 if (!base::ReplaceFile(breadcrumb_new, breadcrumb_path, nullptr)) { |
| 721 base::DeleteFile(breadcrumb_new, false); |
| 722 return false; |
| 723 } |
| 724 |
| 725 return true; |
| 726 } |
| 727 |
| 728 std::string Connection::CollectErrorInfo(int error, Statement* stmt) const { |
| 729 // Buffer for accumulating debugging info about the error. Place |
| 730 // more-relevant information earlier, in case things overflow the |
| 731 // fixed-size reporting buffer. |
| 732 std::string debug_info; |
| 733 |
| 734 // The error message from the failed operation. |
| 735 base::StringAppendF(&debug_info, "db error: %d/%s\n", |
| 736 GetErrorCode(), GetErrorMessage()); |
| 737 |
| 738 // TODO(shess): |error| and |GetErrorCode()| should always be the same, but |
| 739 // reading code does not entirely convince me. Remove if they turn out to be |
| 740 // the same. |
| 741 if (error != GetErrorCode()) |
| 742 base::StringAppendF(&debug_info, "reported error: %d\n", error); |
| 743 |
| 744 // System error information. Interpretation of Windows errors is different |
| 745 // from posix. |
| 746 #if defined(OS_WIN) |
| 747 base::StringAppendF(&debug_info, "LastError: %d\n", GetLastErrno()); |
| 748 #elif defined(OS_POSIX) |
| 749 base::StringAppendF(&debug_info, "errno: %d\n", GetLastErrno()); |
| 750 #else |
| 751 NOTREACHED(); // Add appropriate log info. |
| 752 #endif |
| 753 |
| 754 if (stmt) { |
| 755 base::StringAppendF(&debug_info, "statement: %s\n", |
| 756 stmt->GetSQLStatement()); |
| 757 } else { |
| 758 base::StringAppendF(&debug_info, "statement: NULL\n"); |
| 759 } |
| 760 |
| 761 // SQLITE_ERROR often indicates some sort of mismatch between the statement |
| 762 // and the schema, possibly due to a failed schema migration. |
| 763 if (error == SQLITE_ERROR) { |
| 764 const char* kVersionSql = "SELECT value FROM meta WHERE key = 'version'"; |
| 765 sqlite3_stmt* s; |
| 766 int rc = sqlite3_prepare_v2(db_, kVersionSql, -1, &s, nullptr); |
| 767 if (rc == SQLITE_OK) { |
| 768 rc = sqlite3_step(s); |
| 769 if (rc == SQLITE_ROW) { |
| 770 base::StringAppendF(&debug_info, "version: %d\n", |
| 771 sqlite3_column_int(s, 0)); |
| 772 } else if (rc == SQLITE_DONE) { |
| 773 debug_info += "version: none\n"; |
| 774 } else { |
| 775 base::StringAppendF(&debug_info, "version: error %d\n", rc); |
| 776 } |
| 777 sqlite3_finalize(s); |
| 778 } else { |
| 779 base::StringAppendF(&debug_info, "version: prepare error %d\n", rc); |
| 780 } |
| 781 |
| 782 debug_info += "schema:\n"; |
| 783 |
| 784 // sqlite_master has columns: |
| 785 // type - "index" or "table". |
| 786 // name - name of created element. |
| 787 // tbl_name - name of element, or target table in case of index. |
| 788 // rootpage - root page of the element in database file. |
| 789 // sql - SQL to create the element. |
| 790 // In general, the |sql| column is sufficient to derive the other columns. |
| 791 // |rootpage| is not interesting for debugging, without the contents of the |
| 792 // database. The COALESCE is because certain automatic elements will have a |
| 793 // |name| but no |sql|, |
| 794 const char* kSchemaSql = "SELECT COALESCE(sql, name) FROM sqlite_master"; |
| 795 rc = sqlite3_prepare_v2(db_, kSchemaSql, -1, &s, nullptr); |
| 796 if (rc == SQLITE_OK) { |
| 797 while ((rc = sqlite3_step(s)) == SQLITE_ROW) { |
| 798 base::StringAppendF(&debug_info, "%s\n", sqlite3_column_text(s, 0)); |
| 799 } |
| 800 if (rc != SQLITE_DONE) |
| 801 base::StringAppendF(&debug_info, "error %d\n", rc); |
| 802 sqlite3_finalize(s); |
| 803 } else { |
| 804 base::StringAppendF(&debug_info, "prepare error %d\n", rc); |
| 805 } |
| 806 } |
| 807 |
| 808 return debug_info; |
| 809 } |
| 810 |
| 811 // TODO(shess): Since this is only called in an error situation, it might be |
| 812 // prudent to rewrite in terms of SQLite API calls, and mark the function const. |
| 813 std::string Connection::CollectCorruptionInfo() { |
| 814 AssertIOAllowed(); |
| 815 |
| 816 // If the file cannot be accessed it is unlikely that an integrity check will |
| 817 // turn up actionable information. |
| 818 const base::FilePath db_path = DbPath(); |
| 819 int64 db_size = -1; |
| 820 if (!base::GetFileSize(db_path, &db_size) || db_size < 0) |
| 821 return std::string(); |
| 822 |
| 823 // Buffer for accumulating debugging info about the error. Place |
| 824 // more-relevant information earlier, in case things overflow the |
| 825 // fixed-size reporting buffer. |
| 826 std::string debug_info; |
| 827 base::StringAppendF(&debug_info, "SQLITE_CORRUPT, db size %" PRId64 "\n", |
| 828 db_size); |
| 829 |
| 830 // Only check files up to 8M to keep things from blocking too long. |
| 831 const int64 kMaxIntegrityCheckSize = 8192 * 1024; |
| 832 if (db_size > kMaxIntegrityCheckSize) { |
| 833 debug_info += "integrity_check skipped due to size\n"; |
| 834 } else { |
| 835 std::vector<std::string> messages; |
| 836 |
| 837 // TODO(shess): FullIntegrityCheck() splits into a vector while this joins |
| 838 // into a string. Probably should be refactored. |
| 839 const base::TimeTicks before = base::TimeTicks::Now(); |
| 840 FullIntegrityCheck(&messages); |
| 841 base::StringAppendF( |
| 842 &debug_info, |
| 843 "integrity_check %" PRId64 " ms, %" PRIuS " records:\n", |
| 844 (base::TimeTicks::Now() - before).InMilliseconds(), |
| 845 messages.size()); |
| 846 |
| 847 // SQLite returns up to 100 messages by default, trim deeper to |
| 848 // keep close to the 2000-character size limit for dumping. |
| 849 const size_t kMaxMessages = 20; |
| 850 for (size_t i = 0; i < kMaxMessages && i < messages.size(); ++i) { |
| 851 base::StringAppendF(&debug_info, "%s\n", messages[i].c_str()); |
| 852 } |
| 853 } |
| 854 |
| 855 return debug_info; |
| 856 } |
| 857 |
585 void Connection::TrimMemory(bool aggressively) { | 858 void Connection::TrimMemory(bool aggressively) { |
586 if (!db_) | 859 if (!db_) |
587 return; | 860 return; |
588 | 861 |
589 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. | 862 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. |
590 int original_cache_size; | 863 int original_cache_size; |
591 { | 864 { |
592 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); | 865 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); |
593 if (!sql_get_original.Step()) { | 866 if (!sql_get_original.Step()) { |
594 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); | 867 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); |
(...skipping 932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1527 ignore_result(Execute(kNoWritableSchema)); | 1800 ignore_result(Execute(kNoWritableSchema)); |
1528 | 1801 |
1529 return ret; | 1802 return ret; |
1530 } | 1803 } |
1531 | 1804 |
1532 base::TimeTicks TimeSource::Now() { | 1805 base::TimeTicks TimeSource::Now() { |
1533 return base::TimeTicks::Now(); | 1806 return base::TimeTicks::Now(); |
1534 } | 1807 } |
1535 | 1808 |
1536 } // namespace sql | 1809 } // namespace sql |
OLD | NEW |