[ci] Fix the checkpatch job in a forked repo
[xapian.git] / xapian-core / backends / glass / glass_table.h
blob5ebc1c113509eb0158d5bfd90fd49417a5fd63e8
1 /** @file
2 * @brief Btree implementation
3 */
4 /* Copyright 1999,2000,2001 BrightStation PLC
5 * Copyright 2002-2024 Olly Betts
6 * Copyright 2008 Lemur Consulting Ltd
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 * USA
24 #ifndef XAPIAN_INCLUDED_GLASS_TABLE_H
25 #define XAPIAN_INCLUDED_GLASS_TABLE_H
27 #include <xapian/constants.h>
28 #include <xapian/error.h>
30 #include "glass_freelist.h"
31 #include "glass_cursor.h"
32 #include "glass_defs.h"
34 #include "io_utils.h"
35 #include "omassert.h"
36 #include "str.h"
37 #include "stringutils.h"
38 #include "wordaccess.h"
40 #include "common/compression_stream.h"
42 #include <algorithm>
43 #include <string>
44 #include <string_view>
46 namespace Glass {
48 /** Even for items of at maximum size, it must be possible to get this number of
49 * items in a block */
50 const size_t BLOCK_CAPACITY = 4;
52 /** The largest possible value of a key_len.
54 * This gives the upper limit of the size of a key that may be stored in the
55 * B-tree.
57 #define GLASS_BTREE_MAX_KEY_LEN 255
59 // FIXME: This named constant probably isn't used everywhere it should be...
60 const int BYTES_PER_BLOCK_NUMBER = 4;
62 /* The B-tree blocks have a number of internal lengths and offsets held in 1, 2
63 or 4 bytes. To make the coding a little clearer,
64 we use for
65 ------ ---
66 K1 the 1 byte length of key
67 I2 the 2 byte length of an item (key-tag pair)
68 D2 the 2 byte offset to the item from the directory
69 X2 the 2 byte component counter that ends each key
72 const int K1 = 1;
73 const int I2 = 2;
74 const int D2 = 2;
75 const int X2 = 2;
77 /* and when getting or setting them, we use these methods of the various
78 * *Item* classes: */
80 // getD(p, c)
81 // setD(p, c, x)
82 // getI()
83 // setI(x)
84 // getX(p, c)
85 // setX(p, c, x)
87 /* if you've been reading the comments from the top, the next four procedures
88 will not cause any headaches.
90 Recall that a leaf item has this form:
92 i k x
93 | | |
94 I K key X tag
95 ←K→
96 <---SIZE---->
97 <---I--->
99 Except that X is omitted for the first component of a tag (there is a flag
100 bit in the upper bits of I which indicates these).
102 item_of(p, c) returns i, the address of the item at block address p,
103 directory offset c,
105 component_of(p, c) returns the number marked 'x' above,
107 last_component(p, c) returns true if this is a final component.
110 inline uint4 REVISION(const uint8_t * b) { return aligned_read4(b); }
111 inline int GET_LEVEL(const uint8_t * b) { return b[4]; }
112 inline int MAX_FREE(const uint8_t * b) { return unaligned_read2(b + 5); }
113 inline int TOTAL_FREE(const uint8_t * b) { return unaligned_read2(b + 7); }
114 inline int DIR_END(const uint8_t * b) { return unaligned_read2(b + 9); }
115 const int DIR_START = 11;
117 inline void SET_REVISION(uint8_t * b, uint4 rev) { aligned_write4(b, rev); }
118 inline void SET_LEVEL(uint8_t* b, int x) {
119 AssertRel(x,<,256);
120 b[4] = uint8_t(x);
122 inline void SET_MAX_FREE(uint8_t * b, int x) { unaligned_write2(b + 5, x); }
123 inline void SET_TOTAL_FREE(uint8_t * b, int x) { unaligned_write2(b + 7, x); }
124 inline void SET_DIR_END(uint8_t * b, int x) { unaligned_write2(b + 9, x); }
126 // The item size is stored in 2 bytes, but the top bit is used to store a flag for
127 // "is the tag data compressed" and the next two bits are used to flag if this is the
128 // first and/or last item for this tag.
129 const int I_COMPRESSED_BIT = 0x80;
130 const int I_LAST_BIT = 0x40;
131 const int I_FIRST_BIT = 0x20;
133 const int I_MASK = (I_COMPRESSED_BIT|I_LAST_BIT|I_FIRST_BIT);
135 const int ITEM_SIZE_MASK = (0xffff &~ (I_MASK << 8));
136 const size_t MAX_ITEM_SIZE = (ITEM_SIZE_MASK + 3);
138 /** Freelist blocks have their level set to LEVEL_FREELIST. */
139 const int LEVEL_FREELIST = 254;
141 class RootInfo;
143 class Key {
144 const uint8_t *p;
145 public:
146 explicit Key(const uint8_t * p_) : p(p_) { }
147 const uint8_t * get_address() const { return p; }
148 const uint8_t * data() const { return p + K1; }
149 void read(std::string * key) const {
150 key->assign(reinterpret_cast<const char *>(p + K1), length());
152 int length() const {
153 return p[0];
155 char operator[](size_t i) const {
156 AssertRel(i,<,size_t(length()));
157 return p[i + K1];
161 // LeafItem_wr wants to be "LeafItem with non-const p and more methods" - we can't
162 // achieve that nicely with inheritance, so we use a template base class.
163 template<class T> class LeafItem_base {
164 protected:
165 T p;
166 int get_key_len() const { return p[I2]; }
167 static int getD(const uint8_t * q, int c) {
168 AssertRel(c, >=, DIR_START);
169 AssertRel(c, <, 65535);
170 Assert((c & 1) == 1);
171 return unaligned_read2(q + c);
173 int getI() const { return unaligned_read2(p); }
174 static int getX(const uint8_t * q, int c) { return unaligned_read2(q + c); }
175 public:
176 /* LeafItem from block address and offset to item pointer */
177 LeafItem_base(T p_, int c) : p(p_ + getD(p_, c)) { }
178 explicit LeafItem_base(T p_) : p(p_) { }
179 T get_address() const { return p; }
180 /** SIZE in diagram above. */
181 int size() const {
182 return (getI() & ITEM_SIZE_MASK) + 3;
184 bool get_compressed() const { return *p & I_COMPRESSED_BIT; }
185 bool first_component() const { return *p & I_FIRST_BIT; }
186 bool last_component() const { return *p & I_LAST_BIT; }
187 int component_of() const {
188 if (first_component()) return 1;
189 return getX(p, get_key_len() + I2 + K1);
191 Key key() const { return Key(p + I2); }
192 void append_chunk(std::string * tag) const {
193 // Offset to the start of the tag data.
194 int cd = get_key_len() + I2 + K1;
195 if (!first_component()) cd += X2;
196 // Number of bytes to extract from current component.
197 int l = size() - cd;
198 const char * chunk = reinterpret_cast<const char *>(p + cd);
199 tag->append(chunk, l);
201 bool decompress_chunk(CompressionStream& comp_stream, string& tag) const {
202 // Offset to the start of the tag data.
203 int cd = get_key_len() + I2 + K1;
204 if (!first_component()) cd += X2;
205 // Number of bytes to extract from current component.
206 int l = size() - cd;
207 const char * chunk = reinterpret_cast<const char *>(p + cd);
208 return comp_stream.decompress_chunk(chunk, l, tag);
212 class LeafItem : public LeafItem_base<const uint8_t *> {
213 public:
214 /* LeafItem from block address and offset to item pointer */
215 LeafItem(const uint8_t * p_, int c)
216 : LeafItem_base<const uint8_t *>(p_, c) { }
217 explicit LeafItem(const uint8_t * p_)
218 : LeafItem_base<const uint8_t *>(p_) { }
221 class LeafItem_wr : public LeafItem_base<uint8_t *> {
222 void set_key_len(int x) {
223 AssertRel(x, >=, 0);
224 AssertRel(x, <=, GLASS_BTREE_MAX_KEY_LEN);
225 p[I2] = uint8_t(x);
227 void setI(int x) { unaligned_write2(p, x); }
228 static void setX(uint8_t * q, int c, int x) { unaligned_write2(q + c, x); }
229 public:
230 /* LeafItem_wr from block address and offset to item pointer */
231 LeafItem_wr(uint8_t * p_, int c) : LeafItem_base<uint8_t *>(p_, c) { }
232 explicit LeafItem_wr(uint8_t * p_) : LeafItem_base<uint8_t *>(p_) { }
233 void set_component_of(int i) {
234 AssertRel(i,>,1);
235 *p &=~ I_FIRST_BIT;
236 setX(p, get_key_len() + I2 + K1, i);
238 void set_size(int new_size) {
239 AssertRel(new_size,>=,3);
240 int I = new_size - 3;
241 // We should never be able to pass too large a size here, but don't
242 // corrupt the database if this somehow happens.
243 if (rare(I &~ ITEM_SIZE_MASK)) throw Xapian::DatabaseError("item too large!");
244 setI(I);
246 void form_key(std::string_view key_) {
247 auto key_len = key_.length();
248 if (key_len > GLASS_BTREE_MAX_KEY_LEN) {
249 // We check term length when a term is added to a document but
250 // glass doubles zero bytes, so this can still happen for terms
251 // which contain one or more zero bytes.
252 std::string msg("Key too long: length was ");
253 msg += str(key_len);
254 msg += " bytes, maximum length of a key is "
255 STRINGIZE(GLASS_BTREE_MAX_KEY_LEN) " bytes";
256 throw Xapian::InvalidArgumentError(msg);
259 set_key_len(key_len);
260 *p |= I_FIRST_BIT;
261 if (key_len)
262 std::memmove(p + I2 + K1, key_.data(), key_len);
264 // FIXME passing cd here is icky
265 void set_tag(int cd, const char *start, int len, bool compressed, int i, int m) {
266 if (len) std::memmove(p + cd, start, len);
267 set_size(cd + len);
268 if (compressed) *p |= I_COMPRESSED_BIT;
269 if (i == m) *p |= I_LAST_BIT;
270 if (i == 1) {
271 *p |= I_FIRST_BIT;
272 } else {
273 set_component_of(i);
276 void fake_root_item() {
277 set_key_len(0); // null key length
278 set_size(I2 + K1); // length of the item
279 *p |= I_FIRST_BIT|I_LAST_BIT;
281 operator const LeafItem() const { return LeafItem(p); }
282 static void setD(uint8_t * q, int c, int x) {
283 AssertRel(c, >=, DIR_START);
284 AssertRel(c, <, 65535);
285 Assert((c & 1) == 1);
286 unaligned_write2(q + c, x);
290 /* A branch item has this form:
294 tag K key X
295 ←B→ ←K→
296 <--SIZE--->
298 B = BYTES_PER_BLOCK_NUMBER
300 We can't omit X here, as we've nowhere to store the first and last bit
301 flags which we have in leaf items.
304 // BItem_wr wants to be "BItem with non-const p and more methods" - we can't
305 // achieve that nicely with inheritance, so we use a template base class.
306 template<class T> class BItem_base {
307 protected:
308 T p;
309 int get_key_len() const { return p[BYTES_PER_BLOCK_NUMBER]; }
310 static int getD(const uint8_t * q, int c) {
311 AssertRel(c, >=, DIR_START);
312 AssertRel(c, <, 65535);
313 Assert((c & 1) == 1);
314 return unaligned_read2(q + c);
316 static int getX(const uint8_t * q, int c) { return unaligned_read2(q + c); }
317 public:
318 /* BItem from block address and offset to item pointer */
319 BItem_base(T p_, int c) : p(p_ + getD(p_, c)) { }
320 explicit BItem_base(T p_) : p(p_) { }
321 T get_address() const { return p; }
322 /** SIZE in diagram above. */
323 int size() const {
324 return get_key_len() + K1 + X2 + BYTES_PER_BLOCK_NUMBER;
326 Key key() const { return Key(p + BYTES_PER_BLOCK_NUMBER); }
327 /** Get this item's tag as a block number (this block should not be at
328 * level 0).
330 uint4 block_given_by() const {
331 return unaligned_read4(p);
333 int component_of() const {
334 return getX(p, get_key_len() + BYTES_PER_BLOCK_NUMBER + K1);
338 class BItem : public BItem_base<const uint8_t *> {
339 public:
340 /* BItem from block address and offset to item pointer */
341 BItem(const uint8_t * p_, int c) : BItem_base<const uint8_t *>(p_, c) { }
342 explicit BItem(const uint8_t * p_) : BItem_base<const uint8_t *>(p_) { }
345 class BItem_wr : public BItem_base<uint8_t *> {
346 void set_key_len(int x) {
347 AssertRel(x, >=, 0);
348 AssertRel(x, <, GLASS_BTREE_MAX_KEY_LEN);
349 p[BYTES_PER_BLOCK_NUMBER] = uint8_t(x);
351 static void setX(uint8_t * q, int c, int x) { unaligned_write2(q + c, x); }
352 public:
353 /* BItem_wr from block address and offset to item pointer */
354 BItem_wr(uint8_t * p_, int c) : BItem_base<uint8_t *>(p_, c) { }
355 explicit BItem_wr(uint8_t * p_) : BItem_base<uint8_t *>(p_) { }
356 void set_component_of(int i) {
357 setX(p, get_key_len() + BYTES_PER_BLOCK_NUMBER + K1, i);
359 void set_key_and_block(Key newkey, uint4 n) {
360 int len = newkey.length() + K1 + X2;
361 // Copy the key size, main part of the key and the count part.
362 std::memcpy(p + BYTES_PER_BLOCK_NUMBER, newkey.get_address(), len);
363 // Set tag contents to block number
364 set_block_given_by(n);
366 // Takes size as we may be truncating newkey.
367 void set_truncated_key_and_block(Key newkey, int new_comp,
368 int truncate_size, uint4 n) {
369 int i = truncate_size;
370 AssertRel(i,<=,newkey.length());
371 // Key size
372 set_key_len(i);
373 // Copy the main part of the key, possibly truncating.
374 std::memcpy(p + BYTES_PER_BLOCK_NUMBER + K1, newkey.get_address() + K1, i);
375 // Set the component count.
376 setX(p, BYTES_PER_BLOCK_NUMBER + K1 + i, new_comp);
377 // Set tag contents to block number
378 set_block_given_by(n);
381 /** Set this item's tag to point to block n (this block should not be at
382 * level 0).
384 void set_block_given_by(uint4 n) {
385 unaligned_write4(p, n);
387 /** Form an item with a null key and with block number n in the tag.
389 void form_null_key(uint4 n) {
390 set_block_given_by(n);
391 set_key_len(0); /* null key */
392 set_component_of(0);
394 operator const BItem() const { return BItem(p); }
395 static void setD(uint8_t * q, int c, int x) {
396 AssertRel(c, >=, DIR_START);
397 AssertRel(c, <, 65535);
398 Assert((c & 1) == 1);
399 unaligned_write2(q + c, x);
405 using Glass::RootInfo;
407 class GlassChanges;
409 /** Class managing a Btree table in a Glass database.
411 * A table is a store holding a set of key/tag pairs.
413 * A key is used to access a block of data in a glass table.
415 * Keys are of limited length.
417 * Keys may not be empty (each Btree has a special empty key for internal use).
419 * A tag is a piece of data associated with a given key. The contents
420 * of the tag are opaque to the Btree.
422 * Tags may be of arbitrary length (the Btree imposes a very large limit).
423 * Note though that they will be loaded into memory in their entirety, so
424 * should not be permitted to grow without bound in normal usage.
426 * Tags which are null strings _are_ valid, and are different from a
427 * tag simply not being in the table.
429 class GlassTable {
430 friend class GlassCursor; /* Should probably fix this. */
431 friend class GlassFreeList;
433 private:
434 /// Copying not allowed
435 GlassTable(const GlassTable &);
437 /// Assignment not allowed
438 GlassTable & operator=(const GlassTable &);
440 void basic_open(const RootInfo * root_info,
441 glass_revision_number_t rev);
443 /** Perform the opening operation to read. */
444 void do_open_to_read(const RootInfo * root_info,
445 glass_revision_number_t rev);
447 /** Perform the opening operation to write. */
448 void do_open_to_write(const RootInfo * root_info,
449 glass_revision_number_t rev = 0);
451 public:
452 /** Create a new Btree object.
454 * This does not create the table on disk - the create_and_open()
455 * method must be called to create the table on disk.
457 * This also does not open the table - either the create_and_open()
458 * or open() methods must be called before use is made of the table.
460 * @param tablename_ The name of the table (used in changesets).
461 * @param path_ Path at which the table is stored.
462 * @param readonly_ whether to open the table for read only access.
463 * @param lazy If true, don't create the table until it's
464 * needed.
466 GlassTable(const char* tablename_, std::string_view path_,
467 bool readonly_, bool lazy = false);
469 GlassTable(const char * tablename_, int fd, off_t offset_,
470 bool readonly_, bool lazy = false);
472 /** Close the Btree.
474 * Any outstanding changes (ie, changes made without commit() having
475 * subsequently been called) will be lost.
477 ~GlassTable();
479 /** Close the Btree. This closes and frees any of the btree
480 * structures which have been created and opened.
482 * @param permanent If true, the Btree will not reopen on demand.
484 void close(bool permanent = false);
486 bool readahead_key(std::string_view key) const;
488 /** Determine whether the btree exists on disk.
490 bool exists() const;
492 /** Open the btree.
494 * @param flags_ flags for opening
495 * @param root_info root block info
497 * @exception Xapian::DatabaseCorruptError will be thrown if the table
498 * is in a corrupt state.
499 * @exception Xapian::DatabaseOpeningError will be thrown if the table
500 * cannot be opened (but is not corrupt - eg, permission problems,
501 * not present, etc).
503 void open(int flags_, const RootInfo & root_info,
504 glass_revision_number_t rev);
506 /** Return true if this table is open.
508 * NB If the table is lazy and doesn't yet exist, returns false.
510 bool is_open() const { return handle >= 0; }
512 /** Return true if this table is writable. */
513 bool is_writable() const { return writable; }
515 /** Flush any outstanding changes to the DB file of the table.
517 * This must be called before commit, to ensure that the DB file is
518 * ready to be switched to a new version by the commit.
520 void flush_db();
522 /** Commit any outstanding changes to the table.
524 * Commit changes made by calling add() and del() to the Btree.
526 * If an error occurs during the operation, this will be signalled
527 * by an exception. In case of error, changes made will not be
528 * committed to the Btree - they will be discarded.
530 * @param new_revision The new revision number to store. This must
531 * be greater than the current revision number. FIXME: If
532 * we support rewinding to a previous revision, maybe this
533 * needs to be greater than any previously used revision.
535 * @param root_info Information about the root is returned in this.
537 void commit(glass_revision_number_t revision, RootInfo * root_info);
539 bool sync() {
540 return (flags & Xapian::DB_NO_SYNC) ||
541 handle < 0 ||
542 io_sync(handle);
545 /** Cancel any outstanding changes.
547 * This will discard any modifications which haven't been committed
548 * by calling commit().
550 void cancel(const RootInfo & root_info, glass_revision_number_t rev);
552 /** Read an entry from the table, if and only if it is exactly that
553 * being asked for.
555 * If the key is found in the table, then the tag is copied to @a
556 * tag. If the key is not found tag is left unchanged.
558 * The result is true iff the specified key is found in the Btree.
560 * @param key The key to look for in the table.
561 * @param tag A tag object to fill with the value if found.
563 * @return true if key is found in table,
564 * false if key is not found in table.
566 bool get_exact_entry(std::string_view key, std::string& tag) const;
568 /** Check if a key exists in the Btree.
570 * This is just like get_exact_entry() except it doesn't read the tag
571 * value so is more efficient if you only want to check that the key
572 * exists.
574 * @param key The key to look for in the table.
576 * @return true if key is found in table,
577 * false if key is not found in table.
579 bool key_exists(std::string_view key) const;
581 /** Read the tag value for the key pointed to by cursor C_.
583 * @param keep_compressed Don't uncompress the tag - e.g. useful
584 * if it's just being opaquely copied.
586 * @return true if current_tag holds compressed data (always
587 * false if keep_compressed was false).
589 bool read_tag(Glass::Cursor* C_,
590 std::string* tag,
591 bool keep_compressed) const;
593 /** Add a key/tag pair to the table, replacing any existing pair with
594 * the same key.
596 * If an error occurs during the operation, an exception will be
597 * thrown.
599 * If key is empty, then the null item is replaced.
601 * e.g. btree.add("TODAY", "Mon 9 Oct 2000");
603 * @param key The key to store in the table.
604 * @param tag The tag to store in the table.
605 * @param already_compressed true if tag is already compressed,
606 * for example because it is being opaquely copied
607 * (default: false).
609 void add(std::string_view key,
610 std::string_view tag,
611 bool already_compressed = false);
613 /** Delete an entry from the table.
615 * The entry will be removed from the table, if it exists. If
616 * it does not exist, no action will be taken. The item with
617 * an empty key can't be removed, and false is returned.
619 * If an error occurs during the operation, this will be signalled
620 * by an exception.
622 * e.g. bool deleted = btree.del("TODAY")
624 * @param key The key to remove from the table.
626 * @return true if an entry was removed; false if it did not exist.
628 bool del(std::string_view key);
630 int get_flags() const { return flags; }
632 void set_flags(int new_flags) { flags = new_flags; }
634 /** Create a new empty btree structure on disk and open it at the
635 * initial revision.
637 * The table must be writable - it doesn't make sense to create
638 * a table that is read-only!
640 * The block size must be less than 64K, where K = 1024. It is unwise
641 * to use a small block size (less than 1024 perhaps), so we enforce a
642 * minimum block size of 2K.
644 * Example:
646 * // File will be "X." + GLASS_TABLE_EXTENSION (i.e. "X.glass")
647 * Btree btree("X.");
648 * btree.create_and_open(0, root_info);
650 * @param root_info RootInfo object
652 * @exception Xapian::DatabaseCreateError if the table can't be
653 * created.
654 * @exception Xapian::InvalidArgumentError if the requested blocksize
655 * is unsuitable.
657 void create_and_open(int flags_, const RootInfo & root_info);
659 void set_full_compaction(bool parity);
661 /** Get the revision number at which this table
662 * is currently open.
664 * It is possible that there are other, more recent or older
665 * revisions available.
667 * @return the current revision number.
669 glass_revision_number_t get_open_revision_number() const {
670 return revision_number;
673 /** Return a count of the number of entries in the table.
675 * The count does not include the ever-present item with null key.
677 * Use @a empty() if you only want to know if the table is empty or
678 * not.
680 * @return The number of entries in the table.
682 glass_tablesize_t get_entry_count() const {
683 return item_count;
686 /// Return true if there are no entries in the table.
687 bool empty() const {
688 return (item_count == 0);
691 /** Get a cursor for reading from the table.
693 * The cursor is owned by the caller - it is the caller's
694 * responsibility to ensure that it is deleted.
696 GlassCursor * cursor_get() const;
698 /** Determine whether the object contains uncommitted modifications.
700 * @return true if there have been modifications since the last
701 * the last call to commit().
703 bool is_modified() const { return Btree_modified; }
705 /** Set the maximum item size given the block capacity.
707 * At least this many items of maximum size must fit into a block.
708 * The default is BLOCK_CAPACITY (which is currently 4).
710 void set_max_item_size(size_t block_capacity) {
711 if (block_capacity > Glass::BLOCK_CAPACITY)
712 block_capacity = Glass::BLOCK_CAPACITY;
713 using Glass::DIR_START;
714 using Glass::D2;
715 max_item_size =
716 (block_size - DIR_START - block_capacity * D2) / block_capacity;
717 // Make sure we don't exceed the limit imposed by the format.
718 if (max_item_size > Glass::MAX_ITEM_SIZE)
719 max_item_size = Glass::MAX_ITEM_SIZE;
722 /** Set the GlassChanges object to write changed blocks to.
724 * The GlassChanges object is not owned by the table, so the table
725 * must not delete it.
727 void set_changes(GlassChanges * changes) {
728 changes_obj = changes;
731 /// Throw an exception indicating that the database is closed.
732 [[noreturn]]
733 static void throw_database_closed();
735 string get_path() const {
736 return name + GLASS_TABLE_EXTENSION;
739 protected:
740 bool find(Glass::Cursor *) const;
741 int delete_kt();
742 void read_block(uint4 n, uint8_t *p) const;
743 void write_block(uint4 n, const uint8_t *p,
744 bool appending = false) const;
745 [[noreturn]]
746 void throw_overwritten() const;
747 void block_to_cursor(Glass::Cursor *C_, int j, uint4 n) const;
748 void alter();
749 void compact(uint8_t *p);
750 void enter_key_above_leaf(Glass::LeafItem previtem,
751 Glass::LeafItem newitem);
752 void enter_key_above_branch(int j, Glass::BItem newitem);
753 int mid_point(uint8_t *p) const;
754 void add_item_to_leaf(uint8_t *p, Glass::LeafItem kt, int c);
755 void add_item_to_branch(uint8_t *p, Glass::BItem kt, int c);
756 void add_leaf_item(Glass::LeafItem kt);
757 void add_branch_item(Glass::BItem kt, int j);
758 void delete_leaf_item(bool repeatedly);
759 void delete_branch_item(int j);
760 int add_kt(bool found);
761 void read_root();
762 void split_root(uint4 split_n);
763 void form_key(std::string_view key) const;
765 /// The name of the table (used when writing changesets).
766 const char * tablename;
768 /** revision number of the opened B-tree. */
769 glass_revision_number_t revision_number;
771 /** keeps a count of the number of items in the B-tree. */
772 glass_tablesize_t item_count;
774 /** block size of the B tree in bytes */
775 unsigned int block_size;
777 /** Flags like DB_NO_SYNC and DB_DANGEROUS. */
778 int flags;
780 /** true if the root block is faked (not written to disk).
781 * false otherwise. This is true when the btree hasn't been
782 * modified yet.
784 bool faked_root_block;
786 /** true iff the data has been written in a single write in
787 * sequential order.
789 bool sequential;
791 /** File descriptor of the table.
793 * If close() has been called, this will be -2.
795 * If the table is lazily created and doesn't yet exist, this will be
796 * -1 (for a multi-file database) or -3-fd (for a single-file database).
798 int handle;
800 /// number of levels, counting from 0
801 int level;
803 /// the root block of the B-tree
804 uint4 root;
806 /// buffer of size block_size for making up key-tag items
807 mutable Glass::LeafItem_wr kt;
809 /// buffer of size block_size for reforming blocks
810 uint8_t * buffer;
812 /// List of free blocks.
813 GlassFreeList free_list;
815 /** The path name of the B tree.
817 * For a single-file database, this will be empty.
819 std::string name;
821 /** count of the number of successive instances of purely
822 * sequential addition, starting at SEQ_START_POINT (neg) and
823 * going up to zero. */
824 int seq_count;
826 /** the last block to be changed by an addition */
827 uint4 changed_n;
829 /** directory offset corresponding to last block to be changed
830 * by an addition */
831 int changed_c;
833 /// maximum size of an item (key-tag pair)
834 size_t max_item_size;
836 /// Set to true the first time the B-tree is modified.
837 mutable bool Btree_modified;
839 /// set to true when full compaction is to be achieved
840 bool full_compaction;
842 /// Set to true when the database is opened to write.
843 bool writable;
845 /// Flag for tracking when cursors need to rebuild.
846 mutable bool cursor_created_since_last_modification;
848 /// Version count for tracking when cursors need to rebuild.
849 unsigned long cursor_version;
851 /** The GlassChanges object to write block changes to.
853 * If NULL, no changes will be written.
855 GlassChanges * changes_obj;
857 bool single_file() const {
858 return name.empty();
861 /* B-tree navigation functions */
862 bool prev(Glass::Cursor *C_, int j) const {
863 if (sequential && !single_file())
864 return prev_for_sequential(C_, j);
865 return prev_default(C_, j);
868 bool next(Glass::Cursor *C_, int j) const {
869 if (sequential) return next_for_sequential(C_, j);
870 return next_default(C_, j);
873 /* Default implementations. */
874 bool prev_default(Glass::Cursor *C_, int j) const;
875 bool next_default(Glass::Cursor *C_, int j) const;
877 /* Implementations for sequential mode. */
878 bool prev_for_sequential(Glass::Cursor *C_, int dummy) const;
879 bool next_for_sequential(Glass::Cursor *C_, int dummy) const;
881 static int find_in_leaf(const uint8_t * p,
882 Glass::LeafItem item, int c, bool& exact);
883 static int find_in_branch(const uint8_t * p,
884 Glass::LeafItem item, int c);
885 static int find_in_branch(const uint8_t * p, Glass::BItem item, int c);
887 /** block_given_by(p, c) finds the item at block address p, directory
888 * offset c, and returns its tag value as an integer.
890 static uint4 block_given_by(const uint8_t * p, int c);
892 mutable Glass::Cursor C[GLASS_BTREE_CURSOR_LEVELS];
894 /** Buffer used when splitting a block.
896 * This buffer holds the split off part of the block. It's only used
897 * when updating (in GlassTable::add_item().
899 uint8_t * split_p;
901 /** Minimum size tag to try compressing (0 for no compression). */
902 uint4 compress_min;
904 mutable CompressionStream comp_stream;
906 /// If true, don't create the table until it's needed.
907 bool lazy;
909 /// Last block readahead_key() preread.
910 mutable uint4 last_readahead;
912 /// offset to start of table in file.
913 off_t offset;
915 /* Debugging methods */
916 // void report_block_full(int m, int n, const uint8_t * p);
919 namespace Glass {
921 /** Compare two items by their keys.
923 The result is negative if a precedes b, positive is b precedes a, and
924 0 if a and b are equal. The comparison is for byte sequence collating
925 order, taking lengths into account. So if the keys are made up of lower case
926 ASCII letters we get alphabetical ordering.
928 Now remember that items are added into the B-tree in fastest time
929 when they are preordered by their keys. This is therefore the piece
930 of code that needs to be followed to arrange for the preordering.
932 Note that keys have two parts - a string value and a "component_of" count.
933 If the string values are equal, the comparison is made based on
934 "component_of".
937 template<typename ITEM1, typename ITEM2>
938 int compare(ITEM1 a, ITEM2 b)
940 Key key1 = a.key();
941 Key key2 = b.key();
942 const uint8_t* p1 = key1.data();
943 const uint8_t* p2 = key2.data();
944 int key1_len = key1.length();
945 int key2_len = key2.length();
946 int k_smaller = (key2_len < key1_len ? key2_len : key1_len);
948 // Compare the common part of the keys.
949 int diff = std::memcmp(p1, p2, k_smaller);
950 if (diff == 0) {
951 // If the common part matches, compare the lengths.
952 diff = key1_len - key2_len;
953 if (diff == 0) {
954 // If the strings match, compare component_of().
955 diff = a.component_of() - b.component_of();
958 return diff;
961 /** Compare two BItem objects by their keys.
963 * Specialisation for comparing two BItems, where component_of is always
964 * explicitly stored.
966 inline int
967 compare(BItem a, BItem b)
969 Key key1 = a.key();
970 Key key2 = b.key();
971 const uint8_t* p1 = key1.data();
972 const uint8_t* p2 = key2.data();
973 int key1_len = key1.length();
974 int key2_len = key2.length();
975 if (key1_len == key2_len) {
976 // The keys are the same length, so we can compare the counts in the
977 // same operation since they're stored as 2 byte bigendian numbers.
978 int len = key1_len + X2;
979 return std::memcmp(p1, p2, len);
982 int k_smaller = (key2_len < key1_len ? key2_len : key1_len);
984 // Compare the common part of the keys.
985 int diff = std::memcmp(p1, p2, k_smaller);
986 if (diff == 0) {
987 // If the common part matches, compare the lengths.
988 diff = key1_len - key2_len;
989 // We dealt with the "same length" case above so we never need to check
990 // component_of here.
992 return diff;
997 #ifdef DISABLE_GPL_LIBXAPIAN
998 # error GPL source we cannot relicense included in libxapian
999 #endif
1001 #endif /* XAPIAN_INCLUDED_GLASS_TABLE_H */