| 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 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 Connection::Connection() | 275 Connection::Connection() |
| 276 : db_(NULL), | 276 : db_(NULL), |
| 277 page_size_(0), | 277 page_size_(0), |
| 278 cache_size_(0), | 278 cache_size_(0), |
| 279 exclusive_locking_(false), | 279 exclusive_locking_(false), |
| 280 restrict_to_user_(false), | 280 restrict_to_user_(false), |
| 281 transaction_nesting_(0), | 281 transaction_nesting_(0), |
| 282 needs_rollback_(false), | 282 needs_rollback_(false), |
| 283 in_memory_(false), | 283 in_memory_(false), |
| 284 poisoned_(false), | 284 poisoned_(false), |
| 285 mmap_disabled_(false), |
| 286 mmap_enabled_(false), |
| 287 total_changes_at_last_release_(0), |
| 285 stats_histogram_(NULL), | 288 stats_histogram_(NULL), |
| 286 commit_time_histogram_(NULL), | 289 commit_time_histogram_(NULL), |
| 287 autocommit_time_histogram_(NULL), | 290 autocommit_time_histogram_(NULL), |
| 288 update_time_histogram_(NULL), | 291 update_time_histogram_(NULL), |
| 289 query_time_histogram_(NULL), | 292 query_time_histogram_(NULL), |
| 290 clock_(new TimeSource()) { | 293 clock_(new TimeSource()) { |
| 291 } | 294 } |
| 292 | 295 |
| 293 Connection::~Connection() { | 296 Connection::~Connection() { |
| 294 Close(); | 297 Close(); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 preload_size = file_size; | 462 preload_size = file_size; |
| 460 | 463 |
| 461 scoped_ptr<char[]> buf(new char[page_size]); | 464 scoped_ptr<char[]> buf(new char[page_size]); |
| 462 for (sqlite3_int64 pos = 0; pos < preload_size; pos += page_size) { | 465 for (sqlite3_int64 pos = 0; pos < preload_size; pos += page_size) { |
| 463 rc = file->pMethods->xRead(file, buf.get(), page_size, pos); | 466 rc = file->pMethods->xRead(file, buf.get(), page_size, pos); |
| 464 if (rc != SQLITE_OK) | 467 if (rc != SQLITE_OK) |
| 465 return; | 468 return; |
| 466 } | 469 } |
| 467 } | 470 } |
| 468 | 471 |
| 472 // SQLite keeps unused pages associated with a connection in a cache. It asks |
| 473 // the cache for pages by an id, and if the page is present and the database is |
| 474 // unchanged, it considers the content of the page valid and doesn't read it |
| 475 // from disk. When memory-mapped I/O is enabled, on read SQLite uses page |
| 476 // structures created from the memory map data before consulting the cache. On |
| 477 // write SQLite creates a new in-memory page structure, copies the data from the |
| 478 // memory map, and later writes it, releasing the updated page back to the |
| 479 // cache. |
| 480 // |
| 481 // This means that in memory-mapped mode, the contents of the cached pages are |
| 482 // not re-used for reads, but they are re-used for writes if the re-written page |
| 483 // is still in the cache. The implementation of sqlite3_db_release_memory() as |
| 484 // of SQLite 3.8.7.4 frees all pages from pcaches associated with the |
| 485 // connection, so it should free these pages. |
| 486 // |
| 487 // Unfortunately, the zero page is also freed. That page is never accessed |
| 488 // using memory-mapped I/O, and the cached copy can be re-used after verifying |
| 489 // the file change counter on disk. Also, fresh pages from cache receive some |
| 490 // pager-level initialization before they can be used. Since the information |
| 491 // involved will immediately be accessed in various ways, it is unclear if the |
| 492 // additional overhead is material, or just moving processor cache effects |
| 493 // around. |
| 494 // |
| 495 // TODO(shess): It would be better to release the pages immediately when they |
| 496 // are no longer needed. This would basically happen after SQLite commits a |
| 497 // transaction. I had implemented a pcache wrapper to do this, but it involved |
| 498 // layering violations, and it had to be setup before any other sqlite call, |
| 499 // which was brittle. Also, for large files it would actually make sense to |
| 500 // maintain the existing pcache behavior for blocks past the memory-mapped |
| 501 // segment. I think drh would accept a reasonable implementation of the overall |
| 502 // concept for upstreaming to SQLite core. |
| 503 // |
| 504 // TODO(shess): Another possibility would be to set the cache size small, which |
| 505 // would keep the zero page around, plus some pre-initialized pages, and SQLite |
| 506 // can manage things. The downside is that updates larger than the cache would |
| 507 // spill to the journal. That could be compensated by setting cache_spill to |
| 508 // false. The downside then is that it allows open-ended use of memory for |
| 509 // large transactions. |
| 510 // |
| 511 // TODO(shess): The TrimMemory() trick of bouncing the cache size would also |
| 512 // work. There could be two prepared statements, one for cache_size=1 one for |
| 513 // cache_size=goal. |
| 514 void Connection::ReleaseCacheMemoryIfNeeded(bool implicit_change_performed) { |
| 515 // If memory-mapping is not enabled, the page cache helps performance. |
| 516 if (!mmap_enabled_) |
| 517 return; |
| 518 |
| 519 // On caller request, force the change comparison to fail. Done before the |
| 520 // transaction-nesting test so that the signal can carry to transaction |
| 521 // commit. |
| 522 if (implicit_change_performed) |
| 523 --total_changes_at_last_release_; |
| 524 |
| 525 // Cached pages may be re-used within the same transaction. |
| 526 if (transaction_nesting()) |
| 527 return; |
| 528 |
| 529 // If no changes have been made, skip flushing. This allows the first page of |
| 530 // the database to remain in cache across multiple reads. |
| 531 const int total_changes = sqlite3_total_changes(db_); |
| 532 if (total_changes == total_changes_at_last_release_) |
| 533 return; |
| 534 |
| 535 total_changes_at_last_release_ = total_changes; |
| 536 sqlite3_db_release_memory(db_); |
| 537 } |
| 538 |
| 469 void Connection::TrimMemory(bool aggressively) { | 539 void Connection::TrimMemory(bool aggressively) { |
| 470 if (!db_) | 540 if (!db_) |
| 471 return; | 541 return; |
| 472 | 542 |
| 473 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. | 543 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. |
| 474 int original_cache_size; | 544 int original_cache_size; |
| 475 { | 545 { |
| 476 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); | 546 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); |
| 477 if (!sql_get_original.Step()) { | 547 if (!sql_get_original.Step()) { |
| 478 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); | 548 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 | 839 |
| 770 // Collect the commit time manually, sql::Statement would register it as query | 840 // Collect the commit time manually, sql::Statement would register it as query |
| 771 // time only. | 841 // time only. |
| 772 const base::TimeTicks before = Now(); | 842 const base::TimeTicks before = Now(); |
| 773 bool ret = commit.RunWithoutTimers(); | 843 bool ret = commit.RunWithoutTimers(); |
| 774 const base::TimeDelta delta = Now() - before; | 844 const base::TimeDelta delta = Now() - before; |
| 775 | 845 |
| 776 RecordCommitTime(delta); | 846 RecordCommitTime(delta); |
| 777 RecordOneEvent(EVENT_COMMIT); | 847 RecordOneEvent(EVENT_COMMIT); |
| 778 | 848 |
| 849 // Release dirty cache pages after the transaction closes. |
| 850 ReleaseCacheMemoryIfNeeded(false); |
| 851 |
| 779 return ret; | 852 return ret; |
| 780 } | 853 } |
| 781 | 854 |
| 782 void Connection::RollbackAllTransactions() { | 855 void Connection::RollbackAllTransactions() { |
| 783 if (transaction_nesting_ > 0) { | 856 if (transaction_nesting_ > 0) { |
| 784 transaction_nesting_ = 0; | 857 transaction_nesting_ = 0; |
| 785 DoRollback(); | 858 DoRollback(); |
| 786 } | 859 } |
| 787 } | 860 } |
| 788 | 861 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 859 // sqlite3_exec() does this, presumably to avoid spinning the parser for | 932 // sqlite3_exec() does this, presumably to avoid spinning the parser for |
| 860 // trailing whitespace. | 933 // trailing whitespace. |
| 861 // TODO(shess): Audit to see if this can become a DCHECK. | 934 // TODO(shess): Audit to see if this can become a DCHECK. |
| 862 while (base::IsAsciiWhitespace(*sql)) { | 935 while (base::IsAsciiWhitespace(*sql)) { |
| 863 sql++; | 936 sql++; |
| 864 } | 937 } |
| 865 | 938 |
| 866 const base::TimeDelta delta = Now() - before; | 939 const base::TimeDelta delta = Now() - before; |
| 867 RecordTimeAndChanges(delta, read_only); | 940 RecordTimeAndChanges(delta, read_only); |
| 868 } | 941 } |
| 942 |
| 943 // Most calls to Execute() modify the database. The main exceptions would be |
| 944 // calls such as CREATE TABLE IF NOT EXISTS which could modify the database |
| 945 // but sometimes don't. |
| 946 ReleaseCacheMemoryIfNeeded(true); |
| 947 |
| 869 return rc; | 948 return rc; |
| 870 } | 949 } |
| 871 | 950 |
| 872 bool Connection::Execute(const char* sql) { | 951 bool Connection::Execute(const char* sql) { |
| 873 if (!db_) { | 952 if (!db_) { |
| 874 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; | 953 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
| 875 return false; | 954 return false; |
| 876 } | 955 } |
| 877 | 956 |
| 878 int error = ExecuteAndReturnErrorCode(sql); | 957 int error = ExecuteAndReturnErrorCode(sql); |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1223 | 1302 |
| 1224 // http://www.sqlite.org/pragma.html#pragma_journal_mode | 1303 // http://www.sqlite.org/pragma.html#pragma_journal_mode |
| 1225 // DELETE (default) - delete -journal file to commit. | 1304 // DELETE (default) - delete -journal file to commit. |
| 1226 // TRUNCATE - truncate -journal file to commit. | 1305 // TRUNCATE - truncate -journal file to commit. |
| 1227 // PERSIST - zero out header of -journal file to commit. | 1306 // PERSIST - zero out header of -journal file to commit. |
| 1228 // TRUNCATE should be faster than DELETE because it won't need directory | 1307 // TRUNCATE should be faster than DELETE because it won't need directory |
| 1229 // changes for each transaction. PERSIST may break the spirit of using | 1308 // changes for each transaction. PERSIST may break the spirit of using |
| 1230 // secure_delete. | 1309 // secure_delete. |
| 1231 ignore_result(Execute("PRAGMA journal_mode = TRUNCATE")); | 1310 ignore_result(Execute("PRAGMA journal_mode = TRUNCATE")); |
| 1232 | 1311 |
| 1312 // Enable memory-mapped access. This value will be capped by |
| 1313 // SQLITE_MAX_MMAP_SIZE, which could be different between 32-bit and 64-bit |
| 1314 // platforms. |
| 1315 mmap_enabled_ = false; |
| 1316 if (!mmap_disabled_) |
| 1317 ignore_result(Execute("PRAGMA mmap_size = 268435456")); // 256MB. |
| 1318 { |
| 1319 Statement s(GetUniqueStatement("PRAGMA mmap_size")); |
| 1320 if (s.Step() && s.ColumnInt64(0) > 0) |
| 1321 mmap_enabled_ = true; |
| 1322 } |
| 1323 |
| 1233 const base::TimeDelta kBusyTimeout = | 1324 const base::TimeDelta kBusyTimeout = |
| 1234 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); | 1325 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); |
| 1235 | 1326 |
| 1236 if (page_size_ != 0) { | 1327 if (page_size_ != 0) { |
| 1237 // Enforce SQLite restrictions on |page_size_|. | 1328 // Enforce SQLite restrictions on |page_size_|. |
| 1238 DCHECK(!(page_size_ & (page_size_ - 1))) | 1329 DCHECK(!(page_size_ & (page_size_ - 1))) |
| 1239 << " page_size_ " << page_size_ << " is not a power of two."; | 1330 << " page_size_ " << page_size_ << " is not a power of two."; |
| 1240 const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h | 1331 const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h |
| 1241 DCHECK_LE(page_size_, kSqliteMaxPageSize); | 1332 DCHECK_LE(page_size_, kSqliteMaxPageSize); |
| 1242 const std::string sql = | 1333 const std::string sql = |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1266 | 1357 |
| 1267 // Collect the rollback time manually, sql::Statement would register it as | 1358 // Collect the rollback time manually, sql::Statement would register it as |
| 1268 // query time only. | 1359 // query time only. |
| 1269 const base::TimeTicks before = Now(); | 1360 const base::TimeTicks before = Now(); |
| 1270 rollback.RunWithoutTimers(); | 1361 rollback.RunWithoutTimers(); |
| 1271 const base::TimeDelta delta = Now() - before; | 1362 const base::TimeDelta delta = Now() - before; |
| 1272 | 1363 |
| 1273 RecordUpdateTime(delta); | 1364 RecordUpdateTime(delta); |
| 1274 RecordOneEvent(EVENT_ROLLBACK); | 1365 RecordOneEvent(EVENT_ROLLBACK); |
| 1275 | 1366 |
| 1367 // The cache may have been accumulating dirty pages for commit. |
| 1368 ReleaseCacheMemoryIfNeeded(false); |
| 1369 |
| 1276 needs_rollback_ = false; | 1370 needs_rollback_ = false; |
| 1277 } | 1371 } |
| 1278 | 1372 |
| 1279 void Connection::StatementRefCreated(StatementRef* ref) { | 1373 void Connection::StatementRefCreated(StatementRef* ref) { |
| 1280 DCHECK(open_statements_.find(ref) == open_statements_.end()); | 1374 DCHECK(open_statements_.find(ref) == open_statements_.end()); |
| 1281 open_statements_.insert(ref); | 1375 open_statements_.insert(ref); |
| 1282 } | 1376 } |
| 1283 | 1377 |
| 1284 void Connection::StatementRefDeleted(StatementRef* ref) { | 1378 void Connection::StatementRefDeleted(StatementRef* ref) { |
| 1285 StatementRefSet::iterator i = open_statements_.find(ref); | 1379 StatementRefSet::iterator i = open_statements_.find(ref); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1385 ignore_result(Execute(kNoWritableSchema)); | 1479 ignore_result(Execute(kNoWritableSchema)); |
| 1386 | 1480 |
| 1387 return ret; | 1481 return ret; |
| 1388 } | 1482 } |
| 1389 | 1483 |
| 1390 base::TimeTicks TimeSource::Now() { | 1484 base::TimeTicks TimeSource::Now() { |
| 1391 return base::TimeTicks::Now(); | 1485 return base::TimeTicks::Now(); |
| 1392 } | 1486 } |
| 1393 | 1487 |
| 1394 } // namespace sql | 1488 } // namespace sql |
| OLD | NEW |