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), | |
288 stats_histogram_(NULL), | 285 stats_histogram_(NULL), |
289 commit_time_histogram_(NULL), | 286 commit_time_histogram_(NULL), |
290 autocommit_time_histogram_(NULL), | 287 autocommit_time_histogram_(NULL), |
291 update_time_histogram_(NULL), | 288 update_time_histogram_(NULL), |
292 query_time_histogram_(NULL), | 289 query_time_histogram_(NULL), |
293 clock_(new TimeSource()) { | 290 clock_(new TimeSource()) { |
294 } | 291 } |
295 | 292 |
296 Connection::~Connection() { | 293 Connection::~Connection() { |
297 Close(); | 294 Close(); |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 preload_size = file_size; | 459 preload_size = file_size; |
463 | 460 |
464 scoped_ptr<char[]> buf(new char[page_size]); | 461 scoped_ptr<char[]> buf(new char[page_size]); |
465 for (sqlite3_int64 pos = 0; pos < preload_size; pos += page_size) { | 462 for (sqlite3_int64 pos = 0; pos < preload_size; pos += page_size) { |
466 rc = file->pMethods->xRead(file, buf.get(), page_size, pos); | 463 rc = file->pMethods->xRead(file, buf.get(), page_size, pos); |
467 if (rc != SQLITE_OK) | 464 if (rc != SQLITE_OK) |
468 return; | 465 return; |
469 } | 466 } |
470 } | 467 } |
471 | 468 |
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 | |
539 void Connection::TrimMemory(bool aggressively) { | 469 void Connection::TrimMemory(bool aggressively) { |
540 if (!db_) | 470 if (!db_) |
541 return; | 471 return; |
542 | 472 |
543 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. | 473 // TODO(shess): investigate using sqlite3_db_release_memory() when possible. |
544 int original_cache_size; | 474 int original_cache_size; |
545 { | 475 { |
546 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); | 476 Statement sql_get_original(GetUniqueStatement("PRAGMA cache_size")); |
547 if (!sql_get_original.Step()) { | 477 if (!sql_get_original.Step()) { |
548 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); | 478 DLOG(WARNING) << "Could not get cache size " << GetErrorMessage(); |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
839 | 769 |
840 // Collect the commit time manually, sql::Statement would register it as query | 770 // Collect the commit time manually, sql::Statement would register it as query |
841 // time only. | 771 // time only. |
842 const base::TimeTicks before = Now(); | 772 const base::TimeTicks before = Now(); |
843 bool ret = commit.RunWithoutTimers(); | 773 bool ret = commit.RunWithoutTimers(); |
844 const base::TimeDelta delta = Now() - before; | 774 const base::TimeDelta delta = Now() - before; |
845 | 775 |
846 RecordCommitTime(delta); | 776 RecordCommitTime(delta); |
847 RecordOneEvent(EVENT_COMMIT); | 777 RecordOneEvent(EVENT_COMMIT); |
848 | 778 |
849 // Release dirty cache pages after the transaction closes. | |
850 ReleaseCacheMemoryIfNeeded(false); | |
851 | |
852 return ret; | 779 return ret; |
853 } | 780 } |
854 | 781 |
855 void Connection::RollbackAllTransactions() { | 782 void Connection::RollbackAllTransactions() { |
856 if (transaction_nesting_ > 0) { | 783 if (transaction_nesting_ > 0) { |
857 transaction_nesting_ = 0; | 784 transaction_nesting_ = 0; |
858 DoRollback(); | 785 DoRollback(); |
859 } | 786 } |
860 } | 787 } |
861 | 788 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
932 // sqlite3_exec() does this, presumably to avoid spinning the parser for | 859 // sqlite3_exec() does this, presumably to avoid spinning the parser for |
933 // trailing whitespace. | 860 // trailing whitespace. |
934 // TODO(shess): Audit to see if this can become a DCHECK. | 861 // TODO(shess): Audit to see if this can become a DCHECK. |
935 while (base::IsAsciiWhitespace(*sql)) { | 862 while (base::IsAsciiWhitespace(*sql)) { |
936 sql++; | 863 sql++; |
937 } | 864 } |
938 | 865 |
939 const base::TimeDelta delta = Now() - before; | 866 const base::TimeDelta delta = Now() - before; |
940 RecordTimeAndChanges(delta, read_only); | 867 RecordTimeAndChanges(delta, read_only); |
941 } | 868 } |
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 | |
948 return rc; | 869 return rc; |
949 } | 870 } |
950 | 871 |
951 bool Connection::Execute(const char* sql) { | 872 bool Connection::Execute(const char* sql) { |
952 if (!db_) { | 873 if (!db_) { |
953 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; | 874 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
954 return false; | 875 return false; |
955 } | 876 } |
956 | 877 |
957 int error = ExecuteAndReturnErrorCode(sql); | 878 int error = ExecuteAndReturnErrorCode(sql); |
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1302 | 1223 |
1303 // http://www.sqlite.org/pragma.html#pragma_journal_mode | 1224 // http://www.sqlite.org/pragma.html#pragma_journal_mode |
1304 // DELETE (default) - delete -journal file to commit. | 1225 // DELETE (default) - delete -journal file to commit. |
1305 // TRUNCATE - truncate -journal file to commit. | 1226 // TRUNCATE - truncate -journal file to commit. |
1306 // PERSIST - zero out header of -journal file to commit. | 1227 // PERSIST - zero out header of -journal file to commit. |
1307 // TRUNCATE should be faster than DELETE because it won't need directory | 1228 // TRUNCATE should be faster than DELETE because it won't need directory |
1308 // changes for each transaction. PERSIST may break the spirit of using | 1229 // changes for each transaction. PERSIST may break the spirit of using |
1309 // secure_delete. | 1230 // secure_delete. |
1310 ignore_result(Execute("PRAGMA journal_mode = TRUNCATE")); | 1231 ignore_result(Execute("PRAGMA journal_mode = TRUNCATE")); |
1311 | 1232 |
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 | |
1324 const base::TimeDelta kBusyTimeout = | 1233 const base::TimeDelta kBusyTimeout = |
1325 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); | 1234 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); |
1326 | 1235 |
1327 if (page_size_ != 0) { | 1236 if (page_size_ != 0) { |
1328 // Enforce SQLite restrictions on |page_size_|. | 1237 // Enforce SQLite restrictions on |page_size_|. |
1329 DCHECK(!(page_size_ & (page_size_ - 1))) | 1238 DCHECK(!(page_size_ & (page_size_ - 1))) |
1330 << " page_size_ " << page_size_ << " is not a power of two."; | 1239 << " page_size_ " << page_size_ << " is not a power of two."; |
1331 const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h | 1240 const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h |
1332 DCHECK_LE(page_size_, kSqliteMaxPageSize); | 1241 DCHECK_LE(page_size_, kSqliteMaxPageSize); |
1333 const std::string sql = | 1242 const std::string sql = |
(...skipping 23 matching lines...) Expand all Loading... |
1357 | 1266 |
1358 // Collect the rollback time manually, sql::Statement would register it as | 1267 // Collect the rollback time manually, sql::Statement would register it as |
1359 // query time only. | 1268 // query time only. |
1360 const base::TimeTicks before = Now(); | 1269 const base::TimeTicks before = Now(); |
1361 rollback.RunWithoutTimers(); | 1270 rollback.RunWithoutTimers(); |
1362 const base::TimeDelta delta = Now() - before; | 1271 const base::TimeDelta delta = Now() - before; |
1363 | 1272 |
1364 RecordUpdateTime(delta); | 1273 RecordUpdateTime(delta); |
1365 RecordOneEvent(EVENT_ROLLBACK); | 1274 RecordOneEvent(EVENT_ROLLBACK); |
1366 | 1275 |
1367 // The cache may have been accumulating dirty pages for commit. | |
1368 ReleaseCacheMemoryIfNeeded(false); | |
1369 | |
1370 needs_rollback_ = false; | 1276 needs_rollback_ = false; |
1371 } | 1277 } |
1372 | 1278 |
1373 void Connection::StatementRefCreated(StatementRef* ref) { | 1279 void Connection::StatementRefCreated(StatementRef* ref) { |
1374 DCHECK(open_statements_.find(ref) == open_statements_.end()); | 1280 DCHECK(open_statements_.find(ref) == open_statements_.end()); |
1375 open_statements_.insert(ref); | 1281 open_statements_.insert(ref); |
1376 } | 1282 } |
1377 | 1283 |
1378 void Connection::StatementRefDeleted(StatementRef* ref) { | 1284 void Connection::StatementRefDeleted(StatementRef* ref) { |
1379 StatementRefSet::iterator i = open_statements_.find(ref); | 1285 StatementRefSet::iterator i = open_statements_.find(ref); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1479 ignore_result(Execute(kNoWritableSchema)); | 1385 ignore_result(Execute(kNoWritableSchema)); |
1480 | 1386 |
1481 return ret; | 1387 return ret; |
1482 } | 1388 } |
1483 | 1389 |
1484 base::TimeTicks TimeSource::Now() { | 1390 base::TimeTicks TimeSource::Now() { |
1485 return base::TimeTicks::Now(); | 1391 return base::TimeTicks::Now(); |
1486 } | 1392 } |
1487 | 1393 |
1488 } // namespace sql | 1394 } // namespace sql |
OLD | NEW |