DIRECTORY
Basics USING [UnsafeBlock],
PBasics USING [charsPerWord],
Camelot USING [tidT],
IO USING [Close, GetIndex, PutChar, PutRope, SetLength, 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, Delete, FileFromComponentFiles, FileHandle, Info, 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] ~ {
newStream: BOOL ← FALSE;
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 {
newStream ← TRUE;
attributesStream ← YggFile.StreamFromOpenFileAndTid[meta, transID];
};
FOR macl:
LIST
OF YggRep.metaAttributeMod ← vDoc.metaAttributesChanged, macl.rest
UNTIL macl =
NIL
DO
didUpdate: BOOL ← FALSE;
prevMA: LIST OF YggRep.Attribute ← NIL;
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.TypedPrimitiveElement ← NIL;
FOR listoavs:
LIST
OF YggRep.TypedPrimitiveElement ← loa.first.value.first.valueSet, listoavs.rest
UNTIL listoavs =
NIL
DO
tpe: YggRep.TypedPrimitiveElement ← listoavs.first;
didOnList: DID;
IF tpe.docType # YggRep.did THEN ERROR;
IF macl.first.add
THEN
{
-- already on list; add to end
prev ← listoavs;
LOOP;
};
didOnList ← NARROW[tpe.bits];
IF YggDID.EqualDIDs[didOnList, macl.first.didValue]
THEN {
IF prev = NIL THEN loa.first.value.first.valueSet ← listoavs.rest ELSE prev.rest ← listoavs.rest;
IF loa.first.value.first.valueSet =
NIL
THEN {
IF prevMA = NIL THEN vDoc.metaAttributes ← loa.rest
ELSE prevMA.rest ← loa.rest;
};
didUpdate ← TRUE;
EXIT;
};
prev ← listoavs;
REPEAT
FINISHED =>
IF macl.first.add
THEN {
IF prev = NIL THEN ERROR;
prev.rest ← CONS[[YggRep.did, macl.first.didValue], NIL];
didUpdate ← TRUE;
};
ENDLOOP;
LOOP;
};
prevMA ← loa;
REPEAT
FINISHED =>
IF macl.first.add
AND ~didUpdate
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];
IF newStream
THEN {
IO.SetLength[attributesStream, IO.GetIndex[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, vDoc.tid];
IF contents #
NIL
THEN {
contentsStream: IO.STREAM ← NIL;
contentsStream ← YggFile.StreamFromOpenFileAndTid[contents, transID];
SELECT vDoc.contents.docType
FROM
YggRep.unknown => ERROR;
YggRep.int, YggRep.shortRope, YggRep.float, YggRep.date, YggRep.did => setContentsAsAttribute ← TRUE;
YggRep.rope => {
rRope: ROPE;
rRope ← NARROW[vDoc.contents.bits];
IO.PutRope[contentsStream, rRope];
setContentsAsAttribute ← FALSE;
};
ENDCASE => {
rBits: REF YggRep.BitsRep;
rBits ← NARROW[vDoc.contents.bits];
TRUSTED {
ptBits: LONG POINTER TO YggRep.BitsRep;
unsafeBlock: Basics.UnsafeBlock;
ptBits ← LOOPHOLE[rBits];
unsafeBlock ← [LOOPHOLE[ptBits, LONG POINTER -- TO Basics.RawBytes -- ] + SIZE[YggRep.BitsRep[0]], 0, rBits.validBytes];
IO.UnsafePutBlock [self: contentsStream, block: unsafeBlock];
};
setContentsAsAttribute ← FALSE;
};
IO.SetLength[contentsStream, IO.GetIndex[contentsStream]];
IO.Close[contentsStream];
};
IF contents # NIL THEN {
contentsStream: IO.STREAM ← NIL;
contentsStream ← YggFile.StreamFromOpenFileAndTid[contents, transID];
writeBits[contentsStream, vDoc.contents, TRUE];
IO.SetLength[contentsStream, IO.GetIndex[contentsStream]];
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, vDoc.tid];
};
writeInt:
PROC [attributesStream:
IO.
STREAM, int:
INT] = {
xyzInt: REF INT ← NEW[INT ← int];
TRUSTED {IO.UnsafePutBlock[attributesStream, [LOOPHOLE[xyzInt], 0, BYTES[INT]]];};
};
writeBits:
PROC [attributesStream:
IO.
STREAM, tpe: YggRep.TypedPrimitiveElement, inhibitSizePrefixAndNulls: BOOL ← FALSE ] = {
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[attributesStream, rRope, 0];
};
YggRep.rope => {
len: INT;
rRope: ROPE;
rRope ← NARROW[tpe.bits];
len ← Rope.Length[rRope];
IF ~inhibitSizePrefixAndNulls THEN writeInt[attributesStream, len];
writeString[attributesStream, 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 ← 0;
rBits: REF YggRep.BitsRep;
IF tpe.bits =
NIL
THEN {
writeInt[attributesStream, 0];
}
ELSE {
rBits ← NARROW[tpe.bits];
IF ~inhibitSizePrefixAndNulls THEN writeInt[attributesStream, rBits.validBytes];
TRUSTED {
ptBits: LONG POINTER TO YggRep.BitsRep;
ptBits ← LOOPHOLE[rBits];
IO.UnsafePutBlock[attributesStream, [LOOPHOLE[ptBits , LONG POINTER -- TO Basics.RawBytes -- ] + SIZE[YggRep.BitsRep[0]], 0, rBits.validBytes]];
};
nullsToWrite ← PBasics.charsPerWord - 1 - ((rBits.validBytes + PBasics.charsPerWord - 1) MOD PBasics.charsPerWord);
IF nullsToWrite > 0 AND ~inhibitSizePrefixAndNulls THEN TRUSTED {IO.UnsafePutBlock[attributesStream, [LOOPHOLE[AllNulls], 0 , nullsToWrite]];};
};
};
};
writeString:
PROC [attributesStream:
IO.
STREAM, 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]];};
};
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.
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[attributesStream, 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[attributesStream, rv.first.fieldName, 0]; -- write field name
IF ~preample[0].singletonField
THEN {
count: INT ← 0;
FOR avl:
LIST
OF YggRep.TypedPrimitiveElement ← rv.first.valueSet, avl.rest
UNTIL avl =
NIL
DO
count ← count + 1;
ENDLOOP;
writeInt[attributesStream, count];
};
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[attributesStream, tpe];
ENDLOOP;
ENDLOOP;
};