<> <> <> <> <> <> <> <> 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