pager.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. #ifndef SQL_RECOVER_MODULE_PAGER_H_
  5. #define SQL_RECOVER_MODULE_PAGER_H_
  6. #include <cstdint>
  7. #include <ostream>
  8. #include <vector>
  9. #include "base/check_op.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "base/sequence_checker.h"
  12. struct sqlite3_file;
  13. namespace sql {
  14. namespace recover {
  15. class VirtualTable;
  16. // Page reader for SQLite database files.
  17. //
  18. // Contains logic for retrying reads on I/O errors. Caches the last read page,
  19. // to facilitate layering in higher-level code.
  20. //
  21. // Instances should be members of high-level constructs such as tables or
  22. // cursors. Instances are not thread-safe.
  23. class DatabasePageReader {
  24. public:
  25. // Guaranteed to be an invalid page number.
  26. static constexpr int kInvalidPageId = 0;
  27. // Minimum database page size supported by SQLite.
  28. static constexpr int kMinPageSize = 512;
  29. // Maximum database page size supported by SQLite.
  30. static constexpr int kMaxPageSize = 65536;
  31. // The size of the header at the beginning of a SQLite database file.
  32. static constexpr int kDatabaseHeaderSize = 100;
  33. // Minimum usable size of a SQLite database page.
  34. //
  35. // This differs from |kMinPageSize| because the first page in a SQLite
  36. // database starts with the database header. That page's header starts right
  37. // after the database header.
  38. static constexpr int kMinUsablePageSize = kMinPageSize - kDatabaseHeaderSize;
  39. // Largest valid page ID in a SQLite database.
  40. //
  41. // This is the maximum value of SQLITE_MAX_PAGE_COUNT plus 1, because page IDs
  42. // start at 1. The numerical value, which is the same as
  43. // std::numeric_limits<int32_t>::max() - 1, is quoted from
  44. // https://www.sqlite.org/limits.html.
  45. static constexpr int kMaxPageId = 2147483646 + 1;
  46. // Creates a reader that uses the SQLite VFS backing |table|.
  47. //
  48. // |table| must outlive this instance.
  49. explicit DatabasePageReader(VirtualTable* table);
  50. ~DatabasePageReader();
  51. DatabasePageReader(const DatabasePageReader&) = delete;
  52. DatabasePageReader& operator=(const DatabasePageReader&) = delete;
  53. // The page data read by the last ReadPage() call.
  54. //
  55. // The page data is undefined if the last ReadPage() call failed, or if
  56. // ReadPage() was never called.
  57. const uint8_t* page_data() const {
  58. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  59. DCHECK_NE(page_id_, kInvalidPageId)
  60. << "Successful ReadPage() required before accessing pager state";
  61. return page_data_.data();
  62. }
  63. // The number of bytes in the page read by the last ReadPage() call.
  64. //
  65. // The result is guaranteed to be in [kMinUsablePageSize, kMaxPageSize].
  66. //
  67. // In general, pages have the same size. However, the first page in each
  68. // database is smaller, because it starts after the database header.
  69. //
  70. // The result is undefined if the last ReadPage() call failed, or if
  71. // ReadPage() was never called.
  72. int page_size() const {
  73. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  74. DCHECK_NE(page_id_, kInvalidPageId)
  75. << "Successful ReadPage() required before accessing pager state";
  76. DCHECK_GE(page_size_, kMinUsablePageSize);
  77. DCHECK_LE(page_size_, kMaxPageSize);
  78. return page_size_;
  79. }
  80. // Returns the |page_id| argument for the last successful ReadPage() call.
  81. //
  82. // The result is undefined if the last ReadPage() call failed, or if
  83. // ReadPage() was never called.
  84. int page_id() const {
  85. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  86. DCHECK_NE(page_id_, kInvalidPageId)
  87. << "Successful ReadPage() required before accessing pager state";
  88. return page_id_;
  89. }
  90. // Reads a database page. Returns a SQLite status code.
  91. //
  92. // SQLite uses 1-based indexing for its page numbers.
  93. //
  94. // This method is idempotent, because it caches its result.
  95. int ReadPage(int page_id);
  96. // True if the given database page size is supported by SQLite.
  97. static constexpr bool IsValidPageSize(int page_size) noexcept {
  98. // SQLite page sizes must be powers of two.
  99. return page_size >= kMinPageSize && page_size <= kMaxPageSize &&
  100. (page_size & (page_size - 1)) == 0;
  101. }
  102. // True if the given number is a valid SQLite database page ID.
  103. //
  104. // Valid page IDs are positive 32-bit integers.
  105. static constexpr bool IsValidPageId(int64_t page_id) noexcept {
  106. return page_id > kInvalidPageId && page_id <= kMaxPageId;
  107. }
  108. // Low-level read wrapper. Returns a SQLite error code.
  109. //
  110. // |read_size| and |read_offset| are expressed in bytes.
  111. static int RawRead(sqlite3_file* sqlite_file,
  112. int read_size,
  113. int64_t read_offset,
  114. uint8_t* buffer);
  115. private:
  116. // Points to the last page successfully read by ReadPage().
  117. // Set to kInvalidPageId if the last read was unsuccessful.
  118. int page_id_ = kInvalidPageId;
  119. // Stores the bytes of the last page successfully read by ReadPage().
  120. // The content is undefined if the last call to ReadPage() did not succeed.
  121. std::vector<uint8_t> page_data_;
  122. // Raw pointer usage is acceptable because this instance's owner is expected
  123. // to ensure that the VirtualTable outlives this.
  124. const raw_ptr<VirtualTable> table_;
  125. int page_size_ = 0;
  126. SEQUENCE_CHECKER(sequence_checker_);
  127. };
  128. } // namespace recover
  129. } // namespace sql
  130. #endif // SQL_RECOVER_MODULE_PAGER_H_