DIRECTORY
Rope USING [Equal, Find, InlineFetch, Length, ROPE],
PBasics USING [ByteBlt],
YggDID USING [DID, EqualDIDs, ValidateDID],
YggDIDMap USING [AddRootDID, CreateNewDID, DestroyDID, GetRootDIDs, RemoveRootDID],
YggDIDPrivate USING [DIDRep],
YggEnvironment USING [nullDID, nullTransID, Outcome, TransID],
YggFixedNames USING [],
YggIndex USING [],
YggIndexMaint USING [AddOrRemoveIndexPattern],
YggNav USING [ErrorDesc, LinkList],
YggRep USING [AccurateGMT, AccurateGMTRep, Attribute, AttributeValue, Bits, BitsRep, BytesFromBits, BytesToBits, date, did, DocType, float, int, lastReservedDocType, LatchVDoc, linkMod, metaAttributeMod, noValue, rope, shortRope, SetSizeOfBits, SizeOfBits, symbolicLink, TypedPrimitiveElement, UnlatchVDoc, uninterpretedBytes, VDoc, VolatizeFromDID],
YggTransaction USING [Check, CreateTrans, Finish, GetDefaultContainer, NotePossibleDocumentUpdate, SetDefaultContainer];
Object contents
GetTypeOfContents:
PUBLIC
PROC [trans: YggEnvironment.TransID, did: YggDID.
DID]
RETURNS [YggRep.DocType] ~ {
Get the contents of the object with the specified did.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did];
RETURN[document.contents.docType];
};
IsDocTypeUninterpretedOK:
PROC [docType: YggRep.DocType]
RETURNS [ok:
BOOL] ~ {
IF docType # YggRep.uninterpretedBytes AND docType # YggRep.symbolicLink AND docType <= YggRep.lastReservedDocType THEN RETURN [TRUE] ELSE RETURN [FALSE];
};
GetUninterpretedContents:
PUBLIC
UNSAFE
PROC [trans: YggEnvironment.TransID, did:
DID, firstByte:
CARD, byteCount:
CARD, to:
LONG
POINTER]
RETURNS [bytesMoved:
CARD] ~ {
Get the contents of the object with the specified did. The contents must not be a well known interpreted type (e. g., int, date, float, ...)
Errors: $invalidDID, $invalidTrans, $invalidReservedType
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did];
[] ← YggRep.LatchVDoc[document];
IF IsDocTypeUninterpretedOK[document.contents.docType]
THEN {
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
ERROR Error[[$invalidReservedType, "Attempt to access a TypedPrimitiveElement with reserved type as uninterpreted"]];
};
YggRep.BytesFromBits[bits: document.contents.bits, startByte: firstByte, block: [base: LOOPHOLE[to], startIndex: 0, count: byteCount]];
bytesMoved ← byteCount;
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
GetContents:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [contents: YggRep.TypedPrimitiveElement] ~ {
Get the contents of the object with the specified did.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did];
[] ← YggRep.LatchVDoc[document];
contents ← document.contents;
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
SetUninterpretedContents:
PUBLIC
UNSAFE
PROC [trans: YggEnvironment.TransID, did: YggDID.
DID, setDocType:
BOOL, docType: YggRep.DocType, firstByte:
CARD, byteCount:
CARD, from:
LONG
POINTER]
RETURNS [bytesMoved:
CARD] ~ {
Set the contents of the object with the specified did. The object is grown if needed. The contents type is changed if setDocType is TRUE to docType.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
newRef: BOOL;
newBits: YggRep.Bits;
oldContentsBits: YggRep.Bits;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]];
[] ← YggRep.LatchVDoc[document];
IF setDocType
THEN {
IF IsDocTypeUninterpretedOK[docType]
THEN {
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
ERROR Error[[$invalidReservedType, "Attempt to set a TypedPrimitiveElement with reserved type as uninterpreted"]];
};
document.contents.docType ← docType;
oldContentsBits ← NoBytes;
}
ELSE {
IF IsDocTypeUninterpretedOK[document.contents.docType]
THEN {
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
ERROR Error[[$invalidReservedType, "Attempt to set a TypedPrimitiveElement with reserved type as uninterpreted"]];
};
oldContentsBits ← document.contents.bits;
};
[newRef: newRef, newBits: newBits] ← YggRep.BytesToBits[bits: oldContentsBits, startByte: firstByte, block: [base: LOOPHOLE[from], startIndex: 0, count: byteCount]];
IF newRef THEN document.contents.bits ← newBits;
document.contentsChanged ← TRUE;
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
RETURN[byteCount];
};
SetContents:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, contents: YggRep.TypedPrimitiveElement] ~ {
Set the contents of the object with the specified did. The object is grown if needed.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]];
[] ← YggRep.LatchVDoc[document];
document.contents ← contents;
document.contentsChanged ← TRUE;
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
GetSize:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [size:
CARD] ~ {
Get the size contents of the object with the specified did.
Errors: $invalidDID, $invalidTrans,
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]];
[] ← YggRep.LatchVDoc[document];
IF IsDocTypeUninterpretedOK[document.contents.docType]
THEN {
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
ERROR Error[[$invalidReservedType, "Attempt to get the size of a TypedPrimitiveElement with reserved type as uninterpreted"]];
};
size ← YggRep.SizeOfBits[bits: document.contents.bits];
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
SetSize:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, size:
CARD] ~ {
Set the size contents of the object with the specified did. The object is grown if needed.
Errors: $invalidDID, $invalidTrans,
document: YggRep.VDoc;
newRef: BOOL;
newBits: YggRep.Bits;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]];
[] ← YggRep.LatchVDoc[document];
IF IsDocTypeUninterpretedOK[document.contents.docType]
THEN
{
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
ERROR Error[[$invalidReservedType, "Attempt to set a TypedPrimitiveElement with reserved type as uninterpreted"]];
};
IF YggRep.SizeOfBits[bits: document.contents.bits] # size
THEN {
[newRef: newRef, newBits: newBits] ← YggRep.SetSizeOfBits[bits: document.contents.bits, size: size];
IF newRef THEN document.contents.bits ← newBits;
document.contentsChanged ← TRUE;
};
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
Object property manipulation
GetProperty:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, propertyName:
ROPE]
RETURNS [propertyExists:
BOOL ←
FALSE, property:
LIST
OF YggRep.Attribute ←
NIL] ~ {
Get the named property of the object with the specified did. If the property does not exist, [FALSE, NIL] is returned.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
metaAttributesOnly: BOOL ← FALSE;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
IF Rope.Length[propertyName] > 0
THEN {
IF Rope.InlineFetch[propertyName, 0] = '$ THEN metaAttributesOnly ← TRUE;
};
document ← YggRep.VolatizeFromDID[transID: trans, did: did, metaAttributesOnly: metaAttributesOnly];
[] ← YggRep.LatchVDoc[document];
FOR aL:
LIST
OF YggRep.Attribute ← document.attributes, aL.rest
UNTIL aL =
NIL
DO
IF Rope.Equal[aL.first.attributeName, propertyName]
THEN {
property ← CONS[aL.first, property];
propertyExists ← TRUE;
};
ENDLOOP;
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
GetAllProperties:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [properties:
LIST
OF YggRep.Attribute] ~ {
Get all the properties of the object with the specified did. If no properties exist, NIL is returned.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did];
RETURN[document.attributes];
};
ListAllProperties:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [propertyNames:
LIST
OF
ROPE ←
NIL] ~ {
Get all the property names of the object with the specified did. If no properties exist, NIL is returned.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did];
[] ← YggRep.LatchVDoc[document];
FOR aL:
LIST
OF YggRep.Attribute ← document.attributes, aL.rest
UNTIL aL =
NIL
DO
FOR pN:
LIST
OF
ROPE ← propertyNames, pN.rest
UNTIL pN =
NIL
DO
IF Rope.Equal[aL.first.attributeName, pN.first] THEN EXIT;
REPEAT
FINISHED => {
propertyNames ← CONS[aL.first.attributeName, propertyNames];
};
ENDLOOP;
ENDLOOP;
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
SetProperty:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, propertyName:
ROPE, property: YggRep.Attribute, appendProperty:
BOOL] ~ {
Set the named property of the object with the specified did. If appendProperty is TRUE, the property is appended. If FALSE, it first destroys all properties with this name. A NIL value for the property with appendProperty as TRUE is a noop, and with appendProperty as FALSE deletes the property. A non-NIL value for the property with appendProperty as FALSE makes the new property the one and only value for the property.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
somethingChanged: BOOL ← FALSE;
prev: LIST OF YggRep.Attribute ← NIL;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]];
[] ← YggRep.LatchVDoc[document];
SELECT
TRUE
FROM
appendProperty AND property.value = NIL => NULL; -- nothing to do
appendProperty
AND property.value #
NIL => {
-- add prop to end of list
somethingChanged ← TRUE;
IF document.attributes = NIL THEN document.attributes ← LIST[property]
ELSE {
FOR aL:
LIST
OF YggRep.Attribute ← document.attributes, aL.rest
UNTIL aL =
NIL
DO
IF aL.rest = NIL THEN {aL.rest ← LIST[property]; EXIT};
ENDLOOP;
};
};
~appendProperty
AND property.value =
NIL => {
-- delete all props of this name
IF document.attributes = NIL THEN RETURN -- nothing to do
ELSE {
FOR aL:
LIST
OF YggRep.Attribute ← document.attributes, aL.rest
UNTIL aL =
NIL
DO
IF Rope.Equal[aL.first.attributeName, propertyName]
THEN {
somethingChanged ← TRUE;
IF prev = NIL THEN document.attributes ← aL.rest
ELSE prev.rest ← aL.rest;
LOOP;
};
prev ← aL;
ENDLOOP;
};
};
~appendProperty
AND property.value #
NIL => {
-- delete all props of this name and add this one
somethingChanged ← TRUE;
IF document.attributes = NIL THEN document.attributes ← LIST[property]
ELSE {
FOR aL:
LIST
OF YggRep.Attribute ← document.attributes, aL.rest
UNTIL aL =
NIL
DO
IF Rope.Equal[aL.first.attributeName, propertyName]
THEN {
somethingChanged ← TRUE;
IF prev = NIL THEN document.attributes ← aL.rest
ELSE prev.rest ← aL.rest;
LOOP;
};
prev ← aL;
ENDLOOP;
IF prev = NIL THEN document.attributes ← LIST[property]
ELSE prev.rest ← LIST[property];
};
};
ENDCASE;
IF somethingChanged
THEN {
FOR aC:
LIST
OF
ROPE ← document.namesOfAttributesChanged, aC.rest
UNTIL aC =
NIL
DO
IF Rope.Equal[aC.first, propertyName] THEN EXIT;
REPEAT
FINISHED => {
document.namesOfAttributesChanged ← CONS[propertyName, document.namesOfAttributesChanged];
};
ENDLOOP;
};
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
Object property construction
Note: all of these procedures copy data.
ConstructIntTPE:
PUBLIC
PROC [int:
INT32]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for a 32 bit integer.
Errors: $invalidDID, $invalidTrans
ri: REF INT32;
ri ← NEW[INT32 ← int];
property ← [YggRep.int, ri];
};
ConstructFloatTPE:
PUBLIC
PROC [float:
REAL32]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for a 32 bit real.
rReal: REF REAL32;
rReal ← NEW[REAL32 ← float];
property ← [YggRep.float, rReal];
};
ConstructDateTPE:
PUBLIC
PROC [date: YggRep.AccurateGMTRep]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for a date.
rAccurateGMT: YggRep.AccurateGMT;
rAccurateGMT ← NEW[YggRep.AccurateGMTRep ← date];
property ← [YggRep.date, rAccurateGMT];
};
ConstructShortRopeTPE:
PUBLIC
PROC [rope:
ROPE]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for a ROPE that is short (less than a few disk pages preferred) and contains no nulls.
Errors: $shortRopeWithNulls
IF Rope.Find[rope, "\000"] = -1
THEN {
property ← [YggRep.shortRope, rope];
}
ELSE ERROR Error[[$shortRopeWithNulls, "Rope has nulls"]];
};
ConstructRopeTPE:
PUBLIC
PROC [rope:
ROPE]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for a ROPE that is long (more than a disk page preferred) and may contain no nulls.
property ← [YggRep.rope, rope];
};
ConstructUninterpretedBytesTPE:
PUBLIC
PROC [docType: YggRep.DocType, bytes:
LONG
POINTER, size:
CARD]
RETURNS [property: YggRep.TypedPrimitiveElement] ~ {
Construct a YggRep.TypedPrimitiveElement for an array of bytes.
Errors: $$invalidReservedType
nBytes: CARD;
rBits: REF YggRep.BitsRep;
IF IsDocTypeUninterpretedOK[docType] THEN ERROR Error[[$invalidReservedType, "Attempt to create a TypedPrimitiveElement with reserved type"]];
rBits ← NEW[YggRep.BitsRep[size]];
rBits.validBytes ← size;
TRUSTED {nBytes ← PBasics.ByteBlt[
from: [blockPointer: bytes, startIndex: 0, stopIndexPlusOne: size],
to: [blockPointer: LOOPHOLE[rBits, LONG POINTER] + SIZE[YggRep.BitsRep[0]], startIndex: 0, stopIndexPlusOne: size]];
};
IF nBytes # size THEN ERROR;
property ← [docType, rBits];
};
Links
getTypedLinks:
PROC [links:
LIST
OF YggRep.AttributeValue, linksChanged:
LIST
OF YggRep.linkMod, linkType:
ROPE]
RETURNS [dids:
LIST
OF
DID ←
NIL] ~ {
lastDIDs: LIST OF DID ← NIL;
FOR linkList:
LIST
OF YggRep.AttributeValue ← links, linkList.rest
UNTIL linkList =
NIL
DO
IF linkType =
NIL
OR Rope.Equal[linkType, linkList.first.fieldName,
FALSE]
THEN {
FOR lotpe:
LIST
OF YggRep.TypedPrimitiveElement ← linkList.first.valueSet, lotpe.rest
UNTIL lotpe =
NIL
DO
linkDID: DID;
IF lotpe.first.docType # YggRep.did THEN ERROR;
linkDID ← NARROW[lotpe.first.bits];
IF dids = NIL THEN lastDIDs ← (dids ← LIST[linkDID])
ELSE lastDIDs.rest ← LIST[linkDID];
ENDLOOP;
};
ENDLOOP;
FOR lolm:
LIST
OF YggRep.linkMod ← linksChanged, lolm.rest
UNTIL lolm =
NIL
DO
IF linkType = NIL AND ~Rope.Equal[lolm.first.linkName, linkType, FALSE] THEN LOOP;
IF lolm.first.add
THEN {
IF lastDIDs = NIL THEN lastDIDs ← (dids ← LIST[lolm.first.linkValue])
ELSE lastDIDs.rest ← LIST[lolm.first.linkValue];
}
ELSE {
prevLod: LIST OF DID ← NIL;
FOR lod:
LIST
OF
DID ← dids, lod.rest
UNTIL lod =
NIL
DO
IF YggDID.EqualDIDs[lod.first, lolm.first.linkValue]
THEN {
IF prevLod = NIL THEN dids ← dids.rest
ELSE prevLod.rest ← lod.rest;
IF lastDIDs = lod THEN lastDIDs ← prevLod;
EXIT;
};
prevLod ← lod;
ENDLOOP;
};
ENDLOOP;
};
getLinks:
PROC [links:
LIST
OF YggRep.AttributeValue, linksChanged:
LIST
OF YggRep.linkMod]
RETURNS [currentLinks
: LIST
OF YggNav.LinkList ←
NIL] ~ {
lastCurrentLinks: LIST OF YggNav.LinkList ← NIL;
FOR linkList:
LIST
OF YggRep.AttributeValue ← links, linkList.rest
UNTIL linkList =
NIL
DO
dids: LIST OF DID ← NIL;
lastDIDs: LIST OF DID ← NIL;
FOR lotpe:
LIST
OF YggRep.TypedPrimitiveElement ← linkList.first.valueSet, lotpe.rest
UNTIL lotpe =
NIL
DO
linkDID: DID;
IF lotpe.first.docType # YggRep.did THEN ERROR;
linkDID ← NARROW[lotpe.first.bits];
IF dids = NIL THEN lastDIDs ← (dids ← LIST[linkDID])
ELSE lastDIDs.rest ← LIST[linkDID];
ENDLOOP;
IF currentLinks = NIL THEN currentLinks ← lastCurrentLinks ← LIST[[linkList.first.fieldName, dids]]
ELSE lastCurrentLinks.rest ← LIST[[linkList.first.fieldName, dids]];
ENDLOOP;
FOR lolm:
LIST
OF YggRep.linkMod ← linksChanged, lolm.rest
UNTIL lolm =
NIL
DO
FOR curLnk:
LIST
OF YggNav.LinkList ← currentLinks, curLnk.rest
UNTIL curLnk =
NIL
DO
IF ~Rope.Equal[curLnk.first.linkName, lolm.first.linkName, FALSE] THEN LOOP;
IF lolm.first.add
THEN {
curLnk.first.dids ← CONS[lolm.first.linkValue, curLnk.first.dids];
}
ELSE {
prevLod: LIST OF DID ← NIL;
FOR lod:
LIST
OF
DID ← curLnk.first.dids, lod.rest
UNTIL lod =
NIL
DO
IF YggDID.EqualDIDs[lod.first, lolm.first.linkValue]
THEN {
IF prevLod = NIL THEN curLnk.first.dids ← curLnk.first.dids.rest
ELSE prevLod.rest ← lod.rest;
EXIT;
};
prevLod ← lod;
ENDLOOP;
};
REPEAT FINISHED => IF lolm.first.add
THEN
{
IF currentLinks = NIL THEN currentLinks ← lastCurrentLinks ← LIST[[lolm.first.linkName, LIST [lolm.first.linkValue]]]
ELSE lastCurrentLinks.rest ← LIST[[lolm.first.linkName, LIST [lolm.first.linkValue]]];
};
ENDLOOP;
ENDLOOP;
};
GetTypedOutlinks:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, linkType:
ROPE]
RETURNS [outlinks:
LIST
OF
DID ←
NIL] ~ {
Get the did's of all the outlinks for this object with "link type" propertyName.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did, readOnly, [read, wait]];
[] ← YggRep.LatchVDoc[document];
outlinks ← getTypedLinks[document.outlinks, document.outlinksChanged, linkType];
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
GetAllOutlinks:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [outlinks
: LIST
OF YggNav.LinkList ←
NIL] ~ {
Get the did's of all the outlinks for this object.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did, readOnly, [read, wait]];
[] ← YggRep.LatchVDoc[document];
outlinks ← getLinks[document.outlinks, document.outlinksChanged];
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
GetTypedInlinks:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, linkType:
ROPE]
RETURNS [inlinks:
LIST
OF
DID ←
NIL] ~ {
Get the did's of all the inlinks for this object with "link type" propertyName.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did, readOnly, [read, wait]];
[] ← YggRep.LatchVDoc[document];
inlinks ← getTypedLinks[document.inlinks, document.inlinksChanged, linkType];
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
GetAllInlinks:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID]
RETURNS [inlinks
: LIST
OF YggNav.LinkList ←
NIL] ~ {
Get the did's of all the inlinks for this object.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did, readOnly, [read, wait]];
[] ← YggRep.LatchVDoc[document];
inlinks ← getLinks[document.inlinks, document.inlinksChanged];
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
SnapLink:
PUBLIC
PROC [trans: YggEnvironment.TransID, fromDID:
DID, toDID:
DID, linkType:
ROPE]
RETURNS [linkDID:
DID ←
NIL] ~ {
Construct a link between the two dids.
Errors: $invalidDID, $invalidTrans
lastLinkMod: LIST OF YggRep.linkMod ← NIL;
newLinkMod: LIST OF YggRep.linkMod ← NIL;
fromVDoc: YggRep.VDoc;
toVDoc: YggRep.VDoc;
linkVDoc: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
fromVDoc ← YggRep.VolatizeFromDID[trans, fromDID, readWrite, [write, wait]];
toVDoc ← YggRep.VolatizeFromDID[trans, toDID, readOnly, [read, wait]];
[] ← YggRep.LatchVDoc[fromVDoc];
FOR lolm:
LIST
OF YggRep.linkMod ← fromVDoc.outlinksChanged, lolm.rest
UNTIL lolm =
NIL
DO
lastLinkMod ← lolm;
ENDLOOP;
linkDID ← YggDIDMap.CreateNewDID[trans];
linkVDoc ← YggRep.VolatizeFromDID[trans, linkDID, readWrite, [write, wait]];
linkVDoc.fromDID ← fromDID;
linkVDoc.toDID ← toDID;
linkVDoc.linkType ← linkType;
linkVDoc.contents.docType ← YggRep.noValue;
linkVDoc.linkChanged ← TRUE;
newLinkMod ← LIST[[TRUE, linkType, linkDID]];
IF lastLinkMod = NIL THEN fromVDoc.outlinksChanged ← newLinkMod
ELSE lastLinkMod.rest ← newLinkMod;
IF ~YggRep.UnlatchVDoc[fromVDoc] THEN ERROR;
[] ← YggRep.LatchVDoc[toVDoc];
lastLinkMod ← NIL;
FOR lolm:
LIST
OF YggRep.linkMod ← toVDoc.inlinksChanged, lolm.rest
UNTIL lolm =
NIL
DO
lastLinkMod ← lolm;
ENDLOOP;
newLinkMod ← LIST[[TRUE, linkType, linkDID]];
IF lastLinkMod = NIL THEN toVDoc.inlinksChanged ← newLinkMod
ELSE lastLinkMod.rest ← newLinkMod;
YggTransaction.NotePossibleDocumentUpdate[trans, toVDoc];
IF ~YggRep.UnlatchVDoc[toVDoc] THEN ERROR;
};
RemoveLink:
PUBLIC PROC [trans: YggEnvironment.TransID, linkDID: YggDID.
DID] ~ {
Remove a link.
Errors: $invalidDID, $invalidTrans
lastLinkMod: LIST OF YggRep.linkMod ← NIL;
newLinkMod: LIST OF YggRep.linkMod ← NIL;
fromVDoc: YggRep.VDoc;
toVDoc: YggRep.VDoc;
linkVDoc: YggRep.VDoc;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
linkVDoc ← YggRep.VolatizeFromDID[trans, linkDID, readWrite, [write, wait]];
[] ← YggRep.LatchVDoc[linkVDoc];
fromVDoc ← YggRep.VolatizeFromDID[trans, linkVDoc.fromDID, readWrite, [write, wait]];
toVDoc ← YggRep.VolatizeFromDID[trans, linkVDoc.toDID, readOnly, [read, wait], TRUE];
YggDIDMap.DestroyDID[trans, linkDID];
IF ~YggRep.UnlatchVDoc[linkVDoc] THEN ERROR;
[] ← YggRep.LatchVDoc[fromVDoc];
FOR lolm:
LIST
OF YggRep.linkMod ← fromVDoc.outlinksChanged, lolm.rest
UNTIL lolm =
NIL
DO
lastLinkMod ← lolm;
ENDLOOP;
newLinkMod ← LIST[[FALSE, linkVDoc.linkType, linkDID]];
IF lastLinkMod = NIL THEN fromVDoc.outlinksChanged ← newLinkMod
ELSE lastLinkMod.rest ← newLinkMod;
IF ~YggRep.UnlatchVDoc[fromVDoc] THEN ERROR;
[] ← YggRep.LatchVDoc[toVDoc];
lastLinkMod ← NIL;
FOR lolm:
LIST
OF YggRep.linkMod ← toVDoc.inlinksChanged, lolm.rest
UNTIL lolm =
NIL
DO
lastLinkMod ← lolm;
ENDLOOP;
newLinkMod ← LIST[[FALSE, linkVDoc.linkType, linkDID]];
IF lastLinkMod = NIL THEN toVDoc.inlinksChanged ← newLinkMod
ELSE lastLinkMod.rest ← newLinkMod;
YggTransaction.NotePossibleDocumentUpdate[trans, toVDoc];
IF ~YggRep.UnlatchVDoc[toVDoc] THEN ERROR;
};
Containers
GetDefaultContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID]
RETURNS [
did: DID ←
NIL] ~ {
Get the default container for this transaction.
Errors: $invalidTrans
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
did ← YggTransaction.GetDefaultContainer[trans];
};
SetDefaultContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID] ~ {
Set the default container for this transaction.
Errors: $invalidDID, $invalidTrans
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
YggTransaction.SetDefaultContainer[trans, did];
};
AddToContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, containerDID:
DID] ~ {
Add the object to the container.
Errors: $invalidDID, $invalidTrans
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
addOrRemoveContainer[trans, did, containerDID, TRUE, Parents, Children];
};
RemoveFromContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, containerDID:
DID]
RETURNS [ok:
BOOL ←
TRUE] ~ {
Remove the object from the container.
Errors: $invalidDID, $invalidTrans
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
addOrRemoveContainer[trans, did, containerDID, FALSE, Parents, Children];
};
GetObjectsInContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, containerDID:
DID, dontWait:
BOOL]
RETURNS [dids:
LIST
OF
DID, success:
BOOL] ~ {
Get the did's of all the objects in this container. containerDID of NIL means use the default container.
Errors: $invalidDID, $invalidTrans
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
[dids, success] ← listContainer [trans, containerDID, Children, dontWait];
};
GetParents:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID, dontWait:
BOOL]
RETURNS [dids:
LIST
OF
DID ←
NIL, success:
BOOL] ~ {
Get the did's of all the parents.
Errors: $invalidDID, $invalidTrans
[dids, success] ← listContainer [trans, did, Parents, dontWait];
};
AddContainerToContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, subcontainerDID:
DID, containerDID:
DID] ~ {
Add the subcontainer to the container.
Errors: $invalidDID, $invalidTrans
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
addOrRemoveContainer[trans, subcontainerDID, containerDID, TRUE, ParentContainers, ChildContainers];
};
RemoveContainerFromContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, subcontainerDID:
DID, containerDID:
DID]
RETURNS [ok:
BOOL ←
TRUE] ~ {
Remove the subcontainer from the container.
Errors: $invalidDID, $invalidTrans
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
addOrRemoveContainer[trans, subcontainerDID, containerDID, FALSE, ParentContainers, ChildContainers];
};
GetContainersInContainer:
PUBLIC
PROC [trans: YggEnvironment.TransID, containerDID:
DID, dontWait:
BOOL]
RETURNS [dids:
LIST
OF
DID ←
NIL, success:
BOOL] ~ {
Get the did's of all the containers in this container. containerDID of NIL means use the default container.
Errors: $invalidDID, $invalidTrans
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
[dids, success] ← listContainer [trans, containerDID, ChildContainers, dontWait];
};
GetSuperContainers:
PUBLIC
PROC [trans: YggEnvironment.TransID, containerDID:
DID, dontWait:
BOOL]
RETURNS [dids:
LIST
OF
DID ←
NIL, success:
BOOL] ~ {
Get the did's of all the containers containing this container.
Errors: $invalidDID, $invalidTrans
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
[dids, success] ← listContainer [trans, containerDID, ParentContainers, dontWait];
};
addOrRemoveContainer:
PROC [trans: YggEnvironment.TransID, did:
DID, containerDID:
DID, add:
BOOL, pAN:
ROPE, cN:
ROPE, dontLatchDoc:
BOOL ←
FALSE] ~ {
Add the object to the container.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
containerDocument: YggRep.VDoc;
newCVal: LIST OF YggRep.metaAttributeMod;
document ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]];
IF ~dontLatchDoc THEN {
[] ← YggRep.LatchVDoc[document];
};
newCVal ← LIST [[attributeName: pAN, add: add, didValue: containerDID, stringValue: NIL]];
IF document.metaAttributesChanged = NIL THEN document.metaAttributesChanged ← newCVal
ELSE {
prev: LIST OF YggRep.metaAttributeMod ← NIL;
FOR macl:
LIST
OF YggRep.metaAttributeMod ← document.metaAttributesChanged, macl.rest
UNTIL macl =
NIL
DO
prev ← macl;
ENDLOOP;
prev.rest ← newCVal;
};
IF ~dontLatchDoc THEN {
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
containerDocument ← YggRep.VolatizeFromDID[trans, containerDID, readWrite, [write, wait]];
[] ← YggRep.LatchVDoc[containerDocument];
newCVal ← LIST [[attributeName: cN, add: add, didValue: did, stringValue: NIL]];
IF containerDocument.metaAttributesChanged = NIL THEN containerDocument.metaAttributesChanged ← newCVal
ELSE {
prev: LIST OF YggRep.metaAttributeMod ← NIL;
FOR macl:
LIST
OF YggRep.metaAttributeMod ← containerDocument.metaAttributesChanged, macl.rest
UNTIL macl =
NIL
DO
prev ← macl;
ENDLOOP;
prev.rest ← newCVal;
};
[] ← YggRep.UnlatchVDoc[containerDocument];
};
listContainer:
PROC [trans: YggEnvironment.TransID, did:
DID, pAN:
ROPE, dontWait:
BOOL, dontLatch:
BOOL ←
FALSE]
RETURNS[didList:
LIST
OF
DID ←
NIL, success:
BOOL ←
TRUE] ~ {
Add the object to the container.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
lastDidList: LIST OF DID ← NIL;
didCountItem:
TYPE = RECORD [
count: INT ← 0,
did: DID
];
modifiedDIDs: LIST OF didCountItem ← NIL;
stdValues: LIST OF YggRep.TypedPrimitiveElement ← NIL;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
document ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, IF dontWait THEN fail ELSE wait]];
IF ~dontLatch
THEN {
IF ~YggRep.LatchVDoc[document, ~dontWait] THEN RETURN[NIL, FALSE];
};
find the right list
FOR loa:
LIST
OF YggRep.Attribute ← document.metaAttributes, loa.rest
UNTIL loa =
NIL
DO
IF Rope.Equal[loa.first.attributeName, pAN] THEN {stdValues ← loa.first.value.first.valueSet; EXIT};
ENDLOOP;
flip through looking for DID's that don't have any modifications
FOR lotpe:
LIST
OF YggRep.TypedPrimitiveElement ← stdValues, lotpe.rest
UNTIL lotpe =
NIL
DO
tpe: YggRep.TypedPrimitiveElement ← lotpe.first;
forgetIt: BOOL ← FALSE;
didOnList: DID;
didl2add: LIST OF DID ← NIL;
IF tpe.docType # YggRep.did THEN ERROR;
didOnList ← NARROW[tpe.bits];
FOR macl:
LIST
OF YggRep.metaAttributeMod ← document.metaAttributesChanged, macl.rest
UNTIL macl =
NIL
DO
IF ~Rope.Equal[pAN, macl.first.attributeName] THEN LOOP;
IF ~YggDID.EqualDIDs[macl.first.didValue, didOnList] THEN LOOP;
forgetIt ← TRUE;
FOR mdlist:
LIST
OF didCountItem ← modifiedDIDs, mdlist.rest
UNTIL mdlist =
NIL
DO
IF YggDID.EqualDIDs[mdlist.first.did, didOnList]
THEN
{
mdlist.first.count ← mdlist.first.count + 1;
EXIT;
};
REPEAT FINISHED => modifiedDIDs ← CONS[[1, didOnList], modifiedDIDs];
ENDLOOP;
EXIT;
ENDLOOP;
IF forgetIt THEN LOOP;
didl2add ← LIST[didOnList];
IF didList = NIL THEN lastDidList ← didList ← didl2add
ELSE lastDidList ← (lastDidList.rest ← didl2add);
ENDLOOP;
flip through the mods and see which are visible
FOR macl:
LIST
OF YggRep.metaAttributeMod ← document.metaAttributesChanged, macl.rest
UNTIL macl =
NIL
DO
IF ~Rope.Equal[pAN, macl.first.attributeName] THEN LOOP;
FOR mdlist:
LIST
OF didCountItem ← modifiedDIDs, mdlist.rest
UNTIL mdlist =
NIL
DO
IF YggDID.EqualDIDs[mdlist.first.did, macl.first.didValue]
THEN
{
IF macl.first.add THEN mdlist.first.count ← mdlist.first.count + 1
ELSE mdlist.first.count ← mdlist.first.count - 1;
EXIT;
};
REPEAT FINISHED => ERROR;
ENDLOOP;
ENDLOOP;
spit out dids still visible
FOR mdlist:
LIST
OF didCountItem ← modifiedDIDs, mdlist.rest
UNTIL mdlist =
NIL
DO
IF mdlist.first.count > 0 THEN {
FOR i: INT IN [1..mdlist.first.count] DO
didl2add: LIST OF DID ← NIL;
didl2add ← LIST[mdlist.first.did];
IF didList = NIL THEN lastDidList ← didList ← didl2add
ELSE lastDidList ← (lastDidList.rest ← didl2add);
ENDLOOP;
};
ENDLOOP;
IF ~dontLatch
THEN {
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
};
Object creation and destruction
CreateObject:
PUBLIC
PROC [trans: YggEnvironment.TransID, containerDID:
DID, makeRoot:
BOOL]
RETURNS [did:
DID ←
NIL] ~ {
Make up a new object in the specified container. The default container for the transaction is used if containerDID is NIL.
Errors: $invalidDID, $invalidTrans
foundTrans: BOOL ← FALSE;
activeTrans: BOOL ← FALSE;
ok: BOOL ← FALSE;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
IF containerDID = NIL OR YggDID.EqualDIDs[containerDID, YggEnvironment.nullDID] THEN containerDID ← GetDefaultContainer[trans];
IF (containerDID = NIL OR YggDID.EqualDIDs[containerDID, YggEnvironment.nullDID]) AND ~makeRoot THEN ERROR Error[error: [code: $invalidDID, explanation: "default container and the containerDID specified are both null; a object must have a container"]];
did ← YggDIDMap.CreateNewDID[trans];
IF containerDID # NIL THEN AddToContainer[trans, did, containerDID];
IF makeRoot THEN ok ← YggDIDMap.AddRootDID[did];
};
RemoveObject:
PUBLIC
PROC [trans: YggEnvironment.TransID, did:
DID] ~ {
Remove a object. Any links pointing to this object are also removed. This is a recursive process (if the links are really objects).
Errors: $invalidDID, $invalidTrans
vDoc: YggRep.VDoc;
kidDIDs: LIST OF DID;
superDIDs: LIST OF DID;
subDIDs: LIST OF DID;
parentDIDs: LIST OF DID;
success: BOOL ← TRUE;
IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]];
vDoc ← YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]];
IF vDoc.outlinks # NIL OR vDoc.inlinks # NIL OR vDoc.outlinksChanged # NIL OR vDoc.inlinksChanged # NIL THEN ERROR; -- doesn't handle recursive delete yet
[] ← YggRep.LatchVDoc[vDoc];
[didList: kidDIDs, success: success] ← listContainer[trans: trans, did: did, pAN: Children, dontWait: FALSE, dontLatch: TRUE];
IF kidDIDs #
NIL
THEN {
IF ~YggRep.UnlatchVDoc[vDoc] THEN ERROR;
ERROR Error[error: [code: $containerMustBeEmpty, explanation: "attempt to remove an object that is the root of a container that has objects in it"]];
};
[didList: subDIDs, success: success] ← listContainer[trans: trans, did: did, pAN: ChildContainers, dontWait: FALSE, dontLatch: TRUE];
IF subDIDs #
NIL
THEN {
IF ~YggRep.UnlatchVDoc[vDoc] THEN ERROR;
ERROR Error[error: [code: $containerMustBeEmpty, explanation: "attempt to remove an object that is the root of a container that has containers in it"]];
};
[didList: parentDIDs, success: success] ← listContainer[trans: trans, did: did, pAN: Parents, dontWait: FALSE, dontLatch: TRUE];
[didList: superDIDs, success: success] ← listContainer[trans: trans, did: did, pAN: ParentContainers, dontWait: FALSE, dontLatch: TRUE];
FOR lopd:
LIST
OF
DID ← parentDIDs, lopd.rest
UNTIL lopd =
NIL
DO
addOrRemoveContainer[trans: trans, did: did, containerDID: lopd.first, add: FALSE, pAN: Parents, cN: Children, dontLatchDoc: TRUE];
ENDLOOP;
FOR lopd:
LIST
OF
DID ← superDIDs, lopd.rest
UNTIL lopd =
NIL
DO
addOrRemoveContainer[trans: trans, did: did, containerDID: lopd.first, add: FALSE, pAN: ParentContainers, cN: ChildContainers, dontLatchDoc: TRUE];
ENDLOOP;
vDoc.destroyed ← TRUE;
YggDIDMap.DestroyDID[trans, did];
IF ~YggRep.UnlatchVDoc[vDoc] THEN ERROR;
};