00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef OM_HGUARD_BRASS_TABLE_H
00024 #define OM_HGUARD_BRASS_TABLE_H
00025
00026 #include <xapian/error.h>
00027 #include <xapian/visibility.h>
00028
00029 #include "brass_types.h"
00030 #include "brass_btreebase.h"
00031 #include "brass_cursor.h"
00032
00033 #include "noreturn.h"
00034 #include "omassert.h"
00035 #include "str.h"
00036 #include "stringutils.h"
00037 #include "unaligned.h"
00038
00039 #include <algorithm>
00040 #include <string>
00041
00042 #include <zlib.h>
00043
00044 #define DONT_COMPRESS -1
00045
00048 #define BLOCK_CAPACITY 4
00049
00055 #define BRASS_BTREE_MAX_KEY_LEN 252
00056
00057
00058 #define BYTES_PER_BLOCK_NUMBER 4
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 #define K1 1
00071 #define I2 2
00072 #define D2 2
00073 #define C2 2
00074
00075
00076
00077 #define getK(p, c) getint1(p, c)
00078 #define setD(p, c, x) setint2(p, c, x)
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 #define REVISION(b) static_cast<unsigned int>(getint4(b, 0))
00101 #define GET_LEVEL(b) getint1(b, 4)
00102 #define MAX_FREE(b) getint2(b, 5)
00103 #define TOTAL_FREE(b) getint2(b, 7)
00104 #define DIR_END(b) getint2(b, 9)
00105 #define DIR_START 11
00106
00107 #define SET_REVISION(b, x) setint4(b, 0, x)
00108 #define SET_LEVEL(b, x) setint1(b, 4, x)
00109 #define SET_MAX_FREE(b, x) setint2(b, 5, x)
00110 #define SET_TOTAL_FREE(b, x) setint2(b, 7, x)
00111 #define SET_DIR_END(b, x) setint2(b, 9, x)
00112
00113 namespace Brass {
00114
00115 class XAPIAN_VISIBILITY_DEFAULT Key {
00116 const byte *p;
00117 public:
00118 explicit Key(const byte * p_) : p(p_) { }
00119 const byte * get_address() const { return p; }
00120 void read(std::string * key) const {
00121 key->assign(reinterpret_cast<const char *>(p + K1), length());
00122 }
00123 bool operator==(Key key2) const;
00124 bool operator!=(Key key2) const { return !(*this == key2); }
00125 bool operator<(Key key2) const;
00126 bool operator>=(Key key2) const { return !(*this < key2); }
00127 bool operator>(Key key2) const { return key2 < *this; }
00128 bool operator<=(Key key2) const { return !(key2 < *this); }
00129 int length() const {
00130 AssertRel(getK(p, 0),>=,3);
00131 return getK(p, 0) - C2 - K1;
00132 }
00133 char operator[](size_t i) const {
00134 AssertRel(i,<,(size_t)length());
00135 return p[i + K1];
00136 }
00137 };
00138
00139
00140
00141 template <class T> class Item_base {
00142 protected:
00143 T p;
00144 public:
00145
00146 Item_base(T p_, int c) : p(p_ + getint2(p_, c)) { }
00147 Item_base(T p_) : p(p_) { }
00148 T get_address() const { return p; }
00150 int size() const {
00151 int item_size = getint2(p, 0) & 0x7fff;
00152 AssertRel(item_size,>=,5);
00153 return item_size;
00154 }
00155 bool get_compressed() const { return *p & 0x80; }
00156 int component_of() const {
00157 return getint2(p, getK(p, I2) + I2 - C2);
00158 }
00159 int components_of() const {
00160 return getint2(p, getK(p, I2) + I2);
00161 }
00162 Key key() const { return Key(p + I2); }
00163 void append_chunk(std::string * tag) const {
00164
00165 int cd = getK(p, I2) + I2 + C2;
00166 int l = size() - cd;
00167 tag->append(reinterpret_cast<const char *>(p + cd), l);
00168 }
00172 uint4 block_given_by() const {
00173 AssertRel(size(),>=,BYTES_PER_BLOCK_NUMBER);
00174 return getint4(p, size() - BYTES_PER_BLOCK_NUMBER);
00175 }
00176 };
00177
00178 class Item : public Item_base<const byte *> {
00179 public:
00180
00181 Item(const byte * p_, int c) : Item_base<const byte *>(p_, c) { }
00182 Item(const byte * p_) : Item_base<const byte *>(p_) { }
00183 };
00184
00185 class Item_wr : public Item_base<byte *> {
00186 void set_key_len(int x) { setint1(p, I2, x); }
00187 public:
00188
00189 Item_wr(byte * p_, int c) : Item_base<byte *>(p_, c) { }
00190 Item_wr(byte * p_) : Item_base<byte *>(p_) { }
00191 void set_component_of(int i) {
00192 setint2(p, getK(p, I2) + I2 - C2, i);
00193 }
00194 void set_components_of(int m) {
00195 setint2(p, getK(p, I2) + I2, m);
00196 }
00197
00198 void set_key_and_block(Key newkey, int truncate_size, uint4 n) {
00199 int i = truncate_size;
00200
00201
00202 int newkey_len = newkey.length();
00203 AssertRel(i,<=,newkey_len);
00204 int newsize = I2 + K1 + i + C2;
00205
00206 setint2(p, 0, newsize + BYTES_PER_BLOCK_NUMBER);
00207
00208 setint1(p, I2, newsize - I2);
00209
00210 std::memmove(p + I2 + K1, newkey.get_address() + K1, i);
00211
00212 std::memmove(p + I2 + K1 + i, newkey.get_address() + K1 + newkey_len, C2);
00213
00214
00215 setint4(p, newsize, n);
00216 }
00217
00221 void set_block_given_by(uint4 n) {
00222 setint4(p, size() - BYTES_PER_BLOCK_NUMBER, n);
00223 }
00224 void set_size(int l) {
00225 AssertRel(l,>=,5);
00226 setint2(p, 0, l);
00227 }
00230 void form_null_key(uint4 n) {
00231 setint4(p, I2 + K1, n);
00232 set_key_len(K1);
00233 set_size(I2 + K1 + BYTES_PER_BLOCK_NUMBER);
00234 }
00235 void form_key(const std::string & key_) {
00236 std::string::size_type key_len = key_.length();
00237 if (key_len > BRASS_BTREE_MAX_KEY_LEN) {
00238
00239
00240
00241 std::string msg("Key too long: length was ");
00242 msg += str(key_len);
00243 msg += " bytes, maximum length of a key is "
00244 STRINGIZE(BRASS_BTREE_MAX_KEY_LEN) " bytes";
00245 throw Xapian::InvalidArgumentError(msg);
00246 }
00247
00248 set_key_len(key_len + K1 + C2);
00249 std::memmove(p + I2 + K1, key_.data(), key_len);
00250 set_component_of(1);
00251 }
00252
00253 void set_tag(int cd, const char *start, int len, bool compressed) {
00254 std::memmove(p + cd, start, len);
00255 set_size(cd + len);
00256 if (compressed) *p |= 0x80;
00257 }
00258 void fake_root_item() {
00259 set_key_len(K1 + C2);
00260 set_size(I2 + K1 + 2 * C2);
00261 set_component_of(1);
00262 set_components_of(1);
00263 }
00264 };
00265
00266 }
00267
00268
00269
00270
00271 #define BTREE_CURSOR_LEVELS 10
00272
00293 class XAPIAN_VISIBILITY_DEFAULT BrassTable {
00294 friend class BrassCursor;
00295 private:
00297 BrassTable(const BrassTable &);
00298
00300 BrassTable & operator=(const BrassTable &);
00301
00303 bool really_empty() const;
00304
00305 public:
00322 BrassTable(const char * tablename_, const std::string & path_,
00323 bool readonly_, int compress_strategy_ = DONT_COMPRESS,
00324 bool lazy = false);
00325
00331 ~BrassTable();
00332
00338 void close(bool permanent=false);
00339
00342 bool exists() const;
00343
00352 void open();
00353
00371 bool open(brass_revision_number_t revision_);
00372
00377 bool is_open() const { return handle >= 0; }
00378
00384 void flush_db();
00385
00402 void commit(brass_revision_number_t revision, int changes_fd = -1,
00403 const std::string * changes_tail = NULL);
00404
00409 void write_changed_blocks(int changes_fd);
00410
00416 void cancel();
00417
00432 bool get_exact_entry(const std::string & key, std::string & tag) const;
00433
00445 bool key_exists(const std::string &key) const;
00446
00455 bool read_tag(Brass::Cursor * C_, std::string *tag, bool keep_compressed) const;
00456
00473 void add(const std::string &key, std::string tag, bool already_compressed = false);
00474
00490 bool del(const std::string &key);
00491
00493 void erase();
00494
00499 void set_block_size(unsigned int block_size_);
00500
00503 unsigned int get_block_size() const { return block_size; }
00504
00528 void create_and_open(unsigned int blocksize);
00529
00530 void set_full_compaction(bool parity);
00531
00542 brass_revision_number_t get_latest_revision_number() const {
00543 return latest_revision_number;
00544 }
00545
00554 brass_revision_number_t get_open_revision_number() const {
00555 return revision_number;
00556 }
00557
00567 brass_tablesize_t get_entry_count() const {
00568 return item_count;
00569 }
00570
00572 bool empty() const {
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582 return (level == 0) && really_empty();
00583 }
00584
00590 BrassCursor * cursor_get() const;
00591
00597 bool is_modified() const { return Btree_modified; }
00598
00604 void set_max_item_size(size_t block_capacity) {
00605 if (block_capacity > BLOCK_CAPACITY) block_capacity = BLOCK_CAPACITY;
00606 max_item_size = (block_size - DIR_START - block_capacity * D2)
00607 / block_capacity;
00608 }
00609
00610 protected:
00611
00616 bool do_open_to_read(bool revision_supplied, brass_revision_number_t revision_);
00617
00622 bool do_open_to_write(bool revision_supplied,
00623 brass_revision_number_t revision_,
00624 bool create_db = false);
00625 bool basic_open(bool revision_supplied, brass_revision_number_t revision);
00626
00627 bool find(Brass::Cursor *) const;
00628 int delete_kt();
00629 void read_block(uint4 n, byte *p) const;
00630 void write_block(uint4 n, const byte *p) const;
00631 XAPIAN_NORETURN(void set_overwritten() const);
00632 void block_to_cursor(Brass::Cursor *C_, int j, uint4 n) const;
00633 void alter();
00634 void compact(byte *p);
00635 void enter_key(int j, Brass::Key prevkey, Brass::Key newkey);
00636 int mid_point(byte *p);
00637 void add_item_to_block(byte *p, Brass::Item_wr kt, int c);
00638 void add_item(Brass::Item_wr kt, int j);
00639 void delete_item(int j, bool repeatedly);
00640 int add_kt(bool found);
00641 void read_root();
00642 void split_root(uint4 split_n);
00643 void form_key(const std::string & key) const;
00644
00645 char other_base_letter() const {
00646 return (base_letter == 'A') ? 'B' : 'A';
00647 }
00648
00650 const char * tablename;
00651
00653 void lazy_alloc_deflate_zstream() const;
00654
00656 void lazy_alloc_inflate_zstream() const;
00657
00659 brass_revision_number_t revision_number;
00660
00662 brass_tablesize_t item_count;
00663
00665 unsigned int block_size;
00666
00670 mutable brass_revision_number_t latest_revision_number;
00671
00676 mutable bool both_bases;
00677
00679 char base_letter;
00680
00685 bool faked_root_block;
00686
00690 bool sequential;
00691
00699 int handle;
00700
00702 int level;
00703
00705 uint4 root;
00706
00708 mutable Brass::Item_wr kt;
00709
00711 byte * buffer;
00712
00714 BrassTable_base base;
00715
00717 std::string name;
00718
00722 int seq_count;
00723
00725 uint4 changed_n;
00726
00729 int changed_c;
00730
00732 size_t max_item_size;
00733
00735 mutable bool Btree_modified;
00736
00738 bool full_compaction;
00739
00741 bool writable;
00742
00744 mutable bool cursor_created_since_last_modification;
00745
00747 unsigned long cursor_version;
00748
00749
00750 bool prev(Brass::Cursor *C_, int j) const {
00751 if (sequential) return prev_for_sequential(C_, j);
00752 return prev_default(C_, j);
00753 }
00754
00755 bool next(Brass::Cursor *C_, int j) const {
00756 if (sequential) return next_for_sequential(C_, j);
00757 return next_default(C_, j);
00758 }
00759
00760
00761 bool prev_default(Brass::Cursor *C_, int j) const;
00762 bool next_default(Brass::Cursor *C_, int j) const;
00763
00764
00765 bool prev_for_sequential(Brass::Cursor *C_, int dummy) const;
00766 bool next_for_sequential(Brass::Cursor *C_, int dummy) const;
00767
00768 static int find_in_block(const byte * p, Brass::Key key, bool leaf, int c);
00769
00773 static uint4 block_given_by(const byte * p, int c);
00774
00775 mutable Brass::Cursor C[BTREE_CURSOR_LEVELS];
00776
00782 byte * split_p;
00783
00786 int compress_strategy;
00787
00789 mutable z_stream *deflate_zstream;
00790
00792 mutable z_stream *inflate_zstream;
00793
00795 bool lazy;
00796
00797
00798
00799
00801 XAPIAN_NORETURN(static void throw_database_closed());
00802 };
00803
00804 #endif