DIRECTORY
Basics USING [UnsafeBlock],
PBasics USING [charsPerWord, RawBytes],
Camelot USING [tidT],
IO USING [Close, PutChar, PutRope, STREAM, UnsafePutBlock],
Process USING [MsecToTicks, Pause],
Rope USING [Equal, Length, ROPE],
YggDID USING [DID, EqualDIDs],
YggDIDPrivate USING [DIDRep],
YggDIDMap USING [AddComponentFile, GetComponentFiles, OpenDocumentFromDID, SwapLinkInfo],
YggFile USING [Create, FileFromComponentFiles, FileHandle, PagesForBytes, StreamFromOpenFileAndTid],
YggFixedNames USING [Inlinks, Outlinks],
YggIndexMaint USING [NewValueForAttribute, NewValueForAttributeCommitStatus, NewValueForMetaAttribute],
YggInternal USING [Document, FileHandle],
YggRep USING [AccurateGMT, AccurateGMTRep, AccurateGMTRepByteSize, Attribute, AttributePreamble, AttributeValue, BitsRep, date, did, DocType, float, int, lastReservedDocType, LatchVDoc, linkMod, metaAttributeMod, rope, shortRope, SizeOfBits, TypedPrimitiveElement, unknown, uninterpretedBytes, UnlatchVDoc, VDoc],
YggEnvironment USING [nullDID, nullTransID, TransID],
YggTransaction USING [GetPossibleDocumentUpdates, IsTopLevel],
YggVolatileObjectCache USING [InvalidateDID, PromoteToParent, ReserveDIDInCache, UnreserveDIDInCache];
Exported conversion procedures
StabilizeMetaAttributes:
PUBLIC
PROC [transID: YggEnvironment.TransID, did:
DID, vDoc: YggRep.VDoc, meta: YggFile.FileHandle, attributesStream:
IO.
STREAM] ~ {
applyLinkMods:
PROC [links:
LIST
OF YggRep.AttributeValue, linksChanged:
LIST
OF YggRep.linkMod]
RETURNS [newLinks:
LIST
OF YggRep.AttributeValue] ~ {
newLinks ← links;
FOR lolm:
LIST
OF YggRep.linkMod ← linksChanged, lolm.rest
UNTIL lolm =
NIL
DO
FOR loav:
LIST
OF YggRep.AttributeValue ← newLinks, loav.rest
UNTIL loav =
NIL
DO
IF Rope.Equal[lolm.first.linkName, loav.first.fieldName]
THEN {
IF lolm.first.add
THEN {
-- add the link in
loav.first.valueSet ← CONS[[YggRep.did, lolm.first.linkValue], loav.first.valueSet];
EXIT;
}
ELSE {
-- remove the link
gotOne: BOOL ← FALSE;
prevTPE: LIST OF YggRep.TypedPrimitiveElement ← NIL;
FOR lotpe:
LIST
OF YggRep.TypedPrimitiveElement ← loav.first.valueSet, lotpe.rest
UNTIL lotpe =
NIL
DO
linkDID: DID;
IF lotpe.first.docType # YggRep.did THEN ERROR;
linkDID ← NARROW[lotpe.first.bits];
IF YggDID.EqualDIDs[linkDID, lolm.first.linkValue]
THEN {
gotOne ← TRUE;
IF prevTPE = NIL THEN loav.first.valueSet ← lotpe.rest
ELSE prevTPE.rest ← lotpe.rest;
LOOP;
};
prevTPE ← lotpe;
ENDLOOP;
IF ~gotOne THEN ERROR;
};
};
REPEAT
FINISHED =>
IF lolm.first.add
THEN {
newLinks ← CONS[[lolm.first.linkName, LIST[[YggRep.did, lolm.first.linkValue]]], newLinks];
};
ENDLOOP;
ENDLOOP;
};
IF attributesStream = NIL THEN attributesStream ← YggFile.StreamFromOpenFileAndTid[meta, transID];
FOR macl:
LIST
OF YggRep.metaAttributeMod ← vDoc.metaAttributesChanged, macl.rest
UNTIL macl =
NIL
DO
FOR loa:
LIST
OF YggRep.Attribute ← vDoc.metaAttributes, loa.rest
UNTIL loa =
NIL
DO
IF Rope.Equal[loa.first.attributeName, macl.first.attributeName]
THEN {
prev: LIST OF YggRep.AttributeValue ← NIL;
FOR listoav:
LIST
OF YggRep.AttributeValue ← loa.first.value, listoav.rest
UNTIL listoav =
NIL
DO
tpe: YggRep.TypedPrimitiveElement ← listoav.first.valueSet.first;
didOnList: DID;
IF tpe.docType # YggRep.did THEN ERROR;
didOnList ← NARROW[tpe.bits];
IF YggDID.EqualDIDs[didOnList, macl.first.didValue]
THEN {
IF macl.first.add THEN EXIT; -- already on list
prev.rest ← listoav;
EXIT;
};
prev ← listoav;
REPEAT
FINISHED => IF macl.first.add
THEN {
addItem: LIST OF YggRep.AttributeValue;
addItem ← LIST[[NIL, LIST[[YggRep.did, macl.first.didValue]]]];
IF prev = NIL THEN vDoc.metaAttributes ← LIST[[macl.first.attributeName, FALSE, addItem]]
ELSE prev.rest ← addItem
};
ENDLOOP;
LOOP;
};
REPEAT
FINISHED =>
IF macl.first.add
THEN {
addItem: YggRep.Attribute;
addItem ← [macl.first.attributeName, FALSE, LIST[[NIL, LIST[[YggRep.did, macl.first.didValue]]]]];
vDoc.metaAttributes ← CONS[addItem, vDoc.metaAttributes];
};
ENDLOOP;
ENDLOOP;
FOR restOfAttributes:
LIST
OF YggRep.Attribute ← vDoc.metaAttributes, restOfAttributes.rest
UNTIL restOfAttributes =
NIL
DO
writeAttribute[restOfAttributes.first, attributesStream];
ENDLOOP;
apply link mods
vDoc.outlinks ← applyLinkMods[vDoc.outlinks, vDoc.outlinksChanged];
vDoc.inlinks ← applyLinkMods[vDoc.inlinks, vDoc.inlinksChanged];
IF vDoc.outlinks # NIL THEN writeAttribute[[YggFixedNames.Outlinks, FALSE, vDoc.outlinks], attributesStream];
IF vDoc.inlinks # NIL THEN writeAttribute[[YggFixedNames.Inlinks, FALSE, vDoc.inlinks], attributesStream];
IO.Close[attributesStream];
};
StabilizeToFiles:
PROC [transID: YggEnvironment.TransID, did:
DID, vDoc: YggRep.VDoc, metaAttributesInAttributesFile:
BOOL, contents, attributes, links: YggFile.FileHandle, setContentsAsAttribute:
BOOL]
RETURNS [attributesStream:
IO.
STREAM ←
NIL]~ {
Given a document, write it out to the files.
YggVolatileObjectCache.ReserveDIDInCache[did, transID];
IF contents #
NIL
THEN {
SELECT vDoc.contents.docType
FROM
YggRep.unknown => ERROR;
YggRep.int, YggRep.shortRope, YggRep.float, YggRep.date => {};
YggRep.rope => {
contentsStream: IO.STREAM ← NIL;
rRope: ROPE;
rRope ← NARROW[vDoc.contents.bits];
contentsStream ← YggFile.StreamFromOpenFileAndTid[contents, transID];
IO.PutRope[contentsStream, rRope];
setContentsAsAttribute ← FALSE;
IO.Close[contentsStream];
};
ENDCASE => {
contentsStream: IO.STREAM ← NIL;
rBits: REF YggRep.BitsRep;
rBits ← NARROW[vDoc.contents.bits];
contentsStream ← YggFile.StreamFromOpenFileAndTid[contents, transID];
TRUSTED {
ptBits: LONG POINTER TO YggRep.BitsRep;
unsafeBlock: Basics.UnsafeBlock;
ptBits ← LOOPHOLE[rBits];
unsafeBlock ← [LOOPHOLE[ptBits, LONG POINTER TO PBasics.RawBytes] + SIZE[YggRep.BitsRep[0]], 0, rBits.validBytes];
IO.UnsafePutBlock [self: contentsStream, block: unsafeBlock];
};
setContentsAsAttribute ← FALSE;
IO.Close[contentsStream];
};
};
IF attributes #
NIL
THEN {
attributesStream ← YggFile.StreamFromOpenFileAndTid[attributes, transID];
writeInt[attributesStream, vDoc.contents.docType];
FOR restOfAttributes:
LIST
OF YggRep.Attribute ← vDoc.attributes, restOfAttributes.rest
UNTIL restOfAttributes =
NIL
DO
writeAttribute[restOfAttributes.first, attributesStream];
ENDLOOP;
IF setContentsAsAttribute THEN writeAttribute[["$contents", FALSE, LIST[[NIL, LIST[vDoc.contents]]]], attributesStream];
};
YggVolatileObjectCache.UnreserveDIDInCache[did, transID];
};
writeInt:
PROC [attributesStream:
IO.
STREAM, int:
INT] = {
xyzInt: REF INT ← NEW[INT ← int];
TRUSTED {IO.UnsafePutBlock[attributesStream, [LOOPHOLE[xyzInt], 0, BYTES[INT]]];};
};
writeAttribute:
PROC [attribute: YggRep.Attribute, attributesStream:
IO.
STREAM] = {
Given an attribute, write it out to the stream. See YggRep.mesa for a description of what the format is.
writeBits:
PROC [tpe: YggRep.TypedPrimitiveElement] = {
Write the contents of a TypedPrimitiveElement. The type has already been writen.
SELECT tpe.docType
FROM
YggRep.unknown => ERROR;
YggRep.int => {
ri: REF INT32;
ri ← NARROW[tpe.bits];
writeInt[attributesStream, ri^];
};
YggRep.shortRope => {
rRope: ROPE;
rRope ← NARROW[tpe.bits];
writeString[rRope, 0];
};
YggRep.rope => {
len: INT;
rRope: ROPE;
rRope ← NARROW[tpe.bits];
len ← Rope.Length[rRope];
writeInt[attributesStream, len];
writeString[rRope, 0];
};
YggRep.float => {
rReal: REF REAL32;
rReal ← NARROW[tpe.bits];
TRUSTED {
ptReal: LONG POINTER TO REAL32;
ptReal ← LOOPHOLE[rReal];
IO.UnsafePutBlock[attributesStream, [LOOPHOLE[ptReal], 0, BYTES[REAL32]]];
};
};
YggRep.date => {
rAccurateGMT: YggRep.AccurateGMT;
rAccurateGMT ← NARROW[tpe.bits];
TRUSTED {
ptAGMT: LONG POINTER TO YggRep.AccurateGMTRep;
ptAGMT ← LOOPHOLE[rAccurateGMT];
IO.UnsafePutBlock[attributesStream, [LOOPHOLE[ptAGMT], 0, YggRep.AccurateGMTRepByteSize]];
};
};
YggRep.did => {
rDID: DID;
rDID ← NARROW[tpe.bits];
TRUSTED {
ptDID: LONG POINTER TO DIDRep;
ptDID ← LOOPHOLE[rDID];
IO.UnsafePutBlock[attributesStream, [LOOPHOLE[ptDID], 0, BYTES[DIDRep]]];
};
};
ENDCASE => {
nullsToWrite: INT;
rBits: REF YggRep.BitsRep;
rBits ← NARROW[tpe.bits];
writeInt[attributesStream, rBits.validBytes];
TRUSTED {
ptBits: LONG POINTER TO YggRep.BitsRep;
ptBits ← LOOPHOLE[rBits];
IO.UnsafePutBlock[attributesStream, [LOOPHOLE[ptBits, LONG POINTER TO PBasics.RawBytes] + SIZE[YggRep.BitsRep[0]], 0, rBits.validBytes]];
};
nullsToWrite ← PBasics.charsPerWord - 1 - ((rBits.validBytes + PBasics.charsPerWord - 1) MOD PBasics.charsPerWord);
IF nullsToWrite > 0 THEN TRUSTED {IO.UnsafePutBlock[attributesStream, [LOOPHOLE[AllNulls], 0 , nullsToWrite]];};
};
};
writeString:
PROC [string:
ROPE, extraChars:
INT] = {
len: INT;
nullsToWrite: INT;
len ← Rope.Length[string];
IF len > 0 THEN IO.PutRope[attributesStream, string];
nullsToWrite ← PBasics.charsPerWord - 1 - ((len + extraChars+ PBasics.charsPerWord - 1)) MOD PBasics.charsPerWord;
nullsToWrite ← PBasics.charsPerWord - (len+extraChars) MOD PBasics.charsPerWord;
TRUSTED {IO.UnsafePutBlock[attributesStream, [LOOPHOLE[AllNulls], 0 , nullsToWrite]];};
};
nullFieldNames: BOOL ← TRUE;
singletonFieldValues: BOOL ← TRUE;
numberOfAttributeValues: INT ← 0;
primitiveType: YggRep.DocType ← YggRep.unknown;
preample: YggRep.AttributePreamble;
FOR rv:
LIST
OF YggRep.AttributeValue ← attribute.value, rv.rest
UNTIL rv =
NIL
DO
numberOfAttributeValues ← numberOfAttributeValues + 1;
IF rv.first.fieldName # NIL THEN nullFieldNames ← FALSE;
IF rv.first.valueSet.rest # NIL THEN singletonFieldValues ← FALSE;
FOR avl:
LIST
OF YggRep.TypedPrimitiveElement ← rv.first.valueSet, avl.rest
UNTIL avl =
NIL
DO
tpe: YggRep.TypedPrimitiveElement = avl.first;
IF tpe.docType < YggRep.date AND (primitiveType = YggRep.unknown OR primitiveType = tpe.docType) THEN primitiveType ← tpe.docType ELSE primitiveType ← 10000;
ENDLOOP;
ENDLOOP;
preample[0].ordered ← attribute.ordered;
preample[0].noFieldNames ← nullFieldNames;
preample[0].singletonAttribute ← (numberOfAttributeValues = 1);
preample[0].singletonField ← singletonFieldValues;
preample[0].typeCode ←
SELECT primitiveType
FROM
YggRep.int => integer,
YggRep.rope => ropeLarge,
YggRep.shortRope => ropeShort,
YggRep.float => float,
YggRep.date => date,
YggRep.did => did,
YggRep.uninterpretedBytes => uninterpretedBytes,
ENDCASE => separate;
IF numberOfAttributeValues <= 0 THEN RETURN;
TRUSTED {IO.PutChar[attributesStream, LOOPHOLE[preample[0]]];}; -- @preample points to preample[0]
writeString[attribute.attributeName, 1]; -- write attribute name
IF numberOfAttributeValues # 1 THEN writeInt[attributesStream, numberOfAttributeValues]; -- write number of attribute values;
FOR rv:
LIST
OF YggRep.AttributeValue ← attribute.value, rv.rest
UNTIL rv =
NIL
DO
IF ~nullFieldNames THEN writeString[rv.first.fieldName, 0]; -- write field name
FOR avl:
LIST
OF YggRep.TypedPrimitiveElement ← rv.first.valueSet, avl.rest
UNTIL avl =
NIL
DO
tpe: YggRep.TypedPrimitiveElement = avl.first;
IF preample[0].typeCode = separate THEN writeInt[attributesStream, tpe.docType];
writeBits[tpe];
ENDLOOP;
IF ~preample[0].singletonField THEN writeInt[attributesStream, YggRep.unknown];
ENDLOOP;
};