-- File: RandomIndexTest.mesa -- Contents: program to add and delete random numbers of CedarDB index entries -- Last edited by -- Rick Cattell on September 20, 1982 2:38 pm DIRECTORY DBStorage, DBTuplesConcrete, DBView, DBViewPrivate, IO, Process, Random, Rope, UserExec, UserExecExtras; RandomIndexTest: PROGRAM IMPORTS DBStorage, DBView, DBViewPrivate, IO, Process, Random, Rope, UserExec, UserExecExtras = BEGIN ROPE: TYPE = Rope.ROPE; in, out: IO.Handle; keys: LIST OF ROPE← NIL; value: DBStorage.TupleHandle; keyListLength: INT← 0; nIterations, maxInsertions: INT; cycleCount: INT; stopAtThisCycle: INT← 0; pleaseStop: BOOL← FALSE; paddingStringLength: INT← 5; paddingString: ROPE; index: DBStorage.IndexHandle; prefixArray: ARRAY [0..50) OF ROPE; prefixCount: INT← 10; averageCommitFrequency: INT; WhatNow: SIGNAL = CODE; SystemTSTuple: TYPE = REF tupleSet DBTuplesConcrete.TupleObject; TickTock: PROC = BEGIN cycleCount← cycleCount+1; IF Random.Choose[0, averageCommitFrequency] = 0 THEN BEGIN -- close and re-set-up database out.PutF["Closing & Re-opening..."]; DBView.CloseDatabase[]; []← DBView.OpenDatabase[databaseName: dbName, version: OldOnly]; value← index← DBViewPrivate.systemIndex; END; IF cycleCount=stopAtThisCycle THEN SIGNAL WhatNow; END; GenRandomKey: PROC RETURNS [ROPE] = -- prefix random key with a randomly chosen rope, and follow with padding BEGIN prefix: ROPE ← IF prefixCount#0 THEN prefixArray[Random.Choose[0, prefixCount-1]] ELSE NIL; RETURN[IO.PutFR[ "%g%g%g", IO.rope[prefix], IO.int[Random.Next[]], IO.rope[paddingString] ]]; END; GenPlainRandomKey: PROC RETURNS [ROPE] = -- same as above but without prefix, or padding after {RETURN[IO.PutFR[, IO.int[Random.Next[]] ]]}; PlayWithIndex: PROC = BEGIN out.PutF["Testing index...\n"]; THROUGH [1 .. nIterations] DO AddSomeEntries[]; DeleteSomeEntries[]; ENDLOOP; CheckEntries[]; END; AddSomeEntries: PROC = BEGIN key: ROPE; nToInsert: INT← Random.Choose[0, maxInsertions]; FOR j: INT IN [0..nToInsert) DO TickTock[]; IF pleaseStop THEN RETURN; key← GenRandomKey[]; DBStorage.InsertIntoIndex[index, key, value]; keyListLength← keyListLength + 1; keys← CONS[key, keys]; IF j MOD 10 = 0 THEN out.PutChar['+]; ENDLOOP; out.PutF["... Added %g index entries (now %g)\n", IO.int[nToInsert], IO.int[keyListLength]]; END; DeleteSomeEntries: PROC = BEGIN prevKey: LIST OF ROPE; mDeleted, estToDelete: INT; estToDelete← Random.Choose[0, keyListLength]; -- Delete approx estToDelete entries by deleting each one -- with probability of estToDelete/keyListLength: mDeleted← 0; prevKey← NIL; FOR keysT: LIST OF ROPE← keys, keysT.rest UNTIL keysT=NIL DO IF Random.Choose[0, keyListLength]<estToDelete THEN BEGIN TickTock[]; IF mDeleted MOD 10 = 0 THEN out.PutChar['-]; mDeleted← mDeleted+1; keyListLength← keyListLength-1; DBStorage.DeleteFromIndex[index, keysT.first, value]; IF prevKey=NIL THEN keys← keys.rest -- first elt of list deleted ELSE prevKey.rest← keysT.rest; -- remove it from keys array END ELSE prevKey← keysT; ENDLOOP; out.PutF["... Deleted %g index entries (now %g)\n", IO.int[mDeleted], IO.int[keyListLength]]; END; CheckEntries: PROC = BEGIN count: INT← 0; ish: DBStorage.IndexScanHandle; t: DBStorage.TupleHandle; out.PutF["Checking contents of index..."]; FOR keysT: LIST OF ROPE← keys, keysT.rest UNTIL keysT=NIL DO ish← DBStorage.OpenScanIndex[index, [keysT.first, keysT.first, TRUE, TRUE]]; IF (t←DBStorage.NextScanIndex[ish])= NIL THEN ERROR; -- lost an index entry! IF NOT DBView.Eq[t, value] THEN ERROR; -- wrong value associated with it DBStorage.CloseScanIndex[ish]; ENDLOOP; -- Check to see there are the right number of entries in the index ish← DBStorage.OpenScanIndex[index, ["", "\177", TRUE, TRUE]]; UNTIL DBStorage.NextScanIndex[ish]=NIL DO count← count+1 ENDLOOP; DBStorage.CloseScanIndex[ish]; -- Check that right number of entries in B-tree IF count#keyListLength+2 THEN ERROR; -- add 2 because using owner index, contains 2 system entries END; AskForInt: PROC [question: ROPE, default: INT← -1] RETURNS [v: INT] = -- Ask user question, return int with default value if user hits CR. BEGIN IF default=-1 THEN out.PutF["%g? ", IO.rope[question]] ELSE out.PutF["%g [%g]? ", IO.rope[question], IO.int[default]]; IF default#-1 AND in.PeekChar[]='\n THEN v← default ELSE v← in.GetInt[]; []← in.GetChar[]; -- skip over the CR RETURN[v] END; Main: PROC = BEGIN ENABLE Process.Aborted => GOTO Abort; keys← NIL; cycleCount← 15; keyListLength← 0; []← Random.Init[]; FOR i: INT IN [0..prefixCount) DO prefixArray[i]← GenPlainRandomKey[] ENDLOOP; [in, out]← IO.CreateTTYStreams["IndexTest"]; in← IO.CreateEditedStream[in, out]; out.PutF["Random DBIndex Test Program: Creating database..."]; []← DBView.OpenDatabase[databaseName: dbName, version: NewOnly]; index← DBViewPrivate.systemIndex; -- use the system index already created by DBView value← index; -- just use the index tuple itself as a value to store, it doesn't matter for now! UserExecExtras.DoIt[UserExec.GetExecHandle[], "← DBIndexImpl.CheckFlag← TRUE"]; UserExecExtras.DoIt[UserExec.GetExecHandle[], "← DBIndexImpl.deletionTurnedOn← TRUE"]; nIterations← AskForInt["\nHow many iterations", 10]; maxInsertions← AskForInt["Max insertions per iteration", 300]; stopAtThisCycle← AskForInt["Stop at cycle", 99999]; averageCommitFrequency← AskForInt["Mean re-open frequency", 300]; paddingStringLength← AskForInt["Key padding", 5]; paddingString← NIL; FOR j: INT IN [0.. paddingStringLength) DO paddingString← paddingString.Concat[" ..."] ENDLOOP; PlayWithIndex; out.PutF["Deleting index..."]; DBStorage.DestroyIndex[index]; out.PutF["Closing database..."]; DBView.CloseDatabase[]; out.PutF["Done. Bye.\n"]; EXITS Abort => {out.PutF["Aborting..."]; DBView.CloseDatabase[]; out.PutF["Done. Bye.\n"]}; END; dbName: ROPE ← "[Local]IndexTest"; Start: PROC = {Process.Detach[FORK Main[]]}; Start[]; END. To run: run ExtraCedar run CedarDB compile RandomIndexTest run RandomImpl run RandomIndexTest