blob: 6737a9198328145c3d3a73fcf8441ed94430ba6a [file] [log] [blame]
Avi Drissman69b874f2022-09-15 19:11:141// Copyright 2019 The Chromium Authors
Victor Costan153dd1a2019-05-14 20:41:222// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef SQL_RECOVER_MODULE_BTREE_H_
6#define SQL_RECOVER_MODULE_BTREE_H_
7
8#include <cstdint>
Peter Kastingb2777ce2021-07-20 18:28:549#include <ostream>
Victor Costan153dd1a2019-05-14 20:41:2210
Hans Wennborgca7215962020-06-22 10:27:5211#include "base/check.h"
Victor Costan153dd1a2019-05-14 20:41:2212#include "base/sequence_checker.h"
13
14namespace sql {
15namespace recover {
16
17class DatabasePageReader;
18
19// Streaming decoder for inner pages in SQLite table B-trees.
20//
21// The decoder outputs the page IDs of the inner page's children pages.
22//
23// An instance can only be used to decode a single page. Instances are not
24// thread-safe.
25class InnerPageDecoder {
26 public:
27 // Creates a decoder for a DatabasePageReader's last read page.
28 //
29 // |db_reader| must have been used to read an inner page of a table B-tree.
30 // |db_reader| must outlive this instance.
31 explicit InnerPageDecoder(DatabasePageReader* db_reader) noexcept;
32 ~InnerPageDecoder() noexcept = default;
33
34 InnerPageDecoder(const InnerPageDecoder&) = delete;
35 InnerPageDecoder& operator=(const InnerPageDecoder&) = delete;
36
37 // The ID of the database page decoded by this instance.
38 int page_id() const {
39 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
40 return page_id_;
41 }
42
43 // Returns true iff TryAdvance() may be called.
44 bool CanAdvance() const {
45 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
46 // The <= below is not a typo. Inner nodes store the right-most child
47 // pointer in their headers, so their child count is (cell_count + 1).
48 return next_read_index_ <= cell_count_;
49 }
50
51 // Advances the reader and returns the last read value.
52 //
53 // May return an invalid page ID if database was corrupted or the read failed.
54 // The caller must use DatabasePageReader::IsValidPageId() to verify the
55 // returned page ID. The caller should continue attempting to read as long as
56 // CanAdvance() returns true.
57 int TryAdvance();
58
59 // True if the given reader may point to an inner page in a table B-tree.
60 //
61 // The last ReadPage() call on |db_reader| must have succeeded.
62 static bool IsOnValidPage(DatabasePageReader* db_reader);
63
64 private:
65 // Returns the number of cells in the B-tree page.
66 //
67 // Checks for database corruption. The caller can assume that the cell pointer
68 // array with the returned size will not extend past the page buffer.
69 static int ComputeCellCount(DatabasePageReader* db_reader);
70
71 // The number of the B-tree page this reader is reading.
72 const int page_id_;
73 // Used to read the tree page.
Victor Costane57bc212019-05-15 23:18:0774 //
75 // Raw pointer usage is acceptable because this instance's owner is expected
76 // to ensure that the DatabasePageReader outlives this.
Victor Costan153dd1a2019-05-14 20:41:2277 DatabasePageReader* const db_reader_;
78 // Caches the ComputeCellCount() value for this reader's page.
79 const int cell_count_ = ComputeCellCount(db_reader_);
80
81 // The reader's cursor state.
82 //
83 // Each B-tree page has a header and many cells. In an inner B-tree page, each
84 // cell points to a child page, and the header points to the last child page.
85 // So, an inner page with N cells has N+1 children, and |next_read_index_|
86 // takes values between 0 and |cell_count_| + 1.
87 int next_read_index_ = 0;
88
89 SEQUENCE_CHECKER(sequence_checker_);
90};
91
92// Streaming decoder for leaf pages in SQLite table B-trees.
93//
94// Conceptually, the decoder outputs (rowid, record size, record offset) tuples
95// for all the values stored in the leaf page. The tuple members can be accessed
96// via last_record_{rowid, size, offset}() methods.
97//
98// An instance can only be used to decode a single page. Instances are not
99// thread-safe.
100class LeafPageDecoder {
101 public:
102 // Creates a decoder for a DatabasePageReader's last read page.
103 //
104 // |db_reader| must have been used to read an inner page of a table B-tree.
105 // |db_reader| must outlive this instance.
106 explicit LeafPageDecoder(DatabasePageReader* db_reader) noexcept;
107 ~LeafPageDecoder() noexcept = default;
108
109 LeafPageDecoder(const LeafPageDecoder&) = delete;
110 LeafPageDecoder& operator=(const LeafPageDecoder&) = delete;
111
112 // The rowid of the most recent record read by TryAdvance().
113 //
114 // Must only be called after a successful call to TryAdvance().
115 int64_t last_record_rowid() const {
116 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
117 DCHECK(last_record_size_ != 0)
118 << "TryAdvance() not called / did not succeed";
119 return last_record_rowid_;
120 }
121
122 // The size of the most recent record read by TryAdvance().
123 //
124 // Must only be called after a successful call to TryAdvance().
125 int64_t last_record_size() const {
126 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
127 DCHECK(last_record_size_ != 0)
128 << "TryAdvance() not called / did not succeed";
129 return last_record_size_;
130 }
131
132 // The page offset of the most recent record read by TryAdvance().
133 //
134 // Must only be called after a successful call to TryAdvance().
135 int64_t last_record_offset() const {
136 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
137 DCHECK(last_record_size_ != 0)
138 << "TryAdvance() not called / did not succeed";
139 return last_record_offset_;
140 }
141
142 // Returns true iff TryAdvance() may be called.
143 bool CanAdvance() const {
144 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
145 return next_read_index_ < cell_count_;
146 }
147
148 // Advances the reader and returns the last read value.
149 //
150 // Returns false if the read fails. The caller should continue attempting to
151 // read as long as CanAdvance() returns true.
152 bool TryAdvance();
153
154 // True if the given reader may point to an inner page in a table B-tree.
155 //
156 // The last ReadPage() call on |db_reader| must have succeeded.
157 static bool IsOnValidPage(DatabasePageReader* db_reader);
158
159 private:
160 // Returns the number of cells in the B-tree page.
161 //
162 // Checks for database corruption. The caller can assume that the cell pointer
163 // array with the returned size will not extend past the page buffer.
164 static int ComputeCellCount(DatabasePageReader* db_reader);
165
166 // The number of the B-tree page this reader is reading.
167 const int64_t page_id_;
168 // Used to read the tree page.
Victor Costane57bc212019-05-15 23:18:07169 //
170 // Raw pointer usage is acceptable because this instance's owner is expected
171 // to ensure that the DatabasePageReader outlives this.
Victor Costan153dd1a2019-05-14 20:41:22172 DatabasePageReader* const db_reader_;
173 // Caches the ComputeCellCount() value for this reader's page.
174 const int cell_count_ = ComputeCellCount(db_reader_);
175
176 // The reader's cursor state.
177 //
178 // Each B-tree cell contains a value. So, this member takes values in
179 // [0, cell_count_).
180 int next_read_index_ = 0;
181
182 int64_t last_record_size_ = 0;
183 int64_t last_record_rowid_ = 0;
184 int last_record_offset_ = 0;
185
186 SEQUENCE_CHECKER(sequence_checker_);
187};
188
189} // namespace recover
190} // namespace sql
191
192#endif // SQL_RECOVER_MODULE_BTREE_H_