123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef SQL_RECOVER_MODULE_PAGER_H_
- #define SQL_RECOVER_MODULE_PAGER_H_
- #include <cstdint>
- #include <ostream>
- #include <vector>
- #include "base/check_op.h"
- #include "base/memory/raw_ptr.h"
- #include "base/sequence_checker.h"
- struct sqlite3_file;
- namespace sql {
- namespace recover {
- class VirtualTable;
- // Page reader for SQLite database files.
- //
- // Contains logic for retrying reads on I/O errors. Caches the last read page,
- // to facilitate layering in higher-level code.
- //
- // Instances should be members of high-level constructs such as tables or
- // cursors. Instances are not thread-safe.
- class DatabasePageReader {
- public:
- // Guaranteed to be an invalid page number.
- static constexpr int kInvalidPageId = 0;
- // Minimum database page size supported by SQLite.
- static constexpr int kMinPageSize = 512;
- // Maximum database page size supported by SQLite.
- static constexpr int kMaxPageSize = 65536;
- // The size of the header at the beginning of a SQLite database file.
- static constexpr int kDatabaseHeaderSize = 100;
- // Minimum usable size of a SQLite database page.
- //
- // This differs from |kMinPageSize| because the first page in a SQLite
- // database starts with the database header. That page's header starts right
- // after the database header.
- static constexpr int kMinUsablePageSize = kMinPageSize - kDatabaseHeaderSize;
- // Largest valid page ID in a SQLite database.
- //
- // This is the maximum value of SQLITE_MAX_PAGE_COUNT plus 1, because page IDs
- // start at 1. The numerical value, which is the same as
- // std::numeric_limits<int32_t>::max() - 1, is quoted from
- // https://www.sqlite.org/limits.html.
- static constexpr int kMaxPageId = 2147483646 + 1;
- // Creates a reader that uses the SQLite VFS backing |table|.
- //
- // |table| must outlive this instance.
- explicit DatabasePageReader(VirtualTable* table);
- ~DatabasePageReader();
- DatabasePageReader(const DatabasePageReader&) = delete;
- DatabasePageReader& operator=(const DatabasePageReader&) = delete;
- // The page data read by the last ReadPage() call.
- //
- // The page data is undefined if the last ReadPage() call failed, or if
- // ReadPage() was never called.
- const uint8_t* page_data() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_NE(page_id_, kInvalidPageId)
- << "Successful ReadPage() required before accessing pager state";
- return page_data_.data();
- }
- // The number of bytes in the page read by the last ReadPage() call.
- //
- // The result is guaranteed to be in [kMinUsablePageSize, kMaxPageSize].
- //
- // In general, pages have the same size. However, the first page in each
- // database is smaller, because it starts after the database header.
- //
- // The result is undefined if the last ReadPage() call failed, or if
- // ReadPage() was never called.
- int page_size() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_NE(page_id_, kInvalidPageId)
- << "Successful ReadPage() required before accessing pager state";
- DCHECK_GE(page_size_, kMinUsablePageSize);
- DCHECK_LE(page_size_, kMaxPageSize);
- return page_size_;
- }
- // Returns the |page_id| argument for the last successful ReadPage() call.
- //
- // The result is undefined if the last ReadPage() call failed, or if
- // ReadPage() was never called.
- int page_id() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_NE(page_id_, kInvalidPageId)
- << "Successful ReadPage() required before accessing pager state";
- return page_id_;
- }
- // Reads a database page. Returns a SQLite status code.
- //
- // SQLite uses 1-based indexing for its page numbers.
- //
- // This method is idempotent, because it caches its result.
- int ReadPage(int page_id);
- // True if the given database page size is supported by SQLite.
- static constexpr bool IsValidPageSize(int page_size) noexcept {
- // SQLite page sizes must be powers of two.
- return page_size >= kMinPageSize && page_size <= kMaxPageSize &&
- (page_size & (page_size - 1)) == 0;
- }
- // True if the given number is a valid SQLite database page ID.
- //
- // Valid page IDs are positive 32-bit integers.
- static constexpr bool IsValidPageId(int64_t page_id) noexcept {
- return page_id > kInvalidPageId && page_id <= kMaxPageId;
- }
- // Low-level read wrapper. Returns a SQLite error code.
- //
- // |read_size| and |read_offset| are expressed in bytes.
- static int RawRead(sqlite3_file* sqlite_file,
- int read_size,
- int64_t read_offset,
- uint8_t* buffer);
- private:
- // Points to the last page successfully read by ReadPage().
- // Set to kInvalidPageId if the last read was unsuccessful.
- int page_id_ = kInvalidPageId;
- // Stores the bytes of the last page successfully read by ReadPage().
- // The content is undefined if the last call to ReadPage() did not succeed.
- std::vector<uint8_t> page_data_;
- // Raw pointer usage is acceptable because this instance's owner is expected
- // to ensure that the VirtualTable outlives this.
- const raw_ptr<VirtualTable> table_;
- int page_size_ = 0;
- SEQUENCE_CHECKER(sequence_checker_);
- };
- } // namespace recover
- } // namespace sql
- #endif // SQL_RECOVER_MODULE_PAGER_H_
|