DIRECTORY DBCommon USING [GetDebugStream, Segment, CacheHandle, TupleObject], DBSegment USING [IsValidTID, SegmentFromTID], DBStorage, DBStorageTID USING [TID, NullTID], 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 = DBStorageTID.TID; NullTID: TID = DBStorageTID.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 PROC [segment: Segment] = { establishFinalizationFailed: BOOL _ FALSE; sHandle: SegmentRecordHandle _ 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 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 NOT ISTYPE[x, TupleHandle] THEN RETURN [valid: TRUE]; IF DBSegment.IsValidTID[x.tid] THEN RETURN [valid: TRUE] ELSE { x.tid _ NullTID; RETURN [valid: FALSE]; }; }; InvalidateTuple: PUBLIC PROC [x: TupleHandle] = { IF x#NIL THEN x.tid _ NullTID; }; CallAfterFinishTransaction: PUBLIC 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 IF p.tid # NullTID THEN 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=NIL 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; 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, March 10, 1986 11:48:57 am PST Widom, September 12, 1985 9:13:44 am PDT Module state not requiring monitor protection. 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 ... Κx˜šœ™Jšœ Οmœ1™<—šœ™Jšœ"™"Jšœ#™#Jšœ/™/Icode™'J™(—J˜šΟk ˜ Jšœ žœ5˜CJšœ žœ˜-Jšœ ˜ 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šœ.™.˜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œžœžœ˜5Jšœžœžœ˜*Jšœžœ˜2Jš œžœ$žœžœ žœ˜bJšœV˜VJšœ1žœ˜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šœ˜—šœ<™