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_FLINT_TABLE_H
00024 #define OM_HGUARD_FLINT_TABLE_H
00025
00026 #include <xapian/error.h>
00027 #include <xapian/visibility.h>
00028
00029 #include "flint_types.h"
00030 #include "flint_btreebase.h"
00031 #include "flint_cursor.h"
00032
00033 #include "noreturn.h"
00034 #include "str.h"
00035 #include "stringutils.h"
00036 #include "unaligned.h"
00037
00038 #include <algorithm>
00039 #include <string>
00040
00041 #include <zlib.h>
00042
00043 #define DONT_COMPRESS -1
00044
00050 #define FLINT_BTREE_MAX_KEY_LEN 252
00051
00054 #define BLOCK_CAPACITY 4
00055
00056
00057 #define BYTES_PER_BLOCK_NUMBER 4
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 #define K1 1
00070 #define I2 2
00071 #define D2 2
00072 #define C2 2
00073
00074
00075
00076 #define getK(p, c) getint1(p, c)
00077 #define setD(p, c, x) setint2(p, c, x)
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099 class XAPIAN_VISIBILITY_DEFAULT Key_ {
00100 const byte *p;
00101 public:
00102 explicit Key_(const byte * p_) : p(p_) { }
00103 const byte * get_address() const { return p; }
00104 void read(std::string * key) const {
00105 key->assign(reinterpret_cast<const char *>(p + K1), length());
00106 }
00107 bool operator==(Key_ key2) const;
00108 bool operator!=(Key_ key2) const { return !(*this == key2); }
00109 bool operator<(Key_ key2) const;
00110 bool operator>=(Key_ key2) const { return !(*this < key2); }
00111 bool operator>(Key_ key2) const { return key2 < *this; }
00112 bool operator<=(Key_ key2) const { return !(key2 < *this); }
00113 int length() const {
00114 return getK(p, 0) - C2 - K1;
00115 }
00116 char operator[](size_t i) const {
00117 return p[i + K1];
00118 }
00119 };
00120
00121
00122
00123 template <class T> class Item_base_ {
00124 protected:
00125 T p;
00126 public:
00127
00128 Item_base_(T p_, int c) : p(p_ + getint2(p_, c)) { }
00129 Item_base_(T p_) : p(p_) { }
00130 T get_address() const { return p; }
00131 int size() const { return getint2(p, 0) & 0x7fff; }
00132 bool get_compressed() const { return *p & 0x80; }
00133 int component_of() const {
00134 return getint2(p, getK(p, I2) + I2 - C2);
00135 }
00136 int components_of() const {
00137 return getint2(p, getK(p, I2) + I2);
00138 }
00139 Key_ key() const { return Key_(p + I2); }
00140 void append_chunk(std::string * tag) const {
00141
00142 int cd = getK(p, I2) + I2 + C2;
00143 int l = size() - cd;
00144 tag->append(reinterpret_cast<const char *>(p + cd), l);
00145 }
00149 uint4 block_given_by() const {
00150 return getint4(p, size() - BYTES_PER_BLOCK_NUMBER);
00151 }
00152 };
00153
00154 class Item_ : public Item_base_<const byte *> {
00155 public:
00156
00157 Item_(const byte * p_, int c) : Item_base_<const byte *>(p_, c) { }
00158 Item_(const byte * p_) : Item_base_<const byte *>(p_) { }
00159 };
00160
00161 class Item_wr_ : public Item_base_<byte *> {
00162 void set_key_len(int x) { setint1(p, I2, x); }
00163 public:
00164
00165 Item_wr_(byte * p_, int c) : Item_base_<byte *>(p_, c) { }
00166 Item_wr_(byte * p_) : Item_base_<byte *>(p_) { }
00167 void set_component_of(int i) {
00168 setint2(p, getK(p, I2) + I2 - C2, i);
00169 }
00170 void set_components_of(int m) {
00171 setint2(p, getK(p, I2) + I2, m);
00172 }
00173
00174 void set_key_and_block(Key_ newkey, int truncate_size, uint4 n) {
00175 int i = truncate_size;
00176
00177
00178 int newkey_len = newkey.length();
00179 int newsize = I2 + K1 + i + C2;
00180
00181 setint2(p, 0, newsize + 4);
00182
00183 setint1(p, I2, newsize - I2);
00184
00185 std::memmove(p + I2 + K1, newkey.get_address() + K1, i);
00186
00187 std::memmove(p + I2 + K1 + i, newkey.get_address() + K1 + newkey_len, C2);
00188
00189
00190 setint4(p, newsize, n);
00191 }
00192
00196 void set_block_given_by(uint4 n) {
00197 setint4(p, size() - BYTES_PER_BLOCK_NUMBER, n);
00198 }
00199 void set_size(int l) { setint2(p, 0, l); }
00202 void form_null_key(uint4 n) {
00203 setint4(p, I2 + K1, n);
00204 set_key_len(K1);
00205 set_size(I2 + K1 + 4);
00206 }
00207 void form_key(const std::string & key_) {
00208 std::string::size_type key_len = key_.length();
00209 if (key_len > FLINT_BTREE_MAX_KEY_LEN) {
00210
00211
00212
00213 std::string msg("Key too long: length was ");
00214 msg += str(key_len);
00215 msg += " bytes, maximum length of a key is "
00216 STRINGIZE(FLINT_BTREE_MAX_KEY_LEN) " bytes";
00217 throw Xapian::InvalidArgumentError(msg);
00218 }
00219
00220 set_key_len(key_len + K1 + C2);
00221 std::memmove(p + I2 + K1, key_.data(), key_len);
00222 set_component_of(1);
00223 }
00224
00225 void set_tag(int cd, const char *start, int len, bool compressed) {
00226 std::memmove(p + cd, start, len);
00227 set_size(cd + len);
00228 if (compressed) *p |= 0x80;
00229 }
00230 void fake_root_item() {
00231 set_key_len(K1 + C2);
00232 set_size(I2 + K1 + 2 * C2);
00233 set_component_of(1);
00234 set_components_of(1);
00235 }
00236 };
00237
00238
00239
00240
00241 #define BTREE_CURSOR_LEVELS 10
00242
00263 class XAPIAN_VISIBILITY_DEFAULT FlintTable {
00264 friend class FlintCursor;
00265 private:
00267 FlintTable(const FlintTable &);
00268
00270 FlintTable & operator=(const FlintTable &);
00271
00273 bool really_empty() const;
00274
00275 public:
00292 FlintTable(const char * tablename_, const std::string & path_,
00293 bool readonly_, int compress_strategy_ = DONT_COMPRESS,
00294 bool lazy = false);
00295
00301 ~FlintTable();
00302
00308 void close(bool permanent=false);
00309
00312 bool exists() const;
00313
00322 void open();
00323
00341 bool open(flint_revision_number_t revision_);
00342
00348 void flush_db();
00349
00366 void commit(flint_revision_number_t revision, int changes_fd = -1,
00367 const std::string * changes_tail = NULL);
00368
00373 void write_changed_blocks(int changes_fd);
00374
00380 void cancel();
00381
00396 bool get_exact_entry(const std::string & key, std::string & tag) const;
00397
00409 bool key_exists(const std::string &key) const;
00410
00419 bool read_tag(Cursor_ * C_, std::string *tag, bool keep_compressed) const;
00420
00437 void add(const std::string &key, std::string tag, bool already_compressed = false);
00438
00454 bool del(const std::string &key);
00455
00457 void erase();
00458
00463 void set_block_size(unsigned int block_size_);
00464
00467 unsigned int get_block_size() const { return block_size; }
00468
00492 void create_and_open(unsigned int blocksize);
00493
00494 void set_full_compaction(bool parity);
00495
00506 flint_revision_number_t get_latest_revision_number() const {
00507 return latest_revision_number;
00508 }
00509
00518 flint_revision_number_t get_open_revision_number() const {
00519 return revision_number;
00520 }
00521
00531 flint_tablesize_t get_entry_count() const {
00532 return item_count;
00533 }
00534
00536 bool empty() const {
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 return (level == 0) && really_empty();
00547 }
00548
00554 FlintCursor * cursor_get() const;
00555
00561 bool is_modified() const { return Btree_modified; }
00562
00568 void set_max_item_size(size_t block_capacity) {
00569 if (block_capacity > BLOCK_CAPACITY) block_capacity = BLOCK_CAPACITY;
00570 max_item_size = (block_size - 11 - block_capacity * D2)
00571 / block_capacity;
00572 }
00573
00574 protected:
00575
00580 bool do_open_to_read(bool revision_supplied, flint_revision_number_t revision_);
00581
00586 bool do_open_to_write(bool revision_supplied,
00587 flint_revision_number_t revision_,
00588 bool create_db = false);
00589 bool basic_open(bool revision_supplied, flint_revision_number_t revision);
00590
00591 bool find(Cursor_ *) const;
00592 int delete_kt();
00593 void read_block(uint4 n, byte *p) const;
00594 void write_block(uint4 n, const byte *p) const;
00595 XAPIAN_NORETURN(void set_overwritten() const);
00596 void block_to_cursor(Cursor_ *C_, int j, uint4 n) const;
00597 void alter();
00598 void compact(byte *p);
00599 void enter_key(int j, Key_ prevkey, Key_ newkey);
00600 int mid_point(byte *p);
00601 void add_item_to_block(byte *p, Item_wr_ kt, int c);
00602 void add_item(Item_wr_ kt, int j);
00603 void delete_item(int j, bool repeatedly);
00604 int add_kt(bool found);
00605 void read_root();
00606 void split_root(uint4 split_n);
00607 void form_key(const std::string & key) const;
00608
00610 const char * tablename;
00611
00612 char other_base_letter() const {
00613 return (base_letter == 'A') ? 'B' : 'A';
00614 }
00615
00617 void lazy_alloc_deflate_zstream() const;
00618
00620 void lazy_alloc_inflate_zstream() const;
00621
00623 flint_revision_number_t revision_number;
00624
00626 uint4 item_count;
00627
00629 unsigned int block_size;
00630
00634 mutable flint_revision_number_t latest_revision_number;
00635
00640 mutable bool both_bases;
00641
00643 char base_letter;
00644
00649 bool faked_root_block;
00650
00654 bool sequential;
00655
00657 int handle;
00658
00660 int level;
00661
00663 uint4 root;
00664
00666 mutable Item_wr_ kt;
00667
00669 byte * buffer;
00670
00672 FlintTable_base base;
00673
00675 std::string name;
00676
00680 int seq_count;
00681
00683 uint4 changed_n;
00684
00687 int changed_c;
00688
00690 size_t max_item_size;
00691
00693 mutable bool Btree_modified;
00694
00696 bool full_compaction;
00697
00699 bool writable;
00700
00702 mutable bool cursor_created_since_last_modification;
00703
00705 unsigned long cursor_version;
00706
00707
00708 bool prev(Cursor_ *C_, int j) const {
00709 if (sequential) return prev_for_sequential(C_, j);
00710 return prev_default(C_, j);
00711 }
00712
00713 bool next(Cursor_ *C_, int j) const {
00714 if (sequential) return next_for_sequential(C_, j);
00715 return next_default(C_, j);
00716 }
00717
00718
00719 bool prev_default(Cursor_ *C_, int j) const;
00720 bool next_default(Cursor_ *C_, int j) const;
00721
00722
00723 bool prev_for_sequential(Cursor_ *C_, int dummy) const;
00724 bool next_for_sequential(Cursor_ *C_, int dummy) const;
00725
00726 static int find_in_block(const byte * p, Key_ key, bool leaf, int c);
00727
00731 static uint4 block_given_by(const byte * p, int c);
00732
00733 mutable Cursor_ C[BTREE_CURSOR_LEVELS];
00734
00740 byte * split_p;
00741
00744 int compress_strategy;
00745
00747 mutable z_stream *deflate_zstream;
00748
00750 mutable z_stream *inflate_zstream;
00751
00753 bool lazy;
00754
00755
00756
00757
00759 XAPIAN_NORETURN(static void throw_database_closed());
00760 };
00761
00762 #endif