41 while (n--) out->put(
' ');
46 out->write(reinterpret_cast<const char *>(p), n);
83 *out <<
"Block [" << n <<
"] level " << j <<
", revision *" <<
REVISION(p)
84 <<
" items (" << (dir_end -
DIR_START) /
D2 <<
") usage " 85 << block_usage(p) <<
"%:\n";
97 int space = block_size -
DIR_END(p);
99 return (space - free) * 100 / space;
111 *out <<
"[" << n <<
"] *" <<
REVISION(p) <<
" (" 112 << (dir_end -
DIR_START) /
D2 <<
") " << block_usage(p) <<
"% ";
115 if (c >=
DIR_START + 6 && c < dir_end - 6) {
134 uint8_t * p = C_[j].
p;
142 int total_free = block_size - dir_end;
147 if (base.block_free_at_start(n))
148 failure(
"Block was free at start");
149 if (base.block_free_now(n))
155 failure(
"Block has wrong level");
157 if (dir_end <= DIR_START || dir_end >
int(block_size) || (dir_end & 1) != 1)
158 failure(
"directory end pointer invalid");
161 report_block(3*(level - j), n, p);
164 report_block_full(3*(level - j), n, p);
169 if (o >
int(block_size))
170 failure(
"Item starts outside block");
171 if (o - dir_end <
int(max_free))
172 failure(
"Item overlaps directory");
174 int kt_len = item.
size();
175 if (o + kt_len >
int(block_size))
176 failure(
"Item ends outside block");
177 total_free -= kt_len;
179 if (c > significant_c &&
Item(p, c - D2).key() >= item.
key())
180 failure(
"Items not in sorted order");
186 failure(
"Stored total free space value wrong");
190 if (check_sequential) {
191 if (n >= last_sequential_block) {
192 last_sequential_block = n;
194 check_sequential =
false;
202 block_to_cursor(C_, j - 1,
Item(p, c).block_given_by());
204 block_check(C_, j - 1, opts);
206 uint8_t * q = C_[j - 1].
p;
212 failure(
"Leaf key < left dividing key in level above");
219 failure(
"Key < left dividing key in level above");
224 if (c + D2 < dir_end &&
227 failure(
"Key >= right dividing key in level above");
230 failure(
"Child block has greater revision than parent");
243 if (rev_ptr && *rev_ptr) {
245 if (!B.
open(*rev_ptr)) {
246 string msg =
"Failed to open ";
248 msg +=
" table at revision ";
249 msg +=
str(*rev_ptr);
275 unsigned char buf[65536];
276 uint4 blocksize = 8192;
277 size_t read =
io_read(fd, reinterpret_cast<char*>(buf),
sizeof(buf));
283 blocksize += item.
size();
286 *out <<
"Block size deduced as " << blocksize << endl;
288 if (lseek(fd, 0, SEEK_SET) < 0) {
289 B.
failure(
"Failed to seek to start of table");
294 io_read(fd, reinterpret_cast<char*>(buf), blocksize) == blocksize;
297 if (rev_ptr && *rev_ptr) {
317 if (blk_level <= level)
324 *out <<
"Root guess -> blk " << root <<
" rev " << revision
325 <<
" level " << level << endl;
332 *out <<
"Failed to find a suitable root block with revision " 339 *out <<
"Empty table, but revision number not yet known" << endl;
345 *out <<
"Empty table, assuming default block size of " 346 << blocksize << endl;
366 faked_base +=
"baseA";
367 fake_base.
write_to_file(faked_base,
'A',
string(), -1, NULL);
370 (void)unlink((path +
"baseB").c_str());
373 if (!B.
open(revision)) {
374 string msg =
"Root guess of blk ";
377 msg +=
str(revision);
378 msg +=
" didn't work";
382 if (rev_ptr && !*rev_ptr)
390 <<
" blocksize=" << B.
block_size / 1024 <<
"K" 394 <<
" levels=" << B.
level 413 limit = limit * CHAR_BIT + CHAR_BIT - 1;
415 for (
int j = 0; j <= limit; j++) {
418 if ((j + 1) % 100 == 0) {
420 }
else if ((j + 1) % 10 == 0) {
425 *out <<
'\n' << endl;
435 if (!faked_base.empty())
436 unlink(faked_base.c_str());
444 if (opts & Xapian::DBCHECK_FIX) {
453 string base_name = path;
461 B.
failure(
"Unused block(s) marked used in bitmap");
465 string err =
"Table entry count says ";
467 err +=
" but actually counted ";
473 B.
failure(
"Btree flagged as sequential but isn't");
476 *out <<
"Note: Btree not flagged as sequential, but is " 477 "(not an error)" << endl;
482 *out <<
"B-tree checked okay" << endl;
488 for (
int i = 0; i <= level; i++)
489 *out <<
"p=" << C_[i].p <<
", c=" << C_[i].c <<
", n=[" << C_[i].n
490 <<
"], rewrite=" << C_[i].rewrite << endl;
void set_level(uint4 level_)
void report_cursor(int N, const Cursor *C_) const
int DIR_END(const uint8_t *b)
int c
offset in the block's directory
chert_tablesize_t check_item_count
XAPIAN_REVISION_TYPE rev
Revision number of a database.
chert_tablesize_t get_entry_count() const
Return a count of the number of entries in the table.
void calculate_last_block()
DatabaseOpeningError indicates failure to open a database.
int block_usage(const uint8_t *p) const
Constants in the Xapian namespace.
bool faked_root_block
true if the root block is faked (not written to disk).
WritableDatabase open()
Construct a WritableDatabase object for a new, empty InMemory database.
void append_chunk(std::string *tag) const
void block_check(Cursor *C_, int j, int opts)
chert_tablesize_t item_count
keeps a count of the number of items in the B-tree.
int revision()
Report the revision of the library which the program is linked with.
void open()
Open the btree at the latest revision.
Utility functions for testing files.
Cursor C[BTREE_CURSOR_LEVELS]
void failure(const char *msg) const
const int DBCHECK_SHOW_FREELIST
Show the bitmap for the B-tree.
unsigned int chert_revision_number_t
A type used to store a revision number for a table.
void set_have_fakeroot(bool have_fakeroot_)
static void failure(const char *msg, uint4 n, int c=0)
void set_sequential(bool sequential_)
const int DBCHECK_FULL_TREE
Show a full display of the B-tree contents.
void description_append(std::string &desc, const std::string &s)
chert_revision_number_t get_open_revision_number() const
Get the revision number at which this table is currently open.
int size() const
I in diagram above.
uint8_t * p
pointer to a block
int GET_LEVEL(const uint8_t *b)
chert_revision_number_t revision_number
revision number of the opened B-tree.
void set_root(uint4 root_)
string str(int value)
Convert int to std::string.
void print_key(const uint8_t *p, int c, int j) const
size_t io_read(int fd, char *p, size_t n, size_t min)
Read n bytes (or until EOF) into block pointed to by p from file descriptor fd.
void set_item_count(chert_tablesize_t item_count_)
bool sequential
true iff the data has been written in a single write in sequential order.
const int DBCHECK_FIX
Fix problems.
uint4 block_given_by() const
Get this item's tag as a block number (this block should not be at level 0).
void set_block_size(uint4 block_size_)
Append a string to an object description, escaping invalid UTF-8.
int MAX_FREE(const uint8_t *b)
void report_block(int m, int n, const uint8_t *p) const
ChertTableCheck::report_block(m, n, p) prints the block at p, block number n, indented by m spaces...
void print_bytes(int n, const uint8_t *p) const
void print_tag(const uint8_t *p, int c, int j) const
uint4 get_bit_map_size() const
void report_block_full(int m, int n, const uint8_t *p) const
int components_of() const
char base_letter
the value 'A' or 'B' of the current base
void write_to_file(const std::string &filename, char base_letter, const std::string &tablename, int changes_fd, const std::string *changes_tail)
Write the btree base file to disk.
unsigned int block_size
block size of the B tree in bytes
bool block_free_at_start(uint4 n) const
true iff block n was free at the start of the transaction on the B-tree.
Wrappers for low-level POSIX I/O routines.
uint4 get_last_block() const
off_t file_size(const char *path)
Returns the size of a file.
unsigned REVISION(const uint8_t *b)
static void check(const char *tablename, const std::string &path, chert_revision_number_t *rev_ptr, int opts, std::ostream *out)
ChertTable_base base
For writing back as file baseA or baseB.
void set_revision(uint4 revision_)
DatabaseError indicates some sort of database related error.
void print_spaces(int n) const
int level
number of levels, counting from 0
include <fcntl.h>, but working around broken platforms.
const int DBCHECK_SHORT_TREE
Show a short-format display of the B-tree contents.
void read(std::string *key) const
int TOTAL_FREE(const uint8_t *b)
const int DBCHECK_SHOW_STATS
Show statistics for the B-tree.