YggNavImpl.mesa
Copyright Ó 1988, 1989 by Xerox Corporation. All rights reserved.
Bob Hagmann March 10, 1989 1:04:08 pm PST
Top level navigational ``interface'' for Yggdrasil.
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];
YggNavImpl: CEDAR MONITOR
IMPORTS PBasics, Rope, YggDID, YggDIDMap, YggIndexMaint, YggRep, YggTransaction
EXPORTS YggDID, YggFixedNames, YggNav
~ BEGIN
Types, variables, and constants
ROPE: TYPE = Rope.ROPE;
Error: PUBLIC ERROR [error: YggNav.ErrorDesc] = CODE;
DID: PUBLIC TYPE ~ REF DIDRep;
DIDRep: PUBLIC TYPE ~ YggDIDPrivate.DIDRep;
NoBytes: YggRep.Bits;
Fixed names for properties
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";
Fixed names for index prefix
IndexPrefix: PUBLIC Rope.ROPE ← "$index-";
IndexPrefixSize: PUBLIC INT ← Rope.Length[IndexPrefix];
Fixed names for directory
DirectoryContents: PUBLIC Rope.ROPE ← "$directoryContents";
Fixed names for NFS
NFSPropertyName: PUBLIC Rope.ROPE ← "$NFSProperites"; -- NFS (UNIX) properties
Transactions
StartTransaction: PUBLIC PROC [parentTrans: YggEnvironment.TransID] RETURNS [trans: YggEnvironment.TransID] ~ {
Start up a new transaction.
trans ← YggTransaction.CreateTrans[parentTrans];
};
EndTransaction: PUBLIC PROC [trans: YggEnvironment.TransID, commit: BOOL] RETURNS [ok: BOOLTRUE] ~ {
Commit or abort a transaction.
outcome: YggEnvironment.Outcome;
[outcome: outcome] ← YggTransaction.Finish[transID: trans, requestedOutcome: IF commit THEN commit ELSE abort];
IF outcome = commit THEN RETURN [TRUE] ELSE RETURN [FALSE];
};
CheckTransaction: PUBLIC PROC [trans: YggEnvironment.TransID] RETURNS [found: BOOLFALSE, active: BOOLFALSE, committed: BOOLFALSE] ~ {
Check on a transaction. If it no found, then active and committed are not meaningful. If found, then if active then committed is not meaningful. If not active, then the commit state is returned in committed. Old transactions will not be found.
outcome: YggEnvironment.Outcome;
[outcome: outcome] ← YggTransaction.Check[transID: trans];
SELECT outcome FROM
active => RETURN [TRUE, TRUE, FALSE];
abort => RETURN [TRUE, FALSE, FALSE];
commit => RETURN [TRUE, FALSE, TRUE];
unknown => RETURN [FALSE, FALSE, FALSE];
suspended => RETURN [TRUE, FALSE, FALSE];
ENDCASE => ERROR;
};
Root objects
Note: none of the root operations operate under transaction (or any other!) control
GetRoots: PUBLIC PROC RETURNS [roots: LIST OF DID] ~ {
Get all the root objects for the service.
roots ← YggDIDMap.GetRootDIDs[];
};
AddRoot: PUBLIC PROC [did: DID] RETURNS [ok: BOOL ← FALSE] ~ {
Add a root object. If the DID does not exist, FALSE will be returned.
IF ~YggDID.ValidateDID[did] THEN RETURN [FALSE];
ok ← YggDIDMap.AddRootDID[did];
};
RemoveRoot: PUBLIC PROC [did: DID] RETURNS [ok: BOOL ← TRUE] ~ {
Remove a root object. If the DID is not a root object, FALSE will be returned.
IF ~YggDID.ValidateDID[did] THEN RETURN [FALSE];
ok ← YggDIDMap.RemoveRootDID[did];
};
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: BOOLFALSE, 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: BOOLFALSE;
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;
FOR aL: LIST OF YggRep.Attribute ← document.metaAttributes, 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 ROPENIL] ~ {
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: BOOLFALSE;
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 DIDNIL] ~ {
lastDIDs: LIST OF DIDNIL;
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 DIDNIL;
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 DIDNIL;
lastDIDs: LIST OF DIDNIL;
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 DIDNIL;
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 DIDNIL] ~ {
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 DIDNIL] ~ {
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: DIDNIL] ~ {
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: DIDNIL] ~ {
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: BOOLTRUE] ~ {
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 DIDNIL, 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: BOOLTRUE] ~ {
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 DIDNIL, 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 DIDNIL, 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: BOOLFALSE] ~ {
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: BOOLFALSE] RETURNS[didList: LIST OF DIDNIL, success: BOOLTRUE] ~ {
Add the object to the container.
Errors: $invalidDID, $invalidTrans
document: YggRep.VDoc;
lastDidList: LIST OF DIDNIL;
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: BOOLFALSE;
didOnList: DID;
didl2add: LIST OF DIDNIL;
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 DIDNIL;
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;
};
};
Indexing in containers
AddIndexPatternToContainer: PUBLIC PROC [containerDID: YggDID.DID, pattern: ROPE] RETURNS [patternOK: BOOL] ~ {
Add the pattern to index on for the container.
Errors: $invalidDID
patternOK ← YggIndexMaint.AddOrRemoveIndexPattern[containerDID: containerDID, pattern: pattern, add: TRUE]
};
RemoveIndexPatternFromContainer: PUBLIC PROC [containerDID: YggDID.DID, pattern: ROPE] RETURNS [ok: BOOL] ~ {
Remove the pattern..
Errors: $invalidDID
ok ← YggIndexMaint.AddOrRemoveIndexPattern[containerDID: containerDID, pattern: pattern, add: FALSE]
};
GetPatternsInContainer: PUBLIC PROC [containerDID: YggDID.DID, dontWait: BOOL] RETURNS [patterns: LIST OF ROPENIL, success: BOOLTRUE] ~ {
Get the patterns in this container.
Errors: $invalidDID
document: YggRep.VDoc;
lastPattern: LIST OF ROPENIL;
stdValues: LIST OF YggRep.AttributeValue ← NIL;
document ← YggRep.VolatizeFromDID[YggEnvironment.nullTransID, containerDID, readOnly, [read, IF dontWait THEN fail ELSE wait], TRUE];
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, AutoIndices] THEN {stdValues ← loa.first.value; EXIT};
ENDLOOP;
flip through looking for DID's that don't have any modifications
FOR loav: LIST OF YggRep.AttributeValue ← stdValues, loav.rest UNTIL loav = NIL DO
indexPattern: ROPE ← NIL;
tpe: YggRep.TypedPrimitiveElement ← loav.first.valueSet.first;
SELECT tpe.docType FROM
YggRep.rope, YggRep.shortRope => {
indexPattern ← NARROW[tpe.bits];
};
ENDCASE => ERROR;
IF lastPattern = NIL THEN patterns ← LIST[indexPattern]
ELSE lastPattern ← (lastPattern.rest ← LIST[indexPattern]);
ENDLOOP;
IF ~YggRep.UnlatchVDoc[document] THEN ERROR;
};
Object creation and destruction
CreateObject: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID, makeRoot: BOOL] RETURNS [did: DIDNIL] ~ {
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: BOOLFALSE;
activeTrans: BOOLFALSE;
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: BOOLTRUE;
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;
};
Initialization
NoBytes ← NEW[YggRep.BitsRep[0]];
END.