00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include "safeerrno.h"
00025 #ifdef __WIN32__
00026 # include "msvc_posix_wrapper.h"
00027 #endif
00028
00029 #include <xapian/error.h>
00030
00031 #include "brass_btreebase.h"
00032 #include "io_utils.h"
00033 #include "omassert.h"
00034 #include "pack.h"
00035 #include "str.h"
00036 #include "utils.h"
00037
00038 #include <algorithm>
00039 #include <climits>
00040 #include <cstring>
00041
00042 using namespace std;
00043
00044
00045
00072 #define CURR_FORMAT 5U
00073
00074 BrassTable_base::BrassTable_base()
00075 : revision(0),
00076 block_size(0),
00077 root(0),
00078 level(0),
00079 bit_map_size(0),
00080 item_count(0),
00081 last_block(0),
00082 have_fakeroot(false),
00083 sequential(false),
00084 bit_map_low(0),
00085 bit_map0(0),
00086 bit_map(0)
00087 {
00088 }
00089
00090 BrassTable_base::BrassTable_base(const BrassTable_base &other)
00091 : revision(other.revision),
00092 block_size(other.block_size),
00093 root(other.root),
00094 level(other.level),
00095 bit_map_size(other.bit_map_size),
00096 item_count(other.item_count),
00097 last_block(other.last_block),
00098 have_fakeroot(other.have_fakeroot),
00099 sequential(other.sequential),
00100 bit_map_low(other.bit_map_low),
00101 bit_map0(0),
00102 bit_map(0)
00103 {
00104 try {
00105 bit_map0 = new byte[bit_map_size];
00106 bit_map = new byte[bit_map_size];
00107
00108 memcpy(bit_map0, other.bit_map0, bit_map_size);
00109 memcpy(bit_map, other.bit_map, bit_map_size);
00110 } catch (...) {
00111 delete [] bit_map0;
00112 delete [] bit_map;
00113 }
00114 }
00115
00116 void
00117 BrassTable_base::swap(BrassTable_base &other)
00118 {
00119 std::swap(revision, other.revision);
00120 std::swap(block_size, other.block_size);
00121 std::swap(root, other.root);
00122 std::swap(level, other.level);
00123 std::swap(bit_map_size, other.bit_map_size);
00124 std::swap(item_count, other.item_count);
00125 std::swap(last_block, other.last_block);
00126 std::swap(have_fakeroot, other.have_fakeroot);
00127 std::swap(sequential, other.sequential);
00128 std::swap(bit_map_low, other.bit_map_low);
00129 std::swap(bit_map0, other.bit_map0);
00130 std::swap(bit_map, other.bit_map);
00131 }
00132
00133 BrassTable_base::~BrassTable_base()
00134 {
00135 delete [] bit_map;
00136 bit_map = 0;
00137 delete [] bit_map0;
00138 bit_map0 = 0;
00139 }
00140
00142 static bool
00143 do_unpack_uint(const char **start, const char *end,
00144 uint4 *dest, string &err_msg,
00145 const string &basename,
00146 const char *varname)
00147 {
00148 bool result = unpack_uint(start, end, dest);
00149 if (rare(!result)) {
00150 err_msg += "Unable to read ";
00151 err_msg += varname;
00152 err_msg += " from ";
00153 err_msg += basename;
00154 err_msg += '\n';
00155 }
00156 return result;
00157 }
00158
00159 static bool
00160 do_unpack_uint(const char **start, const char *end,
00161 brass_tablesize_t *dest, string &err_msg,
00162 const string &basename,
00163 const char *varname)
00164 {
00165 bool result = unpack_uint(start, end, dest);
00166 if (rare(!result)) {
00167 err_msg += "Unable to read ";
00168 err_msg += varname;
00169 err_msg += " from ";
00170 err_msg += basename;
00171 err_msg += '\n';
00172 }
00173 return result;
00174 }
00175
00176 #define DO_UNPACK_UINT_ERRCHECK(start, end, var) \
00177 do { \
00178 if (!do_unpack_uint(start, end, &var, err_msg, basename, #var)) { \
00179 return false; \
00180 } \
00181 } while(0)
00182
00183
00184
00185
00186
00187
00188
00189 #define REASONABLE_BASE_SIZE 1024
00190
00191 bool
00192 BrassTable_base::read(const string & name, char ch, bool read_bitmap,
00193 string &err_msg)
00194 {
00195 string basename = name + "base" + ch;
00196 #ifdef __WIN32__
00197 int h = msvc_posix_open(basename.c_str(), O_RDONLY | O_BINARY);
00198 #else
00199 int h = open(basename.c_str(), O_RDONLY | O_BINARY);
00200 #endif
00201
00202 if (h == -1) {
00203 err_msg += "Couldn't open " + basename + ": " + strerror(errno) + "\n";
00204 return false;
00205 }
00206 fdcloser closefd(h);
00207
00208 char buf[REASONABLE_BASE_SIZE];
00209
00210 const char *start = buf;
00211 const char *end = buf + io_read(h, buf, REASONABLE_BASE_SIZE, 0);
00212
00213 DO_UNPACK_UINT_ERRCHECK(&start, end, revision);
00214 uint4 format;
00215 DO_UNPACK_UINT_ERRCHECK(&start, end, format);
00216 if (format != CURR_FORMAT) {
00217 err_msg += "Bad base file format " + str(format) + " in " +
00218 basename + "\n";
00219 return false;
00220 }
00221 DO_UNPACK_UINT_ERRCHECK(&start, end, block_size);
00222 DO_UNPACK_UINT_ERRCHECK(&start, end, root);
00223 DO_UNPACK_UINT_ERRCHECK(&start, end, level);
00224 DO_UNPACK_UINT_ERRCHECK(&start, end, bit_map_size);
00225 DO_UNPACK_UINT_ERRCHECK(&start, end, item_count);
00226 DO_UNPACK_UINT_ERRCHECK(&start, end, last_block);
00227 uint4 have_fakeroot_;
00228 DO_UNPACK_UINT_ERRCHECK(&start, end, have_fakeroot_);
00229 have_fakeroot = have_fakeroot_;
00230
00231 uint4 sequential_;
00232 DO_UNPACK_UINT_ERRCHECK(&start, end, sequential_);
00233 sequential = sequential_;
00234
00235 if (have_fakeroot && !sequential) {
00236 sequential = true;
00237
00238
00239
00240
00241
00242
00243
00244 }
00245
00246 uint4 revision2;
00247 DO_UNPACK_UINT_ERRCHECK(&start, end, revision2);
00248 if (revision != revision2) {
00249 err_msg += "Revision number mismatch in " +
00250 basename + ": " +
00251 str(revision) + " vs " + str(revision2) + "\n";
00252 return false;
00253 }
00254
00255
00256 delete [] bit_map0;
00257 bit_map0 = 0;
00258 delete [] bit_map;
00259 bit_map = 0;
00260
00261 if (!read_bitmap)
00262 return true;
00263
00264 bit_map0 = new byte[bit_map_size];
00265 bit_map = new byte[bit_map_size];
00266
00267 size_t n = end - start;
00268 if (n < bit_map_size) {
00269 memcpy(bit_map0, start, n);
00270 (void)io_read(h, reinterpret_cast<char *>(bit_map0) + n,
00271 bit_map_size - n, bit_map_size - n);
00272 n = 0;
00273 } else {
00274 memcpy(bit_map0, start, bit_map_size);
00275 n -= bit_map_size;
00276 if (n) memmove(buf, start + bit_map_size, n);
00277 }
00278 memcpy(bit_map, bit_map0, bit_map_size);
00279
00280 start = buf;
00281 end = buf + n;
00282 end += io_read(h, buf + n, REASONABLE_BASE_SIZE - n, 0);
00283
00284 uint4 revision3;
00285 if (!unpack_uint(&start, end, &revision3)) {
00286 err_msg += "Couldn't read revision3 from base file " +
00287 basename + "\n";
00288 return false;
00289 }
00290
00291 if (revision != revision3) {
00292 err_msg += "Revision number mismatch in " +
00293 basename + ": " +
00294 str(revision) + " vs " + str(revision3) + "\n";
00295 return false;
00296 }
00297
00298 if (start != end) {
00299 err_msg += "Junk at end of base file " + basename + "\n";
00300 return false;
00301 }
00302
00303 return true;
00304 }
00305
00306 void
00307 BrassTable_base::write_to_file(const string &filename,
00308 char base_letter,
00309 const string &tablename,
00310 int changes_fd,
00311 const string * changes_tail)
00312 {
00313 calculate_last_block();
00314
00315 string buf;
00316 pack_uint(buf, revision);
00317 pack_uint(buf, CURR_FORMAT);
00318 pack_uint(buf, block_size);
00319 pack_uint(buf, static_cast<uint4>(root));
00320 pack_uint(buf, static_cast<uint4>(level));
00321 pack_uint(buf, static_cast<uint4>(bit_map_size));
00322 pack_uint(buf, item_count);
00323 pack_uint(buf, static_cast<uint4>(last_block));
00324 pack_uint(buf, have_fakeroot);
00325 pack_uint(buf, sequential);
00326 pack_uint(buf, revision);
00327 if (bit_map_size > 0) {
00328 buf.append(reinterpret_cast<const char *>(bit_map), bit_map_size);
00329 }
00330 pack_uint(buf, revision);
00331
00332 #ifdef __WIN32__
00333 int h = msvc_posix_open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
00334 #else
00335 int h = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
00336 #endif
00337 if (h < 0) {
00338 string message = string("Couldn't open base ")
00339 + filename + " to write: " + strerror(errno);
00340 throw Xapian::DatabaseOpeningError(message);
00341 }
00342 fdcloser closefd(h);
00343
00344 if (changes_fd >= 0) {
00345 string changes_buf;
00346 pack_uint(changes_buf, 1u);
00347 pack_string(changes_buf, tablename);
00348 changes_buf += base_letter;
00349 pack_uint(changes_buf, buf.size());
00350 io_write(changes_fd, changes_buf.data(), changes_buf.size());
00351 io_write(changes_fd, buf.data(), buf.size());
00352 if (changes_tail != NULL) {
00353 io_write(changes_fd, changes_tail->data(), changes_tail->size());
00354
00355 io_sync(changes_fd);
00356 }
00357 }
00358
00359 io_write(h, buf.data(), buf.size());
00360 io_sync(h);
00361 }
00362
00363
00364
00365
00366
00367
00368 bool
00369 BrassTable_base::block_free_at_start(uint4 n) const
00370 {
00371 size_t i = n / CHAR_BIT;
00372 int bit = 0x1 << n % CHAR_BIT;
00373 return (bit_map0[i] & bit) == 0;
00374 }
00375
00376
00377
00378
00379
00380
00381 void
00382 BrassTable_base::free_block(uint4 n)
00383 {
00384 uint4 i = n / CHAR_BIT;
00385 int bit = 0x1 << n % CHAR_BIT;
00386 bit_map[i] &= ~ bit;
00387
00388 if (bit_map_low > i)
00389 if ((bit_map0[i] & bit) == 0)
00390 bit_map_low = i;
00391 }
00392
00393
00394
00395
00396
00397
00398
00399 #define BIT_MAP_INC 1000
00400
00401
00402 void
00403 BrassTable_base::extend_bit_map()
00404 {
00405 int n = bit_map_size + BIT_MAP_INC;
00406 byte *new_bit_map0 = 0;
00407 byte *new_bit_map = 0;
00408
00409 try {
00410 new_bit_map0 = new byte[n];
00411 new_bit_map = new byte[n];
00412
00413 memcpy(new_bit_map0, bit_map0, bit_map_size);
00414 memset(new_bit_map0 + bit_map_size, 0, n - bit_map_size);
00415
00416 memcpy(new_bit_map, bit_map, bit_map_size);
00417 memset(new_bit_map + bit_map_size, 0, n - bit_map_size);
00418 } catch (...) {
00419 delete [] new_bit_map0;
00420 delete [] new_bit_map;
00421 throw;
00422 }
00423 delete [] bit_map0;
00424 bit_map0 = new_bit_map0;
00425 delete [] bit_map;
00426 bit_map = new_bit_map;
00427 bit_map_size = n;
00428 }
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 uint4
00441 BrassTable_base::next_free_block()
00442 {
00443 uint4 i;
00444 int x;
00445 for (i = bit_map_low;; i++) {
00446 if (i >= bit_map_size) {
00447 extend_bit_map();
00448 }
00449 x = bit_map0[i] | bit_map[i];
00450 if (x != UCHAR_MAX) break;
00451 }
00452 uint4 n = i * CHAR_BIT;
00453 int d = 0x1;
00454 while ((x & d) != 0) { d <<= 1; n++; }
00455 bit_map[i] |= d;
00456 bit_map_low = i;
00457 if (n > last_block) {
00458 last_block = n;
00459 }
00460 return n;
00461 }
00462
00463 bool
00464 BrassTable_base::find_changed_block(uint4 * n)
00465 {
00466
00467
00468 while ((*n) <= last_block) {
00469 size_t offset = (*n) / CHAR_BIT;
00470 int bit = 0x1 << (*n) % CHAR_BIT;
00471
00472 if (((bit_map0[offset] & bit) == 0) && ((bit_map[offset] & bit) != 0)) {
00473 return true;
00474 }
00475 ++(*n);
00476 }
00477
00478 return false;
00479 }
00480
00481 bool
00482 BrassTable_base::block_free_now(uint4 n)
00483 {
00484 uint4 i = n / CHAR_BIT;
00485 int bit = 0x1 << n % CHAR_BIT;
00486 return (bit_map[i] & bit) == 0;
00487 }
00488
00489 void
00490 BrassTable_base::calculate_last_block()
00491 {
00492 if (bit_map_size == 0) {
00493 last_block = 0;
00494 return;
00495 }
00496 int i = bit_map_size - 1;
00497 while (bit_map[i] == 0 && i > 0) {
00498 i--;
00499 }
00500 bit_map_size = i + 1;
00501
00502 int x = bit_map[i];
00503
00504
00505 if (x == 0) {
00506 last_block = 0;
00507 return;
00508 }
00509 uint4 n = (i + 1) * CHAR_BIT - 1;
00510 int d = 0x1 << (CHAR_BIT - 1);
00511 while ((x & d) == 0) { d >>= 1; n--; }
00512
00513 last_block = n;
00514 }
00515
00516 bool
00517 BrassTable_base::is_empty() const
00518 {
00519 for (uint4 i = 0; i < bit_map_size; i++) {
00520 if (bit_map[i] != 0) {
00521 return false;
00522 }
00523 }
00524 return true;
00525 }
00526
00527 void
00528 BrassTable_base::clear_bit_map()
00529 {
00530 memset(bit_map, 0, bit_map_size);
00531 }
00532
00533
00534 void
00535 BrassTable_base::commit()
00536 {
00537 memcpy(bit_map0, bit_map, bit_map_size);
00538 bit_map_low = 0;
00539 }