36 #include <sys/types.h> 59 using namespace Glass;
63 #undef BTREE_DEBUG_FULL 65 #ifdef BTREE_DEBUG_FULL 68 static void print_key(
const uint8_t * p,
int c,
int j);
69 static void print_tag(
const uint8_t * p,
int c,
int j);
87 uint8_t *temp =
new uint8_t[size];
88 memset(temp, 0, size);
146 #define SEQ_START_POINT (-10) 156 #define BYTE_PAIR_RANGE (1 << 2 * CHAR_BIT) 163 LOGCALL_VOID(DB,
"GlassTable::read_block", n | (
void*)p);
164 if (
rare(handle == -2))
166 AssertRel(n,<,free_list.get_first_unused_block());
168 io_read_block(handle, reinterpret_cast<char *>(p), block_size, n, offset);
172 if (
rare(dir_end <
DIR_START ||
unsigned(dir_end) > block_size)) {
173 string msg(
"dir_end invalid in block ");
193 LOGCALL_VOID(DB,
"GlassTable::write_block", n | p | appending);
196 AssertRel(n,<,free_list.get_first_unused_block());
220 const char * p_char =
reinterpret_cast<const char *
>(p);
223 if (!changes_obj)
return;
227 if (strcmp(tablename,
"position") == 0) {
229 }
else if (strcmp(tablename,
"postlist") == 0) {
231 }
else if (strcmp(tablename,
"docdata") == 0) {
233 }
else if (strcmp(tablename,
"spelling") == 0) {
235 }
else if (strcmp(tablename,
"synonym") == 0) {
237 }
else if (strcmp(tablename,
"termlist") == 0) {
243 if (block_size == 2048) {
245 }
else if (block_size == 4096) {
247 }
else if (block_size == 8192) {
249 }
else if (block_size == 16384) {
251 }
else if (block_size == 32768) {
253 }
else if (block_size == 65536) {
264 changes_obj->write_block(buf);
265 changes_obj->write_block(reinterpret_cast<const char *>(p), block_size);
291 LOGCALL_VOID(DB,
"GlassTable::set_overwritten", NO_ARGS);
296 throw Xapian::DatabaseModifiedError(
"The revision being read has been discarded - you should call Xapian::Database::reopen() and retry the operation");
312 LOGCALL_VOID(DB,
"GlassTable::block_to_cursor", (
void*)C_ | j | n);
313 if (n == C_[j].get_n())
return;
315 if (writable && C_[j].rewrite) {
317 write_block(C_[j].get_n(), C_[j].get_p());
324 if (n ==
C[j].get_n()) {
327 uint8_t * q = C_[j].
init(block_size);
342 string msg =
"Expected block ";
344 msg +=
" to be level ";
384 if (
C[j].rewrite)
return;
388 if (rev == revision_number + 1) {
391 Assert(rev < revision_number + 1);
393 free_list.mark_block_unused(
this, block_size, n);
394 SET_REVISION(
C[j].get_modifiable_p(block_size), revision_number + 1);
395 n = free_list.get_block(
this, block_size);
398 if (j == level)
return;
431 if (c < j && i < c) {
440 if (c < j && i < c) {
451 int k = i + ((j - i) / (
D2 * 2)) *
D2;
468 template<
typename ITEM>
int 480 if (c < j && i < c) {
482 if (r == 0)
return c;
486 if (c < j && i < c) {
488 if (r == 0)
return c;
494 int k = i + ((j - i) / (
D2 * 2)) *
D2;
532 LOGCALL(DB,
bool,
"GlassTable::find", (
void*)C_);
536 for (
int j = level; j > 0; --j) {
538 c = find_in_branch(p, kt, C_[j].c);
539 #ifdef BTREE_DEBUG_FULL 540 printf(
"Block in GlassTable:find - code position 1");
541 report_block_full(j, C_[j].get_n(), p);
544 block_to_cursor(C_, j - 1,
BItem(p, c).block_given_by());
548 c = find_in_leaf(p, kt, C_[0].c, exact);
549 #ifdef BTREE_DEBUG_FULL 550 printf(
"Block in GlassTable:find - code position 2");
551 report_block_full(0, C_[0].get_n(), p);
569 uint8_t * b = buffer;
590 memcpy(p + e, b + e, block_size - e);
614 uint8_t * q =
C[level].init(block_size);
615 memset(q, 0, block_size);
617 C[level].set_n(free_list.get_block(
this, block_size));
618 C[level].rewrite =
true;
628 add_branch_item(item, level);
653 Key prevkey = previtem.
key();
654 Key newkey = newitem.
key();
657 uint4 blocknumber =
C[0].get_n();
661 const int newkey_len = newkey.
length();
667 const int min_len = min(newkey_len, prevkey.
length());
668 while (i < min_len && prevkey[i] == newkey[i]) {
673 if (i < newkey_len) i++;
683 AssertEq(
C[1].c, find_in_branch(
C[1].get_p(), item,
C[1].c));
686 add_branch_item(item, 1);
714 uint4 blocknumber =
C[j - 1].get_n();
723 AssertEq(
C[j].c, find_in_branch(
C[j].get_p(), item,
C[j].c));
726 add_branch_item(item, j);
736 LOGCALL(DB,
int,
"GlassTable::mid_point", (
void*)p);
739 int size = block_size -
TOTAL_FREE(p) - dir_end;
749 if (l < n - size)
RETURN(c);
776 int kt_len = kt_.
size();
777 int needed = kt_len +
D2;
788 memmove(p + c + D2, p + c, dir_end - c);
792 int o = dir_end + new_max;
816 int kt_len = kt_.
size();
817 int needed = kt_len +
D2;
828 memmove(p + c + D2, p + c, dir_end - c);
832 int o = dir_end + new_max;
851 uint8_t * p =
C[0].get_modifiable_p(block_size);
855 int needed = kt_.
size() +
D2;
873 uint4 split_n =
C[0].get_n();
874 C[0].set_n(free_list.get_block(
this, block_size));
876 memcpy(split_p, p, block_size);
889 bool add_to_upper_half;
891 add_to_upper_half = (c >= m);
895 add_to_upper_half = (
TOTAL_FREE(split_p) < needed);
898 if (add_to_upper_half) {
903 add_item_to_leaf(p, kt_, c);
908 add_item_to_leaf(split_p, kt_, c);
911 write_block(split_n, split_p);
914 if (0 == level) split_root(split_n);
928 add_item_to_leaf(p, kt_, c);
946 uint8_t * p =
C[j].get_modifiable_p(block_size);
949 int needed = kt_.
size() +
D2;
967 uint4 split_n =
C[j].get_n();
968 C[j].set_n(free_list.get_block(
this, block_size));
970 memcpy(split_p, p, block_size);
983 bool add_to_upper_half;
985 add_to_upper_half = (c >= m);
989 add_to_upper_half = (
TOTAL_FREE(split_p) < needed);
992 if (add_to_upper_half) {
997 add_item_to_branch(p, kt_, c);
1001 add_item_to_branch(split_p, kt_, c);
1003 write_block(split_n, split_p);
1006 if (j == level) split_root(split_n);
1027 add_item_to_branch(p, kt_, c);
1041 LOGCALL_VOID(DB,
"GlassTable::delete_leaf_item", repeatedly);
1043 uint8_t * p =
C[0].get_modifiable_p(block_size);
1050 memmove(p + c, p + c +
D2, dir_end - c);
1055 if (!repeatedly)
return;
1058 free_list.mark_block_unused(
this, block_size,
C[0].get_n());
1059 C[0].rewrite =
false;
1061 C[1].rewrite =
true;
1062 delete_branch_item(1);
1078 uint8_t * p =
C[j].get_modifiable_p(block_size);
1085 memmove(p + c, p + c +
D2, dir_end - c);
1092 free_list.mark_block_unused(
this, block_size,
C[j].get_n());
1093 C[j].rewrite =
false;
1095 C[j + 1].rewrite =
true;
1096 delete_branch_item(j + 1);
1103 free_list.mark_block_unused(
this, block_size,
C[level].get_n());
1107 block_to_cursor(
C, level, new_root);
1109 dir_end =
DIR_END(
C[level].get_p());
1151 LOGCALL(DB,
int,
"GlassTable::add_kt", found);
1167 uint8_t * p =
C[0].get_modifiable_p(block_size);
1172 int kt_size = kt.size();
1173 int needed = kt_size - item.
size();
1179 memmove(const_cast<uint8_t *>(item.
get_address()),
1180 kt.get_address(), kt_size);
1184 int new_max =
MAX_FREE(p) - kt_size;
1187 memmove(p + o, kt.get_address(), kt_size);
1193 delete_leaf_item(
false);
1199 if (changed_n ==
C[0].get_n() && changed_c ==
C[0].c) {
1200 if (seq_count < 0) seq_count++;
1224 LOGCALL(DB,
int,
"GlassTable::delete_kt", NO_ARGS);
1235 delete_leaf_item(
true);
1281 LOGCALL_VOID(DB,
"GlassTable::add", key | tag | already_compressed);
1289 root_info.
init(block_size, compress_min);
1290 do_open_to_write(&root_info);
1295 const char* tag_data = tag.data();
1296 size_t tag_size = tag.size();
1298 bool compressed =
false;
1299 if (already_compressed) {
1301 }
else if (compress_min > 0 && tag_size > compress_min) {
1302 const char * res = comp_stream.compress(tag_data, &tag_size);
1310 const size_t cd = kt.key().length() +
K1 +
I2 +
X2;
1311 const size_t L = max_item_size - cd;
1312 size_t first_L = L +
X2;
1313 bool found = find(
C);
1314 if (tag_size <= first_L) {
1318 }
else if (!found) {
1319 const uint8_t * p =
C[0].get_p();
1335 size_t last = (tag_size -
X2) % L;
1336 if (n >= last || (full_compaction && n >= key.size() + 34)) {
1345 int m = (tag_size - first_L + L - 1) / L + 1;
1353 size_t residue = tag_size;
1354 bool replacement =
false;
1355 bool components_to_del =
false;
1357 for (i = 1; i <= m; ++i) {
1358 size_t l = (i == m ? residue : (i == 1 ? first_L : L));
1359 size_t this_cd = (i == 1 ? cd -
X2 : cd);
1360 Assert(this_cd + l <= block_size);
1361 Assert(o + l <= tag_size);
1362 kt.set_tag(this_cd, tag_data + o, l, compressed, i, m);
1367 if (i > 1) found = find(
C);
1368 int result = add_kt(found);
1369 if (result) replacement =
true;
1370 components_to_del = (result == 1);
1373 if (components_to_del) {
1376 kt.set_component_of(++i);
1377 }
while (delete_kt() == 1);
1379 if (!replacement) ++item_count;
1380 Btree_modified =
true;
1381 if (cursor_created_since_last_modification) {
1382 cursor_created_since_last_modification =
false;
1396 LOGCALL(DB,
bool,
"GlassTable::del", key);
1409 if (key.empty())
RETURN(
false);
1412 int r = delete_kt();
1413 if (r == 0)
RETURN(
false);
1416 kt.set_component_of(++i);
1421 Btree_modified =
true;
1422 if (cursor_created_since_last_modification) {
1423 cursor_created_since_last_modification =
false;
1432 LOGCALL(DB,
bool,
"GlassTable::readahead_key", key);
1459 const uint8_t * p =
C[level].get_p();
1460 int c = find_in_branch(p, kt,
C[level].c);
1464 if (n != last_readahead && n !=
C[level - 1].get_n()) {
1475 LOGCALL(DB,
bool,
"GlassTable::get_exact_entry", key | tag);
1491 (void)read_tag(
C, &tag,
false);
1498 LOGCALL(DB,
bool,
"GlassTable::key_exists", key);
1511 LOGCALL(DB,
bool,
"GlassTable::read_tag",
Literal(
"C_") | tag | keep_compressed);
1516 bool compressed =
false;
1517 bool decompress =
false;
1519 LeafItem item(C_[0].get_p(), C_[0].c);
1523 if (compressed && !keep_compressed) {
1524 comp_stream.decompress_start();
1535 "Too many chunks of compressed data" :
1536 "Too few chunks of compressed data");
1549 RETURN(compressed && keep_compressed);
1555 LOGCALL_VOID(DB,
"GlassTable::set_full_compaction", parity);
1558 if (parity) seq_count = 0;
1559 full_compaction = parity;
1579 LOGCALL_VOID(DB,
"GlassTable::basic_open", root_info|rev);
1580 revision_number =
rev;
1587 if (!fl_serialised.empty()) {
1588 if (!free_list.unpack(fl_serialised))
1601 for (
int j = 0; j <= level; ++j) {
1602 C[j].init(block_size);
1607 if (cursor_created_since_last_modification) {
1608 cursor_created_since_last_modification =
false;
1617 if (faked_root_block) {
1619 uint8_t * p =
C[0].init(block_size);
1625 memset(p, 0, block_size);
1627 int o = block_size -
I2 -
K1;
1646 C[0].set_n(free_list.get_block(
this, block_size));
1647 C[0].rewrite =
true;
1651 block_to_cursor(
C, level, root);
1653 if (
REVISION(
C[level].get_p()) > revision_number) set_overwritten();
1662 LOGCALL_VOID(DB,
"GlassTable::do_open_to_write", root_info|rev);
1668 handle = -3 - handle;
1675 if (lazy && rev && errno == ENOENT) {
1676 revision_number =
rev;
1679 string message((rev == 0) ?
"Couldn't create " :
"Couldn't open ");
1687 basic_open(root_info, rev);
1689 split_p =
new uint8_t[block_size];
1699 bool readonly_,
bool lazy_)
1700 : tablename(tablename_),
1704 faked_root_block(
true),
1717 Btree_modified(
false),
1718 full_compaction(
false),
1719 writable(!readonly_),
1720 cursor_created_since_last_modification(
false),
1725 comp_stream(Z_DEFAULT_STRATEGY),
1730 LOGCALL_CTOR(DB,
"GlassTable", tablename_ | path_ | readonly_ | lazy_);
1734 bool readonly_,
bool lazy_)
1765 LOGCALL_CTOR(DB,
"GlassTable", tablename_ | fd | offset_ | readonly_ | lazy_);
1770 LOGCALL(DB,
bool,
"GlassTable::exists", NO_ARGS);
1778 LOGCALL_VOID(DB,
"GlassTable::create_and_open", flags_|root_info);
1786 Assert(block_size_ >= 2048);
1789 Assert((block_size_ & (block_size_ - 1)) == 0);
1832 for (
int j =
level; j >= 0; --j) {
1856 for (
int j =
level; j >= 0; --j) {
1868 LOGCALL_VOID(DB,
"GlassTable::commit", revision|root_info);
1901 for (
int i = 0; i <=
level; ++i) {
1952 if (!fl_serialised.empty()) {
1961 for (
int j = 0; j <=
level; ++j) {
1983 LOGCALL(DB,
bool,
"GlassTable::do_open_to_read", root_info|rev);
1997 string message(
"Couldn't open ");
2013 LOGCALL_VOID(DB,
"GlassTable::open", flags_|root_info|rev);
2039 if (n == 0)
RETURN(
false);
2041 if (n ==
C[0].get_n()) {
2053 for (j = 1; j <=
level; ++j) {
2054 if (n ==
C[j].get_n())
break;
2056 if (j <=
level)
continue;
2085 const uint8_t * p = C_[0].
get_p();
2097 if (n ==
C[0].get_n()) {
2108 for (j = 1; j <=
level; ++j) {
2109 if (n ==
C[j].get_n())
break;
2111 if (j <=
level)
continue;
2141 LOGCALL(DB,
bool,
"GlassTable::prev_default",
Literal(
"C_") | j);
2142 const uint8_t * p = C_[j].
get_p();
2165 LOGCALL(DB,
bool,
"GlassTable::next_default",
Literal(
"C_") | j);
2166 const uint8_t * p = C_[j].
get_p();
2186 #ifdef BTREE_DEBUG_FULL 2187 printf(
"Block in GlassTable:next_default");
2188 report_block_full(j - 1, C_[j - 1].get_n(), C_[j - 1].get_p());
#define LOGCALL_STATIC(CATEGORY, TYPE, FUNC, PARAMS)
uint4 get_compress_min() const
bool key_exists(const std::string &key) const
Check if a key exists in the Btree.
int io_open_block_rd(const char *fname)
Open a block-based file for reading.
int DIR_END(const uint8_t *b)
static void setD(uint8_t *q, int c, int x)
off_t offset
offset to start of table in file.
bool get_sequential() const
Indicates an attempt to access a closed database.
Glass::LeafItem_wr kt
buffer of size block_size for making up key-tag items
void create_and_open(int flags_, const RootInfo &root_info)
Create a new empty btree structure on disk and open it at the initial revision.
XAPIAN_REVISION_TYPE rev
Revision number of a database.
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_unlink(const std::string &filename)
Delete a file.
bool find(Glass::Cursor *) const
find(C_) searches for the key of B->kt in the B-tree.
void commit(const GlassTable *B, uint4 block_size)
#define AssertRel(A, REL, B)
#define GLASS_BTREE_MAX_KEY_LEN
The largest possible value of a key_len.
InvalidOperationError indicates the API was used in an invalid way.
int TOTAL_FREE(const uint8_t *b)
static int find_in_branch(const uint8_t *p, Glass::LeafItem item, int c)
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.
int changed_c
directory offset corresponding to last block to be changed by an addition
bool readahead_key(const string &key) const
int find_in_branch_(const uint8_t *p, ITEM item, int c)
uint4 REVISION(const uint8_t *b)
uint4 glass_revision_number_t
The revision number of a glass database.
Provides wrappers with POSIXy semantics.
uint8_t * split_p
Buffer used when splitting a block.
unsigned long cursor_version
Version count for tracking when cursors need to rebuild.
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).
void set_blocksize(unsigned b)
Constants in the Xapian namespace.
#define LOGCALL_DTOR(CATEGORY, CLASS)
int io_open_block_wr(const char *fname, bool anew)
Open a block-based file for writing.
bool writable
Set to true when the database is opened to write.
#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 set_truncated_key_and_block(Key newkey, int new_comp, int truncate_size, uint4 n)
Definitions, types, etc for use inside glass.
Convert types to std::string.
int handle
File descriptor of the table.
void set_key_and_block(Key newkey, uint4 n)
void add(const std::string &key, const std::string &tag, bool already_compressed=false)
Add a key/tag pair to the table, replacing any existing pair with the same key.
int revision()
Report the revision of the library which the program is linked with.
Utility functions for testing files.
void compact(uint8_t *p)
compact(p) compact the block at p by shuffling all the items up to the end.
bool lazy
If true, don't create the table until it's needed.
void SET_MAX_FREE(uint8_t *b, int x)
void write_block(uint4 n, const uint8_t *p, bool appending=false) const
write_block(n, p, appending) writes block n in the DB file from address p.
void set_level(int level_)
bool prev_default(Glass::Cursor *C_, int j) const
int flags
Flags like DB_NO_SYNC and DB_DANGEROUS.
~GlassTable()
Close the Btree.
bool full_compaction
set to true when full compaction is to be achieved
int size() const
SIZE in diagram above.
#define GLASS_TABLE_EXTENSION
Glass table extension.
uint4 changed_n
the last block to be changed by an addition
int MAX_FREE(const uint8_t *b)
int compare(ITEM1 a, ITEM2 b)
Compare two items by their keys.
Hierarchy of classes which Xapian can throw as exceptions.
void add_item_to_leaf(uint8_t *p, Glass::LeafItem kt, int c)
add_item_to_leaf(p, kt_, c) adds item kt_ to the leaf block at p.
void set_num_entries(glass_tablesize_t n)
void form_key(const std::string &key) const
void flush_db()
Flush any outstanding changes to the DB file of the table.
void add_item_to_branch(uint8_t *p, Glass::BItem kt, int c)
add_item_to_branch(p, kt_, c) adds item kt_ to the branch block at p.
void enter_key_above_branch(int j, Glass::BItem newitem)
enter_key_above_branch(j, newkey) is called after a branch block split.
const char * tablename
The name of the table (used when writing changesets).
void do_open_to_read(const RootInfo *root_info, glass_revision_number_t rev)
Perform the opening operation to read.
glass_tablesize_t item_count
keeps a count of the number of items in the B-tree.
DatabaseModifiedError indicates a database was modified.
functions for reading and writing different width words
Glass::Cursor C[GLASS_BTREE_CURSOR_LEVELS]
int GET_LEVEL(const uint8_t *b)
void close(bool permanent=false)
Close the Btree.
bool prev_for_sequential(Glass::Cursor *C_, int dummy) const
int add_kt(bool found)
add_kt(found) adds the item (key-tag pair) at B->kt into the B-tree, using cursor C...
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...
static uint8_t * zeroed_new(size_t size)
static int find_in_leaf(const uint8_t *p, Glass::LeafItem item, int c, bool &exact)
find_in_leaf(p, key, c, exact) searches for the key in the leaf block at p.
void commit(glass_revision_number_t revision, RootInfo *root_info)
Commit any outstanding changes to the table.
bool decompress_chunk(CompressionStream &comp_stream, string &tag) const
bool next_for_sequential(Glass::Cursor *C_, int dummy) const
GlassChanges * changes_obj
The GlassChanges object to write block changes to.
uint4 last_readahead
Last block readahead_key() preread.
uint4 get_first_unused_block() const
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)
void set_revision(uint4 revision_)
GlassTable(const GlassTable &)
Copying not allowed.
const uint8_t * clone(const Cursor &o)
string str(int value)
Convert int to std::string.
void alter()
Btree::alter(); is called when the B-tree is to be altered.
void add_branch_item(Glass::BItem kt, int j)
GlassTable::add_item(kt_, j) adds item kt_ to the block at cursor level C[j].
void SET_LEVEL(uint8_t *b, int x)
bool get_compressed() const
bool unpack(const char **pstart, const char *end)
glass_tablesize_t get_num_entries() const
bool last_component() const
CompressionStream comp_stream
bool get_root_is_fake() const
int DIR_END(const uint8_t *b)
static void throw_database_closed()
Throw an exception indicating that the database is closed.
const int DB_DANGEROUS
Update the database in-place.
#define LOGCALL_CTOR(CATEGORY, CLASS, PARAMS)
int seq_count
count of the number of successive instances of purely sequential addition, starting at SEQ_START_POIN...
A cursor pointing to a position in a Btree table, for reading several entries in order, or finding approximate matches.
DatabaseCorruptError indicates database corruption was detected.
#define GLASS_BTREE_CURSOR_LEVELS
Allow for this many levels in the B-tree.
int size() const
SIZE in diagram above.
void open(int flags_, const RootInfo &root_info, glass_revision_number_t rev)
Open the btree.
std::string name
The path name of the B tree.
static void setD(uint8_t *q, int c, int x)
bool Btree_modified
Set to true the first time the B-tree is modified.
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 ...
unsigned int block_size
block size of the B tree in bytes
void pack_uint(std::string &s, U value)
Append an encoded unsigned integer to a string.
void init(unsigned blocksize_, uint4 compress_min_)
#define AssertEqParanoid(A, B)
void read_block(uint4 n, uint8_t *p) const
read_block(n, p) reads block n of the DB file to address p.
const int LEVEL_FREELIST
Freelist blocks have their level set to LEVEL_FREELIST.
bool read_tag(Glass::Cursor *C_, std::string *tag, bool keep_compressed) const
Read the tag value for the key pointed to by cursor C_.
void set_overwritten() const
uint8_t * buffer
buffer of size block_size for reforming blocks
void append_chunk(std::string *tag) const
unsigned get_blocksize() const
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.
Interface to Btree cursors.
glass_block_t get_root() const
void enter_key_above_leaf(Glass::LeafItem previtem, Glass::LeafItem newitem)
enter_key_above_leaf(previtem, newitem) is called after a leaf block split.
bool faked_root_block
true if the root block is faked (not written to disk).
int c
offset in the block's directory
size_t max_item_size
maximum size of an item (key-tag pair)
GlassCursor * cursor_get() const
Get a cursor for reading from the table.
Pack types into strings and unpack them again.
void basic_open(const RootInfo *root_info, glass_revision_number_t rev)
Wrappers for low-level POSIX I/O routines.
void set_root_is_fake(bool f)
void SET_DIR_END(uint8_t *b, int x)
Various handy helpers which std::string really should provide.
void SET_REVISION(uint8_t *b, uint4 rev)
void delete_branch_item(int j)
GlassTable::delete_branch_item(j, repeatedly) is (almost) the converse of add_branch_item.
GlassFreeList free_list
List of free blocks.
void block_to_cursor(Glass::Cursor *C_, int j, uint4 n) const
void add_leaf_item(Glass::LeafItem kt)
GlassTable::add_leaf_item(kt_) adds item kt_ to the leaf block.
uint4 compress_min
Minimum size tag to try compressing (0 for no compression).
unsigned REVISION(const uint8_t *b)
void pack(std::string &buf)
const int BYTES_PER_BLOCK_NUMBER
void cancel(const RootInfo &root_info, glass_revision_number_t rev)
Cancel any outstanding changes.
const uint8_t * get_p() const
Get pointer to block.
Various assertion macros.
glass_revision_number_t revision_number
revision number of the opened B-tree.
bool next_default(Glass::Cursor *C_, int j) const
DatabaseError indicates some sort of database related error.
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...
void set_root(glass_block_t root_)
bool exists() const
Determine whether the btree exists on disk.
void set_sequential(bool f)
uint4 root
the root block of the B-tree
void do_open_to_write(const RootInfo *root_info, glass_revision_number_t rev=0)
Perform the opening operation to write.
void form_null_key(uint4 n)
Form an item with a null key and with block number n in the tag.
int level
number of levels, counting from 0
bool file_exists(const char *path)
Test if a file exists.
void delete_leaf_item(bool repeatedly)
GlassTable::delete_leaf_item(repeatedly) is (almost) the converse of add_leaf_item.
const std::string & get_free_list() const
bool sequential
true iff the data has been written in a single write in sequential order.
void SET_TOTAL_FREE(uint8_t *b, int x)
void set_free_list(const std::string &s)
bool cursor_created_since_last_modification
Flag for tracking when cursors need to rebuild.
uint4 block_given_by() const
Get this item's tag as a block number (this block should not be at level 0).
bool del(const std::string &key)
Delete an entry from the table.
uint4 get_n() const
Get the block number.
uint8_t * init(unsigned block_size)
bool rewrite
true if the block is not the same as on disk, and so needs rewriting
#define LOGCALL(CATEGORY, TYPE, FUNC, PARAMS)
UnimplementedError indicates an attempt to use an unimplemented feature.
#define SEQ_START_POINT
Flip to sequential addition block-splitting after this number of observed sequential additions (in ne...
void set_full_compaction(bool parity)