-- 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