36 #include <sys/types.h>
59 using namespace Glass;
70 #undef BTREE_DEBUG_FULL
72 #ifdef BTREE_DEBUG_FULL
75 static void print_key(
const uint8_t * p,
int c,
int j);
76 static void print_tag(
const uint8_t * p,
int c,
int j);
94 uint8_t *temp =
new uint8_t[size];
95 memset(temp, 0, size);
153 #define SEQ_START_POINT (-10)
163 #define BYTE_PAIR_RANGE (1 << 2 * CHAR_BIT)
170 LOGCALL_VOID(DB,
"GlassTable::read_block", n | (
void*)p);
171 if (
rare(handle == -2))
173 AssertRel(n,<,free_list.get_first_unused_block());
175 io_read_block(handle,
reinterpret_cast<char *
>(p), block_size, n, offset);
179 if (
rare(dir_end <
DIR_START ||
unsigned(dir_end) > block_size)) {
180 string msg(
"dir_end invalid in block ");
200 LOGCALL_VOID(DB,
"GlassTable::write_block", n | p | appending);
203 AssertRel(n,<,free_list.get_first_unused_block());
227 const char * p_char =
reinterpret_cast<const char *
>(p);
230 if (!changes_obj)
return;
234 if (strcmp(tablename,
"position") == 0) {
236 }
else if (strcmp(tablename,
"postlist") == 0) {
238 }
else if (strcmp(tablename,
"docdata") == 0) {
240 }
else if (strcmp(tablename,
"spelling") == 0) {
242 }
else if (strcmp(tablename,
"synonym") == 0) {
244 }
else if (strcmp(tablename,
"termlist") == 0) {
250 if (block_size == 2048) {
252 }
else if (block_size == 4096) {
254 }
else if (block_size == 8192) {
256 }
else if (block_size == 16384) {
258 }
else if (block_size == 32768) {
260 }
else if (block_size == 65536) {
271 changes_obj->write_block(buf);
272 changes_obj->write_block(
reinterpret_cast<const char *
>(p), block_size);
298 LOGCALL_VOID(DB,
"GlassTable::set_overwritten", NO_ARGS);
303 throw Xapian::DatabaseModifiedError(
"The revision being read has been discarded - you should call Xapian::Database::reopen() and retry the operation");
319 LOGCALL_VOID(DB,
"GlassTable::block_to_cursor", (
void*)C_ | j | n);
320 if (n == C_[j].get_n())
return;
322 if (writable && C_[j].rewrite) {
324 write_block(C_[j].get_n(), C_[j].get_p());
331 if (n ==
C[j].get_n()) {
334 uint8_t * q = C_[j].
init(block_size);
349 string msg =
"Expected block ";
351 msg +=
" to be level ";
391 if (
C[j].rewrite)
return;
395 if (
rev == revision_number + 1) {
400 free_list.mark_block_unused(
this, block_size, n);
401 SET_REVISION(
C[j].get_modifiable_p(block_size), revision_number + 1);
402 n = free_list.get_block(
this, block_size);
405 if (j == level)
return;
438 if (c < j && i < c) {
447 if (c < j && i < c) {
458 int k = i + ((j - i) / (
D2 * 2)) *
D2;
475 template<
typename ITEM>
int
487 if (c < j && i < c) {
489 if (r == 0)
return c;
493 if (c < j && i < c) {
495 if (r == 0)
return c;
501 int k = i + ((j - i) / (
D2 * 2)) *
D2;
539 LOGCALL(DB,
bool,
"GlassTable::find", (
void*)C_);
543 for (
int j = level; j > 0; --j) {
545 c = find_in_branch(p, kt, C_[j].c);
546 #ifdef BTREE_DEBUG_FULL
547 printf(
"Block in GlassTable:find - code position 1");
548 report_block_full(j, C_[j].get_n(), p);
551 block_to_cursor(C_, j - 1,
BItem(p, c).block_given_by());
555 c = find_in_leaf(p, kt, C_[0].c, exact);
556 #ifdef BTREE_DEBUG_FULL
557 printf(
"Block in GlassTable:find - code position 2");
558 report_block_full(0, C_[0].get_n(), p);
576 uint8_t * b = buffer;
584 if (e < 0)
throw_corrupt(
"Leaf item size extends outside block");
594 if (e < 0)
throw_corrupt(
"Branch item size extends outside block");
599 memcpy(p + e, b + e, block_size - e);
601 if (e < 0)
throw_corrupt(
"Items overlap with item pointers");
624 uint8_t * q =
C[level].init(block_size);
625 memset(q, 0, block_size);
627 C[level].set_n(free_list.get_block(
this, block_size));
628 C[level].rewrite =
true;
638 add_branch_item(item, level);
663 Key prevkey = previtem.
key();
664 Key newkey = newitem.
key();
667 uint4 blocknumber =
C[0].get_n();
671 const int newkey_len = newkey.
length();
677 const int min_len = min(newkey_len, prevkey.
length());
678 while (i < min_len && prevkey[i] == newkey[i]) {
683 if (i < newkey_len) i++;
693 AssertEq(
C[1].c, find_in_branch(
C[1].get_p(), item,
C[1].c));
696 add_branch_item(item, 1);
724 uint4 blocknumber =
C[j - 1].get_n();
733 AssertEq(
C[j].c, find_in_branch(
C[j].get_p(), item,
C[j].c));
736 add_branch_item(item, j);
746 LOGCALL(DB,
int,
"GlassTable::mid_point", (
void*)p);
749 int size = block_size -
TOTAL_FREE(p) - dir_end;
759 if (l < n - size)
RETURN(c);
786 int kt_len = kt_.
size();
787 int needed = kt_len +
D2;
798 memmove(p + c +
D2, p + c, dir_end - c);
802 int o = dir_end + new_max;
826 int kt_len = kt_.
size();
827 int needed = kt_len +
D2;
838 memmove(p + c +
D2, p + c, dir_end - c);
842 int o = dir_end + new_max;
861 uint8_t * p =
C[0].get_modifiable_p(block_size);
865 int needed = kt_.
size() +
D2;
883 uint4 split_n =
C[0].get_n();
884 C[0].set_n(free_list.get_block(
this, block_size));
886 memcpy(split_p, p, block_size);
899 bool add_to_upper_half;
901 add_to_upper_half = (c >= m);
905 add_to_upper_half = (
TOTAL_FREE(split_p) < needed);
908 if (add_to_upper_half) {
913 add_item_to_leaf(p, kt_, c);
918 add_item_to_leaf(split_p, kt_, c);
921 write_block(split_n, split_p);
924 if (0 == level) split_root(split_n);
938 add_item_to_leaf(p, kt_, c);
956 uint8_t * p =
C[j].get_modifiable_p(block_size);
959 int needed = kt_.
size() +
D2;
977 uint4 split_n =
C[j].get_n();
978 C[j].set_n(free_list.get_block(
this, block_size));
980 memcpy(split_p, p, block_size);
993 bool add_to_upper_half;
995 add_to_upper_half = (c >= m);
999 add_to_upper_half = (
TOTAL_FREE(split_p) < needed);
1002 if (add_to_upper_half) {
1007 add_item_to_branch(p, kt_, c);
1011 add_item_to_branch(split_p, kt_, c);
1013 write_block(split_n, split_p);
1016 if (j == level) split_root(split_n);
1037 add_item_to_branch(p, kt_, c);
1051 LOGCALL_VOID(DB,
"GlassTable::delete_leaf_item", repeatedly);
1053 uint8_t * p =
C[0].get_modifiable_p(block_size);
1060 memmove(p + c, p + c +
D2, dir_end - c);
1065 if (!repeatedly)
return;
1068 free_list.mark_block_unused(
this, block_size,
C[0].get_n());
1069 C[0].rewrite =
false;
1071 C[1].rewrite =
true;
1072 delete_branch_item(1);
1088 uint8_t * p =
C[j].get_modifiable_p(block_size);
1095 memmove(p + c, p + c +
D2, dir_end - c);
1102 free_list.mark_block_unused(
this, block_size,
C[j].get_n());
1103 C[j].rewrite =
false;
1105 C[j + 1].rewrite =
true;
1106 delete_branch_item(j + 1);
1113 free_list.mark_block_unused(
this, block_size,
C[level].get_n());
1117 block_to_cursor(
C, level, new_root);
1119 dir_end =
DIR_END(
C[level].get_p());
1161 LOGCALL(DB,
int,
"GlassTable::add_kt", found);
1177 uint8_t * p =
C[0].get_modifiable_p(block_size);
1182 int kt_size = kt.size();
1183 int needed = kt_size - item.
size();
1189 memmove(
const_cast<uint8_t *
>(item.
get_address()),
1190 kt.get_address(), kt_size);
1194 int new_max =
MAX_FREE(p) - kt_size;
1197 memmove(p + o, kt.get_address(), kt_size);
1203 delete_leaf_item(
false);
1209 if (changed_n ==
C[0].get_n() && changed_c ==
C[0].c) {
1210 if (seq_count < 0) seq_count++;
1234 LOGCALL(DB,
int,
"GlassTable::delete_kt", NO_ARGS);
1245 delete_leaf_item(
true);
1291 LOGCALL_VOID(DB,
"GlassTable::add", key | tag | already_compressed);
1299 root_info.
init(block_size, compress_min);
1300 do_open_to_write(&root_info);
1305 const char* tag_data = tag.data();
1306 size_t tag_size = tag.size();
1308 bool compressed =
false;
1309 if (already_compressed) {
1311 }
else if (compress_min > 0 && tag_size > compress_min) {
1312 const char * res = comp_stream.compress(tag_data, &tag_size);
1320 const size_t cd = kt.key().length() +
K1 +
I2 +
X2;
1321 const size_t L = max_item_size - cd;
1322 size_t first_L = L +
X2;
1323 bool found = find(
C);
1324 if (tag_size <= first_L) {
1328 }
else if (!found) {
1329 const uint8_t * p =
C[0].get_p();
1345 size_t last = (tag_size -
X2) % L;
1346 if (n >= last || (full_compaction && n >= key.size() + 34)) {
1355 int m = (tag_size - first_L + L - 1) / L + 1;
1360 string message =
"Btree tag entry of size ";
1361 message +=
str(tag_size);
1362 message +=
" is too large to store - "
1363 "increase the block size to raise this limit";
1368 size_t residue = tag_size;
1369 bool replacement =
false;
1370 bool components_to_del =
false;
1372 for (i = 1; i <= m; ++i) {
1373 size_t l = (i == m ? residue : (i == 1 ? first_L : L));
1374 size_t this_cd = (i == 1 ? cd -
X2 : cd);
1375 Assert(this_cd + l <= block_size);
1376 Assert(o + l <= tag_size);
1377 kt.set_tag(this_cd, tag_data + o, l, compressed, i, m);
1382 if (i > 1) found = find(
C);
1383 int result = add_kt(found);
1384 if (result) replacement =
true;
1385 components_to_del = (result == 1);
1388 if (components_to_del) {
1391 kt.set_component_of(++i);
1392 }
while (delete_kt() == 1);
1394 if (!replacement) ++item_count;
1395 Btree_modified =
true;
1396 if (cursor_created_since_last_modification) {
1397 cursor_created_since_last_modification =
false;
1411 LOGCALL(DB,
bool,
"GlassTable::del", key);
1424 if (key.empty())
RETURN(
false);
1427 int r = delete_kt();
1428 if (r == 0)
RETURN(
false);
1431 kt.set_component_of(++i);
1436 Btree_modified =
true;
1437 if (cursor_created_since_last_modification) {
1438 cursor_created_since_last_modification =
false;
1447 LOGCALL(DB,
bool,
"GlassTable::readahead_key", key);
1474 const uint8_t * p =
C[level].get_p();
1475 int c = find_in_branch(p, kt,
C[level].c);
1479 if (n != last_readahead && n !=
C[level - 1].get_n()) {
1490 LOGCALL(DB,
bool,
"GlassTable::get_exact_entry", key | tag);
1506 (void)read_tag(
C, &tag,
false);
1513 LOGCALL(DB,
bool,
"GlassTable::key_exists", key);
1526 LOGCALL(DB,
bool,
"GlassTable::read_tag",
Literal(
"C_") | tag | keep_compressed);
1530 LeafItem item(C_[0].get_p(), C_[0].c);
1532 bool decompress =
false;
1533 if (compressed && !keep_compressed) {
1534 comp_stream.decompress_start();
1546 "Too many chunks of compressed data" :
1547 "Too few chunks of compressed data");
1556 item.
init(C_[0].get_p(), C_[0].c);
1561 RETURN(compressed && keep_compressed);
1567 LOGCALL_VOID(DB,
"GlassTable::set_full_compaction", parity);
1570 if (parity) seq_count = 0;
1571 full_compaction = parity;
1592 revision_number =
rev;
1599 if (!fl_serialised.empty()) {
1600 if (!free_list.unpack(fl_serialised))
1613 for (
int j = 0; j <= level; ++j) {
1614 C[j].init(block_size);
1619 if (cursor_created_since_last_modification) {
1620 cursor_created_since_last_modification =
false;
1629 if (faked_root_block) {
1631 uint8_t * p =
C[0].init(block_size);
1637 memset(p, 0, block_size);
1639 int o = block_size -
I2 -
K1;
1658 C[0].set_n(free_list.get_block(
this, block_size));
1659 C[0].rewrite =
true;
1663 block_to_cursor(
C, level, root);
1665 if (
REVISION(
C[level].get_p()) > revision_number) set_overwritten();
1680 handle = -3 - handle;
1687 if (lazy &&
rev && errno == ENOENT) {
1688 revision_number =
rev;
1691 string message((
rev == 0) ?
"Couldn't create " :
"Couldn't open ");
1699 basic_open(root_info,
rev);
1701 split_p =
new uint8_t[block_size];
1711 bool readonly_,
bool lazy_)
1712 : tablename(tablename_),
1716 faked_root_block(
true),
1729 Btree_modified(
false),
1730 full_compaction(
false),
1731 writable(!readonly_),
1732 cursor_created_since_last_modification(
false),
1737 comp_stream(Z_DEFAULT_STRATEGY),
1742 LOGCALL_CTOR(DB,
"GlassTable", tablename_ | path_ | readonly_ | lazy_);
1746 bool readonly_,
bool lazy_)
1747 : tablename(tablename_),
1751 faked_root_block(
true),
1764 Btree_modified(
false),
1765 full_compaction(
false),
1766 writable(!readonly_),
1767 cursor_created_since_last_modification(
false),
1772 comp_stream(Z_DEFAULT_STRATEGY),
1777 LOGCALL_CTOR(DB,
"GlassTable", tablename_ | fd | offset_ | readonly_ | lazy_);
1782 LOGCALL(DB,
bool,
"GlassTable::exists", NO_ARGS);
1790 LOGCALL_VOID(DB,
"GlassTable::create_and_open", flags_|root_info);
1798 Assert(block_size_ >= 2048);
1801 Assert((block_size_ & (block_size_ - 1)) == 0);
1844 for (
int j =
level; j >= 0; --j) {
1868 for (
int j =
level; j >= 0; --j) {
1913 for (
int i = 0; i <=
level; ++i) {
1964 if (!fl_serialised.empty()) {
1973 for (
int j = 0; j <=
level; ++j) {
1995 LOGCALL(DB,
bool,
"GlassTable::do_open_to_read", root_info|
rev);
2009 string message(
"Couldn't open ");
2051 if (n == 0)
RETURN(
false);
2053 if (n ==
C[0].get_n()) {
2065 for (j = 1; j <=
level; ++j) {
2066 if (n ==
C[j].get_n())
break;
2068 if (j <=
level)
continue;
2097 const uint8_t * p = C_[0].
get_p();
2109 if (n ==
C[0].get_n()) {
2120 for (j = 1; j <=
level; ++j) {
2121 if (n ==
C[j].get_n())
break;
2123 if (j <=
level)
continue;
2153 LOGCALL(DB,
bool,
"GlassTable::prev_default",
Literal(
"C_") | j);
2154 const uint8_t * p = C_[j].
get_p();
2177 LOGCALL(DB,
bool,
"GlassTable::next_default",
Literal(
"C_") | j);
2178 const uint8_t * p = C_[j].
get_p();
2198 #ifdef BTREE_DEBUG_FULL
2199 printf(
"Block in GlassTable:next_default");
2200 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.
static void throw_corrupt(const char *message)
#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