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/files/file_path.h" | 10 #include "base/files/file_path.h" |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
459 preload_size = file_size; | 459 preload_size = file_size; |
460 | 460 |
461 scoped_ptr<char[]> buf(new char[page_size]); | 461 scoped_ptr<char[]> buf(new char[page_size]); |
462 for (sqlite3_int64 pos = 0; pos < preload_size; pos += page_size) { | 462 for (sqlite3_int64 pos = 0; pos < preload_size; pos += page_size) { |
463 rc = file->pMethods->xRead(file, buf.get(), page_size, pos); | 463 rc = file->pMethods->xRead(file, buf.get(), page_size, pos); |
464 if (rc != SQLITE_OK) | 464 if (rc != SQLITE_OK) |
465 return; | 465 return; |
466 } | 466 } |
467 } | 467 } |
468 | 468 |
469 // SQLite keeps unused pages associated with a connection in a cache. It asks | |
470 // the cache for pages by an id, and if the page is present and the database is | |
471 // unchanged, it considers the content of the page valid and doesn't read it | |
472 // from disk. When memory-mapped I/O is enabled, on read SQLite uses page | |
473 // structures created from the memory map data before consulting the cache. On | |
474 // write SQLite creates a new in-memory page structure, copies the data from the | |
475 // memory map, and later writes it, releasing the updated page back to the | |
476 // cache. | |
477 // | |
478 // This means that in memory-mapped mode, the contents of the cached pages are | |
479 // not re-used for reads, but they are re-used for writes if the re-written page | |
480 // is still in the cache. The implementation of sqlite3_db_release_memory() as | |
481 // of SQLite 3.8.7.4 frees all pages from pcaches associated with the | |
482 // connection, so it should free these pages. | |
483 // | |
484 // Unfortunately, the zero page is also freed. That page is never accessed | |
485 // using memory-mapped I/O, and the cached copy can be re-used after verifying | |
486 // the file change counter on disk. Also, fresh pages from cache receive some | |
487 // pager-level initialization before they can be used. Since the information | |
488 // involved will immediately be accessed in various ways, it is unclear if the | |
489 // additional overhead is material, or just moving processor cache effects | |
490 // around. | |
Scott Hess - ex-Googler
2015/09/16 22:46:16
Apologies for the mega-comment. I'm not entirely
| |
491 // | |
492 // TODO(shess): It would be better to release the pages immediately when they | |
493 // are no longer needed. This would basically happen after SQLite commits a | |
494 // transaction. I had implemented a pcache wrapper to do this, but it involved | |
495 // layering violations, and it had to be setup before any other sqlite call, | |
496 // which was brittle. Also, for large files it would actually make sense to | |
497 // maintain the existing pcache behavior for blocks past the memory-mapped | |
498 // segment. I think drh would accept a reasonable implementation of the overall | |
499 // concept for upstreaming to SQLite core. | |
500 // | |
501 // TODO(shess): Another possibility would be to set the cache size small, which | |
502 // would keep the zero page around, plus some pre-initialized pages, and SQLite | |
503 // can manage things. The downside is that updates larger than the cache would | |
504 // spill to the journal. That could be compensated by setting cache_spill to | |
505 // false. The downside then is that it allows open-ended use of memory for | |
506 // large transactions. | |
507 // | |
508 // TODO(shess): The TrimMemory() trick of bouncing the cache size would also | |
509 // work. There could be two prepared statements, one for cache_size=1 one for | |
510 // cache_size=goal. | |
511 void Connection::ReleaseCacheMemoryIfNeeded(bool assume_changed) { | |
512 // If memory-mapping is not enabled, the page cache helps performance. | |
513 if (!mmap_enabled_) | |
514 return; | |
515 | |
516 // On caller request, force the change comparison to fail. Done before the | |
517 // transaction-nesting test so that the signal can carry to transaction | |
518 // commit. | |
519 if (assume_changed) | |
520 total_changes_--; | |
521 | |
522 // Cached pages may be re-used within the same transaction. | |
523 if (transaction_nesting()) | |
524 return; | |
525 | |
526 // If no changes have been made, skip flushing. This allows the first page of | |
527 // the database to remain in cache across multiple reads. | |
528 int current_changes = sqlite3_total_changes(db_); | |
529 if (current_changes == total_changes_) | |
530 return; | |
531 | |
532 total_changes_ = current_changes; | |
533 sqlite3_db_release_memory(db_); | |
534 } | |
535 | |
536 // NOTE(shess): When memory-mapped mode is solid, this will be a noop. | |
469 void Connection::TrimMemory(bool aggressively) { | 537 void Connection::TrimMemory(bool aggressively) { |
470 if (!db_) | 538 if (!db_) |
471 return; | 539 return; |
472 | 540 |
473 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. | 541 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. |
474 int original_cache_size; | 542 int original_cache_size; |
475 { | 543 { |
476 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); | 544 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); |
477 if (!sql_get_original.Step()) { | 545 if (!sql_get_original.Step()) { |
478 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); | 546 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
669 bool Connection::Delete(const base::FilePath& path) { | 737 bool Connection::Delete(const base::FilePath& path) { |
670 base::ThreadRestrictions::AssertIOAllowed(); | 738 base::ThreadRestrictions::AssertIOAllowed(); |
671 | 739 |
672 base::FilePath journal_path(path.value() + FILE_PATH_LITERAL("-journal")); | 740 base::FilePath journal_path(path.value() + FILE_PATH_LITERAL("-journal")); |
673 base::FilePath wal_path(path.value() + FILE_PATH_LITERAL("-wal")); | 741 base::FilePath wal_path(path.value() + FILE_PATH_LITERAL("-wal")); |
674 | 742 |
675 std::string journal_str = AsUTF8ForSQL(journal_path); | 743 std::string journal_str = AsUTF8ForSQL(journal_path); |
676 std::string wal_str = AsUTF8ForSQL(wal_path); | 744 std::string wal_str = AsUTF8ForSQL(wal_path); |
677 std::string path_str = AsUTF8ForSQL(path); | 745 std::string path_str = AsUTF8ForSQL(path); |
678 | 746 |
747 InitializeSqlite(); | |
748 | |
679 sqlite3_vfs* vfs = sqlite3_vfs_find(NULL); | 749 sqlite3_vfs* vfs = sqlite3_vfs_find(NULL); |
680 CHECK(vfs); | 750 CHECK(vfs); |
681 CHECK(vfs->xDelete); | 751 CHECK(vfs->xDelete); |
682 CHECK(vfs->xAccess); | 752 CHECK(vfs->xAccess); |
683 | 753 |
684 // We only work with unix, win32 and mojo filesystems. If you're trying to | 754 // We only work with unix, win32 and mojo filesystems. If you're trying to |
685 // use this code with any other VFS, you're not in a good place. | 755 // use this code with any other VFS, you're not in a good place. |
686 CHECK(strncmp(vfs->zName, "unix", 4) == 0 || | 756 CHECK(strncmp(vfs->zName, "unix", 4) == 0 || |
687 strncmp(vfs->zName, "win32", 5) == 0 || | 757 strncmp(vfs->zName, "win32", 5) == 0 || |
688 strcmp(vfs->zName, "mojo") == 0); | 758 strcmp(vfs->zName, "mojo") == 0); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
766 | 836 |
767 // Collect the commit time manually, sql::Statement would register it as query | 837 // Collect the commit time manually, sql::Statement would register it as query |
768 // time only. | 838 // time only. |
769 const base::TimeTicks before = Now(); | 839 const base::TimeTicks before = Now(); |
770 bool ret = commit.RunWithoutTimers(); | 840 bool ret = commit.RunWithoutTimers(); |
771 const base::TimeDelta delta = Now() - before; | 841 const base::TimeDelta delta = Now() - before; |
772 | 842 |
773 RecordCommitTime(delta); | 843 RecordCommitTime(delta); |
774 RecordOneEvent(EVENT_COMMIT); | 844 RecordOneEvent(EVENT_COMMIT); |
775 | 845 |
846 // Release dirty cache pages after the transaction closes. | |
847 ReleaseCacheMemoryIfNeeded(false); | |
848 | |
776 return ret; | 849 return ret; |
777 } | 850 } |
778 | 851 |
779 void Connection::RollbackAllTransactions() { | 852 void Connection::RollbackAllTransactions() { |
780 if (transaction_nesting_ > 0) { | 853 if (transaction_nesting_ > 0) { |
781 transaction_nesting_ = 0; | 854 transaction_nesting_ = 0; |
782 DoRollback(); | 855 DoRollback(); |
783 } | 856 } |
784 } | 857 } |
785 | 858 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
856 // sqlite3_exec() does this, presumably to avoid spinning the parser for | 929 // sqlite3_exec() does this, presumably to avoid spinning the parser for |
857 // trailing whitespace. | 930 // trailing whitespace. |
858 // TODO(shess): Audit to see if this can become a DCHECK. | 931 // TODO(shess): Audit to see if this can become a DCHECK. |
859 while (base::IsAsciiWhitespace(*sql)) { | 932 while (base::IsAsciiWhitespace(*sql)) { |
860 sql++; | 933 sql++; |
861 } | 934 } |
862 | 935 |
863 const base::TimeDelta delta = Now() - before; | 936 const base::TimeDelta delta = Now() - before; |
864 RecordTimeAndChanges(delta, read_only); | 937 RecordTimeAndChanges(delta, read_only); |
865 } | 938 } |
939 | |
940 // Most calls to Execute() modify the database. The main exceptions would be | |
941 // calls such as CREATE TABLE IF NOT EXISTS which could modify the database | |
942 // but sometimes don't. | |
943 ReleaseCacheMemoryIfNeeded(true); | |
944 | |
866 return rc; | 945 return rc; |
867 } | 946 } |
868 | 947 |
869 bool Connection::Execute(const char* sql) { | 948 bool Connection::Execute(const char* sql) { |
870 if (!db_) { | 949 if (!db_) { |
871 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; | 950 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
872 return false; | 951 return false; |
873 } | 952 } |
874 | 953 |
875 int error = ExecuteAndReturnErrorCode(sql); | 954 int error = ExecuteAndReturnErrorCode(sql); |
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1220 | 1299 |
1221 // http://www.sqlite.org/pragma.html#pragma_journal_mode | 1300 // http://www.sqlite.org/pragma.html#pragma_journal_mode |
1222 // DELETE (default) - delete -journal file to commit. | 1301 // DELETE (default) - delete -journal file to commit. |
1223 // TRUNCATE - truncate -journal file to commit. | 1302 // TRUNCATE - truncate -journal file to commit. |
1224 // PERSIST - zero out header of -journal file to commit. | 1303 // PERSIST - zero out header of -journal file to commit. |
1225 // TRUNCATE should be faster than DELETE because it won't need directory | 1304 // TRUNCATE should be faster than DELETE because it won't need directory |
1226 // changes for each transaction. PERSIST may break the spirit of using | 1305 // changes for each transaction. PERSIST may break the spirit of using |
1227 // secure_delete. | 1306 // secure_delete. |
1228 ignore_result(Execute("PRAGMA journal_mode = TRUNCATE")); | 1307 ignore_result(Execute("PRAGMA journal_mode = TRUNCATE")); |
1229 | 1308 |
1309 // Enable memory-mapped access. This value will be capped by | |
1310 // SQLITE_MAX_MMAP_SIZE, which could be different between 32-bit and 64-bit | |
1311 // platforms. | |
1312 mmap_enabled_ = false; | |
1313 ignore_result(Execute("PRAGMA mmap_size = 2147483648")); // 2GB. | |
1314 { | |
1315 Statement s(GetUniqueStatement("PRAGMA mmap_size")); | |
1316 if (s.Step() && s.ColumnInt64(0) > 0) | |
1317 mmap_enabled_ = true; | |
1318 } | |
1319 | |
1230 const base::TimeDelta kBusyTimeout = | 1320 const base::TimeDelta kBusyTimeout = |
1231 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); | 1321 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); |
1232 | 1322 |
1233 if (page_size_ != 0) { | 1323 if (page_size_ != 0) { |
1234 // Enforce SQLite restrictions on |page_size_|. | 1324 // Enforce SQLite restrictions on |page_size_|. |
1235 DCHECK(!(page_size_ & (page_size_ - 1))) | 1325 DCHECK(!(page_size_ & (page_size_ - 1))) |
1236 << " page_size_ " << page_size_ << " is not a power of two."; | 1326 << " page_size_ " << page_size_ << " is not a power of two."; |
1237 const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h | 1327 const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h |
1238 DCHECK_LE(page_size_, kSqliteMaxPageSize); | 1328 DCHECK_LE(page_size_, kSqliteMaxPageSize); |
1239 const std::string sql = | 1329 const std::string sql = |
(...skipping 23 matching lines...) Expand all Loading... | |
1263 | 1353 |
1264 // Collect the rollback time manually, sql::Statement would register it as | 1354 // Collect the rollback time manually, sql::Statement would register it as |
1265 // query time only. | 1355 // query time only. |
1266 const base::TimeTicks before = Now(); | 1356 const base::TimeTicks before = Now(); |
1267 rollback.RunWithoutTimers(); | 1357 rollback.RunWithoutTimers(); |
1268 const base::TimeDelta delta = Now() - before; | 1358 const base::TimeDelta delta = Now() - before; |
1269 | 1359 |
1270 RecordUpdateTime(delta); | 1360 RecordUpdateTime(delta); |
1271 RecordOneEvent(EVENT_ROLLBACK); | 1361 RecordOneEvent(EVENT_ROLLBACK); |
1272 | 1362 |
1363 // The cache may have been accumulating dirty pages for commit. | |
1364 ReleaseCacheMemoryIfNeeded(false); | |
1365 | |
1273 needs_rollback_ = false; | 1366 needs_rollback_ = false; |
1274 } | 1367 } |
1275 | 1368 |
1276 void Connection::StatementRefCreated(StatementRef* ref) { | 1369 void Connection::StatementRefCreated(StatementRef* ref) { |
1277 DCHECK(open_statements_.find(ref) == open_statements_.end()); | 1370 DCHECK(open_statements_.find(ref) == open_statements_.end()); |
1278 open_statements_.insert(ref); | 1371 open_statements_.insert(ref); |
1279 } | 1372 } |
1280 | 1373 |
1281 void Connection::StatementRefDeleted(StatementRef* ref) { | 1374 void Connection::StatementRefDeleted(StatementRef* ref) { |
1282 StatementRefSet::iterator i = open_statements_.find(ref); | 1375 StatementRefSet::iterator i = open_statements_.find(ref); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1382 ignore_result(Execute(kNoWritableSchema)); | 1475 ignore_result(Execute(kNoWritableSchema)); |
1383 | 1476 |
1384 return ret; | 1477 return ret; |
1385 } | 1478 } |
1386 | 1479 |
1387 base::TimeTicks TimeSource::Now() { | 1480 base::TimeTicks TimeSource::Now() { |
1388 return base::TimeTicks::Now(); | 1481 return base::TimeTicks::Now(); |
1389 } | 1482 } |
1390 | 1483 |
1391 } // namespace sql | 1484 } // namespace sql |
OLD | NEW |