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.DID ← NIL,
fileUse: ATOM ← NIL, -- 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: BOOL ← FALSE] 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:
BOOL ←
TRUE, 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.
STREAM ←
NIL] = {
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.
STREAM ←
NIL] = {
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] = {
};