VolatilizeTestImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Bob Hagmann October 27, 1988 1:22:03 pm PDT
DIRECTORY
BasicTime,
Camelot,
Commander,
CommandTool,
Convert,
CountedVM,
File,
FileStream,
FS,
FSBackdoor,
IO,
Mach,
PBasics,
Process,
Random,
Rope,
YggDID,
YggDIDPrivate,
YggDIDMap,
YggDIDMapPrivate,
YggLock,
YggFixedNames,
YggEnvironment,
YggFile,
YggFileStream,
YggIndexMaint,
YggInternal,
YggMonitoringLog,
YggRep,
YggTransaction,
YggVolatileObjectCache;
VolatilizeTestImpl: CEDAR PROGRAM
IMPORTS BasicTime, Commander, CommandTool, Convert, CountedVM, FileStream, FSBackdoor, IO, PBasics, Process, Random, Rope, YggDID, YggRep, YggVolatileObjectCache
EXPORTS YggDID, YggDIDMap, YggFixedNames, YggMonitoringLog, YggLock, YggTransaction, YggIndexMaint, YggInternal, YggFile, YggFileStream
= BEGIN
ROPE: TYPE = Rope.ROPE;
Exported junk
Contents: PUBLIC Rope.ROPE ← "$contents";
Inlinks: PUBLIC Rope.ROPE ← "$inlinks";
Outlinks: PUBLIC Rope.ROPE ← "$outlinks";
Parents: PUBLIC Rope.ROPE ← "$parents";
Children: PUBLIC Rope.ROPE ← "$children";
ParentContainers: PUBLIC Rope.ROPE ← "$parent-containers";
ChildContainers: PUBLIC Rope.ROPE ← "$child-containers";
AutoIndices: PUBLIC Rope.ROPE ← "$auto-indices";
IndexPrefix: PUBLIC Rope.ROPE ← "$index-";
IndexPrefixSize: PUBLIC INT ← Rope.Length[IndexPrefix];
notice: PUBLIC YggMonitoringLog.ProcsRecord ← [];
BigRope: ROPE ← "Four score and seven years ago, our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great blah blah blah";
LittleRopes: ARRAY [0..3) OF ROPE ← ["foo", "bar", "bleah"];
attrNameArray: ARRAY [0..8] OF ROPE ← ["attr0", "thisisattribute1", "two", "attribute three is fairly long", "but then again, attribute four is longer than three", "and attribute five is longer than three and four together", "6", "sept", "eight"];
fieldNameArray: ARRAY [1..5] OF ROPE ← [NIL, "field2", "field3", "the name for field 4 is quite long", "field5"];
DID: PUBLIC TYPE ~ REF DIDRep;
DIDRep: PUBLIC TYPE ~ YggDIDPrivate.DIDRep;
Document: TYPE = REF DocumentRep;
DocumentRep: PUBLIC TYPE = YggDIDMapPrivate.DocumentRep;
FileHandle: TYPE = YggInternal.FileHandle;
FileHandleRep: PUBLIC TYPE = RECORD [
did: YggDID.DIDNIL,
fileUse: ATOMNIL, -- use of the file (e. g., $contents)
fileData: REF FileDataRep
];
Failed: PUBLIC ERROR [why: YggEnvironment.LockFailure] = CODE;
Set: PUBLIC PROC [ trans: YggEnvironment.TransID, lock: YggLock.LockID, mode: YggLock.LockMode, wait: BOOLFALSE] RETURNS [granted: BOOL ← TRUE] ~ {};
MakeLockID: PUBLIC PROC [did: DID] RETURNS [lock: YggLock.LockID] ~ {
Construct the lock identifier for the did
segmentId: Camelot.segmentIdT;
offset: Mach.vmOffsetT;
segmentId ← [did.didHigh];
offset ← did.didLow;
RETURN[[did: did, subEntity: [segmentId, offset]]];
};
TransID: TYPE = YggEnvironment.TransID; -- really a Camelot.tidT
EqualTrans: PUBLIC PROC [transID1: TransID, transID2: TransID] RETURNS [equal: BOOL] ~ {
IF transID1.top = transID2.top AND transID1.bottom = transID2.bottom THEN RETURN [TRUE] ELSE RETURN [FALSE];
};
IsNullTrans: PUBLIC PROC [ transID: YggTransaction.TransID] RETURNS [null: BOOL] ~ {
RETURN [transID = YggEnvironment.nullTransID];
};
IsTopLevel: PUBLIC PROC [transID: TransID] RETURNS [topLevel: BOOL ← TRUE] ~ {
};
UpdateDocList: LIST OF DocUpdate ← NIL;
DocUpdate: TYPE = RECORD [
transID: TransID,
inUse: BOOL,
vDocs: LIST OF YggRep.VDoc
];
NotePossibleDocumentUpdate: PUBLIC PROC [transID: TransID, vDoc: YggRep.VDoc] ~ {
unusedDocUpdate: LIST OF DocUpdate ← NIL;
FOR udl: LIST OF DocUpdate ← UpdateDocList, udl.rest UNTIL udl = NIL DO
IF EqualTrans[transID, udl.first.transID] THEN {
FOR lovd: LIST OF YggRep.VDoc ← udl.first.vDocs, lovd.rest UNTIL lovd = NIL DO
IF EqualDIDs[vDoc.did, lovd.first.did] THEN EXIT;
REPEAT FINISHED => {
udl.first.vDocs ← CONS[vDoc, udl.first.vDocs];
};
ENDLOOP;
EXIT;
};
IF unusedDocUpdate = NIL AND ~udl.first.inUse THEN unusedDocUpdate ← udl;
REPEAT FINISHED => {
IF unusedDocUpdate # NIL THEN {
unusedDocUpdate.first.transID ← transID;
unusedDocUpdate.first.inUse ← TRUE;
unusedDocUpdate.first.vDocs ← LIST[vDoc];
}
ELSE UpdateDocList ← CONS[[transID, TRUE, LIST[vDoc]], UpdateDocList];
};
ENDLOOP;
};
GetPossibleDocumentUpdates: PUBLIC PROC [transID: TransID] RETURNS [ vDocs: LIST OF YggRep.VDoc ← NIL] ~ {
FOR udl: LIST OF DocUpdate ← UpdateDocList, udl.rest UNTIL udl = NIL DO
IF EqualTrans[transID, udl.first.transID] THEN {
RETURN[udl.first.vDocs];
};
ENDLOOP;
};
GetParent: PUBLIC PROC [ transID: YggTransaction.TransID] RETURNS [transFound: BOOLTRUE, parentTransID: YggTransaction.TransID ← YggEnvironment.nullTransID] ~ {
};
NewValueForAttribute: PUBLIC PROC [did: YggDID.DID, tid: Camelot.tidT, attributeName: Rope.ROPE, oldValues: LIST OF LIST OF YggRep.AttributeValue, newValues: LIST OF LIST OF YggRep.AttributeValue] ~ {
Note that this did/attributeName has a new value.
};
NewValueForMetaAttribute: PUBLIC PROC [did: YggDID.DID, tid: Camelot.tidT, metaAttributesChanged: LIST OF YggRep.metaAttributeMod] ~ {
Note that this did/metaattribute has a new value. Called during Pre-Commit.
};
NewValueForAttributeCommitStatus: PUBLIC PROC [did: YggDID.DID, tid: Camelot.tidT, commited: BOOL] ~ {
Note state of previous NewValueForAttribute or NewValueForMetaAttribute call(s). Called during Commit or Abort.
};
EqualDIDs: PUBLIC PROC [did1: DID, did2: DID] RETURNS [equal: BOOL] = {
Compare the dids.
IF did1.didHigh = did2.didHigh AND did1.didLow = did2.didLow THEN RETURN [TRUE] ELSE RETURN [FALSE]
};
SwapLinkInfo: PUBLIC PROC [doc: YggInternal.Document, newFromDID, newToDID: YggDID.DID, newLinkType: Rope.ROPE] RETURNS [oldFromDID, oldToDID: YggDID.DID, oldLinkType: Rope.ROPE] ~ {
};
Exported good stuff
OpenDocumentFromDID: PUBLIC PROC [did: YggDID.DID, tid: Camelot.tidT] RETURNS [doc: YggInternal.Document ← NIL] = {
FOR lokd: LIST OF DIDStuff ← KnownDIDs, lokd.rest UNTIL lokd = NIL DO
IF EqualDIDs[lokd.first.did, did] THEN {doc ← lokd.first.doc; EXIT};
ENDLOOP;
};
GetComponentFiles: PUBLIC PROC [doc: Document] RETURNS [componentFiles: LIST OF YggInternal.FileHandle] ~ {
RETURN[componentFiles ← doc.componentFiles];
};
AddComponentFile: PUBLIC PROC [doc: Document, componentFile: YggInternal.FileHandle, tid: Camelot.tidT] ~ {
lastCF: LIST OF YggInternal.FileHandle ← NIL;
FOR files: LIST OF YggInternal.FileHandle ← doc.componentFiles, files.rest UNTIL files = NIL DO
lastCF ← files;
ENDLOOP;
IF lastCF = NIL THEN doc.componentFiles ← CONS[componentFile, NIL]
ELSE lastCF.rest ← CONS[componentFile, NIL];
};
FileFromComponentFiles: PUBLIC PROC [componentFiles: LIST OF YggInternal.FileHandle, fileUse: ATOM] RETURNS [file: FileHandle ← NIL] ~ {
FOR cf: LIST OF FileHandle ← componentFiles, cf.rest UNTIL cf = NIL DO
IF cf.first.fileUse = fileUse THEN {
RETURN[cf.first];
};
ENDLOOP;
};
StreamFromComponentFilesAndTid: PUBLIC PROC [componentFiles: LIST OF YggInternal.FileHandle, fileUse: ATOM, tid: Camelot.tidT] RETURNS [stream: IO.STREAMNIL] = {
FOR cf: LIST OF YggInternal.FileHandle ← componentFiles, cf.rest UNTIL cf = NIL DO
IF cf.first.fileUse = fileUse THEN {
stream ← StreamFromOpenFileAndTid[cf.first, tid];
RETURN;
};
ENDLOOP;
};
fileLengthZero: SIGNAL = CODE;
StreamFromOpenFileAndTid: PUBLIC PROC [file: FileHandle, tid: Camelot.tidT] RETURNS [stream: IO.STREAMNIL] = {
fsOpenFile: FS.OpenFile;
fsOpenFile ← FSBackdoor.CreateProcsOpenFile[clientFile: file.fileData, fileProcs: FileProcs];
stream ← FileStream.StreamFromOpenFile[fsOpenFile, write, start, [FALSE, FALSE, TRUE], [1,1]];
IF file.fileData.bytes # IO.GetLength[stream] THEN ERROR;
IF file.fileData.bytes # IO.GetLength[stream] THEN ERROR;
};
PagesForBytes: PUBLIC PROC [bytes: CARD] RETURNS [pages: YggFile.PageCount] ~ {
IF bytes = 0 THEN RETURN [0] ELSE RETURN[PBasics.ShiftRight[[int[(bytes-1)]], YggFile.logBytesPerPage].int + 1];
};
My files
FileProcs: REF FSBackdoor.FileProcs ← FSBackdoor.CreateFileProcs[GetClass, SameFile, GetName, GetInfo, SetPageCount, SetByteCountAndCreatedTime, Read, Write, Close];
FileDataRep: TYPE = RECORD [
pages: INT,
bytes: INT,
pageStorage: LIST OF pageStorageRep,
tid: Camelot.tidT
];
pageStorageRep: TYPE = RECORD [
pageNo: INT,
pageAddress: CountedVM.Handle
];
Create: PUBLIC PROC [size: YggFile.PageCount, did: YggDID.DID, fileUse: ATOM, nearToDid: YggDID.DID, tid: Camelot.tidT] RETURNS [file: FileHandle ← NIL] ~ {
file ← NEW[FileHandleRep ← [did: did, fileUse: fileUse, fileData: NEW[FileDataRep ← [pages: size, bytes: 0, pageStorage: NIL, tid: tid]]]];
FOR nowPage: INT IN [0..size) DO
file.fileData.pageStorage ← CONS[[nowPage, CountedVM.Allocate[File.wordsPerPage]], file.fileData.pageStorage];
ENDLOOP;
};
GetClass: PROC [clientFile: REF] RETURNS [ATOM] = {
RETURN [$YggdrasilTest];
};
SameFile: PROC [clientFile1, clientFile2: REF] RETURNS [BOOL] = {
ERROR;
};
GetName: PROC [clientFile: REF] RETURNS [fullFName, attachedTo: Rope.ROPE] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
RETURN [NIL, NIL];
};
ENDCASE => ERROR;
};
GetInfo: PROC [clientFile: REF] RETURNS [keep: CARDINAL ← 1, pages, bytes: INT,
created: BasicTime.GMT ← BasicTime.Now[], lock: FS.Lock ← write, fileType: FS.FileType] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
pages ← fileData.pages;
bytes ← fileData.bytes;
};
ENDCASE => ERROR;
};
SetPageCount: PROC [clientFile: REF, pages: INT] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
maxPage: INT ← -1;
fileData.pages ← pages;
FOR lops: LIST OF pageStorageRep ← fileData.pageStorage, lops.rest UNTIL lops = NIL DO
IF lops.first.pageNo > maxPage THEN maxPage ← lops.first.pageNo;
ENDLOOP;
FOR nowPage: INT IN (maxPage..pages) DO
fileData.pageStorage ← CONS[[nowPage, CountedVM.Allocate[File.wordsPerPage]], fileData.pageStorage];
ENDLOOP;
};
ENDCASE => ERROR;
};
SetByteCountAndCreatedTime: PROC [clientFile: REF, bytes: INT,
created: BasicTime.GMT] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
fileData.bytes ← bytes;
IF bytes # fileData.bytes THEN ERROR;
};
ENDCASE => ERROR;
};
notFirst: INT ← 0;
Read: UNSAFE PROC [clientFile: REF, from, nPages: INT, to: LONG POINTER] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
toPtr: LONG POINTER ← to;
nPagesLeft: INT ← nPages;
FOR nowPage: INT IN [from .. from + nPages) DO
IF nowPage # from THEN notFirst ← notFirst + 1;
FOR lops: LIST OF pageStorageRep ← fileData.pageStorage, lops.rest UNTIL lops = NIL DO
IF lops.first.pageNo = nowPage THEN {
TRUSTED {PBasics.Move[dst: toPtr, src: lops.first.pageAddress.pointer, nWords: File.wordsPerPage/2]; };
toPtr ← toPtr + File.wordsPerPage*UNITS[WORD];
EXIT;
};
REPEAT FINISHED => ERROR;
ENDLOOP;
ENDLOOP;
};
ENDCASE => ERROR;
};
Write: PROC [clientFile: REF, to: INT, nPages: INT, from: LONG POINTER] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
fromPtr: LONG POINTER ← from;
nPagesLeft: INT ← nPages;
FOR nowPage: INT IN [to .. to + nPages) DO
FOR lops: LIST OF pageStorageRep ← fileData.pageStorage, lops.rest UNTIL lops = NIL DO
IF lops.first.pageNo = nowPage THEN {
TRUSTED {PBasics.Move[dst: lops.first.pageAddress.pointer, src: fromPtr, nWords: File.wordsPerPage/2]; };
fromPtr ← fromPtr + File.wordsPerPage*UNITS[WORD];
EXIT;
};
REPEAT FINISHED => ERROR;
ENDLOOP;
ENDLOOP;
};
ENDCASE => ERROR;
};
Close: PROC [clientFile: REF] = {
};
Global data
NextDID: DIDRep ← [33, 400];
KnownDIDs: LIST OF DIDStuff ← NIL;
NumberOfKnownDIDs: INT ← 0;
DIDStuff: TYPE = RECORD [
did: DID,
doc: Document,
contents: YggRep.TypedPrimitiveElement,
attributes: LIST OF YggRep.Attribute ← NIL
];
NextTransCount: CARD ← 10001;
Local procs
GetNextTrans: PROC RETURNS [transID: YggTransaction.TransID] ~ {
NextTransCount ← NextTransCount + 1;
transID ← [top: [lowTicker: NextTransCount], bottom: []];
};
GetNextDID: PROC RETURNS [did: YggDID.DID] ~ {
did ← NEW[YggDIDPrivate.DIDRep ← [NextDID.didHigh, NextDID.didLow]];
NextDID.didLow ← NextDID.didLow + 1;
};
GetNextDIDWithEmptyDoc: PROC RETURNS [did: YggDID.DID, doc: Document, didStuff: LIST OF DIDStuff] ~ {
did ← GetNextDID[];
doc ← NEW[DocumentRep ← [did: did, name: NIL, componentFiles: NIL]];
didStuff ← KnownDIDs ← CONS[[did: did, doc: doc], KnownDIDs];
NumberOfKnownDIDs ← NumberOfKnownDIDs + 1;
};
DoCommit: PROC [transID: YggTransaction.TransID] ~ {
YggRep.PreCommit[transID];
YggRep.Commit[transID];
FOR udl: LIST OF DocUpdate ← UpdateDocList, udl.rest UNTIL udl = NIL DO
IF EqualTrans[transID, udl.first.transID] THEN {
udl.first.inUse ← FALSE;
EXIT;
};
ENDLOOP;
};
VolatilizeTest Command
VolatilizeTestProc: Commander.CommandProc = {
[cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...]
MakeUpTPE: PROC RETURNS [tpe: YggRep.TypedPrimitiveElement] ~ {
tpe.docType ← Random.ChooseInt[randomStream, 1, 8];
SELECT tpe.docType FROM
YggRep.int => {
tpe.bits ← NEW[INT ← Random.ChooseInt[randomStream, 1, 1066]];
};
YggRep.rope => {
tpe.bits ← BigRope;
};
YggRep.shortRope => {
randr: INT = Random.ChooseInt[randomStream, 0, 2];
tpe.bits ← LittleRopes[randr];
};
YggRep.float => {
rr: REAL32;
ii: INT ;
ii ← Random.ChooseInt[randomStream, 1, 1492];
rr ← ii;
tpe.bits ← NEW[REAL32 ← rr];
};
YggRep.date => {
newData: YggRep.AccurateGMT;
newData ← NEW[YggRep.AccurateGMTRep ← [BasicTime.Now[], Random.ChooseInt[randomStream, 1, 1789]]];
tpe.bits ← newData;
};
YggRep.did => {
newDID: DID;
newDID ← GetNextDID[];
tpe.bits ← newDID;
};
YggRep.uninterpretedBytes => {
noBytes: INT ← Random.ChooseInt[randomStream, 1, 1920];
theBytes: REF YggRep.BitsRep;
theBytes ← NEW[YggRep.BitsRep[noBytes]];
theBytes.validBytes ← Random.ChooseInt[randomStream, 1, noBytes];
FOR byteNo: CARD IN [0..theBytes.validBytes) DO
theBytes.b[byteNo] ← Random.ChooseInt[randomStream, 1, 255];
ENDLOOP;
tpe.bits ← theBytes;
};
8 => {
noBytes: INT ← Random.ChooseInt[randomStream, 1, 1920];
theBytes: REF YggRep.BitsRep;
tpe.docType ← Random.ChooseInt[randomStream, YggRep.lastReservedDocType+1, YggRep.lastReservedDocType+1334];
theBytes ← NEW[YggRep.BitsRep[noBytes]];
theBytes.validBytes ← Random.ChooseInt[randomStream, 1, noBytes];
FOR byteNo: CARD IN [0..theBytes.validBytes) DO
theBytes.b[byteNo] ← Random.ChooseInt[randomStream, 1, 255];
ENDLOOP;
tpe.bits ← theBytes;
};
ENDCASE => ERROR;
};
CompareTPE: PROC [tpe1: YggRep.TypedPrimitiveElement, tpe2: YggRep.TypedPrimitiveElement] ~ {
IF tpe1.docType # tpe2.docType THEN ERROR;
SELECT tpe1.docType FROM
YggRep.int => {
vInt: REF INT;
mInt: REF INT;
vInt ← NARROW[tpe1.bits];
mInt ← NARROW[tpe2.bits];
IF vInt^ # mInt^ THEN ERROR;
};
YggRep.rope => {
biggaRope: ROPE;
biggaRope ← NARROW[tpe1.bits];
IF ~Rope.Equal[biggaRope, BigRope] THEN ERROR;
};
YggRep.shortRope => {
smallaRope: ROPE;
listRope: ROPE;
smallaRope ← NARROW[tpe1.bits];
listRope ← NARROW[tpe2.bits];
IF ~Rope.Equal[smallaRope, listRope] THEN ERROR;
};
YggRep.float => {
vReal: REF REAL32;
mReal: REF REAL32;
vReal ← NARROW[tpe1.bits];
mReal ← NARROW[tpe2.bits];
IF vReal^ # mReal^ THEN ERROR;
};
YggRep.date => {
vDate: YggRep.AccurateGMT;
mDate: YggRep.AccurateGMT;
vDate ← NARROW[tpe1.bits];
mDate ← NARROW[tpe2.bits];
IF BasicTime.Period[vDate.gmt, mDate.gmt] # 0 THEN ERROR;
IF vDate.usecs # mDate.usecs THEN ERROR;
};
YggRep.did => {
vDID: DID;
mDID: DID;
vDID ← NARROW[tpe1.bits];
mDID ← NARROW[tpe2.bits];
IF ~YggDID.EqualDIDs[vDID, mDID] THEN ERROR;
};
YggRep.uninterpretedBytes => {
vUnintBytes: REF YggRep.BitsRep;
mUnintBytes: REF YggRep.BitsRep;
vUnintBytes ← NARROW[tpe1.bits];
mUnintBytes ← NARROW[tpe2.bits];
IF vUnintBytes.validBytes # mUnintBytes.validBytes THEN ERROR;
FOR byteNo: CARD IN [0..vUnintBytes.validBytes) DO
IF vUnintBytes.b[byteNo] # mUnintBytes.b[byteNo] THEN ERROR;
ENDLOOP;
};
IN [YggRep.lastReservedDocType+1 .. YggRep.lastReservedDocType+1334] => {
vUnintBytes: REF YggRep.BitsRep;
mUnintBytes: REF YggRep.BitsRep;
vUnintBytes ← NARROW[tpe1.bits];
mUnintBytes ← NARROW[tpe2.bits];
IF vUnintBytes.validBytes # mUnintBytes.validBytes THEN ERROR;
FOR byteNo: CARD IN [0..vUnintBytes.validBytes) DO
IF vUnintBytes.b[byteNo] # mUnintBytes.b[byteNo] THEN ERROR;
ENDLOOP;
};
ENDCASE => ERROR;
};
CheckADID: PROC [lokd: LIST OF DIDStuff] ~ {
vDoc: YggRep.VDoc ← NIL;
trans: YggTransaction.TransID;
vDocAttCount: INT ← 0;
savedAttCount: INT ← 0;
YggVolatileObjectCache.InvalidateDID[did: lokd.first.did, transID: YggEnvironment.nullTransID];
IF YggVolatileObjectCache.LookupDIDInCache[did: lokd.first.did, transID: YggEnvironment.nullTransID, mode: read] # NIL THEN ERROR;
trans ← GetNextTrans[] ;
vDoc ← YggRep.VolatizeFromDID[transID: trans, did: lokd.first.did,
access: readOnly, lock: [read, wait], metaAttributesOnly: FALSE];
IF ~EqualDIDs[vDoc.did, lokd.first.did] THEN ERROR;
CompareTPE[vDoc.contents, lokd.first.contents];
FOR aL: LIST OF YggRep.Attribute ← lokd.first.attributes, aL.rest UNTIL aL = NIL DO
FOR aLVDoc: LIST OF YggRep.Attribute ← vDoc.attributes, aLVDoc.rest UNTIL aLVDoc = NIL DO
IF Rope.Equal[aL.first.attributeName, aLVDoc.first.attributeName] THEN {
savedValue: LIST OF YggRep.AttributeValue ← aL.first.value;
vDocValue: LIST OF YggRep.AttributeValue ← aLVDoc.first.value;
FOR loav: LIST OF YggRep.AttributeValue ← vDocValue, loav.rest UNTIL loav = NIL DO
savedValueSet: LIST OF YggRep.TypedPrimitiveElement;
IF savedValue = NIL THEN ERROR;
savedValueSet ← savedValue.first.valueSet;
IF ~Rope.Equal[savedValue.first.fieldName, loav.first.fieldName] THEN ERROR;
FOR vtpeList: LIST OF YggRep.TypedPrimitiveElement ← loav.first.valueSet, vtpeList.rest UNTIL vtpeList = NIL DO
IF savedValueSet = NIL THEN ERROR;
CompareTPE[vtpeList.first, savedValueSet.first];
savedValueSet ← savedValueSet.rest;
ENDLOOP;
IF savedValueSet # NIL THEN ERROR;
savedValue ← savedValue.rest;
ENDLOOP;
IF savedValue # NIL THEN ERROR;
EXIT;
};
REPEAT FINISHED => ERROR;
ENDLOOP;
savedAttCount ← savedAttCount + 1;
ENDLOOP;
FOR aL: LIST OF YggRep.Attribute ← vDoc.attributes, aL.rest UNTIL aL = NIL DO
vDocAttCount ← vDocAttCount + 1;
ENDLOOP;
IF vDocAttCount # savedAttCount THEN ERROR;
DoCommit[trans];
};
argv: CommandTool.ArgumentVector;
out: IO.STREAM;
randomStream: Random.RandomStream;
noisy: BOOLFALSE;
offset: INT ← 0;
noTests: INT;
out ← cmd.out;
argv ← CommandTool.Parse[cmd: cmd ! CommandTool.Failed => {msg ← errorMsg; GO TO failed}];
IF argv.argc < 2 THEN GOTO failed;
IF Rope.InlineFetch[argv[1], 0] = '- THEN {
c: CHAR;
IF argv[1].Length[] # 2 THEN GOTO failed;
c ← argv[1].InlineFetch[1] ;
SELECT c FROM
'n => noisy ← TRUE;
ENDCASE;
offset ← 1;
};
noTests ← Convert.IntFromRope[argv[1+offset] ! Convert.Error => GOTO failed];
KnownDIDs ← NIL;
NumberOfKnownDIDs ← 0;
UpdateDocList ← NIL;
NextDID.didHigh ← LOOPHOLE[BasicTime.Now[], PBasics.LongNumber].lo;
[] ← GetNextDID[];
IF noTests <= 0 THEN RETURN;
randomStream ← Random.Create[range: 16384, seed: -1] ;
FOR loopCount: INT IN (0..noTests] DO
rand: INT ← Random.ChooseInt[randomStream, 0, 24];
Process.CheckForAbort[];
IF loopCount = noTests THEN rand ← 0;
SELECT rand FROM
IN [0..3) => { -- volatalize and look up old did
lokd: LIST OF DIDStuff;
IF NumberOfKnownDIDs <= 0 THEN LOOP;
FOR lokd ← KnownDIDs, lokd.rest UNTIL lokd = NIL DO
CheckADID[lokd];
ENDLOOP;
IF noisy THEN out.PutF["\nLook Up All Old Dids\n\n"];
};
IN [3..13) => { -- make new doc with a contents
newDID: DID;
doc: Document;
didStuff: LIST OF DIDStuff;
contents: YggRep.TypedPrimitiveElement;
vDoc: YggRep.VDoc;
trans: YggTransaction.TransID;
trans ← GetNextTrans[] ;
[newDID, doc, didStuff] ← GetNextDIDWithEmptyDoc[];
vDoc ← YggRep.VolatizeFromDID[trans, newDID, readWrite, [write, wait]];
contents ← MakeUpTPE[];
didStuff.first.contents ← contents;
vDoc.contents ← contents;
vDoc.contentsChanged ← TRUE;
DoCommit[trans];
IF noisy THEN out.PutF["Make new doc: did= %g\n", IO.card[newDID.didLow] ];
};
IN [8..16) => { -- volatalize and look up old did
rand: INT;
lokd: LIST OF DIDStuff;
IF NumberOfKnownDIDs <= 0 THEN LOOP;
rand ← Random.ChooseInt[randomStream, 0, MIN[16384, NumberOfKnownDIDs]];
FOR lokd ← KnownDIDs, lokd.rest UNTIL lokd = NIL DO
rand ← rand - 1;
IF rand <= 0 THEN EXIT;
ENDLOOP;
IF lokd = NIL THEN LOOP;
CheckADID[lokd];
IF noisy THEN out.PutF["look up old did: did= %g\n", IO.card[lokd.first.did.didLow] ];
};
IN [16..24) => { -- add attribute to did
rand: INT;
trans: YggTransaction.TransID;
lokd: LIST OF DIDStuff;
attrName: ROPE;
noAttrVals: INT ;
property: YggRep.Attribute;
fieldTaken: ARRAY [1..5] OF BOOL ← ALL[FALSE];
vDoc: YggRep.VDoc ← NIL;
IF NumberOfKnownDIDs <= 0 THEN LOOP;
rand ← Random.ChooseInt[randomStream, 0, MIN[16384, NumberOfKnownDIDs]];
FOR lokd ← KnownDIDs, lokd.rest UNTIL lokd = NIL DO
rand ← rand - 1;
IF rand <= 0 THEN EXIT;
ENDLOOP;
IF lokd = NIL THEN LOOP;
trans ← GetNextTrans[] ;
vDoc ← YggRep.VolatizeFromDID[transID: trans, did: lokd.first.did,
access: readWrite, lock: [write, wait], metaAttributesOnly: FALSE];
IF ~EqualDIDs[vDoc.did, lokd.first.did] THEN ERROR;
IF vDoc.contents.docType # lokd.first.contents.docType THEN ERROR;
FOR tryNo: INT IN [0..7] DO
propExists: BOOL ← FALSE;
rand ← Random.ChooseInt[randomStream, 0, 8];
attrName ← attrNameArray[rand];
FOR aL: LIST OF YggRep.Attribute ← vDoc.attributes, aL.rest UNTIL aL = NIL DO
IF Rope.Equal[aL.first.attributeName, attrName] THEN {
propExists ← TRUE;
EXIT;
};
ENDLOOP;
IF ~propExists THEN EXIT;
attrName ← NIL;
ENDLOOP;
IF attrName = NIL THEN {DoCommit[trans]; LOOP;};
noAttrVals ← Random.ChooseInt[randomStream, 1, 5];
property.value ← NIL;
FOR attrValNo: INT IN [0..noAttrVals) DO
attrVal: YggRep.AttributeValue;
fni: INT;
fni ← noAttrVals ← Random.ChooseInt[randomStream, 1, 5];
IF fieldTaken[fni] THEN LOOP;
fieldTaken[fni] ← TRUE;
attrVal.fieldName ← fieldNameArray[fni];
attrVal.valueSet ← NIL;
FOR tpeNo: INT IN [1..fni] DO
attrVal.valueSet ← CONS[MakeUpTPE[], attrVal.valueSet];
ENDLOOP;
property.value ← CONS[attrVal, property.value];
ENDLOOP;
property.attributeName ← attrName;
vDoc.attributes ← CONS[property, vDoc.attributes];
lokd.first.attributes ← CONS[property, lokd.first.attributes];
vDoc.namesOfAttributesChanged ← LIST[attrName];
DoCommit[trans];
IF noisy THEN out.PutF["add attribute to old did: did= %g\n", IO.card[lokd.first.did.didLow]];
};
ENDCASE;
ENDLOOP;
EXITS
failed => {result ← $Failure};
};
Initialization
Init: PROC = {
Commander.Register["VolatilizeTest", VolatilizeTestProc, "VolatilizeTest noTests"];
};
Init[];
END.