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) {
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;
1350 string message =
"Btree tag entry of size ";
1351 message +=
str(tag_size);
1352 message +=
" is too large to store - "
1353 "increase the block size to raise this limit";
1358 size_t residue = tag_size;
1359 bool replacement =
false;
1360 bool components_to_del =
false;
1362 for (i = 1; i <= m; ++i) {
1363 size_t l = (i == m ? residue : (i == 1 ? first_L : L));
1364 size_t this_cd = (i == 1 ? cd -
X2 : cd);
1365 Assert(this_cd + l <= block_size);
1366 Assert(o + l <= tag_size);
1367 kt.set_tag(this_cd, tag_data + o, l, compressed, i, m);
1372 if (i > 1) found = find(
C);
1373 int result = add_kt(found);
1374 if (result) replacement =
true;
1375 components_to_del = (result == 1);
1378 if (components_to_del) {
1381 kt.set_component_of(++i);
1382 }
while (delete_kt() == 1);
1384 if (!replacement) ++item_count;
1385 Btree_modified =
true;
1386 if (cursor_created_since_last_modification) {
1387 cursor_created_since_last_modification =
false;
1401 LOGCALL(DB,
bool,
"GlassTable::del", key);
1414 if (key.empty())
RETURN(
false);
1417 int r = delete_kt();
1418 if (r == 0)
RETURN(
false);
1421 kt.set_component_of(++i);
1426 Btree_modified =
true;
1427 if (cursor_created_since_last_modification) {
1428 cursor_created_since_last_modification =
false;
1437 LOGCALL(DB,
bool,
"GlassTable::readahead_key", key);
1464 const uint8_t * p =
C[level].get_p();
1465 int c = find_in_branch(p, kt,
C[level].c);
1469 if (n != last_readahead && n !=
C[level - 1].get_n()) {
1480 LOGCALL(DB,
bool,
"GlassTable::get_exact_entry", key | tag);
1496 (void)read_tag(
C, &tag,
false);
1503 LOGCALL(DB,
bool,
"GlassTable::key_exists", key);
1516 LOGCALL(DB,
bool,
"GlassTable::read_tag",
Literal(
"C_") | tag | keep_compressed);
1520 LeafItem item(C_[0].get_p(), C_[0].c);
1522 bool decompress =
false;
1523 if (compressed && !keep_compressed) {
1524 comp_stream.decompress_start();
1536 "Too many chunks of compressed data" :
1537 "Too few chunks of compressed data");
1546 item.
init(C_[0].get_p(), C_[0].c);
1551 RETURN(compressed && keep_compressed);
1557 LOGCALL_VOID(DB,
"GlassTable::set_full_compaction", parity);
1560 if (parity) seq_count = 0;
1561 full_compaction = parity;
1582 revision_number =
rev;
1589 if (!fl_serialised.empty()) {
1590 if (!free_list.unpack(fl_serialised))
1603 for (
int j = 0; j <= level; ++j) {
1604 C[j].init(block_size);
1609 if (cursor_created_since_last_modification) {
1610 cursor_created_since_last_modification =
false;
1619 if (faked_root_block) {
1621 uint8_t * p =
C[0].init(block_size);
1627 memset(p, 0, block_size);
1629 int o = block_size -
I2 -
K1;
1648 C[0].set_n(free_list.get_block(
this, block_size));
1649 C[0].rewrite =
true;
1653 block_to_cursor(
C, level, root);
1655 if (
REVISION(
C[level].get_p()) > revision_number) set_overwritten();
1670 handle = -3 - handle;
1677 if (lazy &&
rev && errno == ENOENT) {
1678 revision_number =
rev;
1681 string message((
rev == 0) ?
"Couldn't create " :
"Couldn't open ");
1689 basic_open(root_info,
rev);
1691 split_p =
new uint8_t[block_size];
1701 bool readonly_,
bool lazy_)
1702 : tablename(tablename_),
1706 faked_root_block(
true),
1719 Btree_modified(
false),
1720 full_compaction(
false),
1721 writable(!readonly_),
1722 cursor_created_since_last_modification(
false),
1727 comp_stream(Z_DEFAULT_STRATEGY),
1732 LOGCALL_CTOR(DB,
"GlassTable", tablename_ | path_ | readonly_ | lazy_);
1736 bool readonly_,
bool lazy_)
1737 : tablename(tablename_),
1741 faked_root_block(
true),
1754 Btree_modified(
false),
1755 full_compaction(
false),
1756 writable(!readonly_),
1757 cursor_created_since_last_modification(
false),
1762 comp_stream(Z_DEFAULT_STRATEGY),
1767 LOGCALL_CTOR(DB,
"GlassTable", tablename_ | fd | offset_ | readonly_ | lazy_);
1772 LOGCALL(DB,
bool,
"GlassTable::exists", NO_ARGS);
1780 LOGCALL_VOID(DB,
"GlassTable::create_and_open", flags_|root_info);
1788 Assert(block_size_ >= 2048);
1791 Assert((block_size_ & (block_size_ - 1)) == 0);
1834 for (
int j =
level; j >= 0; --j) {
1858 for (
int j =
level; j >= 0; --j) {
1903 for (
int i = 0; i <=
level; ++i) {
1954 if (!fl_serialised.empty()) {
1963 for (
int j = 0; j <=
level; ++j) {
1985 LOGCALL(DB,
bool,
"GlassTable::do_open_to_read", root_info|
rev);
1999 string message(
"Couldn't open ");
2041 if (n == 0)
RETURN(
false);
2043 if (n ==
C[0].get_n()) {
2055 for (j = 1; j <=
level; ++j) {
2056 if (n ==
C[j].get_n())
break;
2058 if (j <=
level)
continue;
2087 const uint8_t * p = C_[0].
get_p();
2099 if (n ==
C[0].get_n()) {
2110 for (j = 1; j <=
level; ++j) {
2111 if (n ==
C[j].get_n())
break;
2113 if (j <=
level)
continue;
2143 LOGCALL(DB,
bool,
"GlassTable::prev_default",
Literal(
"C_") | j);
2144 const uint8_t * p = C_[j].
get_p();
2167 LOGCALL(DB,
bool,
"GlassTable::next_default",
Literal(
"C_") | j);
2168 const uint8_t * p = C_[j].
get_p();
2188 #ifdef BTREE_DEBUG_FULL
2189 printf(
"Block in GlassTable:next_default");
2190 report_block_full(j - 1, C_[j - 1].get_n(), C_[j - 1].get_p());
int GET_LEVEL(const uint8_t *b)
unsigned REVISION(const uint8_t *b)
int DIR_END(const uint8_t *b)
A cursor pointing to a position in a Btree table, for reading several entries in order,...
void pack(std::string &buf)
uint4 get_first_unused_block() const
void set_revision(uint4 revision_)
void commit(const GlassTable *B, uint4 block_size)
bool unpack(const char **pstart, const char *end)
Class managing a Btree table in a Glass database.
bool readahead_key(const string &key) const
void block_to_cursor(Glass::Cursor *C_, int j, uint4 n) const
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.
bool Btree_modified
Set to true the first time the B-tree is modified.
uint4 changed_n
the last block to be changed by an addition
void alter()
Btree::alter(); is called when the B-tree is to be altered.
bool next_for_sequential(Glass::Cursor *C_, int dummy) const
~GlassTable()
Close the Btree.
void compact(uint8_t *p)
compact(p) compact the block at p by shuffling all the items up to the end.
GlassFreeList free_list
List of free blocks.
int seq_count
count of the number of successive instances of purely sequential addition, starting at SEQ_START_POIN...
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.
uint8_t * buffer
buffer of size block_size for reforming blocks
void basic_open(const RootInfo *root_info, glass_revision_number_t rev)
glass_tablesize_t item_count
keeps a count of the number of items in the B-tree.
void delete_branch_item(int j)
GlassTable::delete_branch_item(j, repeatedly) is (almost) the converse of add_branch_item.
bool faked_root_block
true if the root block is faked (not written to disk).
void commit(glass_revision_number_t revision, RootInfo *root_info)
Commit any outstanding changes to the table.
int changed_c
directory offset corresponding to last block to be changed by an addition
bool next_default(Glass::Cursor *C_, int j) const
uint4 root
the root block of the B-tree
bool del(const std::string &key)
Delete an entry from the table.
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.
uint8_t * split_p
Buffer used when splitting a block.
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 do_open_to_read(const RootInfo *root_info, glass_revision_number_t rev)
Perform the opening operation to read.
int level
number of levels, counting from 0
bool exists() const
Determine whether the btree exists on disk.
void set_overwritten() const
void enter_key_above_branch(int j, Glass::BItem newitem)
enter_key_above_branch(j, newkey) is called after a branch block split.
void flush_db()
Flush any outstanding changes to the DB file of the table.
bool prev_default(Glass::Cursor *C_, int j) const
bool writable
Set to true when the database is opened to write.
void open(int flags_, const RootInfo &root_info, glass_revision_number_t rev)
Open the btree.
GlassTable(const GlassTable &)
Copying not allowed.
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 find(Glass::Cursor *) const
find(C_) searches for the key of B->kt in the B-tree.
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_.
bool key_exists(const std::string &key) const
Check if a key exists in the Btree.
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.
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 add_leaf_item(Glass::LeafItem kt)
GlassTable::add_leaf_item(kt_) adds item kt_ to the leaf block.
void read_block(uint4 n, uint8_t *p) const
read_block(n, p) reads block n of the DB file to address p.
unsigned int block_size
block size of the B tree in bytes
GlassCursor * cursor_get() const
Get a cursor for reading from the table.
bool cursor_created_since_last_modification
Flag for tracking when cursors need to rebuild.
void set_full_compaction(bool parity)
unsigned long cursor_version
Version count for tracking when cursors need to rebuild.
void form_key(const std::string &key) const
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.
std::string name
The path name of the B tree.
bool lazy
If true, don't create the table until it's needed.
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].
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...
static int find_in_branch(const uint8_t *p, Glass::LeafItem item, int c)
void close(bool permanent=false)
Close the Btree.
void delete_leaf_item(bool repeatedly)
GlassTable::delete_leaf_item(repeatedly) is (almost) the converse of add_leaf_item.
Glass::Cursor C[GLASS_BTREE_CURSOR_LEVELS]
int handle
File descriptor of the table.
void cancel(const RootInfo &root_info, glass_revision_number_t rev)
Cancel any outstanding changes.
Glass::LeafItem_wr kt
buffer of size block_size for making up key-tag items
bool prev_for_sequential(Glass::Cursor *C_, int dummy) const
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 do_open_to_write(const RootInfo *root_info, glass_revision_number_t rev=0)
Perform the opening operation to write.
static void throw_database_closed()
Throw an exception indicating that the database is closed.
uint4 compress_min
Minimum size tag to try compressing (0 for no compression).
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.
bool sequential
true iff the data has been written in a single write in sequential order.
int flags
Flags like DB_NO_SYNC and DB_DANGEROUS.
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.
glass_revision_number_t revision_number
revision number of the opened B-tree.
uint4 block_given_by() const
Get this item's tag as a block number (this block should not be at level 0).
int size() const
SIZE in diagram above.
void set_truncated_key_and_block(Key newkey, int new_comp, int truncate_size, uint4 n)
void set_key_and_block(Key newkey, uint4 n)
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).
static void setD(uint8_t *q, int c, int x)
uint8_t * init(unsigned block_size)
bool rewrite
true if the block is not the same as on disk, and so needs rewriting
int c
offset in the block's directory
uint4 get_n() const
Get the block number.
const uint8_t * clone(const Cursor &o)
const uint8_t * get_p() const
Get pointer to block.
int size() const
SIZE in diagram above.
bool last_component() const
void append_chunk(std::string *tag) const
bool get_compressed() const
bool decompress_chunk(CompressionStream &comp_stream, string &tag) const
static void setD(uint8_t *q, int c, int x)
void set_num_entries(glass_tablesize_t n)
const std::string & get_free_list() const
void init(unsigned blocksize_, uint4 compress_min_)
glass_tablesize_t get_num_entries() const
void set_blocksize(unsigned b)
bool get_sequential() const
void set_level(int level_)
unsigned get_blocksize() const
void set_sequential(bool f)
void set_free_list(const std::string &s)
uint4 get_compress_min() const
void set_root_is_fake(bool f)
glass_block_t get_root() const
bool get_root_is_fake() const
void set_root(glass_block_t root_)
Indicates an attempt to access a closed database.
DatabaseCorruptError indicates database corruption was detected.
DatabaseError indicates some sort of database related error.
DatabaseModifiedError indicates a database was modified.
DatabaseOpeningError indicates failure to open a database.
InvalidOperationError indicates the API was used in an invalid way.
UnimplementedError indicates an attempt to use an unimplemented feature.
Constants in the Xapian namespace.
#define LOGCALL(CATEGORY, TYPE, FUNC, PARAMS)
#define LOGCALL_CTOR(CATEGORY, CLASS, PARAMS)
#define LOGCALL_STATIC(CATEGORY, TYPE, FUNC, PARAMS)
#define LOGCALL_VOID(CATEGORY, FUNC, PARAMS)
#define LOGCALL_DTOR(CATEGORY, CLASS)
Hierarchy of classes which Xapian can throw as exceptions.
Utility functions for testing files.
bool file_exists(const char *path)
Test if a file exists.
Interface to Btree cursors.
Definitions, types, etc for use inside glass.
#define GLASS_BTREE_CURSOR_LEVELS
Allow for this many levels in the B-tree.
uint4 glass_revision_number_t
The revision number of a glass database.
#define GLASS_TABLE_EXTENSION
Glass table extension.
#define SEQ_START_POINT
Flip to sequential addition block-splitting after this number of observed sequential additions (in ne...
static uint8_t * zeroed_new(size_t size)
int find_in_branch_(const uint8_t *p, ITEM item, int c)
#define GLASS_BTREE_MAX_KEY_LEN
The largest possible value of a key_len.
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 io_open_block_wr(const char *filename, bool anew)
Open a block-based file for writing.
bool io_unlink(const std::string &filename)
Delete a file.
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.
Wrappers for low-level POSIX I/O routines.
bool io_readahead_block(int, size_t, off_t, off_t=0)
Readahead block b size n bytes from file descriptor fd.
int io_open_block_rd(const char *filename)
Open a block-based file for reading.
int DIR_END(const uint8_t *b)
const int LEVEL_FREELIST
Freelist blocks have their level set to LEVEL_FREELIST.
void SET_DIR_END(uint8_t *b, int x)
int compare(ITEM1 a, ITEM2 b)
Compare two items by their keys.
int TOTAL_FREE(const uint8_t *b)
void SET_LEVEL(uint8_t *b, int x)
int GET_LEVEL(const uint8_t *b)
void SET_REVISION(uint8_t *b, uint4 rev)
int MAX_FREE(const uint8_t *b)
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.
const int BYTES_PER_BLOCK_NUMBER
uint4 REVISION(const uint8_t *b)
void SET_TOTAL_FREE(uint8_t *b, int x)
void SET_MAX_FREE(uint8_t *b, int x)
string str(int value)
Convert int to std::string.
int revision()
Report the revision of the library which the program is linked with.
XAPIAN_REVISION_TYPE rev
Revision number of a database.
const int DB_DANGEROUS
Update the database in-place.
Various assertion macros.
#define AssertEqParanoid(A, B)
#define AssertRel(A, REL, B)
Pack types into strings and unpack them again.
void pack_uint(std::string &s, U value)
Append an encoded unsigned integer to a string.
Provides wrappers with POSIXy semantics.
Convert types to std::string.
Various handy helpers which std::string really should provide.
#define STRINGIZE(X)
The STRINGIZE macro converts its parameter into a string constant.
functions for reading and writing different width words