1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
// Copyright 2019 The Chromium Authors
// 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 <cstdint>
#include <ostream>
#include <vector>
#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);
// True if the last call to Initialize succeeded.
bool IsInitialized() const;
// 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<DatabasePageReader> db_reader_;
// Total size of the current payload.
int64_t payload_size_ = 0;
// 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_ = DatabasePageReader::kInvalidPageId;
// 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_ = 0;
// 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_ = 0;
// Number of overflow pages used by the payload.
int overflow_page_count_ = 0;
// Number of bytes in each overflow page that stores the payload.
int max_overflow_payload_size_ = 0;
// Page IDs for all the payload's overflow pages, in order.
//
// This list is populated on-demand.
std::vector<int> overflow_page_ids_;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace recover
} // namespace sql
#endif // SQL_RECOVER_MODULE_PAYLOAD_H_
|