DIRECTORY DBCommon USING [GetDebugStream, Segment, CacheHandle, TupleObject, TID, NullTID], DBSegment USING [IsValidTID, SegmentFromTID], DBStorage, DBStorageTuple USING [], Process USING [Detach], RefTab, SafeStorage USING [ EnableFinalization, FinalizationQueue, EstablishFinalization, ReEstablishFinalization, CantEstablishFinalization, NewFQ, FQNext], IO; DBStorageTupleImpl: CEDAR MONITOR IMPORTS DBCommon, DBSegment, Process, RefTab, SafeStorage, IO EXPORTS DBStorage, DBStorageTuple = BEGIN TID: TYPE = DBCommon.TID; NullTID: TID = DBCommon.NullTID; Segment: TYPE = DBCommon.Segment; TupleObject: PUBLIC TYPE = DBCommon.TupleObject; TupleHandle: TYPE = REF TupleObject; nullTupleHandle: TupleHandle; storedFinalizationQLen: INT = 100; establishFinalizationFailed: BOOL _ FALSE; tupleFQ: SafeStorage.FinalizationQueue _ SafeStorage.NewFQ[length: storedFinalizationQLen]; systemTuples: TupleHandle _ NIL; freeTuples: TupleHandle _ NIL; freeCount: NAT _ 0; SegmentRecordHandle: TYPE = REF SegmentRecord; SegmentRecord: TYPE = RECORD [ storedTupleList: TupleHandle _ NIL ]; sizeOfSegmentTable: CARDINAL = 17; segmentTable: RefTab.Ref = RefTab.Create[mod: sizeOfSegmentTable]; maxFree: CARDINAL = 100; InitSegmentTuples: PUBLIC ENTRY PROC [segment: Segment] = { sHandle: SegmentRecordHandle _ NARROW[RefTab.Fetch[segmentTable, segment].val]; IF sHandle # NIL THEN RETURN; sHandle _ NEW[SegmentRecord]; sHandle.storedTupleList _ NEW[TupleObject _ [tid: NullTID, pred: NIL, succ: NIL, cacheHint: NIL]]; sHandle.storedTupleList.pred _ sHandle.storedTupleList.succ _ sHandle.storedTupleList; [] _ RefTab.Store[segmentTable, segment, sHandle] }; ConsTupleObject: PUBLIC ENTRY PROC [tid: TID, cacheHint: DBCommon.CacheHandle] RETURNS [result: TupleHandle] = { ENABLE UNWIND => InitSegmentTuples[DBSegment.SegmentFromTID[tid]]; segment: Segment = DBSegment.SegmentFromTID[tid]; sHandle: SegmentRecordHandle; found: BOOLEAN; item: RefTab.Val; [found, item] _ RefTab.Fetch[segmentTable, segment]; IF NOT found THEN ERROR; sHandle _ NARROW[item]; IF freeCount > 0 THEN { result _ GetFreeTuple[sHandle.storedTupleList]; result.tid _ tid; result.cacheHint _ cacheHint } ELSE { result _ NEW[TupleObject _ [tid: tid, cacheHint: cacheHint]]; result.pred _ sHandle.storedTupleList.pred; result.succ _ sHandle.storedTupleList; sHandle.storedTupleList.pred.succ _ result; sHandle.storedTupleList.pred _ result; SafeStorage.EnableFinalization[result] }; RETURN[result]; }; GetFreeTuple: INTERNAL PROC[head: TupleHandle] RETURNS[result: TupleHandle] = { result _ freeTuples.succ; result.succ.pred _ result.pred; result.pred.succ _ result.succ; result.succ _ head.succ; result.pred _ head; head.succ.pred _ result; head.succ _ result; freeCount _ freeCount - 1; SafeStorage.EnableFinalization[result] }; ConsSystemTupleObject: PUBLIC ENTRY PROC [] RETURNS [result: TupleHandle] = { IF freeCount > 0 THEN { result _ GetFreeTuple[systemTuples] } ELSE { result _ NEW[TupleObject _ []]; result.pred _ systemTuples.pred; result.succ _ systemTuples; systemTuples.pred.succ _ result; systemTuples.pred _ result; SafeStorage.EnableFinalization[result] }; RETURN[result] }; TupleObjectFinalizerProcess: PROC [] = { FinalizeStoredTupleObject: ENTRY PROC [t: TupleHandle] = { ENABLE UNWIND => NULL; IF freeCount < maxFree THEN { t.succ.pred _ t.pred; t.pred.succ _ t.succ; t.succ _ freeTuples.succ; t.pred _ freeTuples; freeTuples.succ.pred _ t; freeTuples.succ _ t; freeCount _ freeCount + 1 } ELSE { t.succ.pred _ t.pred; t.pred.succ _ t.succ; t.succ _ t.pred _ NIL; } }; DO th: TupleHandle _ NARROW[SafeStorage.FQNext[tupleFQ]]; FinalizeStoredTupleObject[th]; ENDLOOP; }; TIDOfTuple: PUBLIC PROC [x: TupleHandle] RETURNS [TID] = { RETURN[x.tid] }; EqualTuple: PUBLIC PROC [x, y: TupleHandle] RETURNS [BOOLEAN] = { IF x=NIL THEN x _ nullTupleHandle; IF y=NIL THEN y _ nullTupleHandle; RETURN[x.tid = y.tid]; }; NullTupleHandle: PUBLIC PROC [] RETURNS [TupleHandle] = { RETURN[nullTupleHandle] }; InvalidateMatchingTuples: PUBLIC ENTRY PROC [x: TupleHandle] = { xTID: TID = x.tid; s: Segment = DBSegment.SegmentFromTID[x.tid]; sHandle: SegmentRecordHandle; found: BOOLEAN; item: RefTab.Val; [found, item] _ RefTab.Fetch[segmentTable, s]; IF NOT found THEN ERROR; sHandle _ NARROW[item]; FOR p: TupleHandle _ sHandle.storedTupleList.succ, p.succ UNTIL p=sHandle.storedTupleList DO IF p.tid=xTID THEN p.tid _ NullTID; ENDLOOP; }; IsValidTuple: PUBLIC PROC [x: TupleHandle] RETURNS [valid: BOOL] = { IF DBSegment.IsValidTID[x.tid] THEN RETURN [valid: TRUE] ELSE { x.tid _ NullTID; RETURN [valid: FALSE] }; }; NullTuple: PUBLIC PROC [x: TupleHandle] RETURNS [yes: BOOL] = { IF x = NIL THEN RETURN [TRUE]; RETURN[ x.tid = NullTID]; }; InvalidateTuple: PUBLIC PROC [x: TupleHandle] = { IF x#NIL THEN x.tid _ NullTID; }; CallAfterFinishTransaction: PUBLIC ENTRY PROC [s: Segment] = { sHandle: SegmentRecordHandle; found: BOOLEAN; item: RefTab.Val; [found, item] _ RefTab.Fetch[segmentTable, s]; IF NOT found THEN ERROR; sHandle _ NARROW[item]; FOR p: TupleHandle _ sHandle.storedTupleList.succ, p.succ UNTIL p=sHandle.storedTupleList DO p.tid _ NullTID ENDLOOP }; PrintTupleObjectToStream: PROC [t: TupleHandle, debugStream: IO.STREAM] = { IOref: PROC[p: REF ANY] RETURNS[IO.Value] = INLINE { RETURN[IO.card[LOOPHOLE[p, LONG CARDINAL]]]}; debugStream.PutF["tupleHdl: %11bB, tupleID: %12bB, cacheHdl: %11bB", IOref[t], IO.card[t.tid], IOref[t.cacheHint]] }; PrintTupleObject: PUBLIC PROC [t: TupleHandle] = { PrintTupleObjectToStream[t, DBCommon.GetDebugStream[]] }; PrintTupleList: PROC [t: TupleHandle] = BEGIN start: TupleHandle_ t; out: IO.STREAM = DBCommon.GetDebugStream[]; out.PutF["tid %g\n", IO.int[t.tid]]; FOR t_ start.succ, t.succ UNTIL t=start DO out.PutF["tid %g\n", IO.int[t.tid]] ENDLOOP; END; SafeStorage.EstablishFinalization[ type: CODE[TupleObject], npr: 2, fq: tupleFQ ! SafeStorage.CantEstablishFinalization => {establishFinalizationFailed_ TRUE; CONTINUE} ]; IF establishFinalizationFailed THEN SafeStorage.ReEstablishFinalization[ type: CODE[TupleObject], npr: 2, fq: tupleFQ ]; systemTuples _ NEW[TupleObject _ [tid: NullTID, pred: NIL, succ: NIL, cacheHint: NIL]]; systemTuples.pred _ systemTuples.succ _ systemTuples; freeTuples _ NEW[TupleObject _ [tid: NullTID, pred: NIL, succ: NIL, cacheHint: NIL]]; freeTuples.pred _ freeTuples.succ _ freeTuples; nullTupleHandle _ NEW[TupleObject _ [tid: NullTID, pred: NIL, succ: NIL, cacheHint: NIL]]; TRUSTED{ Process.Detach[ FORK TupleObjectFinalizerProcess[] ] } END.--DBStorageTupleImpl θFile: DBStorageTupleImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last edited by MBrown on December 6, 1982 9:27 am Cattell on November 4, 1983 2:26 am Willie-Sue on February 15, 1985 12:38:55 pm PST Donahue, May 22, 1986 11:23:33 am PDT Widom, September 12, 1985 9:13:44 am PDT After initialization, points to a TupleObject with tid = NullTID (on storedTupleList.) This is returned by NullTupleHandle[] so that others may share. Nobody should modify! For each segment in use there is an associated storedTupleList (head of doubly-linked list (through pred, succ) of all in-use stored tuple objects). A RefTab is used to map segments to their tuple and free lists. The segment table and the free list are monitored Remove the handle from the free list And add it to the list of stored handles that begins at head Cut it out of the list to which it belongs Stitch it back into the free list Next line is a noop for single-element list (t.succ = t), but that is ok ... ΚŽ˜šœ™Jšœ Οmœ1™<—šœ™Jšœ"™"Jšœ#™#Jšœ/™/Icode™%J™(—J˜šΟk ˜ Jšœ žœ5žœ ˜QJšœ žœ˜-Jšœ ˜ Jšœžœ˜Jšœžœ ˜Jšœ˜šœ žœ˜J˜VJ˜*—Jšžœ˜J˜—šœžœž˜!šž˜J˜ J˜ J˜J˜J˜ Jšž˜—šž˜J˜ J˜—Jšœž˜J˜Jšžœžœ žœ˜Jšœ žœ˜ J˜Jšœ žœ˜!J˜Jšœ žœžœ˜0Jšœ žœžœ ˜$J˜˜JšœV™VJšœV™VJ˜—Jšœžœ˜"J˜Jšœžœžœ˜*J˜Jšœ[˜[J˜Jšœžœ˜ J˜Jšœžœ˜J˜Jšœ žœ˜J˜Jšœ”™”Jšœžœžœ˜.Jšœžœžœ"žœ˜DJ˜Jšœr™rJšœžœ˜"JšœB˜BJ˜Jšœ žœ˜J˜šΟnœžœž œ˜;Jšœžœ*˜OJšžœ žœžœžœ˜Jšœ žœ˜Jš œžœ$žœžœ žœ˜bJšœV˜VJšœ4˜4J˜—š Ÿœžœžœžœžœ"žœ˜pJšžœžœ5˜BJ˜1Jšœ˜Jšœžœ˜!Jšœ4˜4Jšžœžœžœžœ˜Jšœ žœ˜šžœžœ˜Jšœ/˜/Jšœ.˜.J˜—šžœ˜Jšœ žœ1˜=Jšœ+˜+Jšœ&˜&Jšœ+˜+Jšœ&˜&J˜)—Jšžœ ˜J˜J˜—šŸ œžœžœžœ˜OJšœ˜šœ$™$Jšœ˜Jšœ˜—šœ<™Jšœ˜Jšœžœ˜!Jšœ.˜.Jšžœžœžœžœ˜Jšœ žœ˜Jšžœ7žœžœžœ˜wJ˜—šŸœžœžœžœ˜KšŸœžœžœžœžœžœ žœ˜4Jš žœžœžœžœžœ˜-—˜DJšœ žœ$˜0—J˜—šŸœžœžœ˜2J˜6J˜J˜—šŸœžœ˜'Jšžœ˜Jšœžœžœ˜+Jšœžœ ˜$šžœžœ ž˜*Jšœžœ žœ˜-—Jšžœ˜—J˜šœ)žœ$˜QJšœGžœžœ˜Y—šžœž˜#Jšœ+žœ%˜T—J˜Jš œžœ$žœžœ žœ˜WJšœ5˜5J˜Jš œ žœ$žœžœ žœ˜UJšœ/˜/J˜Jš œžœ$žœžœ žœ˜ZJ˜Jšžœžœ"˜?J˜—šžœΟc˜J˜——…—¨&