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]; YggStabilizeImpl: CEDAR PROGRAM IMPORTS IO, Process, Rope, YggDID, YggDIDMap, YggFile, YggFixedNames, YggIndexMaint, YggRep, YggTransaction, YggVolatileObjectCache EXPORTS YggDID, YggRep ~ BEGIN ROPE: TYPE ~ Rope.ROPE; DID: PUBLIC TYPE ~ REF DIDRep; DIDRep: PUBLIC TYPE ~ YggDIDPrivate.DIDRep; AllNulls: REF PACKED ARRAY [0..PBasics.charsPerWord) OF CHAR _ NEW[ PACKED ARRAY [0..PBasics.charsPerWord) OF CHAR _ ALL[0C]]; PreCommit: PUBLIC PROC[tid: Camelot.tidT] ~ { vDocs: LIST OF YggRep.VDoc; IF YggTransaction.IsTopLevel[tid] THEN { -- top level xact trying to commit tryingToLatch: BOOL _ TRUE; vDocs _ YggTransaction.GetPossibleDocumentUpdates[tid]; -- get documents (really VDoc's) that were write locked during the xact WHILE tryingToLatch DO latchFailed: LIST OF YggRep.VDoc _ NIL; FOR vD: LIST OF YggRep.VDoc _ vDocs, vD.rest UNTIL vD = NIL DO IF ~YggRep.LatchVDoc[vD.first, FALSE] THEN { latchFailed _ vD; EXIT; }; ENDLOOP; IF latchFailed # NIL THEN { FOR vD: LIST OF YggRep.VDoc _ vDocs, vD.rest UNTIL vD = NIL DO IF vD = latchFailed THEN EXIT; IF ~YggRep.UnlatchVDoc[vD.first] THEN ERROR; ENDLOOP; Process.Pause[Process.MsecToTicks[13]]; LOOP; }; tryingToLatch _ FALSE; FOR vD: LIST OF YggRep.VDoc _ vDocs, vD.rest UNTIL vD = NIL DO doc: YggInternal.Document _ NIL; meta: YggInternal.FileHandle _ NIL; metaAttributesInAttributesFileChanged: BOOL _ FALSE; contentsInAttributesFileChanged: BOOL _ FALSE; setContentsAsAttribute: BOOL _ FALSE; componentFiles: LIST OF YggInternal.FileHandle _ NIL; attributesStream: IO.STREAM _ NIL; doc _ YggDIDMap.OpenDocumentFromDID[vD.first.did, tid, TRUE]; [vD.first.fromDID, vD.first.toDID, vD.first.linkType] _ YggDIDMap.SwapLinkInfo[doc, vD.first.fromDID, vD.first.toDID, vD.first.linkType]; componentFiles _ YggDIDMap.GetComponentFiles[doc]; IF vD.first.destroyed THEN { FOR comFiles: LIST OF YggInternal.FileHandle _ componentFiles, comFiles.rest UNTIL comFiles = NIL DO YggFile.Delete[file: comFiles.first, tid: tid]; ENDLOOP; } ELSE { meta _ YggFile.FileFromComponentFiles[componentFiles: componentFiles, fileUse: $meta]; IF meta = NIL AND (vD.first.outlinksChanged # NIL OR vD.first.inlinksChanged # NIL OR vD.first.metaAttributesChanged # NIL) THEN metaAttributesInAttributesFileChanged _ TRUE; IF vD.first.contentsChanged OR vD.first.namesOfAttributesChanged # NIL OR metaAttributesInAttributesFileChanged THEN { -- if a change really occured contents, attributes, links: YggInternal.FileHandle _ NIL; componentFiles: LIST OF YggInternal.FileHandle; componentFiles _ YggDIDMap.GetComponentFiles[doc]; IF vD.first.contentsChanged THEN { contents _ YggFile.FileFromComponentFiles[componentFiles: componentFiles, fileUse: $contents]; IF contents = NIL THEN { contentsInAttributesFileChanged _ TRUE; setContentsAsAttribute _ TRUE; IF vD.first.contents.docType = YggRep.uninterpretedBytes OR vD.first.contents.docType >= YggRep.lastReservedDocType THEN { byteSize: INT; IF (byteSize _ YggRep.SizeOfBits[vD.first.contents.bits]) > 200 THEN { contents _ YggFile.Create[size: YggFile.PagesForBytes[byteSize], did: vD.first.did, fileUse: $contents, nearToDid: YggEnvironment.nullDID, tid: tid]; YggDIDMap.AddComponentFile[doc: doc, componentFile: contents, tid: tid]; contentsInAttributesFileChanged _ FALSE; setContentsAsAttribute _ FALSE; }; }; }; } ELSE { testContents: YggInternal.FileHandle _ NIL; testContents _ YggFile.FileFromComponentFiles[componentFiles: componentFiles, fileUse: $contents]; IF testContents = NIL THEN setContentsAsAttribute _ TRUE ELSE IF YggFile.Info[testContents, tid].byteSize = 0 THEN setContentsAsAttribute _ TRUE; }; IF vD.first.namesOfAttributesChanged # NIL OR metaAttributesInAttributesFileChanged OR contentsInAttributesFileChanged OR contents # NIL OR vD.first.contentsChanged THEN { attributes _ YggFile.FileFromComponentFiles[componentFiles: componentFiles, fileUse: $attributes]; IF attributes = NIL THEN { attributes _ YggFile.Create[size: 1, did: vD.first.did, fileUse: $attributes, nearToDid: YggEnvironment.nullDID, tid: tid]; YggDIDMap.AddComponentFile[doc: doc, componentFile: attributes, tid: tid]; }; }; attributesStream _ StabilizeToFiles[tid, vD.first.did, vD.first, metaAttributesInAttributesFileChanged, contents, attributes, links, setContentsAsAttribute]; IF meta = NIL THEN StabilizeMetaAttributes[tid, vD.first.did, vD.first, NIL, attributesStream]; -- apply changes (if any) and write it out }; IF vD.first.namesOfAttributesChanged # NIL THEN { -- if an attribute really occured FOR loa: LIST OF YggRep.Attribute _ vD.first.attributes, loa.rest UNTIL loa = NIL DO FOR aC: LIST OF ROPE _ vD.first.namesOfAttributesChanged, aC.rest UNTIL aC = NIL DO IF Rope.Equal[aC.first, loa.first.attributeName] THEN { vD.first.attributesChanged _ CONS[loa.first, vD.first.attributesChanged]; EXIT; }; ENDLOOP; ENDLOOP; }; IF vD.first.metaAttributesChanged # NIL OR vD.first.outlinksChanged # NIL OR vD.first.inlinksChanged # NIL THEN { -- if a meta attribute change occured IF meta # NIL THEN StabilizeMetaAttributes[tid, vD.first.did, vD.first, meta, attributesStream]; -- apply changes and write it out IF vD.first.metaAttributesChanged # NIL THEN YggIndexMaint.NewValueForMetaAttribute[vD.first.did, tid, vD.first.metaAttributesChanged]; }; IF attributesStream # NIL THEN { IO.SetLength[attributesStream, IO.GetIndex[attributesStream]]; IO.Close[attributesStream]; }; IF vD.first.namesOfAttributesChanged # NIL THEN { -- if a change really occured vDoc: YggRep.VDoc; newValues: LIST OF LIST OF YggRep.AttributeValue _ NIL; oldValues: LIST OF LIST OF YggRep.AttributeValue _ NIL; vDoc _ vD.first; FOR aC: LIST OF ROPE _ vDoc.namesOfAttributesChanged, aC.rest UNTIL aC = NIL DO FOR loa: LIST OF YggRep.Attribute _ vDoc.attributes, loa.rest UNTIL loa = NIL DO IF Rope.Equal[aC.first, loa.first.attributeName] THEN newValues _ CONS[loa.first.value, newValues]; ENDLOOP; FOR loa: LIST OF YggRep.Attribute _ vDoc.attributesChanged, loa.rest UNTIL loa = NIL DO IF Rope.Equal[aC.first, loa.first.attributeName] THEN oldValues _ CONS[loa.first.value, oldValues]; ENDLOOP; YggIndexMaint.NewValueForAttribute[vDoc.did, tid, aC.first, oldValues, newValues]; ENDLOOP; }; }; ENDLOOP; FOR vD: LIST OF YggRep.VDoc _ vDocs, vD.rest UNTIL vD = NIL DO IF ~YggRep.UnlatchVDoc[vD.first] THEN ERROR; ENDLOOP; ENDLOOP; }; }; Commit: PUBLIC PROC[tid: Camelot.tidT] ~ { vDocs: LIST OF YggRep.VDoc; vDocs _ YggTransaction.GetPossibleDocumentUpdates[tid]; FOR vD: LIST OF YggRep.VDoc _ vDocs, vD.rest UNTIL vD = NIL DO IF YggTransaction.IsTopLevel[tid] THEN { IF vD.first.namesOfAttributesChanged # NIL OR vD.first.metaAttributesChanged # NIL THEN { -- if a change really occured YggIndexMaint.NewValueForAttributeCommitStatus[vD.first.did, tid, TRUE]; }; vD.first.namesOfAttributesChanged _ NIL; vD.first.attributesChanged _ NIL; vD.first.metaAttributesChanged _ NIL; vD.first.outlinksChanged _ NIL; vD.first.inlinksChanged _ NIL; vD.first.contentsChanged _ FALSE; vD.first.linkChanged _ FALSE; }; YggVolatileObjectCache.PromoteToParent[vD.first.did, tid]; ENDLOOP; }; Abort: PUBLIC PROC[tid: Camelot.tidT] ~ { vDocs: LIST OF YggRep.VDoc; vDocs _ YggTransaction.GetPossibleDocumentUpdates[tid]; IF YggTransaction.IsTopLevel[tid] THEN { -- must back out of applied intentions FOR vD: LIST OF YggRep.VDoc _ vDocs, vD.rest UNTIL vD = NIL DO doc: YggInternal.Document _ NIL; doc _ YggDIDMap.OpenDocumentFromDID[vD.first.did, tid]; [] _ YggDIDMap.SwapLinkInfo[doc, vD.first.fromDID, vD.first.toDID, vD.first.linkType]; YggVolatileObjectCache.InvalidateDID[vD.first.did, YggEnvironment.nullTransID]; IF vD.first.namesOfAttributesChanged # NIL OR vD.first.metaAttributesChanged # NIL THEN { -- if a change really occured YggIndexMaint.NewValueForAttributeCommitStatus[vD.first.did, tid, FALSE]; }; vD.first.namesOfAttributesChanged _ NIL; vD.first.attributesChanged _ NIL; vD.first.metaAttributesChanged _ NIL; vD.first.outlinksChanged _ NIL; vD.first.inlinksChanged _ NIL; vD.first.contentsChanged _ FALSE; vD.first.linkChanged _ FALSE; ENDLOOP; } ELSE { -- smash object cache for xact that aborted FOR vD: LIST OF YggRep.VDoc _ vDocs, vD.rest UNTIL vD = NIL DO YggVolatileObjectCache.InvalidateDID[vD.first.did, tid]; ENDLOOP; }; }; 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; 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]~ { 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 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 ] = { 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] = { 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; }; END.  YggStabilizeImpl.mesa Copyright ำ 1988 by Xerox Corporation. All rights reserved. Bob Hagmann March 6, 1989 10:47:17 am PST Take a volatile form of a document, and write it onto some files. Exported procedures for transactions A transaction is trying to commit. Apply intentions. Take the volatile form of documents, and write them out fetch all the new values for the attribute Commit actually occured. Transaction has aborted. This transaction may or may not have gone through PreCommit. Smash object cache for the null transaction => this makes the system rebuild the cache from stable values the next time. That's semantically OK, but not fast. If there are lots of aborts (which is not the expected case), then this could be a performance loose. Exported conversion procedures apply link mods Given a document, write it out to the files. 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]; }; Write the contents of a TypedPrimitiveElement. The type has already been writen. Given an attribute, write it out to the stream. See YggRep.mesa for a description of what the format is. ส๛˜code•Mark outsideHeaderšœ™Kšœ<™KšœœJ˜f—K˜Kšัblnœœ˜Kšœœy˜ƒKšœ˜šœ˜K˜Kšœœœ˜K˜Kšœœœœ˜Kšœœœ˜+K˜Kšœ  œœœœ œœœ œ˜~—headšœ$™$šฯn œœœ˜-K™5K™7Kšœœœ ˜šœ œฯc"˜LKšœœœ˜Kšœ9 G˜€šœ˜Kšœ œœœ˜'š œœœœœ˜>šœœœ˜,Kšœ˜Kšœ˜K˜—Kšœ˜šœœœ˜š œœœœœ˜>Kšœœœ˜Kšœœœ˜,Kšœ˜—Kšœ'˜'Kšœ˜K˜——Kšœœ˜š œœœœœ˜>Kšœœ˜ Kšœœ˜#Kšœ'œœ˜4Kšœ!œœ˜.Kšœœœ˜%Kšœœœœ˜5Kšœœœœ˜"Kšœ7œ˜=Kšœ‰˜‰Kšœ2˜2šœœ˜š œ œœ8œ œ˜dKšœ/˜/Kšœ˜—K˜—šœœ˜KšœV˜VKšœœœœœœœ"œœ)œ˜ฎš œœ%œœ'œ ˜•Kšœ6œ˜:Kšœœœ˜/Kšœ2˜2šœœ˜"Kšœ^˜^šœ œœ˜Kšœ"œ˜'Kšœœ˜šœ7œ9œ˜zKšœ œ˜šœ>œ˜FKšœ•˜•KšœH˜HKšœ"œ˜(Kšœœ˜K˜—K˜—K˜—K˜—šœœ˜Kšœ'œ˜+Kšœb˜bKšœœœ˜8Kš œœœ.œœ˜YK˜—šœ%œœ'œ!œ œœœ˜ซKšœb˜bšœœœ˜Kšœ{˜{KšœJ˜JK˜—K˜—Kšœ˜Kš œœœ6œ *˜‹Kšœ˜—šœ%œœ !˜Sš œœœ2œœ˜Tš œœœœ.œœ˜Sšœ/œ˜7Kšœœ(˜JKšœ˜K˜—Kšœ˜—Kšœ˜—Kšœ˜—šœ"œœœœœœ %˜˜KšœœœP !˜ƒKšœ"œœ[˜‡Kšœ˜—šœœœ˜ Kšœœ˜>Kšœ˜K˜—šœ%œœ ˜PK˜Kš œ œœœœœ˜7Kš œ œœœœœ˜7Kšœ˜š œœœœ*œœ˜OK™*š œœœ.œœ˜PKšœ/œ œ˜cKšœ˜—š œœœ5œœ˜WKšœ/œ œ˜cKšœ˜—KšœR˜RKšœ˜—K˜—K˜—Kšœ˜—š œœœœœ˜>Kšœœœ˜,Kšœ˜—Kšœ˜—K˜—K˜—K˜šŸœœœ˜*K™Kšœœœ ˜Kšœ7˜7š œœœœœ˜>šœ œ˜(š œ%œœ$œ ˜xKšœBœ˜HK˜—Kšœ(˜(Kšœ!˜!Kšœ%˜%Kšœ˜Kšœ˜Kšœœ˜!Kšœœ˜K˜—Kšœ:˜:Kšœ˜—K˜—K˜šŸœœœ˜)Kšœ+ฯrœกœ™VKšœœœ ˜Kšœ7˜7šœ œ &˜Pš œœœœœ˜>Kšœœ˜ Kšœ7˜7KšœV˜VšœO˜OKšœ†™†—š œ%œœ$œ ˜xKšœBœ˜IK˜—Kšœ(˜(Kšœ!˜!Kšœ%˜%Kšœ˜Kšœ˜Kšœœ˜!Kšœœ˜Kšœ˜—K˜—šœœ +˜4š œœœœœ˜>Kšœ8˜8Kšœ˜—K˜—K˜—K˜—šœ™š Ÿœœœ(œAœœ˜žKšœ œœ˜šฯbœœ œœ&œœœ œœ˜–Kšœ˜š œœœ*œœ˜Nš œœœ-œœ˜Qšœ7œ˜?šœœ ˜+Kšœœ:˜TKšœ˜K˜—šœœ ˜Kšœœœ˜Kšœ œœ$˜4š œœœ@œ œ˜fKšœ œ˜ Kšœ"œœ˜/Kšœ œ˜#šœ1œ˜9Kšœ œ˜Kšœ œœ!˜6Kšœœ˜ Kšœ˜K˜—Kšœ˜Kšœ˜—Kšœ œœ˜K˜—K˜—šœœœœ˜+Kšœ œœ1˜[K˜—Kšœ˜—Kšœ˜—K˜—šœœœ˜ K˜KšœC˜CK˜—š œœœAœœ˜eKšœ œœ˜Kšœœœ˜'š œœœ2œœ˜Tšœ?œ˜GKšœœœ œ˜1š œ œœNœ œœ˜{Jšœ4˜4Kšœ œ˜Jšœœœ˜(šœœ ˜8Jšœ˜Jšœ˜J˜—Jšœ œ ˜šœ2œ˜:Jšœœœ0œ˜ašœ"œœ˜.Jšœ œœ˜3Jšœœ˜J˜—Jšœ œ˜Jšœ˜J˜—Jšœ˜šœœœœ˜+Jšœœ ˜Jšœ œ$œ˜9Jšœ œ˜J˜—Jšœ˜—Kšœ˜K˜—Kšœ ˜ š œœœœ œ˜:Jšœ˜Jš œ%œœœœ'˜bJšœœ˜9K˜—Kšœ˜—Kšœ˜—š œœœ?œœ˜{Kšœ9˜9Kšœ˜K™—KšœC˜CKšœ@˜@Kšœœœ)œ$˜mKšœœœ(œ#˜jšœ ˜Kšœœ˜>Kšœ˜K˜—K˜K˜—šŸœœ(œ5œKœœœœœ˜๙Kšœ,™,K˜K˜Kšœ8˜8K˜šœ œœ˜Kšœœœœ˜ KšœE˜Ešœ˜!Kšœœ˜Kšœ`œ˜ešœ˜Kšœœ˜ Kšœœ˜#Kšœ ˜"Kšœœ˜K˜—šœ˜ Kšœœ˜Kšœœ˜#šœ˜ Kšœ œœ˜'Kšœ ˜ Kšœ œ˜Kš œœ  œœœ*˜xKšœ;˜=K˜—Kšœœ˜K˜——Kšœœ˜:Kšœ˜Kšœ˜K˜—šœ œœ™Kšœœœœ™ KšœE™EKšœ)œ™/Kšœœ™:Kšœ™Kšœ™K™—šœœœ˜KšœI˜IKšœ2˜2š œœœ;œœ˜wKšœ9˜9Kšœ˜—Kš œœœœœœ&˜xK˜—K˜Kšœ:˜:K˜K˜K™—š ขœœœœœ˜:Kš œœœœœ˜!Kš œœ#œ œœ˜RKšœ˜—K˜šข œœœœR˜~KšœQ™Qšœ ˜Kšœœ˜šœ˜Kšœœœ˜Kšœœ ˜Kšœ ˜ K˜—šœ˜Kšœœ˜ Kšœœ ˜Kšœ(˜(K˜—šœ˜Kšœœ˜ Kšœœ˜ Kšœœ ˜Kšœ˜KšœC˜CKšœ(˜(K˜—šœ˜Kšœœœ˜Kšœœ ˜šœ˜ Kšœ œœœ˜Kšœ œ˜Kšœ#œœ˜JKšœ˜—Kšœ˜—šœ˜Kšœ!˜!Kšœœ ˜ šœ˜ Kšœ œœ˜.Kšœ œ˜ Kšœ#œ-˜ZKšœ˜—Kšœ˜—šœ˜Kšœœ˜ Kšœœ ˜šœ˜ Kšœ œœ˜Kšœœ˜Kšœ#œ œ ˜IKšœ˜—Kšœ˜—šœ˜ Kšœœ˜Kšœœ˜šœ œœ˜Kšœ˜K˜—šœœ˜Kšœœ ˜Kšœœ.˜Pšœ˜ Kšœœœœ˜'Kšœ œ˜Kš œ#œ œœ œœ+˜‘Kšœ˜—KšœYœ˜sKš œœœœœ#œ!˜K˜—K˜——Kšœ˜K˜—š ข œœœœ œœ˜RKšœœ˜ Kšœœ˜Kšœ˜Kšœ œœ#˜5KšœYœ˜rKšœ7œ˜PKšœœ#œ!˜WKšœ˜K˜—šขœœ1œœ˜SKšœi™iKšœœœ˜Kšœœœ˜"Kšœœ˜!Kšœ/˜/Kšœ#˜#š œœœ2œœ˜RKšœ6˜6Kšœœœœ˜8Kšœœœœ˜Bš œœœ<œœ˜^Kšœ.˜.Kš œœ!œœœ˜Kšœ˜—Kšœ˜—Kšœ(˜(Kšœ*˜*Kšœ?˜?Kšœ2˜2šœœ˜0Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ0˜0Kšœ ˜—Kšœœœ˜,Kšœœœ "˜cKšœ< ˜TKšœœ7 %˜š œœœ2œœ˜RKšœœ8 ˜cšœœ˜%K˜š œœœ<œœ˜^K˜Kšœ˜—Kšœ"˜"Kšœ˜—š œœœ<œœ˜^Kšœ.˜.Kšœ!œ)˜PKšœ!˜!Kšœ˜—Kšœ˜—K˜K˜—™K™——K˜Kšœ˜—…—Mฌiว