00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <config.h>
00024
00025 #include "safeerrno.h"
00026
00027 #include "btreecheck.h"
00028 #include "unixcmds.h"
00029 #include "testsuite.h"
00030 #include "testutils.h"
00031 #include "utils.h"
00032
00033 #include <algorithm>
00034 #include <fstream>
00035 #include <string>
00036
00037 using namespace std;
00038
00039 #include <sys/types.h>
00040 #include "safesysstat.h"
00041
00042 #define BTREE_CHECK(DIR, OPTS) BtreeCheck::check(DIR, OPTS, tout)
00043
00044 static string tmpdir;
00045 static string datadir;
00046
00047 static void make_dir(const string & filename)
00048 {
00049 if (mkdir(filename, 0700) == -1 && errno != EEXIST) {
00050 tout << "Couldn't create directory `" << filename << "' ("
00051 << strerror(errno) << ")";
00052 }
00053 }
00054
00056 static off_t get_filesize(const string &filename)
00057 {
00058 struct stat buf;
00059 int result = stat(filename, &buf);
00060 if (result) return -1;
00061 return buf.st_size;
00062 }
00063
00064 static int process_lines(Btree & btree, ifstream &f)
00065 {
00066 int count = 0;
00067 while (true) {
00068 string s;
00069 if (!getline(f, s)) return count;
00070 if (s.empty()) continue;
00071 if (s[0] == '+') {
00072 string::size_type sp = s.find(' ');
00073 btree.add(s.substr(1, min(sp - 1, BTREE_MAX_KEY_LEN)),
00074 s.substr(sp + 1));
00075 ++count;
00076 } else if (s[0] == '-') {
00077 btree.del(s.substr(1, BTREE_MAX_KEY_LEN));
00078 --count;
00079 } else {
00080 throw "No '+' or '-' on line `" + s + "'";
00081 }
00082 }
00083 }
00084
00085 static int do_update(const string & btree_dir,
00086 const string & datafile,
00087 bool full_compact = false)
00088 {
00089 Btree btree(btree_dir, false);
00090 btree.open();
00091
00092 if (full_compact) {
00093 tout << "Compact mode\n";
00094 btree.set_full_compaction(true);
00095 }
00096
00097 int count;
00098 {
00099 ifstream f(datafile.c_str());
00100 TEST_AND_EXPLAIN(f.is_open(), "File " << datafile << " not found");
00101 count = process_lines(btree, f);
00102 }
00103
00104 btree.commit(btree.get_open_revision_number() + 1);
00105
00106 return count;
00107 }
00108
00109 static void do_create(const string & btree_dir, int block_size = 2048)
00110 {
00111 if (btree_dir.empty()) return;
00112
00113
00114 string no_slash = btree_dir;
00115 if (no_slash[no_slash.size() - 1] == '/')
00116 no_slash.resize(no_slash.size() - 1);
00117 rm_rf(no_slash);
00118 make_dir(no_slash);
00119
00120 Btree dummy(btree_dir, false);
00121 dummy.create(block_size);
00122 tout << btree_dir << "/DB created with block size " << block_size << "\n";
00123 }
00124
00125 static void unlink_table(const string & path)
00126 {
00127 unlink(path + "DB");
00128 unlink(path + "baseA");
00129 unlink(path + "baseB");
00130 }
00131
00132 static void check_table_values_hello(Btree & table, const string &world)
00133 {
00134 string tag;
00135
00136
00137 tag = "foo";
00138 TEST(table.get_exact_entry("hello", tag));
00139 TEST_EQUAL(tag, world);
00140
00141 tag = "foo";
00142 TEST(!table.get_exact_entry("jello", tag));
00143 TEST_EQUAL(tag, "foo");
00144
00145 tag = "foo";
00146 TEST(!table.get_exact_entry("bello", tag));
00147 TEST_EQUAL(tag, "foo");
00148
00149 Bcursor * cursor = table.cursor_get();
00150
00151
00152 tag = "foo";
00153 TEST(cursor->find_entry("hello"));
00154 TEST_EQUAL(cursor->current_key, "hello");
00155 cursor->read_tag();
00156 TEST_EQUAL(cursor->current_tag, world);
00157
00158 tag = "foo";
00159 TEST(!cursor->find_entry("jello"));
00160 TEST_EQUAL(cursor->current_key, "hello");
00161 cursor->read_tag();
00162 TEST_EQUAL(cursor->current_tag, world);
00163
00164 tag = "foo";
00165 TEST(!cursor->find_entry("bello"));
00166 TEST_EQUAL(cursor->current_key, "");
00167 cursor->read_tag();
00168 TEST_EQUAL(cursor->current_tag, "");
00169
00170 delete cursor;
00171 }
00172
00174 static void check_table_values_empty(Btree & table)
00175 {
00176 string tag;
00177
00178
00179 tag = "foo";
00180 TEST(!table.get_exact_entry("hello", tag));
00181 TEST_EQUAL(tag, "foo");
00182
00183 tag = "foo";
00184 TEST(!table.get_exact_entry("jello", tag));
00185 TEST_EQUAL(tag, "foo");
00186
00187 tag = "foo";
00188 TEST(!table.get_exact_entry("bello", tag));
00189 TEST_EQUAL(tag, "foo");
00190
00191 Bcursor * cursor = table.cursor_get();
00192
00193
00194 tag = "foo";
00195 TEST(!cursor->find_entry("hello"));
00196 TEST_EQUAL(cursor->current_key, "");
00197 cursor->read_tag();
00198 TEST_EQUAL(cursor->current_tag, "");
00199
00200 tag = "foo";
00201 TEST(!cursor->find_entry("jello"));
00202 TEST_EQUAL(cursor->current_key, "");
00203 cursor->read_tag();
00204 TEST_EQUAL(cursor->current_tag, "");
00205
00206 tag = "foo";
00207 TEST(!cursor->find_entry("bello"));
00208 TEST_EQUAL(cursor->current_key, "");
00209 cursor->read_tag();
00210 TEST_EQUAL(cursor->current_tag, "");
00211
00212 delete cursor;
00213 }
00214
00216 static bool test_simple1()
00217 {
00218 const string path = tmpdir + "/test_simple1_";
00219 Btree btree(path, true);
00220 btree.create(8192);
00221 btree.open();
00222
00223 string key = "foo";
00224 {
00225 Bcursor cursor(&btree);
00226 int found = cursor.find_entry(key);
00227 TEST(!found);
00228 }
00229 {
00230 Bcursor cursor(&btree);
00231 int found = cursor.find_entry(key);
00232 TEST(!found);
00233 }
00234
00235 return true;
00236 }
00237
00239 static bool test_insertdelete1()
00240 {
00241 const string btree_dir = tmpdir + "/B/";
00242 do_create(btree_dir);
00243 BTREE_CHECK(btree_dir, OPT_SHOW_STATS);
00244
00245 if (!file_exists(datadir + "ord+") || !file_exists(datadir + "ord-"))
00246 SKIP_TEST("Data files not present");
00247
00248 unsigned int count = do_update(btree_dir, datadir + "ord+");
00249 BTREE_CHECK(btree_dir, OPT_SHOW_STATS);
00250 {
00251 Btree btree(btree_dir, true);
00252 btree.open();
00253 TEST_EQUAL(count, btree.get_entry_count());
00254 }
00255
00256 count += do_update(btree_dir, datadir + "ord-");
00257 BTREE_CHECK(btree_dir, OPT_SHOW_STATS | OPT_SHORT_TREE);
00258 {
00259 Btree btree(btree_dir, true);
00260 btree.open();
00261 TEST_EQUAL(btree.get_entry_count(), 0);
00262 TEST_EQUAL(count, btree.get_entry_count());
00263 }
00264
00265 return true;
00266 }
00267
00269 static bool test_sequent1()
00270 {
00271 const string btree_dir = tmpdir + "/B/";
00272 do_create(btree_dir);
00273 BTREE_CHECK(btree_dir, OPT_SHOW_STATS);
00274
00275 if (!file_exists(datadir + "ordnum+") || !file_exists(datadir + "ordnum-"))
00276 SKIP_TEST("Data files not present");
00277
00278 do_update(btree_dir, datadir + "ord+");
00279 BTREE_CHECK(btree_dir, OPT_SHOW_STATS);
00280
00281 do_update(btree_dir, datadir + "ordnum+");
00282 BTREE_CHECK(btree_dir, OPT_SHOW_STATS);
00283
00284 do_update(btree_dir, datadir + "ord-");
00285 BTREE_CHECK(btree_dir, OPT_SHOW_STATS | OPT_SHORT_TREE);
00286
00287 do_update(btree_dir, datadir + "ordnum-");
00288 BTREE_CHECK(btree_dir, OPT_SHOW_STATS | OPT_SHORT_TREE);
00289
00290 Btree btree(btree_dir, true);
00291 btree.open();
00292 TEST_EQUAL(btree.get_entry_count(), 0);
00293
00294 return true;
00295 }
00296
00297 static bool test_emptykey1()
00298 {
00299 const string btree_dir = tmpdir + "/B/";
00300 do_create(btree_dir);
00301 BTREE_CHECK(btree_dir, OPT_SHOW_STATS);
00302
00303 {
00304 Btree btree(btree_dir, false);
00305 btree.open();
00306
00307 tout << "Setting tag to jam" << endl;
00308 btree.add("", "jam");
00309 btree.commit(btree.get_open_revision_number() + 1);
00310 }
00311 BTREE_CHECK(btree_dir, OPT_SHOW_STATS);
00312
00313 {
00314 Btree btree(btree_dir, false);
00315 btree.open();
00316 TEST_EQUAL(btree.get_entry_count(), 0);
00317
00318 tout << "Setting tag to marmite" << endl;
00319 btree.add("", "marmite");
00320 btree.commit(btree.get_open_revision_number() + 1);
00321 }
00322 BTREE_CHECK(btree_dir, OPT_SHOW_STATS);
00323
00324 {
00325 Btree btree(btree_dir, false);
00326 btree.open();
00327 TEST_EQUAL(btree.get_entry_count(), 0);
00328
00329 tout << "Deleting tag" << endl;
00330 btree.del("");
00331 btree.commit(btree.get_open_revision_number() + 1);
00332 }
00333 BTREE_CHECK(btree_dir, OPT_SHOW_STATS);
00334
00335 {
00336 Btree btree(btree_dir, false);
00337 btree.open();
00338 TEST_EQUAL(btree.get_entry_count(), 0);
00339
00340 tout << "Setting tag to butter" << endl;
00341 btree.add("", "butter");
00342 btree.add("test", "me");
00343 btree.commit(btree.get_open_revision_number() + 1);
00344 }
00345 BTREE_CHECK(btree_dir, OPT_SHOW_STATS);
00346
00347 Btree btree(btree_dir, true);
00348 btree.open();
00349 TEST_EQUAL(btree.get_entry_count(), 1);
00350
00351 return true;
00352 }
00353
00355 static bool test_table1()
00356 {
00357 const string tablename = tmpdir + "/test_table1_";
00358 unlink_table(tablename);
00359 {
00360 Btree table0(tablename, true);
00361 TEST_EXCEPTION(Xapian::DatabaseOpeningError, table0.open());
00362 TEST_EXCEPTION(Xapian::DatabaseOpeningError, table0.open(10));
00363 }
00364 Btree rw_table(tablename, false);
00365 rw_table.create(8192);
00366 rw_table.open();
00367 Btree ro_table(tablename, true);
00368 ro_table.open();
00369
00370 quartz_revision_number_t rev1 = ro_table.get_open_revision_number();
00371 quartz_revision_number_t rev2 = rw_table.get_open_revision_number();
00372
00373 TEST_EQUAL(rev1, ro_table.get_open_revision_number());
00374 TEST_EQUAL(rev2, rw_table.get_open_revision_number());
00375 TEST_EQUAL(ro_table.get_entry_count(), 0);
00376 TEST_EQUAL(rw_table.get_entry_count(), 0);
00377
00378
00379
00380 #ifdef XAPIAN_DEBUG
00381 TEST_EXCEPTION(Xapian::AssertionError,
00382 ro_table.commit(ro_table.get_latest_revision_number() + 1));
00383 #endif
00384 rw_table.commit(rw_table.get_latest_revision_number() + 1);
00385
00386 TEST_EQUAL(rev1, ro_table.get_open_revision_number());
00387 TEST_NOT_EQUAL(rev2, rw_table.get_open_revision_number());
00388 rev1 = ro_table.get_open_revision_number();
00389 rev2 = rw_table.get_open_revision_number();
00390 TEST_EQUAL(ro_table.get_entry_count(), 0);
00391 TEST_EQUAL(rw_table.get_entry_count(), 0);
00392
00393
00394 #ifdef XAPIAN_DEBUG
00395 TEST_EXCEPTION(Xapian::AssertionError, ro_table.add("hello", "world"));
00396 #endif
00397 rw_table.add("hello", "world");
00398 rw_table.commit(rw_table.get_latest_revision_number() + 1);
00399
00400 TEST_EQUAL(rev1, ro_table.get_open_revision_number());
00401 TEST_NOT_EQUAL(rev2, rw_table.get_open_revision_number());
00402 rev1 = ro_table.get_open_revision_number();
00403 rev2 = rw_table.get_open_revision_number();
00404 TEST_EQUAL(ro_table.get_entry_count(), 0);
00405 TEST_EQUAL(rw_table.get_entry_count(), 1);
00406
00407
00408 check_table_values_empty(ro_table);
00409 check_table_values_hello(rw_table, "world");
00410
00411
00412 #ifdef XAPIAN_DEBUG
00413 TEST_EXCEPTION(Xapian::AssertionError, ro_table.add("hello", "world"));
00414 #endif
00415 rw_table.add("hello", "world");
00416 rw_table.commit(rw_table.get_latest_revision_number() + 1);
00417
00418 TEST_EQUAL(rev1, ro_table.get_open_revision_number());
00419 TEST_NOT_EQUAL(rev2, rw_table.get_open_revision_number());
00420 rev1 = ro_table.get_open_revision_number();
00421 rev2 = rw_table.get_open_revision_number();
00422 TEST_EQUAL(ro_table.get_entry_count(), 0);
00423 TEST_EQUAL(rw_table.get_entry_count(), 1);
00424
00425
00426 check_table_values_empty(ro_table);
00427 check_table_values_hello(rw_table, "world");
00428
00429 #ifdef XAPIAN_DEBUG
00430
00431
00432 TEST_EXCEPTION(Xapian::AssertionError, ro_table.add("", "world"));
00433
00434
00435
00436 #endif
00437
00438
00439 #ifdef XAPIAN_DEBUG
00440 TEST_EXCEPTION(Xapian::AssertionError, ro_table.add("hello", ""));
00441 #endif
00442 rw_table.add("hello", "");
00443 rw_table.commit(rw_table.get_latest_revision_number() + 1);
00444
00445 TEST_EQUAL(rev1, ro_table.get_open_revision_number());
00446 TEST_NOT_EQUAL(rev2, rw_table.get_open_revision_number());
00447 rev1 = ro_table.get_open_revision_number();
00448 rev2 = rw_table.get_open_revision_number();
00449 TEST_EQUAL(ro_table.get_entry_count(), 0);
00450 TEST_EQUAL(rw_table.get_entry_count(), 1);
00451
00452
00453 check_table_values_empty(ro_table);
00454 check_table_values_hello(rw_table, "");
00455
00456
00457 #ifdef XAPIAN_DEBUG
00458 TEST_EXCEPTION(Xapian::AssertionError, ro_table.del("hello"));
00459 #endif
00460 rw_table.del("hello");
00461 rw_table.commit(rw_table.get_latest_revision_number() + 1);
00462
00463 TEST_EQUAL(rev1, ro_table.get_open_revision_number());
00464 TEST_NOT_EQUAL(rev2, rw_table.get_open_revision_number());
00465 rev1 = ro_table.get_open_revision_number();
00466 rev2 = rw_table.get_open_revision_number();
00467 TEST_EQUAL(ro_table.get_entry_count(), 0);
00468 TEST_EQUAL(rw_table.get_entry_count(), 0);
00469
00470
00471 check_table_values_empty(ro_table);
00472 check_table_values_empty(rw_table);
00473
00474
00475 rw_table.add("hello", "world");
00476 rw_table.add("whooo", "world");
00477
00478 rw_table.commit(rw_table.get_latest_revision_number() + 1);
00479
00480 TEST_EQUAL(rev1, ro_table.get_open_revision_number());
00481 TEST_NOT_EQUAL(rev2, rw_table.get_open_revision_number());
00482 rev1 = ro_table.get_open_revision_number();
00483 rev2 = rw_table.get_open_revision_number();
00484 TEST_EQUAL(ro_table.get_entry_count(), 0);
00485 TEST_EQUAL(rw_table.get_entry_count(), 2);
00486
00487
00488 check_table_values_empty(ro_table);
00489 check_table_values_hello(rw_table, "world");
00490
00491 return true;
00492 }
00493
00495 static bool test_table2()
00496 {
00497 const string tablename = tmpdir + "/test_table2_";
00498 unlink_table(tablename);
00499
00500 Btree table(tablename, false);
00501 table.create(8192);
00502 table.open();
00503 TEST_EQUAL(get_filesize(tmpdir + "/test_table2_DB"), 0);
00504
00505 table.commit(table.get_latest_revision_number() + 1);
00506 TEST_EQUAL(get_filesize(tmpdir + "/test_table2_DB"), 0);
00507
00508 table.commit(table.get_latest_revision_number() + 1);
00509 TEST_EQUAL(get_filesize(tmpdir + "/test_table2_DB"), 0);
00510
00511 table.commit(table.get_latest_revision_number() + 1);
00512 TEST_EQUAL(get_filesize(tmpdir + "/test_table2_DB"), 0);
00513
00514 table.add("foo", "bar");
00515 table.commit(table.get_latest_revision_number() + 1);
00516 TEST_EQUAL(get_filesize(tmpdir + "/test_table2_DB"), 8192);
00517
00518 return true;
00519 }
00520
00522 static bool test_table3()
00523 {
00524 const string tablename = tmpdir + "/test_table3_";
00525 unlink_table(tablename);
00526
00527 Btree table(tablename, false);
00528 table.create(8192);
00529 table.open();
00530
00531 table.commit(table.get_latest_revision_number() + 1);
00532
00533 table.add("trad", string(2200, 'a'));
00534 table.add("trade", string(3800, 'b'));
00535 table.add("tradea", string(2000, 'c'));
00536
00537 table.commit(table.get_latest_revision_number() + 1);
00538
00539 {
00540 Bcursor * cursor = table.cursor_get();
00541 TEST(cursor->find_entry("trade"));
00542 TEST_EQUAL(cursor->current_key, "trade");
00543 cursor->read_tag();
00544 TEST_EQUAL(cursor->current_tag.size(), 3800);
00545
00546 cursor->next();
00547 TEST_EQUAL(cursor->current_key, "tradea");
00548 delete cursor;
00549 }
00550
00551 table.add("trade", string(4000, 'd'));
00552 table.commit(table.get_latest_revision_number() + 1);
00553
00554 {
00555 Bcursor * cursor = table.cursor_get();
00556 TEST(cursor->find_entry("trade"));
00557 TEST_EQUAL(cursor->current_key, "trade");
00558 cursor->read_tag();
00559 TEST_EQUAL(cursor->current_tag.size(), 4000);
00560
00561 cursor->next();
00562 TEST_EQUAL(cursor->current_key, "tradea");
00563 delete cursor;
00564 }
00565
00566 return true;
00567 }
00568
00570 static bool test_table4()
00571 {
00572 const string tablename = tmpdir + "/test_table4_";
00573 unlink_table(tablename);
00574 Btree table_rw(tablename, false);
00575 table_rw.create(8192);
00576 table_rw.open();
00577 Btree table_ro(tablename, true);
00578 table_ro.open();
00579
00580 TEST_EQUAL(table_ro.get_entry_count(), 0);
00581 TEST_EQUAL(table_rw.get_entry_count(), 0);
00582
00583 table_rw.del("foo1");
00584 TEST_EQUAL(table_ro.get_entry_count(), 0);
00585 TEST_EQUAL(table_rw.get_entry_count(), 0);
00586
00587 table_rw.add("foo1", "");
00588 TEST_EQUAL(table_ro.get_entry_count(), 0);
00589 TEST_EQUAL(table_rw.get_entry_count(), 1);
00590
00591 quartz_revision_number_t new_revision =
00592 table_ro.get_latest_revision_number() + 1;
00593 table_rw.commit(new_revision);
00594 table_ro.open();
00595 TEST_EQUAL(table_ro.get_entry_count(), 1);
00596 TEST_EQUAL(table_rw.get_entry_count(), 1);
00597
00598 table_rw.add("foo1", "");
00599 TEST_EQUAL(table_ro.get_entry_count(), 1);
00600 TEST_EQUAL(table_rw.get_entry_count(), 1);
00601
00602 table_rw.del("foo1");
00603 TEST_EQUAL(table_ro.get_entry_count(), 1);
00604 TEST_EQUAL(table_rw.get_entry_count(), 0);
00605
00606 table_rw.del("foo1");
00607 TEST_EQUAL(table_ro.get_entry_count(), 1);
00608 TEST_EQUAL(table_rw.get_entry_count(), 0);
00609
00610 table_rw.add("bar", "");
00611 TEST_EQUAL(table_ro.get_entry_count(), 1);
00612 TEST_EQUAL(table_rw.get_entry_count(), 1);
00613
00614 table_rw.add("bar2", "");
00615 TEST_EQUAL(table_ro.get_entry_count(), 1);
00616 TEST_EQUAL(table_rw.get_entry_count(), 2);
00617
00618 new_revision += 1;
00619 table_rw.commit(new_revision);
00620 table_ro.open();
00621
00622 TEST_EQUAL(table_ro.get_entry_count(), 2);
00623 TEST_EQUAL(table_rw.get_entry_count(), 2);
00624
00625 return true;
00626 }
00627
00629 static bool test_table5()
00630 {
00631 const string tablename = tmpdir + "/test_table5_";
00632 unlink_table(tablename);
00633 quartz_revision_number_t new_revision;
00634 quartz_revision_number_t old_revision;
00635 {
00636
00637 Btree table_rw(tablename, false);
00638 table_rw.create(8192);
00639 table_rw.open();
00640 Btree table_ro(tablename, true);
00641 table_ro.open();
00642
00643 TEST_EQUAL(table_ro.get_entry_count(), 0);
00644 TEST_EQUAL(table_rw.get_entry_count(), 0);
00645
00646 table_rw.add("foo1", "bar1");
00647 table_rw.add("foo2", "bar2");
00648 table_rw.add("foo3", "bar3");
00649
00650 new_revision = table_ro.get_latest_revision_number() + 1;
00651 table_rw.commit(new_revision);
00652 table_ro.open();
00653
00654 TEST_EQUAL(new_revision, table_ro.get_latest_revision_number());
00655 TEST_EQUAL(new_revision, table_ro.get_open_revision_number());
00656 }
00657 {
00658
00659 Btree table_rw(tablename, false);
00660 table_rw.open();
00661 Btree table_ro(tablename, true);
00662 table_ro.open();
00663
00664 TEST_EQUAL(table_ro.get_entry_count(), 3);
00665 TEST_EQUAL(table_rw.get_entry_count(), 3);
00666
00667 TEST_EQUAL(new_revision, table_ro.get_latest_revision_number());
00668 TEST_EQUAL(new_revision, table_ro.get_open_revision_number());
00669
00670 Bcursor * cursor = table_rw.cursor_get();
00671 TEST(!cursor->find_entry("foo"));
00672 TEST_EQUAL(cursor->current_key, "");
00673 cursor->read_tag();
00674 TEST_EQUAL(cursor->current_tag, "");
00675
00676 cursor->next();
00677 TEST(!cursor->after_end());
00678 TEST_EQUAL(cursor->current_key, "foo1");
00679 cursor->read_tag();
00680 TEST_EQUAL(cursor->current_tag, "bar1");
00681
00682 cursor->next();
00683 TEST(!cursor->after_end());
00684 TEST_EQUAL(cursor->current_key, "foo2");
00685 cursor->read_tag();
00686 TEST_EQUAL(cursor->current_tag, "bar2");
00687
00688 cursor->next();
00689 TEST(!cursor->after_end());
00690 TEST_EQUAL(cursor->current_key, "foo3");
00691 cursor->read_tag();
00692 TEST_EQUAL(cursor->current_tag, "bar3");
00693
00694 cursor->next();
00695 TEST(cursor->after_end());
00696
00697
00698 table_rw.add("foo25", "bar25");
00699 old_revision = new_revision;
00700 new_revision += 1;
00701 table_rw.commit(new_revision);
00702 table_ro.open();
00703
00704 TEST_EQUAL(table_ro.get_entry_count(), 4);
00705 TEST_EQUAL(table_rw.get_entry_count(), 4);
00706
00707 TEST_EQUAL(new_revision, table_ro.get_latest_revision_number());
00708 TEST_EQUAL(new_revision, table_ro.get_open_revision_number());
00709 delete cursor;
00710 }
00711 {
00712
00713 Btree table_rw(tablename, false);
00714 TEST(table_rw.open(old_revision));
00715 Btree table_ro(tablename, true);
00716 table_ro.open(old_revision);
00717
00718 TEST_EQUAL(table_ro.get_entry_count(), 3);
00719 TEST_EQUAL(table_rw.get_entry_count(), 3);
00720
00721 TEST_EQUAL(new_revision, table_ro.get_latest_revision_number());
00722 TEST_EQUAL(old_revision, table_ro.get_open_revision_number());
00723
00724
00725 table_rw.add("foo26", "bar26");
00726 new_revision += 1;
00727 table_rw.commit(new_revision);
00728 table_ro.open();
00729
00730 TEST_EQUAL(table_ro.get_entry_count(), 4);
00731 TEST_EQUAL(table_rw.get_entry_count(), 4);
00732
00733
00734 table_rw.add("foo37", "bar37");
00735 TEST_EQUAL(table_ro.get_entry_count(), 4);
00736 TEST_EQUAL(table_rw.get_entry_count(), 5);
00737
00738 TEST_EQUAL(new_revision, table_ro.get_latest_revision_number());
00739 TEST_EQUAL(new_revision, table_ro.get_open_revision_number());
00740 }
00741 {
00742
00743 Btree table_rw(tablename, false);
00744 table_rw.open();
00745 Btree table_ro(tablename, true);
00746 table_ro.open();
00747
00748 TEST_EQUAL(table_ro.get_entry_count(), 4);
00749 TEST_EQUAL(table_rw.get_entry_count(), 4);
00750
00751 TEST_EQUAL(new_revision, table_ro.get_latest_revision_number());
00752 TEST_EQUAL(new_revision, table_ro.get_open_revision_number());
00753
00754 Bcursor * cursor = table_rw.cursor_get();
00755 TEST(!cursor->find_entry("foo"));
00756 TEST_EQUAL(cursor->current_key, "");
00757 cursor->read_tag();
00758 TEST_EQUAL(cursor->current_tag, "");
00759
00760 cursor->next();
00761 TEST(!cursor->after_end());
00762 TEST_EQUAL(cursor->current_key, "foo1");
00763 cursor->read_tag();
00764 TEST_EQUAL(cursor->current_tag, "bar1");
00765
00766 cursor->next();
00767 TEST(!cursor->after_end());
00768 TEST_EQUAL(cursor->current_key, "foo2");
00769 cursor->read_tag();
00770 TEST_EQUAL(cursor->current_tag, "bar2");
00771
00772 cursor->next();
00773 TEST(!cursor->after_end());
00774 TEST_EQUAL(cursor->current_key, "foo26");
00775 cursor->read_tag();
00776 TEST_EQUAL(cursor->current_tag, "bar26");
00777
00778 cursor->next();
00779 TEST(!cursor->after_end());
00780 TEST_EQUAL(cursor->current_key, "foo3");
00781 cursor->read_tag();
00782 TEST_EQUAL(cursor->current_tag, "bar3");
00783
00784 cursor->next();
00785 TEST(cursor->after_end());
00786 delete cursor;
00787 }
00788 {
00789
00790
00791 Btree table_ro(tablename, false);
00792 TEST(!table_ro.open(new_revision + 10));
00793 }
00794
00795 return true;
00796 }
00797
00799 static bool test_table6()
00800 {
00801 const string tablename = tmpdir + "/test_table6_";
00802 unlink_table(tablename);
00803 quartz_revision_number_t new_revision;
00804 {
00805
00806 Btree table_rw(tablename, false);
00807 table_rw.create(8192);
00808 table_rw.open();
00809 Btree table_ro(tablename, true);
00810 table_ro.open();
00811
00812 TEST_EQUAL(table_ro.get_entry_count(), 0);
00813 TEST_EQUAL(table_rw.get_entry_count(), 0);
00814
00815 table_rw.add("foo1", "bar1");
00816
00817 table_rw.add("foo2", "bar2");
00818 table_rw.cancel();
00819
00820 table_rw.add("foo3", "bar3");
00821
00822 new_revision = table_ro.get_latest_revision_number() + 1;
00823 table_rw.commit(new_revision);
00824 table_ro.open();
00825
00826 TEST_EQUAL(new_revision, table_ro.get_latest_revision_number());
00827 TEST_EQUAL(new_revision, table_ro.get_open_revision_number());
00828 }
00829 {
00830
00831 Btree table_rw(tablename, false);
00832 table_rw.open();
00833 Btree table_ro(tablename, true);
00834 table_ro.open();
00835
00836 TEST_EQUAL(table_ro.get_entry_count(), 1);
00837 TEST_EQUAL(table_rw.get_entry_count(), 1);
00838
00839 TEST_EQUAL(new_revision, table_ro.get_latest_revision_number());
00840 TEST_EQUAL(new_revision, table_ro.get_open_revision_number());
00841
00842 Bcursor * cursor = table_rw.cursor_get();
00843 TEST(!cursor->find_entry("foo"));
00844 TEST_EQUAL(cursor->current_key, "");
00845 cursor->read_tag();
00846 TEST_EQUAL(cursor->current_tag, "");
00847
00848 cursor->next();
00849 TEST(!cursor->after_end());
00850 TEST_EQUAL(cursor->current_key, "foo3");
00851 cursor->read_tag();
00852 TEST_EQUAL(cursor->current_tag, "bar3");
00853
00854 cursor->next();
00855 TEST(cursor->after_end());
00856 delete cursor;
00857 }
00858 return true;
00859 }
00860
00862 static bool test_cursor1()
00863 {
00864 const string tablename = tmpdir + "/test_cursor1_";
00865 unlink_table(tablename);
00866
00867
00868 Btree table_rw(tablename, false);
00869 table_rw.create(8192);
00870 table_rw.open();
00871 Btree table_ro(tablename, true);
00872 table_ro.open();
00873
00874 table_rw.add("foo1", "bar1");
00875 table_rw.add("foo2", "bar2");
00876 table_rw.add("foo3", "bar3");
00877 quartz_revision_number_t new_revision = table_ro.get_latest_revision_number();
00878 new_revision += 1;
00879 table_rw.commit(new_revision);
00880 table_ro.open();
00881
00882 Btree * table = &table_ro;
00883 int count = 2;
00884
00885 while (count != 0) {
00886 Bcursor * cursor = table->cursor_get();
00887 TEST(!cursor->find_entry("foo25"));
00888 TEST_EQUAL(cursor->current_key, "foo2");
00889 cursor->read_tag();
00890 TEST_EQUAL(cursor->current_tag, "bar2");
00891
00892 cursor->next();
00893 TEST(!cursor->after_end());
00894 TEST_EQUAL(cursor->current_key, "foo3");
00895 cursor->read_tag();
00896 TEST_EQUAL(cursor->current_tag, "bar3");
00897
00898 cursor->next();
00899 TEST(cursor->after_end());
00900
00901 TEST(!cursor->find_entry("foo"));
00902 TEST_EQUAL(cursor->current_key, "");
00903 cursor->read_tag();
00904 TEST_EQUAL(cursor->current_tag, "");
00905
00906 cursor->next();
00907 TEST(!cursor->after_end());
00908 TEST_EQUAL(cursor->current_key, "foo1");
00909 cursor->read_tag();
00910 TEST_EQUAL(cursor->current_tag, "bar1");
00911
00912 TEST(cursor->find_entry("foo2"));
00913 TEST_EQUAL(cursor->current_key, "foo2");
00914 cursor->read_tag();
00915 TEST_EQUAL(cursor->current_tag, "bar2");
00916
00917 cursor->next();
00918 TEST(!cursor->after_end());
00919 TEST_EQUAL(cursor->current_key, "foo3");
00920 cursor->read_tag();
00921 TEST_EQUAL(cursor->current_tag, "bar3");
00922
00923 cursor->next();
00924 TEST(cursor->after_end());
00925
00926 table = &table_rw;
00927 count -= 1;
00928
00929 delete cursor;
00930 }
00931
00932
00933 table_rw.add("foo25", "bar25");
00934
00935 table_rw.del("foo26");
00936 table_rw.del("foo1");
00937
00938 Bcursor * cursor = table_ro.cursor_get();
00939 TEST(!cursor->find_entry("foo25"));
00940 TEST_EQUAL(cursor->current_key, "foo2");
00941 cursor->read_tag();
00942 TEST_EQUAL(cursor->current_tag, "bar2");
00943
00944 cursor->next();
00945 TEST(!cursor->after_end());
00946 TEST_EQUAL(cursor->current_key, "foo3");
00947 cursor->read_tag();
00948 TEST_EQUAL(cursor->current_tag, "bar3");
00949 delete cursor;
00950
00951 cursor = table_rw.cursor_get();
00952 TEST(cursor->find_entry("foo25"));
00953 TEST_EQUAL(cursor->current_key, "foo25");
00954 cursor->read_tag();
00955 TEST_EQUAL(cursor->current_tag, "bar25");
00956
00957 cursor->next();
00958 TEST(!cursor->after_end());
00959 TEST_EQUAL(cursor->current_key, "foo3");
00960 cursor->read_tag();
00961 TEST_EQUAL(cursor->current_tag, "bar3");
00962 delete cursor;
00963
00964 cursor = table_rw.cursor_get();
00965 TEST(!cursor->find_entry("foo26"));
00966 TEST_EQUAL(cursor->current_key, "foo25");
00967 cursor->read_tag();
00968 TEST_EQUAL(cursor->current_tag, "bar25");
00969
00970 cursor->next();
00971 TEST(!cursor->after_end());
00972 TEST_EQUAL(cursor->current_key, "foo3");
00973 cursor->read_tag();
00974 TEST_EQUAL(cursor->current_tag, "bar3");
00975
00976 TEST(cursor->find_entry("foo2"));
00977 TEST_EQUAL(cursor->current_key, "foo2");
00978 cursor->read_tag();
00979 TEST_EQUAL(cursor->current_tag, "bar2");
00980
00981 cursor->next();
00982 TEST(!cursor->after_end());
00983 TEST_EQUAL(cursor->current_key, "foo25");
00984 cursor->read_tag();
00985 TEST_EQUAL(cursor->current_tag, "bar25");
00986
00987 cursor->next();
00988 TEST(!cursor->after_end());
00989 TEST_EQUAL(cursor->current_key, "foo3");
00990 cursor->read_tag();
00991 TEST_EQUAL(cursor->current_tag, "bar3");
00992
00993 cursor->next();
00994 TEST(cursor->after_end());
00995
00996 TEST(!cursor->find_entry("foo1"));
00997 TEST_EQUAL(cursor->current_key, "");
00998 cursor->read_tag();
00999 TEST_EQUAL(cursor->current_tag, "");
01000
01001 cursor->next();
01002 TEST(!cursor->after_end());
01003 TEST_EQUAL(cursor->current_key, "foo2");
01004 cursor->read_tag();
01005 TEST_EQUAL(cursor->current_tag, "bar2");
01006
01007 cursor->next();
01008 TEST(!cursor->after_end());
01009 TEST_EQUAL(cursor->current_key, "foo25");
01010 cursor->read_tag();
01011 TEST_EQUAL(cursor->current_tag, "bar25");
01012
01013 cursor->next();
01014 TEST(!cursor->after_end());
01015 TEST_EQUAL(cursor->current_key, "foo3");
01016 cursor->read_tag();
01017 TEST_EQUAL(cursor->current_tag, "bar3");
01018 delete cursor;
01019
01020 new_revision += 1;
01021 table_rw.commit(new_revision);
01022 table_ro.open();
01023
01024 cursor = table_rw.cursor_get();
01025 TEST(cursor->find_entry("foo2"));
01026 TEST_EQUAL(cursor->current_key, "foo2");
01027 cursor->read_tag();
01028 TEST_EQUAL(cursor->current_tag, "bar2");
01029
01030 TEST(!cursor->find_entry("foo24"));
01031 TEST_EQUAL(cursor->current_key, "foo2");
01032 cursor->read_tag();
01033 TEST_EQUAL(cursor->current_tag, "bar2");
01034
01035 TEST(cursor->find_entry("foo25"));
01036 TEST_EQUAL(cursor->current_key, "foo25");
01037 cursor->read_tag();
01038 TEST_EQUAL(cursor->current_tag, "bar25");
01039
01040 TEST(!cursor->find_entry("foo24"));
01041 TEST_EQUAL(cursor->current_key, "foo2");
01042 cursor->read_tag();
01043 TEST_EQUAL(cursor->current_tag, "bar2");
01044
01045 table_rw.del("foo25");
01046 delete cursor;
01047
01048 cursor = table_rw.cursor_get();
01049 TEST(!cursor->find_entry("foo25"));
01050 TEST_EQUAL(cursor->current_key, "foo2");
01051 cursor->read_tag();
01052 TEST_EQUAL(cursor->current_tag, "bar2");
01053
01054 cursor->next();
01055 TEST(!cursor->after_end());
01056 TEST_EQUAL(cursor->current_key, "foo3");
01057 cursor->read_tag();
01058 TEST_EQUAL(cursor->current_tag, "bar3");
01059
01060 delete cursor;
01061
01062 return true;
01063 }
01064
01066 static bool test_cursor2()
01067 {
01068 const string tablename = tmpdir + "/test_cursor2_";
01069 unlink_table(tablename);
01070
01071
01072 Btree table_rw(tablename, false);
01073 table_rw.create(8192);
01074 table_rw.open();
01075 Btree table_ro(tablename, true);
01076 table_ro.open();
01077
01078 table_rw.add("a", string(2036, '\x00'));
01079 table_rw.add("c", "bar2");
01080 quartz_revision_number_t new_revision = table_ro.get_latest_revision_number();
01081 new_revision += 1;
01082 table_rw.commit(new_revision);
01083 table_ro.open();
01084
01085 Bcursor * cursor = table_ro.cursor_get();
01086
01087 TEST(!cursor->find_entry("b"));
01088 TEST_EQUAL(cursor->current_key, "a");
01089 cursor->read_tag();
01090 TEST_EQUAL(cursor->current_tag, string(2036, '\x00'));
01091
01092 delete cursor;
01093
01094 return true;
01095 }
01096
01099 static bool test_cursor3()
01100 {
01101 const string tablename = tmpdir + "/test_cursor3_";
01102 unlink_table(tablename);
01103 quartz_revision_number_t new_revision;
01104 {
01105
01106 Btree table_rw(tablename, false);
01107 table_rw.create(8192);
01108 table_rw.open();
01109 Btree table_ro(tablename, true);
01110 table_ro.open();
01111
01112 TEST_EQUAL(table_ro.get_entry_count(), 0);
01113 table_rw.add("A", "A");
01114 table_rw.add("B", "B");
01115
01116 {
01117 Bcursor * cursor = table_rw.cursor_get();
01118 TEST(!cursor->find_entry("AA"));
01119 TEST_EQUAL(cursor->current_key, "A");
01120 cursor->read_tag();
01121 TEST_EQUAL(cursor->current_tag, "A");
01122
01123 cursor->next();
01124 TEST(!cursor->after_end());
01125 TEST_EQUAL(cursor->current_key, "B");
01126 cursor->read_tag();
01127 TEST_EQUAL(cursor->current_tag, "B");
01128
01129 delete cursor;
01130 }
01131
01132 new_revision = table_ro.get_latest_revision_number() + 1;
01133 table_rw.commit(new_revision);
01134 table_ro.open();
01135
01136 {
01137 Bcursor * cursor = table_rw.cursor_get();
01138 TEST(!cursor->find_entry("AA"));
01139 TEST_EQUAL(cursor->current_key, "A");
01140 cursor->read_tag();
01141 TEST_EQUAL(cursor->current_tag, "A");
01142
01143 cursor->next();
01144 TEST(!cursor->after_end());
01145 TEST_EQUAL(cursor->current_key, "B");
01146 cursor->read_tag();
01147 TEST_EQUAL(cursor->current_tag, "B");
01148
01149 delete cursor;
01150 }
01151
01152 TEST_EQUAL(new_revision, table_ro.get_latest_revision_number());
01153 TEST_EQUAL(new_revision, table_ro.get_open_revision_number());
01154 }
01155 {
01156
01157 Btree table_ro(tablename, false);
01158 table_ro.open();
01159 TEST_EQUAL(table_ro.get_entry_count(), 2);
01160
01161 TEST_EQUAL(new_revision, table_ro.get_latest_revision_number());
01162 TEST_EQUAL(new_revision, table_ro.get_open_revision_number());
01163
01164 {
01165 Bcursor * cursor = table_ro.cursor_get();
01166 TEST(!cursor->find_entry("AA"));
01167 TEST_EQUAL(cursor->current_key, "A");
01168 cursor->read_tag();
01169 TEST_EQUAL(cursor->current_tag, "A");
01170
01171 cursor->next();
01172 TEST(!cursor->after_end());
01173 TEST_EQUAL(cursor->current_key, "B");
01174 cursor->read_tag();
01175 TEST_EQUAL(cursor->current_tag, "B");
01176
01177 delete cursor;
01178 }
01179 }
01180 return true;
01181 }
01182
01184 static bool test_bitmap1()
01185 {
01186 const string tablename = tmpdir + "/test_bitmap1_";
01187 unlink_table(tablename);
01188
01189 Btree table_rw(tablename, false);
01190 table_rw.create(2048);
01191 table_rw.open();
01192 Btree table_ro(tablename, true);
01193 table_ro.open();
01194
01195 quartz_revision_number_t new_revision;
01196
01197 for (int j = 0; j < 100; ++j) {
01198 for (int i = 1; i <= 1000; ++i) {
01199 string str_i = om_tostring(i);
01200 table_rw.add("foo" + om_tostring(j) + "_" + str_i, "bar" + str_i);
01201 }
01202 new_revision = table_ro.get_latest_revision_number() + 1;
01203 table_rw.commit(new_revision);
01204 table_ro.open();
01205 }
01206 return true;
01207 }
01208
01210 static bool test_overwrite1()
01211 {
01212 const string tablename = tmpdir + "/test_overwrite1_";
01213 unlink_table(tablename);
01214 Btree bufftable(tablename, false);
01215 bufftable.create(2048);
01216 bufftable.open();
01217 Btree disktable(tablename, true);
01218 disktable.open();
01219
01220 for (int i = 1; i <= 1000; ++i) {
01221 bufftable.add("foo" + om_tostring(i), "bar" + om_tostring(i));
01222 }
01223
01224 bufftable.commit(disktable.get_latest_revision_number() + 1);
01225 disktable.open();
01226
01227 Btree disktable_ro(tablename, true);
01228 disktable_ro.open();
01229 string tag;
01230 TEST(disktable_ro.get_exact_entry("foo1", tag));
01231 TEST_EQUAL(tag, "bar1");
01232
01233 bufftable.add("foo1", "bar2");
01234 bufftable.commit(disktable.get_latest_revision_number() + 1);
01235 disktable.open();
01236 TEST(disktable_ro.get_exact_entry("foo999", tag));
01237 TEST(disktable_ro.get_exact_entry("foo1", tag));
01238 TEST_EQUAL(tag, "bar1");
01239
01240 bufftable.add("foo1", "bar3");
01241 bufftable.commit(disktable.get_latest_revision_number() + 1);
01242 disktable.open();
01243 TEST(disktable_ro.get_exact_entry("foo999", tag));
01244 TEST_EXCEPTION(Xapian::DatabaseModifiedError,
01245 disktable_ro.get_exact_entry("foo1", tag));
01246
01247
01248 return true;
01249 }
01250
01251
01252
01253
01254
01255
01256 test_desc tests[] = {
01257 {"simple1", test_simple1},
01258 {"insertdelete1", test_insertdelete1},
01259 {"sequent1", test_sequent1},
01260 {"emptykey1", test_emptykey1},
01261 {"table1", test_table1},
01262 {"table2", test_table2},
01263 {"table3", test_table3},
01264 {"table4", test_table4},
01265 {"table5", test_table5},
01266 {"table6", test_table6},
01267 {"cursor1", test_cursor1},
01268 {"cursor2", test_cursor2},
01269 {"cursor3", test_cursor3},
01270 {"bitmap1", test_bitmap1},
01271 {"overwrite1", test_overwrite1},
01272 {0, 0}
01273 };
01274
01275 int main(int argc, char **argv)
01276 {
01277 const char * e_tmpdir = getenv("BTREETMP");
01278 if (e_tmpdir) {
01279 tmpdir = e_tmpdir;
01280 } else {
01281 tmpdir = ".btreetmp";
01282 }
01283 rm_rf(tmpdir);
01284 make_dir(tmpdir);
01285 test_driver::parse_command_line(argc, argv);
01286 datadir = test_driver::get_srcdir() + "/testdata/btreetest_";
01287 return test_driver::run(tests);
01288 }