50 #include <sys/types.h> 74 #undef BTREE_DEBUG_FULL 76 #ifdef BTREE_DEBUG_FULL 79 static void print_key(
const uint8_t * p,
int c,
int j);
80 static void print_tag(
const uint8_t * p,
int c,
int j);
98 uint8_t *temp =
new uint8_t[size];
99 memset(temp, 0, size);
151 #define SEQ_START_POINT (-10) 166 #define BYTE_PAIR_RANGE (1 << 2 * CHAR_BIT) 173 LOGCALL_VOID(DB,
"ChertTable::read_block", n | (
void*)p);
174 if (
rare(handle == -2))
180 Assert(n / CHAR_BIT < base.get_bit_map_size());
182 io_read_block(handle, reinterpret_cast<char *>(p), block_size, n);
185 if (
rare(dir_end <
DIR_START ||
unsigned(dir_end) > block_size)) {
186 string msg(
"dir_end invalid in block ");
204 Assert(n / CHAR_BIT < base.get_bit_map_size());
222 latest_revision_number = revision_number;
225 io_write_block(handle, reinterpret_cast<const char *>(p), block_size, n);
253 LOGCALL_VOID(DB,
"ChertTable::set_overwritten", NO_ARGS);
258 throw Xapian::DatabaseModifiedError(
"The revision being read has been discarded - you should call Xapian::Database::reopen() and retry the operation");
274 LOGCALL_VOID(DB,
"ChertTable::block_to_cursor", (
void*)C_ | j | n);
275 if (n == C_[j].n)
return;
276 uint8_t * p = C_[j].
p;
283 write_block(C_[j].n, p);
291 memcpy(p,
C[j].p, block_size);
306 string msg =
"Expected block ";
308 msg +=
" to be level ";
346 uint8_t * p =
C[j].p;
348 if (
C[j].rewrite)
return;
352 if (base.block_free_at_start(n)) {
358 n = base.next_free_block();
362 if (j == level)
return;
399 if (c < j && i < c &&
Item(p, c).key() <= key)
402 if (c < j && i < c && key <
Item(p, c).key())
407 int k = i + ((j - i)/(
D2 * 2))*
D2;
408 if (key <
Item(p, k).
key()) j = k;
else i = k;
435 LOGCALL(DB,
bool,
"ChertTable::find", (
void*)C_);
440 for (
int j = level; j > 0; --j) {
442 c = find_in_block(p, key,
false, C_[j].c);
443 #ifdef BTREE_DEBUG_FULL 444 printf(
"Block in ChertTable:find - code position 1");
445 report_block_full(j, C_[j].n, p);
448 block_to_cursor(C_, j - 1,
Item(p, c).block_given_by());
451 c = find_in_block(p, key,
true, C_[0].c);
452 #ifdef BTREE_DEBUG_FULL 453 printf(
"Block in ChertTable:find - code position 2");
454 report_block_full(0, C_[0].n, p);
474 uint8_t * b = buffer;
483 memmove(p + e, b + e, block_size - e);
508 C[level].n = base.next_free_block();
509 C[level].rewrite =
true;
519 add_item(item, level);
545 uint4 blocknumber =
C[j - 1].n;
549 const int newkey_len = newkey.
length();
557 const int min_len = min(newkey_len, prevkey.
length());
558 while (i < min_len && prevkey[i] == newkey[i]) {
563 if (i < newkey_len) i++;
572 uint8_t b[UCHAR_MAX + 6];
582 uint8_t * p =
C[j - 1].p;
586 auto byte_addr =
const_cast<uint8_t*
>(newkey.
get_address());
593 AssertEq(
C[j].c, find_in_block(
C[j].p, item.
key(),
false,
C[j].c));
606 LOGCALL(DB,
int,
"ChertTable::mid_point", (
void*)p);
609 int size = block_size -
TOTAL_FREE(p) - dir_end;
614 if (l < n - size)
RETURN(c);
641 int kt_len = kt_.
size();
642 int needed = kt_len +
D2;
653 memmove(p + c + D2, p + c, dir_end - c);
657 int o = dir_end + new_max;
676 uint8_t * p =
C[j].p;
680 int needed = kt_.
size() +
D2;
699 C[j].n = base.next_free_block();
701 memcpy(split_p, p, block_size);
714 bool add_to_upper_half;
716 add_to_upper_half = (c >= m);
720 add_to_upper_half = (
TOTAL_FREE(split_p) < needed);
723 if (add_to_upper_half) {
728 add_item_to_block(p, kt_, c);
733 add_item_to_block(split_p, kt_, c);
736 write_block(split_n, split_p);
739 if (j == level) split_root(split_n);
754 add_item_to_block(p, kt_, c);
773 LOGCALL_VOID(DB,
"ChertTable::delete_item", j | repeatedly);
775 uint8_t * p =
C[j].p;
782 memmove(p + c, p + c +
D2, dir_end - c);
787 if (!repeatedly)
return;
790 base.free_block(
C[j].n);
791 C[j].rewrite =
false;
793 C[j + 1].rewrite =
true;
794 delete_item(j + 1,
true);
803 base.free_block(
C[level].n);
804 C[level].rewrite =
false;
808 block_to_cursor(
C, level, new_root);
848 LOGCALL(DB,
int,
"ChertTable::add_kt", found);
864 uint8_t * p =
C[0].p;
869 int kt_size = kt.size();
870 int needed = kt_size - item.
size();
877 kt.get_address(), kt_size);
881 int new_max =
MAX_FREE(p) - kt_size;
884 memmove(p + o, kt.get_address(), kt_size);
890 delete_item(0,
false);
896 if (changed_n ==
C[0].n && changed_c ==
C[0].c) {
897 if (seq_count < 0) seq_count++;
916 LOGCALL(DB,
int,
"ChertTable::delete_kt", NO_ARGS);
919 bool found = find(
C);
934 delete_item(0,
true);
980 LOGCALL_VOID(DB,
"ChertTable::add", key | tag | already_compressed);
983 if (handle < 0) create_and_open(block_size);
987 bool compressed =
false;
988 if (already_compressed) {
992 "DONT_COMPRESS clashes with zlib constant");
994 "DONT_COMPRESS clashes with zlib constant");
996 "DONT_COMPRESS clashes with zlib constant");
999 "DONT_COMPRESS clashes with zlib constant");
1002 lazy_alloc_deflate_zstream();
1004 deflate_zstream->next_in =
1005 reinterpret_cast<Bytef *
>(
const_cast<char *
>(tag.data()));
1006 deflate_zstream->avail_in =
static_cast<uInt
>(tag.size());
1009 unsigned long blk_len = tag.size() - 1;
1010 unsigned char * blk =
new unsigned char[blk_len];
1011 deflate_zstream->next_out = blk;
1012 deflate_zstream->avail_out =
static_cast<uInt
>(blk_len);
1014 int err = deflate(deflate_zstream, Z_FINISH);
1015 if (err == Z_STREAM_END) {
1018 tag.assign(reinterpret_cast<const char *>(blk), deflate_zstream->total_out);
1028 const size_t cd = kt.key().length() +
K1 +
I2 +
C2 +
C2;
1029 const size_t L = max_item_size - cd;
1031 bool found = find(
C);
1033 uint8_t * p =
C[0].p;
1049 size_t last = tag.length() % L;
1050 if (n >= last || (full_compaction && n >= key.size() + 34))
1056 int m = tag.empty() ? 1 : (tag.length() - first_L + L - 1) / L + 1;
1067 size_t residue = tag.length();
1068 int replacement =
false;
1070 kt.set_components_of(m);
1071 for (i = 1; i <= m; i++) {
1072 size_t l = (i == m ? residue : (i == 1 ? first_L : L));
1073 Assert(cd + l <= block_size);
1074 Assert(string::size_type(o + l) <= tag.length());
1075 kt.set_tag(cd, tag.data() + o, l, compressed);
1076 kt.set_component_of(i);
1081 if (i > 1) found = find(
C);
1083 if (n > 0) replacement =
true;
1086 for (i = m + 1; i <= n; i++) {
1087 kt.set_component_of(i);
1090 if (!replacement) ++item_count;
1091 Btree_modified =
true;
1092 if (cursor_created_since_last_modification) {
1093 cursor_created_since_last_modification =
false;
1107 LOGCALL(DB,
bool,
"ChertTable::del", key);
1120 if (key.empty())
RETURN(
false);
1123 int n = delete_kt();
1124 if (n <= 0)
RETURN(
false);
1126 for (
int i = 2; i <= n; i++) {
1127 kt.set_component_of(i);
1132 Btree_modified =
true;
1133 if (cursor_created_since_last_modification) {
1134 cursor_created_since_last_modification =
false;
1143 LOGCALL(DB,
bool,
"ChertTable::readahead_key", key);
1164 Key ktkey = kt.key();
1168 const uint8_t * p =
C[level].p;
1169 int c = find_in_block(p, ktkey,
false,
C[level].c);
1173 if (n != last_readahead && n !=
C[level - 1].n) {
1177 Assert(n / CHAR_BIT < base.get_bit_map_size());
1189 LOGCALL(DB,
bool,
"ChertTable::get_exact_entry", key | tag);
1205 (void)read_tag(
C, &tag,
false);
1212 LOGCALL(DB,
bool,
"ChertTable::key_exists", key);
1225 LOGCALL(DB,
bool,
"ChertTable::read_tag",
Literal(
"C_") | tag | keep_compressed);
1226 Item item(C_[0].p, C_[0].c);
1234 if (n > 1) tag->reserve((max_item_size - (1 +
K1 +
I2 +
C2 +
C2)) * n);
1239 for (
int i = 2; i <= n; i++) {
1247 if (!compressed || keep_compressed)
RETURN(compressed);
1255 utag.reserve(tag->size() + tag->size() / 2);
1259 lazy_alloc_inflate_zstream();
1261 inflate_zstream->next_in =
1262 reinterpret_cast<Bytef*
>(
const_cast<char *
>(tag->data()));
1263 inflate_zstream->avail_in =
static_cast<uInt
>(tag->size());
1266 while (err != Z_STREAM_END) {
1267 inflate_zstream->next_out = buf;
1268 inflate_zstream->avail_out =
static_cast<uInt
>(
sizeof(buf));
1269 err = inflate(inflate_zstream, Z_SYNC_FLUSH);
1270 if (err == Z_BUF_ERROR && inflate_zstream->avail_in == 0) {
1271 LOGLINE(DB,
"Z_BUF_ERROR - faking checksum of " << inflate_zstream->adler);
1274 inflate_zstream->next_in = header2;
1275 inflate_zstream->avail_in = 4;
1276 err = inflate(inflate_zstream, Z_SYNC_FLUSH);
1277 if (err == Z_STREAM_END)
break;
1280 if (err != Z_OK && err != Z_STREAM_END) {
1281 if (err == Z_MEM_ERROR)
throw std::bad_alloc();
1282 string msg =
"inflate failed";
1283 if (inflate_zstream->msg) {
1285 msg += inflate_zstream->msg;
1291 utag.append(reinterpret_cast<const char *>(buf),
1292 inflate_zstream->next_out - buf);
1294 if (utag.size() != inflate_zstream->total_out) {
1295 string msg =
"compressed tag didn't expand to the expected size: ";
1296 msg +=
str(utag.size());
1299 msg +=
str(
size_t(inflate_zstream->total_out));
1311 LOGCALL_VOID(DB,
"ChertTable::set_full_compaction", parity);
1314 if (parity) seq_count = 0;
1315 full_compaction = parity;
1335 LOGCALL(DB,
bool,
"ChertTable::basic_open", revision_supplied | revision_);
1339 const size_t BTREE_BASES = 2;
1341 static const char basenames[BTREE_BASES] = {
'A',
'B' };
1344 bool base_ok[BTREE_BASES];
1347 bool valid_base =
false;
1349 for (
size_t i = 0; i < BTREE_BASES; ++i) {
1350 bool ok = bases[i].
read(
name, basenames[i], writable, err_msg);
1365 string message =
"Error opening table '";
1372 if (revision_supplied) {
1373 bool found_revision =
false;
1374 for (
size_t i = 0; i < BTREE_BASES; ++i) {
1375 if (base_ok[i] && bases[i].get_revision() == revision_) {
1377 found_revision =
true;
1381 if (!found_revision) {
1390 for (
size_t i = 0; i < BTREE_BASES; ++i) {
1391 if (base_ok[i] && bases[i].get_revision() >= highest_revision) {
1401 for (
size_t i = 0; i < BTREE_BASES; ++i) {
1402 LOGLINE(DB,
"Checking (ch == " << ch <<
") against " 1403 "basenames[" << i <<
"] == " << basenames[i]);
1404 LOGLINE(DB,
"bases[" << i <<
"].get_revision() == " <<
1405 bases[i].get_revision());
1406 LOGLINE(DB,
"base_ok[" << i <<
"] == " << base_ok[i]);
1407 if (ch == basenames[i]) {
1411 size_t otherbase_num = 1 - i;
1412 if (base_ok[otherbase_num]) {
1413 other_base = &bases[otherbase_num];
1427 revision_number = base.get_revision();
1428 block_size = base.get_block_size();
1429 root = base.get_root();
1430 level = base.get_level();
1434 item_count = base.get_item_count();
1435 faked_root_block = base.get_have_fakeroot();
1436 sequential = base.get_sequential();
1438 if (other_base != 0) {
1440 if (revision_number > latest_revision_number)
1441 latest_revision_number = revision_number;
1443 latest_revision_number = revision_number;
1454 if (cursor_created_since_last_modification) {
1455 cursor_created_since_last_modification =
false;
1468 if (faked_root_block) {
1470 uint8_t * p =
C[0].p;
1476 memset(p, 0, block_size);
1478 int o = block_size -
I2 -
K1 -
C2 -
C2;
1497 C[0].n = base.next_free_block();
1501 block_to_cursor(
C, level, root);
1503 if (
REVISION(
C[level].p) > revision_number) set_overwritten();
1513 LOGCALL(DB,
bool,
"ChertTable::do_open_to_write", revision_supplied | revision_ | create_db);
1521 if (lazy && !create_db && errno == ENOENT) {
1522 revision_number = revision_;
1525 string message(create_db ?
"Couldn't create " :
"Couldn't open ");
1527 message +=
"DB read/write: ";
1532 if (!basic_open(revision_supplied, revision_)) {
1535 if (!revision_supplied) {
1546 for (
int j = 0; j <= level; j++) {
1548 C[j].p =
new uint8_t[block_size];
1550 split_p =
new uint8_t[block_size];
1563 bool readonly_,
int compress_strategy_,
bool lazy_)
1564 : tablename(tablename_),
1568 latest_revision_number(0),
1571 faked_root_block(
true),
1584 Btree_modified(
false),
1585 full_compaction(
false),
1586 writable(!readonly_),
1587 cursor_created_since_last_modification(
false),
1590 compress_strategy(compress_strategy_),
1591 deflate_zstream(NULL),
1592 inflate_zstream(NULL),
1596 LOGCALL_CTOR(DB,
"ChertTable", tablename_ | path_ | readonly_ | compress_strategy_ | lazy_);
1630 err = deflateInit2(
deflate_zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
1632 if (
rare(err != Z_OK)) {
1633 if (err == Z_MEM_ERROR) {
1636 throw std::bad_alloc();
1638 string msg =
"deflateInit2 failed (";
1669 if (
rare(err != Z_OK)) {
1670 if (err == Z_MEM_ERROR) {
1673 throw std::bad_alloc();
1675 string msg =
"inflateInit2 failed (";
1690 LOGCALL(DB,
bool,
"ChertTable::exists", NO_ARGS);
1709 LOGCALL_VOID(DB,
"ChertTable::set_block_size", block_size_);
1712 (block_size_ & (block_size_ - 1)) != 0) {
1721 LOGCALL_VOID(DB,
"ChertTable::create_and_open", block_size_);
1789 for (
int j =
level; j >= 0; j--) {
1814 for (
int j =
level; j >= 0; j--) {
1827 const string * changes_tail)
1829 LOGCALL_VOID(DB,
"ChertTable::commit", revision | changes_fd | changes_tail);
1875 string basefile =
name;
1886 (void)unlink(tmp.c_str());
1891 string msg(
"Couldn't update base file ");
1911 LOGCALL_VOID(DB,
"ChertTable::write_changed_blocks", changes_fd);
1920 io_write(changes_fd, buf.data(), buf.size());
1931 io_write(changes_fd, buf.data(), buf.size());
1937 io_write(changes_fd, reinterpret_cast<const char *>(p),
1949 io_write(changes_fd, buf.data(), buf.size());
1988 for (
int j = 0; j <=
level; j++) {
2009 LOGCALL(DB,
bool,
"ChertTable::do_open_to_read", revision_supplied | revision_);
2020 string message(
"Couldn't open ");
2022 message +=
"DB to read: ";
2027 if (!
basic_open(revision_supplied, revision_)) {
2030 if (revision_supplied) {
2040 for (
int j = 0; j <=
level; j++) {
2069 LOGCALL(DB,
bool,
"ChertTable::open", revision);
2070 LOGLINE(DB,
"opening for particular revision at path " <<
name);
2101 uint8_t * p = C_[0].
p;
2105 if (n == 0)
RETURN(
false);
2119 for (j = 1; j <=
level; ++j) {
2120 if (n ==
C[j].n)
break;
2122 if (j <=
level)
continue;
2152 uint8_t * p = C_[0].
p;
2175 for (j = 1; j <=
level; ++j) {
2176 if (n ==
C[j].n)
break;
2178 if (j <=
level)
continue;
2205 LOGCALL(DB,
bool,
"ChertTable::prev_default",
Literal(
"C_") | j);
2206 uint8_t * p = C_[j].
p;
2228 LOGCALL(DB,
bool,
"ChertTable::next_default",
Literal(
"C_") | j);
2229 uint8_t * p = C_[j].
p;
2248 #ifdef BTREE_DEBUG_FULL 2249 printf(
"Block in ChertTable:next_default");
2250 report_block_full(j - 1, C_[j - 1].n, C_[j - 1].p);
2279 LOGCALL(DB,
bool,
"Key::operator<", static_cast<const void*>(key2.
p));
2280 int key1_len = length();
2281 int key2_len = key2.
length();
2282 if (key1_len == key2_len) {
2289 int k_smaller = (key2_len < key1_len ? key2_len : key1_len);
2292 int diff = memcmp(p +
K1, key2.
p +
K1, k_smaller);
2293 if (diff != 0)
RETURN(diff < 0);
2297 RETURN(key1_len < key2_len);
2302 LOGCALL(DB,
bool,
"Key::operator==", static_cast<const void*>(key2.
p));
2303 int key1_len = length();
bool get_sequential() const
void set_overwritten() const
static uint8_t * zeroed_new(size_t size)
#define LOGCALL_STATIC(CATEGORY, TYPE, FUNC, PARAMS)
bool get_have_fakeroot() const
char other_base_letter() const
int io_open_block_rd(const char *fname)
Open a block-based file for reading.
void set_level(uint4 level_)
int DIR_END(const uint8_t *b)
bool both_bases
set to true if baseA and baseB both exist as valid bases.
int c
offset in the block's directory
void io_write(int fd, const char *p, size_t n)
Write n bytes from block pointed to by p to file descriptor fd.
A cursor pointing to a position in a Btree table, for reading several entries in order, or finding approximate matches.
Indicates an attempt to access a closed database.
void add_item(Item_wr kt, int j)
ChertTable::add_item(kt_, j) adds item kt_ to the block at cursor level C[j].
int add_kt(bool found)
add_kt(found) adds the item (key-tag pair) at B->kt into the B-tree, using cursor C...
z_stream * inflate_zstream
Zlib state object for inflating.
bool io_unlink(const std::string &filename)
Delete a file.
bool next()
Advance to the next key.
#define AssertRel(A, REL, B)
int getint4(const unsigned char *p, int c)
void calculate_last_block()
DatabaseOpeningError indicates failure to open a database.
void io_read_block(int fd, char *p, size_t n, off_t b, off_t o)
Read block b size n bytes into buffer p from file descriptor fd, offset o.
const size_t BLOCK_CAPACITY
Even for items of at maximum size, it must be possible to get this number of items in a block...
bool io_sync(int fd)
Ensure all data previously written to file descriptor fd has been written to disk.
void compact(uint8_t *p)
compact(p) compact the block at p by shuffling all the items up to the end.
void set_full_compaction(bool parity)
const char * tablename
The name of the table (used when writing changesets).
Convert errno value to std::string, thread-safe if possible.
#define LOGCALL_DTOR(CATEGORY, CLASS)
bool faked_root_block
true if the root block is faked (not written to disk).
int io_open_block_wr(const char *fname, bool anew)
Open a block-based file for writing.
Btree base file implementation.
uint4 root
the root block of the B-tree
Item_wr kt
buffer of size block_size for making up key-tag items
#define STRINGIZE(X)
The STRINGIZE macro converts its parameter into a string constant.
bool io_readahead_block(int, size_t, off_t, off_t=0)
Readahead block b size n bytes from file descriptor fd.
#define LOGCALL_VOID(CATEGORY, FUNC, PARAMS)
void append_chunk(std::string *tag) const
void lazy_alloc_inflate_zstream() const
Allocate the zstream for inflating, if not already allocated.
Convert types to std::string.
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]
unsigned long cursor_version
Version count for tracking when cursors need to rebuild.
bool exists() const
Determine whether the btree exists on disk.
bool key_exists(const std::string &key) const
Check if a key exists in the Btree.
void create_and_open(unsigned int blocksize)
Create a new empty btree structure on disk and open it at the initial revision.
unsigned int chert_revision_number_t
A type used to store a revision number for a table.
void aligned_write4(unsigned char *ptr, T value)
chert_tablesize_t get_item_count() const
void set_have_fakeroot(bool have_fakeroot_)
uint8_t * split_p
Buffer used when splitting a block.
ChertTable(const ChertTable &)
Copying not allowed.
Hierarchy of classes which Xapian can throw as exceptions.
bool readahead_key(const string &key) const
bool del(const std::string &key)
Delete an entry from the table.
static uint4 block_given_by(const uint8_t *p, int c)
block_given_by(p, c) finds the item at block address p, directory offset c, and returns its tag value...
bool prev_for_sequential(Cursor *C_, int dummy) const
~ChertTable()
Close the Btree.
bool next_for_sequential(Cursor *C_, int dummy) const
bool io_full_sync(int fd)
void set_sequential(bool sequential_)
uint4 get_block_size() const
bool next_default(Cursor *C_, int j) const
DatabaseModifiedError indicates a database was modified.
void cancel()
Cancel any outstanding changes.
functions for reading and writing different width words
void errno_to_string(int e, string &s)
int size() const
I in diagram above.
void form_null_key(uint4 n)
Form an item with a null key and with block number n in the tag.
void set_block_given_by(uint4 n)
Set this item's tag to point to block n (this block should not be at level 0).
Interface to Btree cursors.
bool do_open_to_read(bool revision_supplied, chert_revision_number_t revision_)
Perform the opening operation to read.
std::string name
The path name of the B tree.
bool rewrite
true if the block is not the same as on disk, and so needs rewriting
void SET_LEVEL(uint8_t *b, int x)
uint8_t * p
pointer to a block
void io_write_block(int fd, const char *p, size_t n, off_t b, off_t o)
Write block b size n bytes from buffer p to file descriptor fd, offset o.
int GET_LEVEL(const uint8_t *b)
bool do_open_to_write(bool revision_supplied, chert_revision_number_t revision_, bool create_db=false)
Perform the opening operation to write.
bool operator<(Key key2) const
Compares this key with key2.
chert_revision_number_t revision_number
revision number of the opened B-tree.
bool get_exact_entry(const std::string &key, std::string &tag) const
Read an entry from the table, if and only if it is exactly that being asked for.
void set_root(uint4 root_)
string str(int value)
Convert int to std::string.
void erase()
Erase this table from disk.
static int find_in_block(const uint8_t *p, Key key, bool leaf, int c)
find_in_block(p, key, leaf, c) searches for the key in the block at p.
bool io_tmp_rename(const std::string &tmp_file, const std::string &real_file)
Rename a temporary file to its final position.
void set_block_size(unsigned int block_size_)
Set the block size.
void SET_DIR_END(uint8_t *b, int x)
bool writable
Set to true when the database is opened to write.
bool find_changed_block(uint4 *n) const
Find the first changed block at or after position *n.
bool read(const std::string &name, char ch, bool read_bitmap, std::string &err_msg)
Read values from a base file.
void close(bool permanent=false)
Close the Btree.
bool really_empty() const
Return true if there are no entries in the table.
ChertCursor * cursor_get() const
Get a cursor for reading from the table.
void set_item_count(chert_tablesize_t item_count_)
bool basic_open(bool revision_supplied, chert_revision_number_t revision)
void setD(unsigned char *p, int c, int x)
void write_changed_blocks(int changes_fd)
Append the list of blocks changed to a changeset file.
bool sequential
true iff the data has been written in a single write in sequential order.
#define AssertParanoid(COND)
void enter_key(int j, Key prevkey, Key newkey)
enter_key(j, prevkey, newkey) is called after a block split.
z_stream * deflate_zstream
Zlib state object for deflating.
bool prev_default(Cursor *C_, int j) const
#define LOGCALL_CTOR(CATEGORY, CLASS, PARAMS)
bool find(Cursor *) const
find(C_) searches for the key of B->kt in the B-tree.
uint4 changed_n
the last block to be changed by an addition
void commit(chert_revision_number_t revision, int changes_fd=-1, const std::string *changes_tail=NULL)
Commit any outstanding changes to the table.
void lazy_alloc_deflate_zstream() const
Allocate the zstream for deflating, if not already allocated.
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_)
DatabaseCorruptError indicates database corruption was detected.
int mid_point(uint8_t *p) const
mid_point(p) finds the directory entry in c that determines the approximate mid point of the data in ...
void block_to_cursor(Cursor *C_, int j, uint4 n) const
void add(const std::string &key, std::string tag, bool already_compressed=false)
Add a key/tag pair to the table, replacing any existing pair with the same key.
uint4 get_revision() const
bool get_compressed() const
int MAX_FREE(const uint8_t *b)
void pack_uint(std::string &s, U value)
Append an encoded unsigned integer to a string.
int seq_count
count of the number of successive instances of purely sequential addition, starting at SEQ_START_POIN...
#define CHERT_DEFAULT_BLOCK_SIZE
The default block size to use in a B-tree table.
#define AssertEqParanoid(A, B)
void alter()
Btree::alter(); is called when the B-tree is to be altered.
#define SEQ_START_POINT
Flip to sequential addition block-splitting after this number of observed sequential additions (in ne...
void pack_string(std::string &s, const std::string &value)
Append an encoded std::string to a string.
bool Btree_modified
Set to true the first time the B-tree is modified.
#define CHERT_BTREE_MAX_KEY_LEN
The largest possible value of a key_len.
void delete_item(int j, bool repeatedly)
ChertTable::delete_item(j, repeatedly) is (almost) the converse of add_item.
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.
chert_revision_number_t latest_revision_number
Revision number of the other base, or zero if there is only one base file.
unsigned int block_size
block size of the B tree in bytes
int changed_c
directory offset corresponding to last block to be changed by an addition
Pack types into strings and unpack them again.
int handle
File descriptor of the table.
Wrappers for low-level POSIX I/O routines.
const int BTREE_CURSOR_LEVELS
Various handy helpers which std::string really should provide.
void form_key(const std::string &key) const
uint4 get_last_block() const
void read_block(uint4 n, uint8_t *p) const
read_block(n, p) reads block n of the DB file to address p.
void flush_db()
Flush any outstanding changes to the DB file of the table.
unsigned REVISION(const uint8_t *b)
ChertTable_base base
For writing back as file baseA or baseB.
bool operator==(Key key2) const
bool cursor_created_since_last_modification
Flag for tracking when cursors need to rebuild.
void write_block(uint4 n, const uint8_t *p) const
write_block(n, p) writes block n in the DB file from address p.
Various assertion macros.
void set_revision(uint4 revision_)
DatabaseError indicates some sort of database related error.
void split_root(uint4 split_n)
Btree needs to gain a new level to insert more items: so split root block and construct a new one...
const size_t COMPRESS_MIN
uint8_t * buffer
buffer of size block_size for reforming blocks
static void throw_database_closed()
Throw an exception indicating that the database is closed.
bool file_exists(const char *path)
Test if a file exists.
void SET_REVISION(uint8_t *b, uint4 rev)
int level
number of levels, counting from 0
bool find_entry(const string &key)
Position the cursor on the highest entry with key <= key.
void SET_MAX_FREE(uint8_t *b, int x)
bool lazy
If true, don't create the table until it's needed.
void set_key_and_block(Key newkey, int truncate_size, uint4 n)
#define LOGCALL(CATEGORY, TYPE, FUNC, PARAMS)
UnimplementedError indicates an attempt to use an unimplemented feature.
int TOTAL_FREE(const uint8_t *b)
void add_item_to_block(uint8_t *p, Item_wr kt, int c)
add_item_to_block(p, kt_, c) adds item kt_ to the block at p.
void SET_TOTAL_FREE(uint8_t *b, int x)
bool read_tag(Cursor *C_, std::string *tag, bool keep_compressed) const
Read the tag value for the key pointed to by cursor C_.
const uint8_t * get_address() const
int compress_strategy
DONT_COMPRESS or Z_DEFAULT_STRATEGY, Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE.