// // $Id: testsuite.in.in,v 1.13 2000/04/25 15:59:44 mirar Exp $ #module Mird { //----------------------------------------------------------------------- #chapter empty database #test create rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); db->close(); ok(); #test open of old database rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); db->close(); db=Mird.Glue.Mird("test.mird"); db->close(); ok(); #test empty transaction rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->close(); db->close(); ok(); #test empty transaction cancelled rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->cancel(); db->close(); ok(); #test empty transactions (10) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); array tr=allocate(10,Mird.Glue.Transaction)(db); tr[..5]->close(); reverse(tr[6..])->close(); db->close(); ok(); #test empty transactions cancelled (10) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); array tr=allocate(10,Mird.Glue.Transaction)(db); tr[..5]->cancel(); reverse(tr[6..])->cancel(); db->close(); ok(); #test empty transaction closed twice rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->close(); mixed err=catch { tr->close(); }; if (!err) fail("no exception\n"); db->close(); ok(); #test empty transaction closed and then cancelled rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->close(); mixed err=catch { tr->cancel(); }; if (!err) fail("no exception\n"); db->close(); ok(); #test empty transaction cancelled and then closed rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->cancel(); mixed err=catch { tr->close(); }; if (!err) fail("no exception\n"); db->close(); ok(); #test empty transaction cancelled twice rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->cancel(); mixed err=catch { tr->cancel(); }; if (!err) fail("no exception\n"); db->close(); ok(); #test forgotten transactions rm("test.mird"); class Forget { void create() { object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); db->close(); } }(); ok(); //----------------------------------------------------------------------- #chapter low level storage #test creating tables rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); db->close(); ok(); #test reading from non-existing table rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); mixed err=catch { db->fetch(17,42); }; if (!err) fail("no exception\n"); db->close(); ok(); #test create and read from empty table rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); string s=db->fetch(17,42); if (s) fail(sprintf("illegal result (%O)\n",s)); db->close(); ok(); #test create, close and read from empty table rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); db->close(); object db=Mird.Glue.Mird("test.mird"); string s=db->fetch(17,42); if (s) fail(sprintf("illegal result (%O)\n",s)); db->close(); ok(); #test create, write and read from table rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->store(17,42,"test data"); string s=tr->fetch(17,42); if (s!="test data") fail(sprintf("illegal result (%O) (tr)\n",s)); tr->close(); s=db->fetch(17,42); if (s!="test data") fail(sprintf("illegal result (%O) (db)\n",s)); db->close(); ok(); #test removing tables rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr=Mird.Glue.Transaction(db); tr->delete_table(17); tr->close(); object tr=Mird.Glue.Transaction(db); mixed err=catch { tr->store(17,42,"hej"); }; if (!err) fail("no exception"); tr->close(); db->close(); ok(); #test removing tables 2 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17|0x1000); tr->new_hashkey_table(17|0x0100); tr->new_hashkey_table(17); tr->close(); object tr=Mird.Glue.Transaction(db); tr->delete_table(17); tr->close(); object tr=Mird.Glue.Transaction(db); mixed err=catch { tr->store(17,42,"hej"); }; if (!err) fail("no exception"); tr->close(); db->close(); ok(); #test single keys of different sizes int i; for (i=0; i<20000; i=(i*3)/2+1) { werror("."); rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->store(17,42,"test data"*i); string s=tr->fetch(17,42); if (s!="test data"*i) fail(sprintf("illegal result (tr), len=%d\n",i)); tr->close(); s=db->fetch(17,42); if (s!="test data"*i) fail(sprintf("illegal result (db), len=%d\n",i)); db->close(); object db=Mird.Glue.Mird("test.mird"); s=db->fetch(17,42); if (s!="test data"*i) fail(sprintf("illegal result (db 2), len=%d\n",i)); db->close(); } ok(); #test keys of size 0..2048 int i; int z=2048; rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); string re=((string)enumerate(256))*100; werror("w"); int t=time(); float t1=time(t); for (i=0; istore(17,4713*i,re[..i-1]); werror("[%.0fkps] r",z/(time(t)-t1)); t1=time(t); for (i=0; ifetch(17,4713*i); if (s!=re[..i-1]) fail(sprintf("illegal result (tr), i=%d\n",i)); } tr->close(); werror("[%.0fkps] r",z/(time(t)-t1)); t1=time(t); for (i=0; ifetch(17,4713*i); if (s!=re[..i-1]) fail(sprintf("illegal result (db), i=%d\n",i)); } werror("[%.0fkps] ",z/(time(t)-t1)); db->close(); object db=Mird.Glue.Mird("test.mird"); werror("r"); t1=time(t); for (i=0; ifetch(17,4713*i); if (s!=re[..i-1]) fail(sprintf("illegal result (db 2), i=%d\n",i)); } db->close(); werror("[%.0fkps]...",z/(time(t)-t1)); ok(); #test large keys int i; int z=204800; int N=2000; rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); string re=((string)enumerate(256))*1000; werror("w"); int t=time(); float t1=time(t); for (i=0; istore(17,4713*i,re[..i-1]); werror("[%.0fkps] r",(z/N)/(time(t)-t1)); t1=time(t); for (i=0; ifetch(17,4713*i); if (s!=re[..i-1]) fail(sprintf("illegal result (tr), i=%d\n",i)); } tr->close(); werror("[%.0fkps] r",(z/N)/(time(t)-t1)); t1=time(t); for (i=0; ifetch(17,4713*i); if (s!=re[..i-1]) fail(sprintf("illegal result (db), i=%d\n",i)); } werror("[%.0fkps] ",(z/N)/(time(t)-t1)); db->close(); object db=Mird.Glue.Mird("test.mird"); werror("r"); t1=time(t); for (i=0; ifetch(17,4713*i); if (s!=re[..i-1]) fail(sprintf("illegal result (db 2), i=%d\n",i)); } db->close(); werror("[%.0fkps]...",(z/N)/(time(t)-t1)); ok(); #test find-next-key int z=3000; rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr=Mird.Glue.Transaction(db); int i; int t=time(); float t1=time(t); for (i=0; ifirst_unused_key(17); if (j!=i) fail("wrong next key at i="+i); tr->store(17,i,""); } werror("[%.0fkps]...",z/(time(t)-t1)); tr->cancel(); db->close(); ok(); //----------------------------------------------------------------------- #chapter recover (journal file readback) #test serial transactions 1 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; for (i=0; i<20; i++) { object tr=Mird.Glue.Transaction(db); tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"*1000); tr->close(); } db->_debug_cut(); db=Mird.Glue.Mird("test.mird"); for (i=0; i<20; i++) { if (db->fetch(17,i*4711)!="test data") fail("entry "+i+" in table 17 mismatch\n"); if (db->fetch(18,i*13)!="test data"*1000) fail("entry "+i+" in table 18 mismatch\n"); } db->close(); ok(); #test parallell transactions 1 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; array tr=allocate(20,Mird.Glue.Transaction)(db); for (i=0; i<20; i++) { tr[i]->store(17,i*4711,"test data"); tr[i]->store(18,i*13,"test data"*1000); } tr->close(); db->_debug_cut(); db=Mird.Glue.Mird("test.mird"); for (i=0; i<20; i++) { if (db->fetch(17,i*4711)!="test data") fail(sprintf("entry "+i+" in table 17 mismatch: %O\n",db->fetch(17,i*4711))); if (db->fetch(18,i*13)!="test data"*1000) fail("entry "+i+" in table 18 mismatch\n"); } db->close(); ok(); #test serial transactions 2 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; for (i=0; i<20; i++) { object tr=Mird.Glue.Transaction(db); tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"*1000); if (i&1) tr->close(); else tr->cancel(); } db->_debug_cut(); db=Mird.Glue.Mird("test.mird"); for (i=0; i<20; i++) if (i&1) { if (db->fetch(17,i*4711)!="test data") fail("entry "+i+" in table 17 mismatch "+ sprintf("(%O)",db->fetch(17,i*4711))+"\n"); if (db->fetch(18,i*13)!="test data"*1000) fail("entry "+i+" in table 18 mismatch\n"); } else { if (db->fetch(17,i*4711)!=0) fail("entry "+i+" in table 17 entry alive\n"); if (db->fetch(18,i*13)!=0) fail("entry "+i+" in table 18 entry alive\n"); } db->close(); ok(); #test parallell transactions 2 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; array tr=allocate(20,Mird.Glue.Transaction)(db); for (i=0; i<20; i++) { tr[i]->store(17,i*4711,"test data"); tr[i]->store(18,i*13,"test data"*1000); } for (i=0; i<20; i++) if (i&1) tr[i]->close(); else tr[i]->cancel(); db->_debug_cut(); db=Mird.Glue.Mird("test.mird"); for (i=0; i<20; i++) if (i&1) { if (db->fetch(17,i*4711)!="test data") fail("entry "+i+" in table 17 mismatch\n"); if (db->fetch(18,i*13)!="test data"*1000) fail("entry "+i+" in table 18 mismatch\n"); } else { if (db->fetch(17,i*4711)!=0) fail("entry "+i+" in table 17 entry alive\n"); if (db->fetch(18,i*13)!=0) fail("entry "+i+" in table 18 entry alive\n"); } db->close(); ok(); //----------------------------------------------------------------------- #chapter conflicts #test same key (both new) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); tr1->store(17,42,"value"); object tr2=Mird.Glue.Transaction(db); tr2->store(17,42,"value"); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); #test same key (change) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->store(17,42,"first value"); tr->close(); object tr1=Mird.Glue.Transaction(db); tr1->store(17,42,"value"); object tr2=Mird.Glue.Transaction(db); tr2->store(17,42,"value"); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); #test same key (first delete) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->store(17,42,"first value"); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->delete(17,42); tr2->store(17,42,"value"); tr1->close(); mixed err=catch { tr2->close(); }; if (!err) fail("no exception"); ok(); #test same key (second delete) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->store(17,42,"first value"); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->store(17,42,"value"); tr2->delete(17,42); tr1->close(); mixed err=catch { tr2->close(); }; if (!err) fail("no exception"); ok(); #test same key (both delete) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->store(17,42,"first value"); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->delete(17,42); tr2->delete(17,42); tr1->close(); mixed err=catch { tr2->close(); }; if (!err) fail("no exception"); ok(); // #test same key (both new + delete) // rm("test.mird"); // object db=Mird.Glue.Mird("test.mird"); // object tr=Mird.Glue.Transaction(db); // tr->new_hashkey_table(17); // tr->close(); // object tr1=Mird.Glue.Transaction(db); // object tr2=Mird.Glue.Transaction(db); // tr1->store(17,42,"first value"); // tr2->store(17,42,"first value"); // tr1->delete(17,42); // tr2->delete(17,42); // tr1->close(); // mixed err=catch { tr2->close(); }; // if (!err) fail("no exception"); // ok(); #test same key (both new, delete, create in first) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->store(17,42,"value"); tr2->store(17,42,"value"); tr1->delete(17,42); tr2->delete(17,42); tr1->store(17,42,"value"); tr1->close(); mixed err=catch { tr2->close(); }; if (!err) fail("no exception"); ok(); #test same table (both new) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr1=Mird.Glue.Transaction(db); tr1->new_hashkey_table(17); object tr2=Mird.Glue.Transaction(db); tr2->new_hashkey_table(17); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); #test same table (first delete, second delete + new) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->delete_table(17); tr2->delete_table(17); tr2->new_hashkey_table(17); tr1->close(); mixed err=catch { tr2->close(); }; if (!err) fail("no exception"); ok(); #test same table (second delete, first delete + new) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->delete_table(17); tr1->new_hashkey_table(17); tr2->delete_table(17); tr1->close(); mixed err=catch { tr2->close(); }; if (!err) fail("no exception"); ok(); #test same table (both delete) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->delete_table(17); tr2->delete_table(17); tr1->close(); mixed err=catch { tr2->close(); }; if (!err) fail("no exception"); ok(); #test same table (both new, delete) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->new_hashkey_table(17); tr2->new_hashkey_table(17); tr1->delete_table(17); tr2->delete_table(17); tr1->close(); mixed err=catch { tr2->close(); }; if (!err) fail("no exception"); ok(); #test same table (both new, delete, new) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->new_hashkey_table(17); tr2->new_hashkey_table(17); tr1->delete_table(17); tr2->delete_table(17); tr1->new_hashkey_table(17); tr2->new_hashkey_table(17); tr1->close(); mixed err=catch { tr2->close(); }; if (!err) fail("no exception"); ok(); #test same table (both new, delete, second +n+d) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->new_hashkey_table(17); tr2->new_hashkey_table(17); tr1->delete_table(17); tr2->delete_table(17); tr2->new_hashkey_table(17); tr2->delete_table(17); tr1->close(); mixed err=catch { tr2->close(); }; if (!err) fail("no exception"); ok(); #test if conflicts stays rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); tr1->store(17,42,"value"); object tr2=Mird.Glue.Transaction(db); tr2->store(17,42,"value"); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); mixed err=catch { tr1->close(); }; if (!err) fail("no exception (2)"); mixed err=catch { tr1->close(); }; if (!err) fail("no exception (3)"); ok(); #test if conflicts stays after resolve() rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); tr1->store(17,42,"value"); object tr2=Mird.Glue.Transaction(db); tr2->store(17,42,"value"); tr2->close(); mixed err=catch { tr1->resolve(); }; if (!err) fail("no exception"); mixed err=catch { tr1->resolve(); }; if (!err) fail("no exception (2)"); mixed err=catch { tr1->close(); }; if (!err) fail("no exception (3)"); ok(); #test table write / delete rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->store(17,42,"value"); tr2->delete_table(17); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); #test table new + write / new + delete rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->new_hashkey_table(17); tr1->store(17,42,"value"); tr2->new_hashkey_table(17); tr2->delete_table(17); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); #test table new + delete / new + write rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr2->new_hashkey_table(17); tr2->store(17,42,"value"); tr1->new_hashkey_table(17); tr1->delete_table(17); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); #test table new + write + delete / new + delete rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->new_hashkey_table(17); tr1->store(17,42,"value"); tr1->delete_table(17); tr2->new_hashkey_table(17); tr2->delete_table(17); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); #test table new + delete / new + write + delete rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr2->new_hashkey_table(17); tr2->store(17,42,"value"); tr2->delete_table(17); tr1->new_hashkey_table(17); tr1->delete_table(17); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); #test table depend / write rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr2->store(17,42,"value"); tr1->depend_table(17); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); #test table depend / depend rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr2->depend_table(17); tr1->depend_table(17); tr2->close(); tr1->close(); // no conflict! ok(); #test table write / depend rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr1->store(17,42,"value"); tr2->depend_table(17); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); #test table delete / write rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->close(); object tr1=Mird.Glue.Transaction(db); object tr2=Mird.Glue.Transaction(db); tr2->store(17,42,"value"); tr1->delete_table(17); tr2->close(); mixed err=catch { tr1->close(); }; if (!err) fail("no exception"); ok(); //----------------------------------------------------------------------- #chapter usage #test cancelled parallell transactions rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); array tr=allocate(10,Mird.Glue.Transaction)(db); tr->new_hashkey_table(17); tr->store(17,42,"test data"); tr->new_hashkey_table(18); tr->store(18,42,"test data"*1000); tr->cancel(); db->_debug_check_free(1); db->close(); ok(); #test cancelled serial transactions rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); int i; for (i=0; i<10; i++) { object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->store(17,42,"test data"); tr->new_hashkey_table(18); tr->store(18,42,"test data"*1000); tr->cancel(); } db->_debug_check_free(1); db->close(); ok(); #test closed serial transactions rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); int i; object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); for (i=0; i<10; i++) { object tr=Mird.Glue.Transaction(db); tr->store(17,42,"test data"); tr->store(18,42,"test data"*1000); tr->close(); } for (i=0; i<10; i++) { object tr=Mird.Glue.Transaction(db); (i&1)?tr->store(17,42,"test data") :tr->store(18,42,"test data"*1000); tr->close(); } db->_debug_check_free(1); db->close(); ok(); #test closed parallel transactions (conflicts) rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); int i; object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); array tr=allocate(10,Mird.Glue.Transaction)(db); tr->store(17,42,"test data"); tr->store(18,42,"test data"*1000); for (i=0; i<10; i++) catch { tr[i]->close(); }; tr->destroy(); db->_debug_check_free(1); db->close(); ok(); //----------------------------------------------------------------------- #chapter usage and recover #test serial transactions 2 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; for (i=0; i<20; i++) { object tr=Mird.Glue.Transaction(db); tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"*1000); if (i&1) tr->close(); else tr->cancel(); } db->_debug_cut(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test parallell transactions 2 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; array tr=allocate(20,Mird.Glue.Transaction)(db); for (i=0; i<20; i++) { tr[i]->store(17,i*4711,"test data"); tr[i]->store(18,i*13,"test data"*1000); } for (i=0; i<20; i++) if (i&1) tr[i]->close(); else tr[i]->cancel(); db->_debug_cut(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test destruction of tables rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); int i; for (i=0; i<2000; i++) { tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"); } tr->close(); object tr=Mird.Glue.Transaction(db); tr->delete_table(17); tr->close(); db->_debug_cut(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); object tr=Mird.Glue.Transaction(db); tr->delete_table(18); tr->close(); db->_debug_cut(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test table conflicts 1 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); array tr=allocate(10,Mird.Glue.Transaction)(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); int i; for (i=0; i<20; i++) { tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"); } for (i=0; i<10; i++) catch { tr[i]->close(); }; tr->destroy(); db->_debug_cut(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test table conflicts 2 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); int i,j; for (i=0; i<20; i++) { tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"); } tr->close(); array tr=allocate(24,Mird.Glue.Transaction)(db); for (i=0; i<24; i++) { for (j=0; j<20; j++) { tr[i]->store(17,j,"test data"); tr[i]->store(18,j,"test data"); } tr[i]->delete_table(17); tr[i]->delete_table(18); if (!(i%2)) { tr[i]->new_hashkey_table(17); for (j=0; j<20; j++) tr[i]->store(17,j*13,"test data"); } if (!(i%3)) { tr[i]->new_hashkey_table(18); for (j=0; j<20; j++) tr[i]->store(18,j*4711,"test data"); } if (!(i%12)) { tr[i]->delete_table(17); tr[i]->delete_table(18); } if (!i) { tr[i]->new_hashkey_table(17); tr[i]->new_hashkey_table(18); } catch { for (j=0; j<20; j++) { tr[i]->store(17,j*4711,"test data"); tr[i]->store(18,j*13,"test data"); } }; } for (i=0; i<10; i++) catch { tr[i]->close(); }; tr->destroy(); db->_debug_cut(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test table conflicts 2 / broken journal rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); int i,j; for (i=0; i<20; i++) { tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"); } tr->close(); array tr=allocate(24,Mird.Glue.Transaction)(db); for (i=0; i<24; i++) { for (j=0; j<20; j++) { tr[i]->store(17,j,"test data"); tr[i]->store(18,j,"test data"); } tr[i]->delete_table(17); tr[i]->delete_table(18); if (!(i%2)) { tr[i]->new_hashkey_table(17); for (j=0; j<20; j++) tr[i]->store(17,j*13,"test data"); } if (!(i%3)) { tr[i]->new_hashkey_table(18); for (j=0; j<20; j++) tr[i]->store(18,j*4711,"test data"); } if (!(i%12)) { tr[i]->delete_table(17); tr[i]->delete_table(18); } if (!i) { tr[i]->new_hashkey_table(17); tr[i]->new_hashkey_table(18); } catch { for (j=0; j<20; j++) { tr[i]->store(17,j*4711,"test data"); tr[i]->store(18,j*13,"test data"); } }; } for (i=0; i<10; i++) catch { tr[i]->close(); }; tr->destroy(); db->_debug_cut(); object f=Stdio.File("test.mird.journal","wr"); f->truncate(40960); f->seek(40960); f->close(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test parallel transactions / broken database file rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; array tr=allocate(20,Mird.Glue.Transaction)(db); for (i=0; i<20; i++) { tr[i]->store(17,i*4711,"test data"); tr[i]->store(18,i*13,"test data"*1000); } for (i=0; i<20; i++) if (i&1) tr[i]->close(); else tr[i]->cancel(); db->_debug_cut(); object f=Stdio.File("test.mird","wr"); // f->seek(8192); // f->write("blaha blaha"); for (i=0; i<100; i++) { f->seek(10000+i*1000); f->write("blaha blaha"); } f->close(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test cancelled transactions / cut journal file rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; object tr=Mird.Glue.Transaction(db); for (i=0; i<2000; i++) tr->store(17,i*4711,"test data"); tr->cancel(); db->_debug_cut(); object f=Stdio.File("test.mird.journal","wr"); f->truncate(Stdio.file_size("test.mird.journal")-70); f->close(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test litter in journal file rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; object tr=Mird.Glue.Transaction(db); for (i=0; i<20; i++) { tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"); } tr->close(); db->_debug_cut(); object f=Stdio.File("test.mird.journal","wr"); string s=f->read(0x7ffffff); s=s[..24*6-1]+replace(s[24*6..],"allo","lttr"); f->seek(0); f->write(s); f->close(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test litter in journal file 2 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; object tr=Mird.Glue.Transaction(db); for (i=0; i<20; i++) { tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"); } tr->close(); db->_debug_cut(); object f=Stdio.File("test.mird.journal","wr"); string s=f->read(0x7ffffff); s=s[..24*6-1]+replace(s[24*6..],"free","lttr"); f->seek(0); f->write(s); f->close(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test litter in journal file 3 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; object tr=Mird.Glue.Transaction(db); for (i=0; i<20; i++) { tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"); } tr->cancel(); db->_debug_cut(); object f=Stdio.File("test.mird.journal","wr"); string s=f->read(0x7ffffff); s=s[..24*6-1]+replace(s[24*6..],"allo","lttr"); f->seek(0); f->write(s); f->close(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); #test litter in journal file 4 rm("test.mird"); object db=Mird.Glue.Mird("test.mird"); object tr=Mird.Glue.Transaction(db); tr->new_hashkey_table(17); tr->new_hashkey_table(18); tr->close(); int i; object tr=Mird.Glue.Transaction(db); for (i=0; i<20; i++) { tr->store(17,i*4711,"test data"); tr->store(18,i*13,"test data"); } tr->cancel(); db->_debug_cut(); object f=Stdio.File("test.mird.journal","wr"); string s=f->read(0x7ffffff); s=s[..24*6-1]+replace(s[24*6..],"free","lttr"); f->seek(0); f->write(s); f->close(); db=Mird.Glue.Mird("test.mird"); db->_debug_check_free(1); db->close(); ok(); // ---------------------------------------------------------------- #chapter Pike high-level interface #test Creating (nice) rm("test.mird"); object m=Mird("test.mird"); m->close(); ok(); #test Creating (forget) rm("test.mird"); object t=Mird("test.mird")->transaction(); gc(); t->tables(); t=0; gc(); ok(); #test Tables string res; rm("test.mird"); object db=Mird("test.mird"); object tr=db->transaction(); tr->new_stringkey_table("string"); tr->new_hashkey_table("hash"); res=tr->table("hash")[18]; res=tr->table("string")["blah?"]; tr->close(); if ( sizeof(db->tables() & ({"string","hash"})) < 2 ) fail("too few names"); res=db->table("hash")[18]; res=db->table("string")["blah?"]; object tr=db->transaction(); tr->table("string")["blah"]="test"; tr->table("hash")[17]="more"; if (tr->table("string")["blah"]!="test") fail("wrong stringtable data 4"); if (tr->table("hash")[17]!="more") fail("wrong hashtable data 4"); tr->close(); if (db->table("string")["blah"]!="test") fail("wrong stringtable data 1"); if (db->table("hash")[17]!="more") fail("wrong hashtable data 1"); db->close(); db=Mird("test.mird"); if (db->table("string")["blah"]!="test") fail("wrong stringtable data 2"); if (db->table("hash")[17]!="more") fail("wrong hashtable data 2"); object tr=db->transaction(); if (tr->table("string")["blah"]!="test") fail("wrong stringtable data 3"); if (tr->table("hash")[17]!="more") fail("wrong hashtable data 3"); tr->cancel(); db->close(); ok(); #test Tables rm("test.mird"); object db=Mird("test.mird"); db->new_stringkey_table("string"); db->new_hashkey_table("hash"); if ( sizeof(db->tables() & ({"string","hash"})) < 2 ) fail("too few names"); string res; res=db->table("hash")[18]; res=db->table("string")["blah?"]; db->table("string")["blah"]="test"; db->table("hash")[17]="more"; if (db->table("string")["blah"]!="test") fail("wrong stringtable data"); if (db->table("hash")[17]!="more") fail("wrong hashtable data"); db->close(); db=Mird("test.mird"); if (db->table("string")["blah"]!="test") fail("wrong stringtable data"); if (db->table("hash")[17]!="more") fail("wrong hashtable data"); db->close(); ok(); #test indices & values rm("test.mird"); object db=Mird("test.mird"); object tr=db->transaction(); tr->new_stringkey_table("string"); tr->new_hashkey_table("hash"); object th=tr->table("hash"); object ts=tr->table("string"); foreach (enumerate(1000),int x) { th[x]=x+"x"; ts[x+"y"]=x+"z"; } tr->close(); array ind=indices(db->table("hash")); array val=values(db->table("hash")); if (sizeof(ind-enumerate(1000)) || sizeof(enumerate(1000)-ind)) fail("hash indicices wrong"); if (sizeof(val-map(enumerate(1000),`+,"x")) || sizeof(map(enumerate(1000),`+,"x")-val)) fail("hash values wrong"); array ind=indices(db->table("string")); array val=values(db->table("string")); if (sizeof(ind-map(enumerate(1000),`+,"y")) || sizeof(map(enumerate(1000),`+,"y")-ind)) fail("string indices wrong"); if (sizeof(val-map(enumerate(1000),`+,"z")) || sizeof(map(enumerate(1000),`+,"z")-val)) fail("string values wrong"); ok(); #test scanner continuation rm("test.mird"); object db=Mird("test.mird"); object tr=db->transaction(); tr->new_hashkey_table("hash"); tr->new_stringkey_table("string"); object th=tr->table("hash"); object ts=tr->table("string"); foreach (enumerate(1000),int x) { th[x]=x+"x"; ts[x+"y"]=x+"z"; } tr->close(); mapping keys=([]); object sc=db->table("hash")->scanner(); foreach (indices(sc->read(100)),int ind) if (keys[ind]++) fail("duplicate entry hash:"+ind+" (1)\n"); int next=sc->next_key(); sc=db->table("hash")->scanner(next); foreach (indices(sc->read(100)),int ind) if (keys[ind]++) fail("duplicate entry hash:"+ind+" (1)\n"); next=sc->next_key(); sc=db->table("hash")->scanner(next); foreach (indices(sc->read(10000)),int ind) if (keys[ind]++) fail("duplicate entry hash:"+ind+" (1)\n"); if (sizeof(indices(keys)-enumerate(1000)) || sizeof(enumerate(1000)-indices(keys))) fail("hash indicices wrong"); keys=([]); sc=db->table("string")->scanner(); foreach (indices(sc->read(100)),string ind) if (keys[ind]++) fail("duplicate entry string:"+ind+" (1)\n"); next=sc->next_key(); sc=db->table("string")->scanner(next); foreach (indices(sc->read(100)),string ind) if (keys[ind]++) fail("duplicate entry string:"+ind+" (2)\n"); next=sc->next_key(); sc=db->table("string")->scanner(next); foreach (indices(sc->read(10000)),string ind) if (keys[ind]++) fail("duplicate entry string:"+ind+" (3)\n"); if (sizeof(indices(keys)-map(enumerate(1000),`+,"y")) || sizeof(map(enumerate(1000),`+,"y")-indices(keys))) fail("hash indicices wrong"); ok(); #chapter finish #test memory leaks gc(); if (Mird.Glue._debug_check_mem()) fail("leaks"); ok();