// 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_PAYLOAD_H_ #define SQL_RECOVER_MODULE_PAYLOAD_H_ #include #include #include #include "base/check_op.h" #include "base/memory/raw_ptr.h" #include "base/sequence_checker.h" #include "sql/recover_module/pager.h" namespace sql { namespace recover { class DatabasePageReader; // Reads payloads (records) across B-tree pages and overflow pages. // // Instances are designed to be reused for reading multiple payloads. Instances // are not thread-safe. // // Reading a payload is started by calling Initialize() with the information // from LeafPageDecoder. If the call succeeds, ReadPayload() can be called // repeatedly. class LeafPayloadReader { public: // Number of payload bytes guaranteed to be on the B-tree page. // // The value is derived from the minimum SQLite usable page size, which is // 380 bytes, and the formula for the minimum payload size given a usable page // size. static constexpr int kMinInlineSize = ((380 - 12) * 32) / 255 - 23; explicit LeafPayloadReader(DatabasePageReader* db_reader); ~LeafPayloadReader(); LeafPayloadReader(const LeafPayloadReader&) = delete; LeafPayloadReader& operator=(const LeafPayloadReader&) = delete; // Sets up the reader for a new payload. // // The DatabasePageReader passed to the constructor must be focused on the // page containing the payload. // // This method must complete successfully before any other method on this // class can be called. bool Initialize(int64_t payload_size, int payload_offset); // The number of payload bytes that are stored on the B-tree page. // // The return value is guaranteed to be non-negative and at most // payload_size(). int inline_payload_size() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(page_id_ != DatabasePageReader::kInvalidPageId) << "Initialize() not called, or last call did not succeed"; DCHECK_LE(inline_payload_size_, payload_size_); return inline_payload_size_; } // Total payload size, in bytes. // // This includes the bytes stored in the B-tree page, as well as any bytes // stored in overflow pages. // // The return value is guaranteed to be at least inline_payload_size(). int payload_size() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(page_id_ != DatabasePageReader::kInvalidPageId) << "Initialize() not called, or last call did not succeed"; DCHECK_LE(inline_payload_size_, payload_size_); return payload_size_; } // Copies a subset of the payload into a given buffer. // // Returns true if the read succeeds. // // May only be called after a previous call to Initialize() that returns true. bool ReadPayload(int64_t offset, int64_t size, uint8_t* buffer); // Pulls the B-tree containing the payload into the database reader's cache. // // Returns a pointer to the beginning of the payload bytes. The pointer is // inside the database reader's buffer, and may get invalidated if the // database reader is used. // // Returns null if the read operation fails. // // May only be called after a previous call to Initialize() that returns true. const uint8_t* ReadInlinePayload(); private: // Extends the cached list of overflow page IDs by one page. // // Returns false if the operation failed. Failures are due to read errors or // database corruption. bool PopulateNextOverflowPageId(); // Used to read the pages containing the payload. // // Raw pointer usage is acceptable because this instance's owner is expected // to ensure that the DatabasePageReader outlives this. const raw_ptr db_reader_; // Total size of the current payload. int64_t payload_size_; // The ID of the B-tree page containing the current payload's inline bytes. // // Set to kInvalidPageId if the reader wasn't successfully initialized. int page_id_; // The start of the current payload's inline bytes on the B-tree page. // // Large payloads extend past the B-tree page containing the payload, via // overflow pages. int inline_payload_offset_; // Number of bytes in the current payload stored in its B-tree page. // // The rest of the payload is stored on overflow pages. int inline_payload_size_; // Number of overflow pages used by the payload. int overflow_page_count_; // Number of bytes in each overflow page that stores the payload. int max_overflow_payload_size_; // Page IDs for all the payload's overflow pages, in order. // // This list is populated on-demand. std::vector overflow_page_ids_; SEQUENCE_CHECKER(sequence_checker_); }; } // namespace recover } // namespace sql #endif // SQL_RECOVER_MODULE_PAYLOAD_H_