END;
model state
MaxNItems: CARDINAL = 1000;
MaxOldItems: CARDINAL = 100;
nItems: CARDINAL ← 0;
items: REF ItemArray ← NEW[ItemArray];
ItemArray: TYPE = ARRAY [0..MaxNItems) OF Item;
Item: TYPE = RECORD[k: ShortKey, v: ROPE];
ShortKey: TYPE = RECORD[ wordNum: [0..9), kval: CARDINAL ];
LongKey: TYPE = ARRAY [0..9) OF CARDINAL;
nOldItems: CARDINAL ← 0;
oldItems: REF OldItemArray ← NEW[OldItemArray];
OldItemArray: TYPE = ARRAY[0..MaxOldItems) OF Item;
ActionCodes: TYPE = {modify, delete};
interestingKey: CARDINAL ← 56920;
random actions
InsertARandomItem:
PROCEDURE
RETURNS[
BOOLEAN] =
BEGIN
item: Item;
IF nItems = MaxNItems THEN RETURN[FALSE];
item.k ← PickARandomNonEntryKey[];
item.v ← PickARandomValue[];
InsertInModel[item];
NoteAction[item.k, modify];
Change[item];
RETURN[TRUE];
END;
ChangeARandomEntry:
PROCEDURE
RETURNS[
BOOLEAN] =
BEGIN
item: Item;
IF nItems = 0 THEN RETURN[FALSE];
item.k ← PickARandomEntryKey[];
item.v ← PickARandomNewValueFor[item.k];
InsertInModel[item];
NoteAction[item.k, modify];
Change[item];
RETURN[TRUE];
END;
DeleteARandomEntry:
PROCEDURE
RETURNS[
BOOLEAN] =
BEGIN
k: ShortKey;
IF nItems = 0 THEN RETURN[FALSE];
k ← PickARandomEntryKey[];
DeleteFromModel[k];
NoteAction[k, delete];
Delete[k];
RETURN[TRUE];
END;
DeleteARandomOldEntry:
PROCEDURE
RETURNS[
BOOLEAN] =
BEGIN
k: ShortKey;
IF nOldItems = 0 THEN RETURN[FALSE];
k ← PickARandomOldKey[];
no need to delete it from model, and doing so would add it to the old list
NoteAction[k, delete];
Delete[k];
RETURN[TRUE];
END;
DeleteARandomNonEntry:
PROCEDURE
RETURNS[
BOOLEAN] =
BEGIN
k: ShortKey ← PickARandomNonEntryKey[];
NoteAction[k, delete];
Delete[k];
RETURN[TRUE];
END;
CheckARandomOldEntry:
PROCEDURE
RETURNS[
BOOLEAN] =
BEGIN
k: ShortKey;
v: ROPE;
IF nOldItems = 0 THEN RETURN[FALSE];
k ← PickARandomOldKey[];
v ← LookUpInModel[k];
IF LookUp[k] # v THEN ERROR;
RETURN[TRUE];
END;
CheckARandomNonEntry:
PROCEDURE
RETURNS[
BOOLEAN] =
BEGIN
k: ShortKey ← PickARandomNonEntryKey[];
IF LookUp[k] # NIL THEN ERROR;
RETURN[TRUE];
END;
LookUp:
PROC [k: ShortKey]
RETURNS [v:
ROPE] ~ {
longKey: LongKey ← ALL[0];
longKey[k.wordNum] ← k.kval;
v ← BackupBTree.GetFileInfo[LOOPHOLE[longKey]].name;
};
Delete:
PROC [k: ShortKey] ~ {
longKey: LongKey ← ALL[0];
longKey[k.wordNum] ← k.kval;
[] ← BackupBTree.DeleteFileInfo[LOOPHOLE[longKey]];
};
Change:
PROC [item: Item] ~ {
longKey: LongKey ← ALL[0];
longKey[item.k.wordNum] ← item.k.kval;
BackupBTree.SetFileInfo[universalFile: LOOPHOLE[longKey], name: item.v];
};
model support code
InitModel:
PROCEDURE =
BEGIN
nItems ← 0;
nOldItems ← 0;
END;
InsertInModel:
PROCEDURE[item: Item] =
BEGIN
x: CARDINAL;
FOR I:
CARDINAL
IN [0..nItems]
DO
IF items[I].k = item.k THEN {x ← I; EXIT};
IF I = nItems
OR items[I].k.kval > item.k.kval
THEN
BEGIN
IF nItems = MaxNItems THEN ERROR;
FOR J:
CARDINAL
DECREASING
IN [I..nItems)
DO
items[J+1] ← items[J];
ENDLOOP;
nItems ← nItems+1;
x ← I; EXIT;
END;
ENDLOOP;
items[x] ← item;
END;
DeleteFromModel:
PROCEDURE[k:
ShortKey] =
BEGIN
FOR I:
CARDINAL
IN [0..nItems)
DO
IF items[I].k = k
THEN
BEGIN
RememberAsOld[items[I]];
FOR J:
CARDINAL
IN (I..nItems)
DO
items[J-1] ← items[J];
ENDLOOP;
nItems ← nItems - 1;
END;
IF items[I].k.kval > k.kval THEN EXIT;
ENDLOOP;
END;
LookUpInModel:
PROCEDURE[k: ShortKey]
RETURNS[
ROPE] =
BEGIN
FOR I:
CARDINAL
IN [0..nItems)
DO
IF items[I].k = k THEN RETURN[items[I].v];
IF items[I].k.kval > k.kval THEN EXIT;
ENDLOOP;
RETURN[NIL];
END;
PickARandomEntryKey:
PROCEDURE
RETURNS[
ShortKey] =
BEGIN
IF nItems = 0 THEN ERROR;
RETURN[items[Random[] MOD nItems].k];
END;
PickARandomNonEntryKey:
PROCEDURE
RETURNS[
ShortKey] =
BEGIN
k: ShortKey;
DO
k ← [0,0];
WHILE k = [0,0] DO k ← [Random[] MOD 9, Random[]] ENDLOOP;
IF LookUpInModel[k] = NIL THEN RETURN[k];
ENDLOOP;
END;
PickARandomValue:
PROCEDURE
RETURNS[
ROPE] =
BEGIN
v: CARDINAL ← 0;
WHILE v = 0 DO v ← Random[] ENDLOOP;
RETURN[Convert.RopeFromCard[v]];
END;
PickARandomNewValueFor:
PROCEDURE[k: ShortKey]
RETURNS[
ROPE] =
BEGIN
old: ROPE ← LookUpInModel[k];
v: ROPE ← "";
IF old = NIL THEN ERROR;
v ← Convert.RopeFromCard[Random[]];
RETURN[v];
RememberAsOld:
PROCEDURE[i: Item] =
BEGIN
x: CARDINAL;
IF nOldItems # MaxOldItems
THEN
BEGIN
x ← nOldItems;
nOldItems ← nOldItems+1;
END
ELSE x ← Random[] MOD nOldItems;
oldItems[x] ← i;
END;
PickARandomOldKey:
PROCEDURE
RETURNS[
ShortKey] =
BEGIN
k: ShortKey;
IF nOldItems = 0 THEN ERROR;
DO
k ← oldItems[Random[] MOD nOldItems].k;
IF LookUpInModel[k] = NIL THEN RETURN[k];
ENDLOOP;
END;
NoteAction:
PROCEDURE[k:
ShortKey, act: ActionCodes] =
BEGIN
IF k.kval = interestingKey
THEN
BEGIN
rAct: Rope.
ROPE ←
SELECT act
FROM
modify => "modify",
delete => "delete",
ENDCASE => "other";
ttyOut.PutF["\n\tat tick = %g, performing %g on key = %g\n", IO.card[tick.tick], IO.rope[rAct], IO.card[k.kval]];
END;
END;
testing support
ttyOut: IO.STREAM;
TickRec: TYPE = RECORD [tick: LONG CARDINAL𡤀, stop, pause: BOOLEAN ← FALSE];
tick: REF TickRec ← NEW[TickRec];
InitTestSupport:
PROCEDURE =
BEGIN
[ , ttyOut] ← ViewerIO.CreateViewerStreams["test.log"];
ttyOut.PutF["here we go\N"];
tick.tick ← 0;
END;
DefineAction:
PROCEDURE[name: Rope.
ROPE, proc: ActionProcedure]
RETURNS[Action] =
{RETURN[NEW[ActionBody ← [name, proc, 0]]]};
DefinePhase:
PROCEDURE[list:
LIST
OF PhaseCase]
RETURNS[Phase] =
BEGIN
nItems: CARDINAL ← 0;
totalWeight: LONG CARDINAL ← 0;
totalWeightShort: CARDINAL ← 0;
phase: Phase;
i: CARDINAL;
FOR p:
LIST
OF PhaseCase ← list, p.rest
UNTIL p =
NIL
DO
nItems ← nItems + 1;
totalWeight ← totalWeight+LONG[p.first.weight];
totalWeightShort ← totalWeightShort+p.first.weight;
ENDLOOP;
IF nItems > MaxNItemsInPhase THEN ERROR;
IF totalWeight > MaxTotalWeightOfPhase THEN ERROR;
phase ← NEW[PhaseBody[nItems] ← [nItems, totalWeightShort, ]];
i ← 0;
FOR p:
LIST
OF PhaseCase ← list, p.rest
UNTIL p =
NIL
DO
phase.items[i] ← p.first;
i ← i + 1;
ENDLOOP;
RETURN[phase];
END;
PerformOneRandomAct:
PROCEDURE[phase: Phase] =
BEGIN
k: CARDINAL ← Random[] MOD phase.totalWeight;
DO
runningWeight: CARDINAL ← 0;
FOR I:
CARDINAL
IN [0..phase.nItems)
DO
runningWeight ← runningWeight + phase.items[I].weight;
IF k <= runningWeight
THEN
BEGIN
IF (phase.items[I].act.proc)[]
THEN
BEGIN
phase.items[I].act.count ← phase.items[I].act.count + 1;
tick.tick ← tick.tick+1;
RETURN;
END;
END;
ENDLOOP;
ENDLOOP;
END;