00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025
00026 #include "brass_table.h"
00027
00028 #include <xapian/error.h>
00029
00030 #include "safeerrno.h"
00031 #ifdef __WIN32__
00032 # include "msvc_posix_wrapper.h"
00033 #endif
00034
00035 #include "omassert.h"
00036 #include "str.h"
00037 #include "stringutils.h"
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 #include <sys/types.h>
00053
00054
00055
00056
00057
00058
00059 #if defined HAVE_PREAD && defined PREAD_PROTOTYPE
00060 PREAD_PROTOTYPE
00061 #endif
00062 #if defined HAVE_PWRITE && defined PWRITE_PROTOTYPE
00063 PWRITE_PROTOTYPE
00064 #endif
00065
00066 #include <cstdio>
00067 #include <cstring>
00068 #include <climits>
00069
00070 #include "brass_btreebase.h"
00071 #include "brass_cursor.h"
00072
00073 #include "debuglog.h"
00074 #include "io_utils.h"
00075 #include "omassert.h"
00076 #include "pack.h"
00077 #include "unaligned.h"
00078 #include "utils.h"
00079
00080 #include <algorithm>
00081 #include <string>
00082
00083 using namespace Brass;
00084 using namespace std;
00085
00086
00087 const size_t COMPRESS_MIN = 4;
00088
00089
00090 #undef BTREE_DEBUG_FULL
00091
00092 #ifdef BTREE_DEBUG_FULL
00093
00094
00095 static void print_key(const byte * p, int c, int j);
00096 static void print_tag(const byte * p, int c, int j);
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110 #endif
00111
00112 static inline byte *zeroed_new(size_t size)
00113 {
00114 byte *temp = new byte[size];
00115
00116
00117 Assert(temp);
00118 memset(temp, 0, size);
00119 return temp;
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00170 #define SEQ_START_POINT (-10)
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 #define BYTE_PAIR_RANGE (1 << 2 * CHAR_BIT)
00185
00187 void
00188 BrassTable::read_block(uint4 n, byte * p) const
00189 {
00190
00191 LOGCALL_VOID(DB, "BrassTable::read_block", n | (void*)p);
00192
00193
00194
00195 Assert(n / CHAR_BIT < base.get_bit_map_size());
00196
00197 #ifdef HAVE_PREAD
00198 off_t offset = off_t(block_size) * n;
00199 int m = block_size;
00200 while (true) {
00201 ssize_t bytes_read = pread(handle, reinterpret_cast<char *>(p), m,
00202 offset);
00203
00204 if (bytes_read == m) return;
00205 if (bytes_read == -1) {
00206 if (errno == EINTR) continue;
00207 string message = "Error reading block " + str(n) + ": ";
00208 message += strerror(errno);
00209 throw Xapian::DatabaseError(message);
00210 } else if (bytes_read == 0) {
00211 string message = "Error reading block " + str(n) + ": got end of file";
00212 throw Xapian::DatabaseError(message);
00213 } else if (bytes_read < m) {
00214
00215
00216
00217 m -= int(bytes_read);
00218 p += bytes_read;
00219 offset += bytes_read;
00220 }
00221 }
00222 #else
00223 if (lseek(handle, off_t(block_size) * n, SEEK_SET) == -1) {
00224 string message = "Error seeking to block: ";
00225 message += strerror(errno);
00226 throw Xapian::DatabaseError(message);
00227 }
00228
00229 io_read(handle, reinterpret_cast<char *>(p), block_size, block_size);
00230 #endif
00231 }
00232
00239 void
00240 BrassTable::write_block(uint4 n, const byte * p) const
00241 {
00242 LOGCALL_VOID(DB, "BrassTable::write_block", n | p);
00243 Assert(writable);
00244
00245 Assert(n / CHAR_BIT < base.get_bit_map_size());
00246
00247 ;
00248 AssertParanoid(base.block_free_at_start(n));
00249
00250
00251 AssertEqParanoid(REVISION(p), latest_revision_number + 1);
00252
00253 if (both_bases) {
00254
00255
00256
00257
00258
00259
00260
00261 (void)io_unlink(name + "base" + other_base_letter());
00262 both_bases = false;
00263 latest_revision_number = revision_number;
00264 }
00265
00266 #ifdef HAVE_PWRITE
00267 off_t offset = off_t(block_size) * n;
00268 int m = block_size;
00269 while (true) {
00270 ssize_t bytes_written = pwrite(handle, p, m, offset);
00271 if (bytes_written == m) {
00272
00273 return;
00274 } else if (bytes_written == -1) {
00275 if (errno == EINTR) continue;
00276 string message = "Error writing block: ";
00277 message += strerror(errno);
00278 throw Xapian::DatabaseError(message);
00279 } else if (bytes_written == 0) {
00280 string message = "Error writing block: wrote no data";
00281 throw Xapian::DatabaseError(message);
00282 } else if (bytes_written < m) {
00283
00284
00285
00286 m -= bytes_written;
00287 p += bytes_written;
00288 offset += bytes_written;
00289 }
00290 }
00291 #else
00292 if (lseek(handle, (off_t)block_size * n, SEEK_SET) == -1) {
00293 string message = "Error seeking to block: ";
00294 message += strerror(errno);
00295 throw Xapian::DatabaseError(message);
00296 }
00297
00298 io_write(handle, reinterpret_cast<const char *>(p), block_size);
00299 #endif
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 void
00325 BrassTable::set_overwritten() const
00326 {
00327 LOGCALL_VOID(DB, "BrassTable::set_overwritten", NO_ARGS);
00328
00329
00330 if (writable)
00331 throw Xapian::DatabaseCorruptError("Db block overwritten - are there multiple writers?");
00332 throw Xapian::DatabaseModifiedError("The revision being read has been discarded - you should call Xapian::Database::reopen() and retry the operation");
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 void
00346 BrassTable::block_to_cursor(Brass::Cursor * C_, int j, uint4 n) const
00347 {
00348 LOGCALL_VOID(DB, "BrassTable::block_to_cursor", (void*)C_ | j | n);
00349 if (n == C_[j].n) return;
00350 byte * p = C_[j].p;
00351 Assert(p);
00352
00353
00354 if (C_[j].rewrite) {
00355 Assert(writable);
00356 Assert(C == C_);
00357 write_block(C_[j].n, p);
00358 C_[j].rewrite = false;
00359 }
00360
00361
00362
00363 if (writable && n == C[j].n) {
00364 if (p != C[j].p)
00365 memcpy(p, C[j].p, block_size);
00366 } else {
00367 read_block(n, p);
00368 }
00369
00370 C_[j].n = n;
00371 if (j < level) {
00372
00373 if (rare(REVISION(p) > REVISION(C_[j + 1].p))) {
00374 set_overwritten();
00375 return;
00376 }
00377 }
00378
00379 if (rare(j != GET_LEVEL(p))) {
00380 string msg = "Expected block ";
00381 msg += str(j);
00382 msg += ", not ";
00383 msg += str(GET_LEVEL(p));
00384 throw Xapian::DatabaseCorruptError(msg);
00385 }
00386 }
00387
00409 void
00410 BrassTable::alter()
00411 {
00412 LOGCALL_VOID(DB, "BrassTable::alter", NO_ARGS);
00413 Assert(writable);
00414 #ifdef DANGEROUS
00415 C[0].rewrite = true;
00416 #else
00417 int j = 0;
00418 byte * p = C[j].p;
00419 while (true) {
00420 if (C[j].rewrite) return;
00421 C[j].rewrite = true;
00422
00423 uint4 n = C[j].n;
00424 if (base.block_free_at_start(n)) {
00425 Assert(REVISION(p) == latest_revision_number + 1);
00426 return;
00427 }
00428 Assert(REVISION(p) < latest_revision_number + 1);
00429 base.free_block(n);
00430 n = base.next_free_block();
00431 C[j].n = n;
00432 SET_REVISION(p, latest_revision_number + 1);
00433
00434 if (j == level) return;
00435 j++;
00436 p = C[j].p;
00437 Item_wr(p, C[j].c).set_block_given_by(n);
00438 }
00439 #endif
00440 }
00441
00454 int
00455 BrassTable::find_in_block(const byte * p, Key key, bool leaf, int c)
00456 {
00457 LOGCALL_STATIC(DB, int, "BrassTable::find_in_block", (void*)p | (const void *)key.get_address() | leaf | c);
00458 int i = DIR_START;
00459 if (leaf) i -= D2;
00460 int j = DIR_END(p);
00461
00462 if (c != -1) {
00463 if (c < j && i < c && Item(p, c).key() <= key)
00464 i = c;
00465 c += D2;
00466 if (c < j && i < c && key < Item(p, c).key())
00467 j = c;
00468 }
00469
00470 while (j - i > D2) {
00471 int k = i + ((j - i)/(D2 * 2))*D2;
00472 if (key < Item(p, k).key()) j = k; else i = k;
00473 }
00474 RETURN(i);
00475 }
00476
00484 bool
00485 BrassTable::find(Brass::Cursor * C_) const
00486 {
00487 LOGCALL(DB, bool, "BrassTable::find", (void*)C_);
00488
00489 const byte * p;
00490 int c;
00491 Key key = kt.key();
00492 for (int j = level; j > 0; --j) {
00493 p = C_[j].p;
00494 c = find_in_block(p, key, false, C_[j].c);
00495 #ifdef BTREE_DEBUG_FULL
00496 printf("Block in BrassTable:find - code position 1");
00497 report_block_full(j, C_[j].n, p);
00498 #endif
00499 C_[j].c = c;
00500 block_to_cursor(C_, j - 1, Item(p, c).block_given_by());
00501 }
00502 p = C_[0].p;
00503 c = find_in_block(p, key, true, C_[0].c);
00504 #ifdef BTREE_DEBUG_FULL
00505 printf("Block in BrassTable:find - code position 2");
00506 report_block_full(0, C_[0].n, p);
00507 #endif
00508 C_[0].c = c;
00509 if (c < DIR_START) RETURN(false);
00510 RETURN(Item(p, c).key() == key);
00511 }
00512
00518 void
00519 BrassTable::compact(byte * p)
00520 {
00521 LOGCALL_VOID(DB, "BrassTable::compact", (void*)p);
00522 Assert(writable);
00523 int e = block_size;
00524 byte * b = buffer;
00525 int dir_end = DIR_END(p);
00526 for (int c = DIR_START; c < dir_end; c += D2) {
00527 Item item(p, c);
00528 int l = item.size();
00529 e -= l;
00530 memmove(b + e, item.get_address(), l);
00531 setD(p, c, e);
00532 }
00533 memmove(p + e, b + e, block_size - e);
00534 e -= dir_end;
00535 SET_TOTAL_FREE(p, e);
00536 SET_MAX_FREE(p, e);
00537 }
00538
00542 void
00543 BrassTable::split_root(uint4 split_n)
00544 {
00545 LOGCALL_VOID(DB, "BrassTable::split_root", split_n);
00546
00547 ++level;
00548
00549
00550
00551 if (level == BTREE_CURSOR_LEVELS) {
00552 throw Xapian::DatabaseCorruptError("Btree has grown impossibly large ("STRINGIZE(BTREE_CURSOR_LEVELS)" levels)");
00553 }
00554
00555 byte * q = zeroed_new(block_size);
00556 C[level].p = q;
00557 C[level].c = DIR_START;
00558 C[level].n = base.next_free_block();
00559 C[level].rewrite = true;
00560 SET_REVISION(q, latest_revision_number + 1);
00561 SET_LEVEL(q, level);
00562 SET_DIR_END(q, DIR_START);
00563 compact(q);
00564
00565
00566 byte b[10];
00567 Item_wr item(b);
00568 item.form_null_key(split_n);
00569 add_item(item, level);
00570 }
00571
00587 void
00588 BrassTable::enter_key(int j, Key prevkey, Key newkey)
00589 {
00590 LOGCALL_VOID(DB, "BrassTable::enter_key", j | Literal("prevkey") | Literal("newkey"));
00591 Assert(writable);
00592 Assert(prevkey < newkey);
00593 AssertRel(j,>=,1);
00594
00595 uint4 blocknumber = C[j - 1].n;
00596
00597
00598
00599 const int newkey_len = newkey.length();
00600 AssertRel(newkey_len,>,0);
00601 int i;
00602
00603 if (j == 1) {
00604
00605
00606 i = 0;
00607 const int min_len = min(newkey_len, prevkey.length());
00608 while (i < min_len && prevkey[i] == newkey[i]) {
00609 i++;
00610 }
00611
00612
00613 if (i < newkey_len) i++;
00614 } else {
00615
00616
00617
00618
00619 i = newkey_len;
00620 }
00621
00622 byte b[UCHAR_MAX + 6];
00623 Item_wr item(b);
00624 Assert(i <= 256 - I2 - C2);
00625 Assert(i <= (int)sizeof(b) - I2 - C2 - 4);
00626 item.set_key_and_block(newkey, i, blocknumber);
00627
00628
00629
00630
00631 if (j > 1) {
00632 byte * p = C[j - 1].p;
00633 uint4 n = getint4(newkey.get_address(), newkey_len + K1 + C2);
00634 int new_total_free = TOTAL_FREE(p) + newkey_len + C2;
00635
00636 Item_wr(const_cast<byte*>(newkey.get_address()) - I2).form_null_key(n);
00637 SET_TOTAL_FREE(p, new_total_free);
00638 }
00639
00640 C[j].c = find_in_block(C[j].p, item.key(), false, 0) + D2;
00641 C[j].rewrite = true;
00642 add_item(item, j);
00643 }
00644
00649 int
00650 BrassTable::mid_point(byte * p)
00651 {
00652 LOGCALL(DB, int, "BrassTable::mid_point", (void*)p);
00653 int n = 0;
00654 int dir_end = DIR_END(p);
00655 int size = block_size - TOTAL_FREE(p) - dir_end;
00656 for (int c = DIR_START; c < dir_end; c += D2) {
00657 int l = Item(p, c).size();
00658 n += 2 * l;
00659 if (n >= size) {
00660 if (l < n - size) RETURN(c);
00661 RETURN(c + D2);
00662 }
00663 }
00664
00665
00666 Assert(false);
00667 RETURN(0);
00668 }
00669
00679 void
00680 BrassTable::add_item_to_block(byte * p, Item_wr kt_, int c)
00681 {
00682 LOGCALL_VOID(DB, "BrassTable::add_item_to_block", (void*)p | Literal("kt_") | c);
00683 Assert(writable);
00684 int dir_end = DIR_END(p);
00685 int kt_len = kt_.size();
00686 int needed = kt_len + D2;
00687 int new_total = TOTAL_FREE(p) - needed;
00688 int new_max = MAX_FREE(p) - needed;
00689
00690 Assert(new_total >= 0);
00691
00692 AssertRel(MAX_FREE(p),>=,needed);
00693
00694 Assert(dir_end >= c);
00695
00696 memmove(p + c + D2, p + c, dir_end - c);
00697 dir_end += D2;
00698 SET_DIR_END(p, dir_end);
00699
00700 int o = dir_end + new_max;
00701 setD(p, c, o);
00702 memmove(p + o, kt_.get_address(), kt_len);
00703
00704 SET_MAX_FREE(p, new_max);
00705
00706 SET_TOTAL_FREE(p, new_total);
00707 }
00708
00714 void
00715 BrassTable::add_item(Item_wr kt_, int j)
00716 {
00717 LOGCALL_VOID(DB, "BrassTable::add_item", Literal("kt_") | j);
00718 Assert(writable);
00719 byte * p = C[j].p;
00720 int c = C[j].c;
00721 uint4 n;
00722
00723 int needed = kt_.size() + D2;
00724 if (TOTAL_FREE(p) < needed) {
00725 int m;
00726
00727
00728
00729
00730
00731 if (seq_count < 0) {
00732
00733
00734 m = mid_point(p);
00735 } else {
00736
00737 m = c;
00738 }
00739
00740 uint4 split_n = C[j].n;
00741 C[j].n = base.next_free_block();
00742
00743 memcpy(split_p, p, block_size);
00744 SET_DIR_END(split_p, m);
00745 compact(split_p);
00746
00747 {
00748 int residue = DIR_END(p) - m;
00749 int new_dir_end = DIR_START + residue;
00750 memmove(p + DIR_START, p + m, residue);
00751 SET_DIR_END(p, new_dir_end);
00752 }
00753
00754 compact(p);
00755
00756 bool add_to_upper_half;
00757 if (seq_count < 0) {
00758 add_to_upper_half = (c >= m);
00759 } else {
00760
00761
00762 add_to_upper_half = (TOTAL_FREE(split_p) < needed);
00763 }
00764
00765 if (add_to_upper_half) {
00766 c -= (m - DIR_START);
00767 Assert(seq_count < 0 || c <= DIR_START + D2);
00768 Assert(c >= DIR_START);
00769 Assert(c <= DIR_END(p));
00770 add_item_to_block(p, kt_, c);
00771 n = C[j].n;
00772 } else {
00773 Assert(c >= DIR_START);
00774 Assert(c <= DIR_END(split_p));
00775 add_item_to_block(split_p, kt_, c);
00776 n = split_n;
00777 }
00778 write_block(split_n, split_p);
00779
00780
00781 if (j == level) split_root(split_n);
00782
00783
00784
00785 enter_key(j + 1,
00786 Item(split_p, DIR_END(split_p) - D2).key(),
00787 Item(p, DIR_START).key());
00788 } else {
00789 AssertRel(TOTAL_FREE(p),>=,needed);
00790
00791 if (MAX_FREE(p) < needed) {
00792 compact(p);
00793 AssertRel(MAX_FREE(p),>=,needed);
00794 }
00795
00796 add_item_to_block(p, kt_, c);
00797 n = C[j].n;
00798 }
00799 if (j == 0) {
00800 changed_n = n;
00801 changed_c = c;
00802 }
00803 }
00804
00812 void
00813 BrassTable::delete_item(int j, bool repeatedly)
00814 {
00815 LOGCALL_VOID(DB, "BrassTable::delete_item", j | repeatedly);
00816 Assert(writable);
00817 byte * p = C[j].p;
00818 int c = C[j].c;
00819 int kt_len = Item(p, c).size();
00820 int dir_end = DIR_END(p) - D2;
00821
00822 memmove(p + c, p + c + D2, dir_end - c);
00823 SET_DIR_END(p, dir_end);
00824 SET_MAX_FREE(p, MAX_FREE(p) + D2);
00825 SET_TOTAL_FREE(p, TOTAL_FREE(p) + kt_len + D2);
00826
00827 if (!repeatedly) return;
00828 if (j < level) {
00829 if (dir_end == DIR_START) {
00830 base.free_block(C[j].n);
00831 C[j].rewrite = false;
00832 C[j].n = BLK_UNUSED;
00833 C[j + 1].rewrite = true;
00834 delete_item(j + 1, true);
00835 }
00836 } else {
00837 Assert(j == level);
00838 while (dir_end == DIR_START + D2 && level > 0) {
00839
00840 uint4 new_root = Item(p, DIR_START).block_given_by();
00841 delete [] p;
00842 C[level].p = 0;
00843 base.free_block(C[level].n);
00844 C[level].rewrite = false;
00845 C[level].n = BLK_UNUSED;
00846 level--;
00847
00848 block_to_cursor(C, level, new_root);
00849
00850 p = C[level].p;
00851 dir_end = DIR_END(p);
00852 }
00853 }
00854 }
00855
00856
00857
00858
00859
00885 int
00886 BrassTable::add_kt(bool found)
00887 {
00888 LOGCALL(DB, int, "BrassTable::add_kt", found);
00889 Assert(writable);
00890 int components = 0;
00891
00892
00893
00894
00895
00896
00897
00898 alter();
00899
00900 if (found) {
00901 seq_count = SEQ_START_POINT;
00902 sequential = false;
00903
00904 byte * p = C[0].p;
00905 int c = C[0].c;
00906 Item item(p, c);
00907 int kt_size = kt.size();
00908 int needed = kt_size - item.size();
00909
00910 components = item.components_of();
00911
00912 if (needed <= 0) {
00913
00914 memmove(const_cast<byte *>(item.get_address()),
00915 kt.get_address(), kt_size);
00916 SET_TOTAL_FREE(p, TOTAL_FREE(p) - needed);
00917 } else {
00918
00919 int new_max = MAX_FREE(p) - kt_size;
00920 if (new_max >= 0) {
00921 int o = DIR_END(p) + new_max;
00922 memmove(p + o, kt.get_address(), kt_size);
00923 setD(p, c, o);
00924 SET_MAX_FREE(p, new_max);
00925 SET_TOTAL_FREE(p, TOTAL_FREE(p) - needed);
00926 } else {
00927
00928 delete_item(0, false);
00929 add_item(kt, 0);
00930 }
00931 }
00932 } else {
00933
00934 if (changed_n == C[0].n && changed_c == C[0].c) {
00935 if (seq_count < 0) seq_count++;
00936 } else {
00937 seq_count = SEQ_START_POINT;
00938 sequential = false;
00939 }
00940 C[0].c += D2;
00941 add_item(kt, 0);
00942 }
00943 RETURN(components);
00944 }
00945
00946
00947
00948
00949
00950
00951 int
00952 BrassTable::delete_kt()
00953 {
00954 LOGCALL(DB, int, "BrassTable::delete_kt", NO_ARGS);
00955 Assert(writable);
00956
00957 bool found = find(C);
00958
00959 int components = 0;
00960 seq_count = SEQ_START_POINT;
00961 sequential = false;
00962
00963
00964
00965
00966
00967
00968
00969 if (found) {
00970 components = Item(C[0].p, C[0].c).components_of();
00971 alter();
00972 delete_item(0, true);
00973 }
00974 RETURN(components);
00975 }
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986 void BrassTable::form_key(const string & key) const
00987 {
00988 LOGCALL_VOID(DB, "BrassTable::form_key", key);
00989 kt.form_key(key);
00990 }
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015 void
01016 BrassTable::add(const string &key, string tag, bool already_compressed)
01017 {
01018 LOGCALL_VOID(DB, "BrassTable::add", key | tag | already_compressed);
01019 Assert(writable);
01020
01021 if (handle < 0) create_and_open(block_size);
01022
01023 form_key(key);
01024
01025 bool compressed = false;
01026 if (already_compressed) {
01027 compressed = true;
01028 } else if (compress_strategy != DONT_COMPRESS && tag.size() > COMPRESS_MIN) {
01029 CompileTimeAssert(DONT_COMPRESS != Z_DEFAULT_STRATEGY);
01030 CompileTimeAssert(DONT_COMPRESS != Z_FILTERED);
01031 CompileTimeAssert(DONT_COMPRESS != Z_HUFFMAN_ONLY);
01032 #ifdef Z_RLE
01033 CompileTimeAssert(DONT_COMPRESS != Z_RLE);
01034 #endif
01035
01036 lazy_alloc_deflate_zstream();
01037
01038 deflate_zstream->next_in = (Bytef *)const_cast<char *>(tag.data());
01039 deflate_zstream->avail_in = (uInt)tag.size();
01040
01041
01042 unsigned long blk_len = tag.size() - 1;
01043 unsigned char * blk = new unsigned char[blk_len];
01044 deflate_zstream->next_out = blk;
01045 deflate_zstream->avail_out = (uInt)blk_len;
01046
01047 int err = deflate(deflate_zstream, Z_FINISH);
01048 if (err == Z_STREAM_END) {
01049
01050
01051 tag.assign(reinterpret_cast<const char *>(blk), deflate_zstream->total_out);
01052 compressed = true;
01053 } else {
01054
01055 }
01056
01057 delete [] blk;
01058 }
01059
01060
01061 const size_t cd = kt.key().length() + K1 + I2 + C2 + C2;
01062 const size_t L = max_item_size - cd;
01063 size_t first_L = L;
01064 bool found = find(C);
01065 if (!found) {
01066 byte * p = C[0].p;
01067 size_t n = TOTAL_FREE(p) % (max_item_size + D2);
01068 if (n > D2 + cd) {
01069 n -= (D2 + cd);
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082 size_t last = tag.length() % L;
01083 if (n >= last || (full_compaction && n >= key.size() + 34))
01084 first_L = n;
01085 }
01086 }
01087
01088
01089 int m = tag.empty() ? 1 : (tag.length() - first_L + L - 1) / L + 1;
01090
01091
01092
01093
01094 if (m >= BYTE_PAIR_RANGE)
01095 throw Xapian::UnimplementedError("Can't handle insanely large tags");
01096
01097 int n = 0;
01098
01099 int o = 0;
01100 size_t residue = tag.length();
01101 int replacement = false;
01102 int i;
01103 kt.set_components_of(m);
01104 for (i = 1; i <= m; i++) {
01105 size_t l = (i == m ? residue : (i == 1 ? first_L : L));
01106 Assert(cd + l <= block_size);
01107 Assert(string::size_type(o + l) <= tag.length());
01108 kt.set_tag(cd, tag.data() + o, l, compressed);
01109 kt.set_component_of(i);
01110
01111 o += l;
01112 residue -= l;
01113
01114 if (i > 1) found = find(C);
01115 n = add_kt(found);
01116 if (n > 0) replacement = true;
01117 }
01118
01119 for (i = m + 1; i <= n; i++) {
01120 kt.set_component_of(i);
01121 delete_kt();
01122 }
01123 if (!replacement) ++item_count;
01124 Btree_modified = true;
01125 if (cursor_created_since_last_modification) {
01126 cursor_created_since_last_modification = false;
01127 ++cursor_version;
01128 }
01129 }
01130
01131
01132
01133
01134
01135
01136
01137 bool
01138 BrassTable::del(const string &key)
01139 {
01140 LOGCALL(DB, bool, "BrassTable::del", key);
01141 Assert(writable);
01142
01143 if (handle < 0) {
01144 if (handle == -2) {
01145 BrassTable::throw_database_closed();
01146 }
01147 RETURN(false);
01148 }
01149
01150
01151 if (key.size() > BRASS_BTREE_MAX_KEY_LEN) RETURN(false);
01152
01153 if (key.empty()) RETURN(false);
01154 form_key(key);
01155
01156 int n = delete_kt();
01157 if (n <= 0) RETURN(false);
01158
01159 for (int i = 2; i <= n; i++) {
01160 kt.set_component_of(i);
01161 delete_kt();
01162 }
01163
01164 item_count--;
01165 Btree_modified = true;
01166 if (cursor_created_since_last_modification) {
01167 cursor_created_since_last_modification = false;
01168 ++cursor_version;
01169 }
01170 RETURN(true);
01171 }
01172
01173 bool
01174 BrassTable::get_exact_entry(const string &key, string & tag) const
01175 {
01176 LOGCALL(DB, bool, "BrassTable::get_exact_entry", key | tag);
01177 Assert(!key.empty());
01178
01179 if (handle < 0) {
01180 if (handle == -2) {
01181 BrassTable::throw_database_closed();
01182 }
01183 RETURN(false);
01184 }
01185
01186
01187 if (key.size() > BRASS_BTREE_MAX_KEY_LEN) RETURN(false);
01188
01189 form_key(key);
01190 if (!find(C)) RETURN(false);
01191
01192 (void)read_tag(C, &tag, false);
01193 RETURN(true);
01194 }
01195
01196 bool
01197 BrassTable::key_exists(const string &key) const
01198 {
01199 LOGCALL(DB, bool, "BrassTable::key_exists", key);
01200 Assert(!key.empty());
01201
01202
01203 if (key.size() > BRASS_BTREE_MAX_KEY_LEN) RETURN(false);
01204
01205 form_key(key);
01206 RETURN(find(C));
01207 }
01208
01209 bool
01210 BrassTable::read_tag(Brass::Cursor * C_, string *tag, bool keep_compressed) const
01211 {
01212 LOGCALL(DB, bool, "BrassTable::read_tag", Literal("C_") | tag | keep_compressed);
01213 Item item(C_[0].p, C_[0].c);
01214
01215
01216 int n = item.components_of();
01217
01218 tag->resize(0);
01219
01220
01221 if (n > 1) tag->reserve((max_item_size - (1 + K1 + I2 + C2 + C2)) * n);
01222
01223 item.append_chunk(tag);
01224 bool compressed = item.get_compressed();
01225
01226 for (int i = 2; i <= n; i++) {
01227 if (!next(C_, 0)) {
01228 throw Xapian::DatabaseCorruptError("Unexpected end of table when reading continuation of tag");
01229 }
01230 (void)Item(C_[0].p, C_[0].c).append_chunk(tag);
01231 }
01232
01233
01234 if (!compressed || keep_compressed) RETURN(compressed);
01235
01236
01237
01238
01239
01240 string utag;
01241
01242 utag.reserve(tag->size() + tag->size() / 2);
01243
01244 Bytef buf[8192];
01245
01246 lazy_alloc_inflate_zstream();
01247
01248 inflate_zstream->next_in = (Bytef*)const_cast<char *>(tag->data());
01249 inflate_zstream->avail_in = (uInt)tag->size();
01250
01251 int err = Z_OK;
01252 while (err != Z_STREAM_END) {
01253 inflate_zstream->next_out = buf;
01254 inflate_zstream->avail_out = (uInt)sizeof(buf);
01255 err = inflate(inflate_zstream, Z_SYNC_FLUSH);
01256 if (err == Z_BUF_ERROR && inflate_zstream->avail_in == 0) {
01257 LOGLINE(DB, "Z_BUF_ERROR - faking checksum of " << inflate_zstream->adler);
01258 Bytef header2[4];
01259 setint4(header2, 0, inflate_zstream->adler);
01260 inflate_zstream->next_in = header2;
01261 inflate_zstream->avail_in = 4;
01262 err = inflate(inflate_zstream, Z_SYNC_FLUSH);
01263 if (err == Z_STREAM_END) break;
01264 }
01265
01266 if (err != Z_OK && err != Z_STREAM_END) {
01267 if (err == Z_MEM_ERROR) throw std::bad_alloc();
01268 string msg = "inflate failed";
01269 if (inflate_zstream->msg) {
01270 msg += " (";
01271 msg += inflate_zstream->msg;
01272 msg += ')';
01273 }
01274 throw Xapian::DatabaseError(msg);
01275 }
01276
01277 utag.append(reinterpret_cast<const char *>(buf),
01278 inflate_zstream->next_out - buf);
01279 }
01280 if (utag.size() != inflate_zstream->total_out) {
01281 string msg = "compressed tag didn't expand to the expected size: ";
01282 msg += str(utag.size());
01283 msg += " != ";
01284
01285 msg += str((size_t)inflate_zstream->total_out);
01286 throw Xapian::DatabaseCorruptError(msg);
01287 }
01288
01289 swap(*tag, utag);
01290
01291 RETURN(false);
01292 }
01293
01294 void
01295 BrassTable::set_full_compaction(bool parity)
01296 {
01297 LOGCALL_VOID(DB, "BrassTable::set_full_compaction", parity);
01298 Assert(writable);
01299
01300 if (parity) seq_count = 0;
01301 full_compaction = parity;
01302 }
01303
01304 BrassCursor * BrassTable::cursor_get() const {
01305 LOGCALL(DB, BrassCursor *, "BrassTable::cursor_get", NO_ARGS);
01306 if (handle < 0) {
01307 if (handle == -2) {
01308 BrassTable::throw_database_closed();
01309 }
01310 RETURN(NULL);
01311 }
01312
01313 RETURN(new BrassCursor(const_cast<BrassTable *>(this)));
01314 }
01315
01316
01317
01318 bool
01319 BrassTable::basic_open(bool revision_supplied, brass_revision_number_t revision_)
01320 {
01321 LOGCALL(DB, bool, "BrassTable::basic_open", revision_supplied | revision_);
01322 int ch = 'X';
01323
01324 {
01325 const size_t BTREE_BASES = 2;
01326 string err_msg;
01327 static const char basenames[BTREE_BASES] = { 'A', 'B' };
01328
01329 BrassTable_base bases[BTREE_BASES];
01330 bool base_ok[BTREE_BASES];
01331
01332 both_bases = true;
01333 bool valid_base = false;
01334 {
01335 for (size_t i = 0; i < BTREE_BASES; ++i) {
01336 bool ok = bases[i].read(name, basenames[i], writable, err_msg);
01337 base_ok[i] = ok;
01338 if (ok) {
01339 valid_base = true;
01340 } else {
01341 both_bases = false;
01342 }
01343 }
01344 }
01345
01346 if (!valid_base) {
01347 if (handle >= 0) {
01348 ::close(handle);
01349 handle = -1;
01350 }
01351 string message = "Error opening table `";
01352 message += name;
01353 message += "':\n";
01354 message += err_msg;
01355 throw Xapian::DatabaseOpeningError(message);
01356 }
01357
01358 if (revision_supplied) {
01359 bool found_revision = false;
01360 for (size_t i = 0; i < BTREE_BASES; ++i) {
01361 if (base_ok[i] && bases[i].get_revision() == revision_) {
01362 ch = basenames[i];
01363 found_revision = true;
01364 break;
01365 }
01366 }
01367 if (!found_revision) {
01368
01369
01370
01371
01372 RETURN(false);
01373 }
01374 } else {
01375 brass_revision_number_t highest_revision = 0;
01376 for (size_t i = 0; i < BTREE_BASES; ++i) {
01377 if (base_ok[i] && bases[i].get_revision() >= highest_revision) {
01378 ch = basenames[i];
01379 highest_revision = bases[i].get_revision();
01380 }
01381 }
01382 }
01383
01384 BrassTable_base *basep = 0;
01385 BrassTable_base *other_base = 0;
01386
01387 for (size_t i = 0; i < BTREE_BASES; ++i) {
01388 LOGLINE(DB, "Checking (ch == " << ch << ") against "
01389 "basenames[" << i << "] == " << basenames[i]);
01390 LOGLINE(DB, "bases[" << i << "].get_revision() == " <<
01391 bases[i].get_revision());
01392 LOGLINE(DB, "base_ok[" << i << "] == " << base_ok[i]);
01393 if (ch == basenames[i]) {
01394 basep = &bases[i];
01395
01396
01397 size_t otherbase_num = 1-i;
01398 if (base_ok[otherbase_num]) {
01399 other_base = &bases[otherbase_num];
01400 }
01401 break;
01402 }
01403 }
01404 Assert(basep);
01405
01406
01407
01408
01409
01410
01411 base.swap(*basep);
01412
01413 revision_number = base.get_revision();
01414 block_size = base.get_block_size();
01415 root = base.get_root();
01416 level = base.get_level();
01417
01418 item_count = base.get_item_count();
01419 faked_root_block = base.get_have_fakeroot();
01420 sequential = base.get_sequential();
01421
01422 if (other_base != 0) {
01423 latest_revision_number = other_base->get_revision();
01424 if (revision_number > latest_revision_number)
01425 latest_revision_number = revision_number;
01426 } else {
01427 latest_revision_number = revision_number;
01428 }
01429 }
01430
01431
01432 kt = Item_wr(zeroed_new(block_size));
01433
01434 set_max_item_size(BLOCK_CAPACITY);
01435
01436 base_letter = ch;
01437
01438
01439
01440 RETURN(true);
01441 }
01442
01443 void
01444 BrassTable::read_root()
01445 {
01446 LOGCALL_VOID(DB, "BrassTable::read_root", NO_ARGS);
01447 if (faked_root_block) {
01448
01449 byte * p = C[0].p;
01450 Assert(p);
01451
01452
01453
01454
01455 memset(p, 0, block_size);
01456
01457 int o = block_size - I2 - K1 - C2 - C2;
01458 Item_wr(p + o).fake_root_item();
01459
01460 setD(p, DIR_START, o);
01461 SET_DIR_END(p, DIR_START + D2);
01462
01463 o -= (DIR_START + D2);
01464 SET_MAX_FREE(p, o);
01465 SET_TOTAL_FREE(p, o);
01466 SET_LEVEL(p, 0);
01467
01468 if (!writable) {
01469
01470
01471 SET_REVISION(p, 0);
01472 C[0].n = 0;
01473 } else {
01474
01475 SET_REVISION(p, latest_revision_number + 1);
01476 C[0].n = base.next_free_block();
01477 }
01478 } else {
01479
01480 block_to_cursor(C, level, root);
01481
01482 if (REVISION(C[level].p) > revision_number) set_overwritten();
01483
01484 }
01485 }
01486
01487 bool
01488 BrassTable::do_open_to_write(bool revision_supplied,
01489 brass_revision_number_t revision_,
01490 bool create_db)
01491 {
01492 LOGCALL(DB, bool, "BrassTable::do_open_to_write", revision_supplied | revision_ | create_db);
01493 if (handle == -2) {
01494 BrassTable::throw_database_closed();
01495 }
01496 int flags = O_RDWR | O_BINARY;
01497 if (create_db) flags |= O_CREAT | O_TRUNC;
01498 handle = ::open((name + "DB").c_str(), flags, 0666);
01499 if (handle < 0) {
01500
01501
01502 if (lazy && !create_db && errno == ENOENT) {
01503 revision_number = revision_;
01504 RETURN(true);
01505 }
01506 string message(create_db ? "Couldn't create " : "Couldn't open ");
01507 message += name;
01508 message += "DB read/write: ";
01509 message += strerror(errno);
01510 throw Xapian::DatabaseOpeningError(message);
01511 }
01512
01513 if (!basic_open(revision_supplied, revision_)) {
01514 ::close(handle);
01515 handle = -1;
01516 if (!revision_supplied) {
01517 throw Xapian::DatabaseOpeningError("Failed to open for writing");
01518 }
01519
01520
01521
01522 RETURN(false);
01523 }
01524
01525 writable = true;
01526
01527 for (int j = 0; j <= level; j++) {
01528 C[j].n = BLK_UNUSED;
01529 C[j].p = new byte[block_size];
01530 if (C[j].p == 0) {
01531 throw std::bad_alloc();
01532 }
01533 }
01534 split_p = new byte[block_size];
01535 if (split_p == 0) {
01536 throw std::bad_alloc();
01537 }
01538 read_root();
01539
01540 buffer = zeroed_new(block_size);
01541
01542 changed_n = 0;
01543 changed_c = DIR_START;
01544 seq_count = SEQ_START_POINT;
01545
01546 RETURN(true);
01547 }
01548
01549 BrassTable::BrassTable(const char * tablename_, const string & path_,
01550 bool readonly_, int compress_strategy_, bool lazy_)
01551 : tablename(tablename_),
01552 revision_number(0),
01553 item_count(0),
01554 block_size(0),
01555 latest_revision_number(0),
01556 both_bases(false),
01557 base_letter('A'),
01558 faked_root_block(true),
01559 sequential(true),
01560 handle(-1),
01561 level(0),
01562 root(0),
01563 kt(0),
01564 buffer(0),
01565 base(),
01566 name(path_),
01567 seq_count(0),
01568 changed_n(0),
01569 changed_c(0),
01570 max_item_size(0),
01571 Btree_modified(false),
01572 full_compaction(false),
01573 writable(!readonly_),
01574 cursor_created_since_last_modification(false),
01575 cursor_version(0),
01576 split_p(0),
01577 compress_strategy(compress_strategy_),
01578 deflate_zstream(NULL),
01579 inflate_zstream(NULL),
01580 lazy(lazy_)
01581 {
01582 LOGCALL_CTOR(DB, "BrassTable", tablename_ | path_ | readonly_ | compress_strategy_ | lazy_);
01583 }
01584
01585 bool
01586 BrassTable::really_empty() const
01587 {
01588 if (handle < 0) {
01589 if (handle == -2) {
01590 BrassTable::throw_database_closed();
01591 }
01592 return true;
01593 }
01594 BrassCursor cur(const_cast<BrassTable*>(this));
01595 cur.find_entry(string());
01596 return !cur.next();
01597 }
01598
01599 void
01600 BrassTable::lazy_alloc_deflate_zstream() const {
01601 if (usual(deflate_zstream)) {
01602 if (usual(deflateReset(deflate_zstream) == Z_OK)) return;
01603
01604 delete deflate_zstream;
01605 }
01606
01607 deflate_zstream = new z_stream;
01608
01609 deflate_zstream->zalloc = reinterpret_cast<alloc_func>(0);
01610 deflate_zstream->zfree = reinterpret_cast<free_func>(0);
01611 deflate_zstream->opaque = (voidpf)0;
01612
01613
01614
01615 int err;
01616 err = deflateInit2(deflate_zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
01617 -15, 9, compress_strategy);
01618 if (rare(err != Z_OK)) {
01619 if (err == Z_MEM_ERROR) {
01620 delete deflate_zstream;
01621 deflate_zstream = 0;
01622 throw std::bad_alloc();
01623 }
01624 string msg = "deflateInit2 failed (";
01625 if (deflate_zstream->msg) {
01626 msg += deflate_zstream->msg;
01627 } else {
01628 msg += str(err);
01629 }
01630 msg += ')';
01631 delete deflate_zstream;
01632 deflate_zstream = 0;
01633 throw Xapian::DatabaseError(msg);
01634 }
01635 }
01636
01637 void
01638 BrassTable::lazy_alloc_inflate_zstream() const {
01639 if (usual(inflate_zstream)) {
01640 if (usual(inflateReset(inflate_zstream) == Z_OK)) return;
01641
01642 delete inflate_zstream;
01643 }
01644
01645 inflate_zstream = new z_stream;
01646
01647 inflate_zstream->zalloc = reinterpret_cast<alloc_func>(0);
01648 inflate_zstream->zfree = reinterpret_cast<free_func>(0);
01649
01650 inflate_zstream->next_in = Z_NULL;
01651 inflate_zstream->avail_in = 0;
01652
01653 int err = inflateInit2(inflate_zstream, -15);
01654 if (rare(err != Z_OK)) {
01655 if (err == Z_MEM_ERROR) {
01656 delete inflate_zstream;
01657 inflate_zstream = 0;
01658 throw std::bad_alloc();
01659 }
01660 string msg = "inflateInit2 failed (";
01661 if (inflate_zstream->msg) {
01662 msg += inflate_zstream->msg;
01663 } else {
01664 msg += str(err);
01665 }
01666 msg += ')';
01667 delete inflate_zstream;
01668 inflate_zstream = 0;
01669 throw Xapian::DatabaseError(msg);
01670 }
01671 }
01672
01673 bool
01674 BrassTable::exists() const {
01675 LOGCALL(DB, bool, "BrassTable::exists", NO_ARGS);
01676 return (file_exists(name + "DB") &&
01677 (file_exists(name + "baseA") || file_exists(name + "baseB")));
01678 }
01679
01680 void
01681 BrassTable::erase()
01682 {
01683 LOGCALL_VOID(DB, "BrassTable::erase", NO_ARGS);
01684 close();
01685
01686 (void)io_unlink(name + "baseA");
01687 (void)io_unlink(name + "baseB");
01688 (void)io_unlink(name + "DB");
01689 }
01690
01691 void
01692 BrassTable::set_block_size(unsigned int block_size_)
01693 {
01694 LOGCALL_VOID(DB, "BrassTable::set_block_size", block_size_);
01695
01696 if (block_size_ < 2048 || block_size_ > BYTE_PAIR_RANGE ||
01697 (block_size_ & (block_size_ - 1)) != 0) {
01698 block_size_ = BRASS_DEFAULT_BLOCK_SIZE;
01699 }
01700 block_size = block_size_;
01701 }
01702
01703 void
01704 BrassTable::create_and_open(unsigned int block_size_)
01705 {
01706 LOGCALL_VOID(DB, "BrassTable::create_and_open", block_size_);
01707 if (handle == -2) {
01708 BrassTable::throw_database_closed();
01709 }
01710 Assert(writable);
01711 close();
01712
01713 if (block_size_ == 0) abort();
01714 set_block_size(block_size_);
01715
01716
01717
01718
01719
01720
01721
01722
01723 BrassTable_base base_;
01724 base_.set_revision(revision_number);
01725 base_.set_block_size(block_size_);
01726 base_.set_have_fakeroot(true);
01727 base_.set_sequential(true);
01728 base_.write_to_file(name + "baseA", 'A', string(), -1, NULL);
01729
01730
01731 (void)io_unlink(name + "baseB");
01732
01733
01734 (void)do_open_to_write(false, 0, true);
01735 }
01736
01737 BrassTable::~BrassTable() {
01738 LOGCALL_DTOR(DB, "BrassTable");
01739 BrassTable::close();
01740
01741 if (deflate_zstream) {
01742
01743
01744 (void) deflateEnd(deflate_zstream);
01745 delete deflate_zstream;
01746 }
01747
01748 if (inflate_zstream) {
01749
01750
01751 (void) inflateEnd(inflate_zstream);
01752 delete inflate_zstream;
01753 }
01754 }
01755
01756 void BrassTable::close(bool permanent) {
01757 LOGCALL_VOID(DB, "BrassTable::close", NO_ARGS);
01758
01759 if (handle >= 0) {
01760
01761
01762 (void)::close(handle);
01763 handle = -1;
01764 }
01765
01766 if (permanent) {
01767 handle = -2;
01768
01769
01770 return;
01771 }
01772 for (int j = level; j >= 0; j--) {
01773 delete [] C[j].p;
01774 C[j].p = 0;
01775 }
01776 delete [] split_p;
01777 split_p = 0;
01778
01779 delete [] kt.get_address();
01780 kt = 0;
01781 delete [] buffer;
01782 buffer = 0;
01783 }
01784
01785 void
01786 BrassTable::flush_db()
01787 {
01788 LOGCALL_VOID(DB, "BrassTable::flush_db", NO_ARGS);
01789 Assert(writable);
01790 if (handle < 0) {
01791 if (handle == -2) {
01792 BrassTable::throw_database_closed();
01793 }
01794 return;
01795 }
01796
01797 for (int j = level; j >= 0; j--) {
01798 if (C[j].rewrite) {
01799 write_block(C[j].n, C[j].p);
01800 }
01801 }
01802
01803 if (Btree_modified) {
01804 faked_root_block = false;
01805 }
01806 }
01807
01808 void
01809 BrassTable::commit(brass_revision_number_t revision, int changes_fd,
01810 const string * changes_tail)
01811 {
01812 LOGCALL_VOID(DB, "BrassTable::commit", revision | changes_fd | changes_tail);
01813 Assert(writable);
01814
01815 if (revision <= revision_number) {
01816 throw Xapian::DatabaseError("New revision too low");
01817 }
01818
01819 if (handle < 0) {
01820 if (handle == -2) {
01821 BrassTable::throw_database_closed();
01822 }
01823 latest_revision_number = revision_number = revision;
01824 return;
01825 }
01826
01827 try {
01828 if (faked_root_block) {
01829
01830 base.clear_bit_map();
01831 }
01832
01833 base.set_revision(revision);
01834 base.set_root(C[level].n);
01835 base.set_level(level);
01836 base.set_item_count(item_count);
01837 base.set_have_fakeroot(faked_root_block);
01838 base.set_sequential(sequential);
01839
01840 base_letter = other_base_letter();
01841
01842 both_bases = true;
01843 latest_revision_number = revision_number = revision;
01844 root = C[level].n;
01845
01846 Btree_modified = false;
01847
01848 for (int i = 0; i < BTREE_CURSOR_LEVELS; ++i) {
01849 C[i].n = BLK_UNUSED;
01850 C[i].c = -1;
01851 C[i].rewrite = false;
01852 }
01853
01854
01855
01856 string tmp = name;
01857 tmp += "tmp";
01858 string basefile = name;
01859 basefile += "base";
01860 basefile += char(base_letter);
01861 base.write_to_file(tmp, base_letter, tablename, changes_fd, changes_tail);
01862
01863
01864
01865
01866 if (!io_sync(handle)) {
01867 (void)::close(handle);
01868 handle = -1;
01869 (void)unlink(tmp);
01870 throw Xapian::DatabaseError("Can't commit new revision - failed to flush DB to disk");
01871 }
01872
01873 #if defined __WIN32__
01874 if (msvc_posix_rename(tmp.c_str(), basefile.c_str()) < 0)
01875 #else
01876 if (rename(tmp.c_str(), basefile.c_str()) < 0)
01877 #endif
01878 {
01879
01880
01881
01882
01883
01884 int saved_errno = errno;
01885 if (unlink(tmp) == 0 || errno != ENOENT) {
01886 string msg("Couldn't update base file ");
01887 msg += basefile;
01888 msg += ": ";
01889 msg += strerror(saved_errno);
01890 throw Xapian::DatabaseError(msg);
01891 }
01892 }
01893 base.commit();
01894
01895 read_root();
01896
01897 changed_n = 0;
01898 changed_c = DIR_START;
01899 seq_count = SEQ_START_POINT;
01900 } catch (...) {
01901 BrassTable::close();
01902 throw;
01903 }
01904 }
01905
01906 void
01907 BrassTable::write_changed_blocks(int changes_fd)
01908 {
01909 LOGCALL_VOID(DB, "BrassTable::write_changed_blocks", changes_fd);
01910 Assert(changes_fd >= 0);
01911 if (handle < 0) return;
01912 if (faked_root_block) return;
01913
01914 string buf;
01915 pack_uint(buf, 2u);
01916 pack_string(buf, tablename);
01917 pack_uint(buf, block_size);
01918 io_write(changes_fd, buf.data(), buf.size());
01919
01920
01921
01922 uint4 n = 0;
01923 byte * p = new byte[block_size];
01924 try {
01925 base.calculate_last_block();
01926 while (base.find_changed_block(&n)) {
01927 buf.resize(0);
01928 pack_uint(buf, n + 1);
01929 io_write(changes_fd, buf.data(), buf.size());
01930
01931
01932 read_block(n, p);
01933
01934
01935 io_write(changes_fd, reinterpret_cast<const char *>(p), block_size);
01936 ++n;
01937 }
01938 delete[] p;
01939 p = 0;
01940 } catch (...) {
01941 delete[] p;
01942 throw;
01943 }
01944 buf.resize(0);
01945 pack_uint(buf, 0u);
01946 io_write(changes_fd, buf.data(), buf.size());
01947 }
01948
01949 void
01950 BrassTable::cancel()
01951 {
01952 LOGCALL_VOID(DB, "BrassTable::cancel", NO_ARGS);
01953 Assert(writable);
01954
01955 if (handle < 0) {
01956 if (handle == -2) {
01957 BrassTable::throw_database_closed();
01958 }
01959 latest_revision_number = revision_number;
01960 return;
01961 }
01962
01963
01964
01965 string err_msg;
01966 if (!base.read(name, base_letter, writable, err_msg)) {
01967 throw Xapian::DatabaseCorruptError(string("Couldn't reread base ") + base_letter);
01968 }
01969
01970 revision_number = base.get_revision();
01971 block_size = base.get_block_size();
01972 root = base.get_root();
01973 level = base.get_level();
01974
01975 item_count = base.get_item_count();
01976 faked_root_block = base.get_have_fakeroot();
01977 sequential = base.get_sequential();
01978
01979 latest_revision_number = revision_number;
01980
01981 Btree_modified = false;
01982
01983 for (int j = 0; j <= level; j++) {
01984 C[j].n = BLK_UNUSED;
01985 C[j].rewrite = false;
01986 }
01987 read_root();
01988
01989 changed_n = 0;
01990 changed_c = DIR_START;
01991 seq_count = SEQ_START_POINT;
01992 }
01993
01994
01995
01996 bool
01997 BrassTable::do_open_to_read(bool revision_supplied, brass_revision_number_t revision_)
01998 {
01999 LOGCALL(DB, bool, "BrassTable::do_open_to_read", revision_supplied | revision_);
02000 if (handle == -2) {
02001 BrassTable::throw_database_closed();
02002 }
02003 handle = ::open((name + "DB").c_str(), O_RDONLY | O_BINARY);
02004 if (handle < 0) {
02005 if (lazy) {
02006
02007 revision_number = revision_;
02008 RETURN(true);
02009 }
02010 string message("Couldn't open ");
02011 message += name;
02012 message += "DB to read: ";
02013 message += strerror(errno);
02014 throw Xapian::DatabaseOpeningError(message);
02015 }
02016
02017 if (!basic_open(revision_supplied, revision_)) {
02018 ::close(handle);
02019 handle = -1;
02020 if (revision_supplied) {
02021
02022
02023
02024
02025 RETURN(false);
02026 }
02027 throw Xapian::DatabaseOpeningError("Failed to open table for reading");
02028 }
02029
02030 for (int j = 0; j <= level; j++) {
02031 C[j].n = BLK_UNUSED;
02032 C[j].p = new byte[block_size];
02033 if (C[j].p == 0) {
02034 throw std::bad_alloc();
02035 }
02036 }
02037
02038 read_root();
02039 RETURN(true);
02040 }
02041
02042 void
02043 BrassTable::open()
02044 {
02045 LOGCALL_VOID(DB, "BrassTable::open", NO_ARGS);
02046 LOGLINE(DB, "opening at path " << name);
02047 close();
02048
02049 if (!writable) {
02050
02051 (void)do_open_to_read(false, 0);
02052 return;
02053 }
02054
02055
02056 (void)do_open_to_write(false, 0);
02057 }
02058
02059 bool
02060 BrassTable::open(brass_revision_number_t revision)
02061 {
02062 LOGCALL(DB, bool, "BrassTable::open", revision);
02063 LOGLINE(DB, "opening for particular revision at path " << name);
02064 close();
02065
02066 if (!writable) {
02067 if (do_open_to_read(true, revision)) {
02068 AssertEq(revision_number, revision);
02069 RETURN(true);
02070 } else {
02071 close();
02072 RETURN(false);
02073 }
02074 }
02075
02076 if (!do_open_to_write(true, revision)) {
02077
02078 close();
02079 RETURN(false);
02080 }
02081
02082 AssertEq(revision_number, revision);
02083 RETURN(true);
02084 }
02085
02086 bool
02087 BrassTable::prev_for_sequential(Brass::Cursor * C_, int ) const
02088 {
02089 LOGCALL(DB, bool, "BrassTable::prev_for_sequential", Literal("C_") | Literal("/*dummy*/"));
02090 int c = C_[0].c;
02091 if (c == DIR_START) {
02092 byte * p = C_[0].p;
02093 Assert(p);
02094 uint4 n = C_[0].n;
02095 while (true) {
02096 if (n == 0) RETURN(false);
02097 n--;
02098 if (writable) {
02099 if (n == C[0].n) {
02100
02101
02102 memcpy(p, C[0].p, block_size);
02103 } else {
02104
02105
02106
02107
02108
02109 int j;
02110 for (j = 1; j <= level; ++j) {
02111 if (n == C[j].n) break;
02112 }
02113 if (j <= level) continue;
02114
02115
02116
02117
02118 read_block(n, p);
02119 }
02120 } else {
02121 read_block(n, p);
02122 }
02123 if (writable) AssertEq(revision_number, latest_revision_number);
02124 if (REVISION(p) > revision_number + writable) {
02125 set_overwritten();
02126 RETURN(false);
02127 }
02128 if (GET_LEVEL(p) == 0) break;
02129 }
02130 c = DIR_END(p);
02131 C_[0].n = n;
02132 }
02133 c -= D2;
02134 C_[0].c = c;
02135 RETURN(true);
02136 }
02137
02138 bool
02139 BrassTable::next_for_sequential(Brass::Cursor * C_, int ) const
02140 {
02141 LOGCALL(DB, bool, "BrassTable::next_for_sequential", Literal("C_") | Literal("/*dummy*/"));
02142 byte * p = C_[0].p;
02143 Assert(p);
02144 int c = C_[0].c;
02145 c += D2;
02146 Assert((unsigned)c < block_size);
02147 if (c == DIR_END(p)) {
02148 uint4 n = C_[0].n;
02149 while (true) {
02150 n++;
02151 if (n > base.get_last_block()) RETURN(false);
02152 if (writable) {
02153 if (n == C[0].n) {
02154
02155
02156 memcpy(p, C[0].p, block_size);
02157 } else {
02158
02159
02160
02161
02162
02163 int j;
02164 for (j = 1; j <= level; ++j) {
02165 if (n == C[j].n) break;
02166 }
02167 if (j <= level) continue;
02168
02169
02170
02171
02172 read_block(n, p);
02173 }
02174 } else {
02175 read_block(n, p);
02176 }
02177 if (writable) AssertEq(revision_number, latest_revision_number);
02178 if (REVISION(p) > revision_number + writable) {
02179 set_overwritten();
02180 RETURN(false);
02181 }
02182 if (GET_LEVEL(p) == 0) break;
02183 }
02184 c = DIR_START;
02185 C_[0].n = n;
02186 }
02187 C_[0].c = c;
02188 RETURN(true);
02189 }
02190
02191 bool
02192 BrassTable::prev_default(Brass::Cursor * C_, int j) const
02193 {
02194 LOGCALL(DB, bool, "BrassTable::prev_default", Literal("C_") | j);
02195 byte * p = C_[j].p;
02196 int c = C_[j].c;
02197 Assert(c >= DIR_START);
02198 Assert((unsigned)c < block_size);
02199 Assert(c <= DIR_END(p));
02200 if (c == DIR_START) {
02201 if (j == level) RETURN(false);
02202 if (!prev_default(C_, j + 1)) RETURN(false);
02203 c = DIR_END(p);
02204 }
02205 c -= D2;
02206 C_[j].c = c;
02207 if (j > 0) {
02208 block_to_cursor(C_, j - 1, Item(p, c).block_given_by());
02209 }
02210 RETURN(true);
02211 }
02212
02213 bool
02214 BrassTable::next_default(Brass::Cursor * C_, int j) const
02215 {
02216 LOGCALL(DB, bool, "BrassTable::next_default", Literal("C_") | j);
02217 byte * p = C_[j].p;
02218 int c = C_[j].c;
02219 Assert(c >= DIR_START);
02220 c += D2;
02221 Assert((unsigned)c < block_size);
02222
02223 if (c >= DIR_END(p)) {
02224 if (j == level) RETURN(false);
02225 if (!next_default(C_, j + 1)) RETURN(false);
02226 c = DIR_START;
02227 }
02228 C_[j].c = c;
02229 if (j > 0) {
02230 block_to_cursor(C_, j - 1, Item(p, c).block_given_by());
02231 #ifdef BTREE_DEBUG_FULL
02232 printf("Block in BrassTable:next_default");
02233 report_block_full(j - 1, C_[j - 1].n, C_[j - 1].p);
02234 #endif
02235 }
02236 RETURN(true);
02237 }
02238
02239 void
02240 BrassTable::throw_database_closed()
02241 {
02242 throw Xapian::DatabaseError("Database has been closed");
02243 }
02244
02260 bool Key::operator<(Key key2) const
02261 {
02262 LOGCALL(DB, bool, "Key::operator<", static_cast<const void*>(key2.p));
02263 int key1_len = length();
02264 int key2_len = key2.length();
02265 if (key1_len == key2_len) {
02266
02267
02268
02269 RETURN(memcmp(p + K1, key2.p + K1, key1_len + C2) < 0);
02270 }
02271
02272 int k_smaller = (key2_len < key1_len ? key2_len : key1_len);
02273
02274
02275 int diff = memcmp(p + K1, key2.p + K1, k_smaller);
02276 if (diff != 0) RETURN(diff < 0);
02277
02278
02279
02280 RETURN(key1_len < key2_len);
02281 }
02282
02283 bool Key::operator==(Key key2) const
02284 {
02285 LOGCALL(DB, bool, "Key::operator==", static_cast<const void*>(key2.p));
02286 int key1_len = length();
02287 if (key1_len != key2.length()) RETURN(false);
02288
02289
02290
02291 RETURN(memcmp(p + K1, key2.p + K1, key1_len + C2) == 0);
02292 }