pager.cc 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "sql/recover_module/pager.h"
  5. #include <limits>
  6. #include "sql/recover_module/table.h"
  7. #include "third_party/sqlite/sqlite3.h"
  8. namespace sql {
  9. namespace recover {
  10. constexpr int DatabasePageReader::kInvalidPageId;
  11. constexpr int DatabasePageReader::kMinPageSize;
  12. constexpr int DatabasePageReader::kMaxPageSize;
  13. constexpr int DatabasePageReader::kDatabaseHeaderSize;
  14. constexpr int DatabasePageReader::kMinUsablePageSize;
  15. constexpr int DatabasePageReader::kMaxPageId;
  16. static_assert(DatabasePageReader::kMaxPageId <= std::numeric_limits<int>::max(),
  17. "ints are not appropriate for representing page IDs");
  18. DatabasePageReader::DatabasePageReader(VirtualTable* table)
  19. : page_data_(table->page_size()), table_(table) {
  20. DCHECK(table != nullptr);
  21. DCHECK(IsValidPageSize(table->page_size()));
  22. }
  23. DatabasePageReader::~DatabasePageReader() = default;
  24. int DatabasePageReader::ReadPage(int page_id) {
  25. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  26. DCHECK_GT(page_id, kInvalidPageId);
  27. DCHECK_LE(page_id, kMaxPageId);
  28. if (page_id_ == page_id)
  29. return SQLITE_OK;
  30. sqlite3_file* const sqlite_file = table_->SqliteFile();
  31. const int page_size = table_->page_size();
  32. const int page_offset = (page_id == 1) ? kDatabaseHeaderSize : 0;
  33. const int read_size = page_size - page_offset;
  34. static_assert(kMinPageSize >= kDatabaseHeaderSize,
  35. "The |read_size| computation above may overflow");
  36. page_size_ = read_size;
  37. DCHECK_GE(page_size_, kMinUsablePageSize);
  38. DCHECK_LE(page_size_, kMaxPageSize);
  39. const int64_t read_offset =
  40. static_cast<int64_t>(page_id - 1) * page_size + page_offset;
  41. static_assert(static_cast<int64_t>(kMaxPageId - 1) * kMaxPageSize +
  42. kDatabaseHeaderSize <=
  43. std::numeric_limits<int64_t>::max(),
  44. "The |read_offset| computation above may overflow");
  45. int sqlite_status =
  46. RawRead(sqlite_file, read_size, read_offset, page_data_.data());
  47. // |page_id_| needs to be set to kInvalidPageId if the read failed.
  48. // Otherwise, future ReadPage() calls with the previous |page_id_| value
  49. // would return SQLITE_OK, but the page data buffer might be trashed.
  50. page_id_ = (sqlite_status == SQLITE_OK) ? page_id : kInvalidPageId;
  51. return sqlite_status;
  52. }
  53. // static
  54. int DatabasePageReader::RawRead(sqlite3_file* sqlite_file,
  55. int read_size,
  56. int64_t read_offset,
  57. uint8_t* result_buffer) {
  58. DCHECK(sqlite_file != nullptr);
  59. DCHECK_GE(read_size, 0);
  60. DCHECK_GE(read_offset, 0);
  61. DCHECK(result_buffer != nullptr);
  62. // Retry the I/O operations a few times if they fail. This is especially
  63. // useful when recovering from database corruption.
  64. static constexpr int kRetryCount = 10;
  65. int sqlite_status;
  66. bool got_lock = false;
  67. for (int i = kRetryCount; i > 0; --i) {
  68. sqlite_status =
  69. sqlite_file->pMethods->xLock(sqlite_file, SQLITE_LOCK_SHARED);
  70. if (sqlite_status == SQLITE_OK) {
  71. got_lock = true;
  72. break;
  73. }
  74. }
  75. // Try reading even if we don't have a shared lock on the database. If the
  76. // read fails, the database page is completely skipped, so any data we might
  77. // get from the read is better than nothing.
  78. for (int i = kRetryCount; i > 0; --i) {
  79. sqlite_status = sqlite_file->pMethods->xRead(sqlite_file, result_buffer,
  80. read_size, read_offset);
  81. if (sqlite_status == SQLITE_OK)
  82. break;
  83. if (sqlite_status == SQLITE_IOERR_SHORT_READ) {
  84. // The read succeeded, but hit EOF. The extra bytes in the page buffer
  85. // are set to zero. This is acceptable for our purposes.
  86. sqlite_status = SQLITE_OK;
  87. break;
  88. }
  89. }
  90. if (got_lock) {
  91. // TODO(pwnall): This logic was ported from the old C-in-SQLite-style patch.
  92. // Dropping the lock here is incorrect, because the file
  93. // descriptor is shared with the SQLite pager, which may
  94. // expect to be holding a lock.
  95. sqlite_file->pMethods->xUnlock(sqlite_file, SQLITE_LOCK_NONE);
  96. }
  97. return sqlite_status;
  98. }
  99. } // namespace recover
  100. } // namespace sql