<> <> <> <> <> <> <> <> <> DIRECTORY DB USING [InternalError], DBCommon USING[DBPage, NullDBPage, CacheHandle], DBSegment USING[ReadPage, UnlockPage], DBStorage USING[TupleHandle, FirstLast], DBStorageConcrete USING[TuplesetScanObject], DBStorageField USING[TuplesetFieldHandle], DBStoragePagetags USING[AssertPageIsTuplePage], DBStoragePrivate USING[GetNWordBase], DBStorageTID USING[TID, ConsTID], DBStorageTSDict USING[GetIndex, EntryFromIndex, TSDictSlotIndex], DBStorageTuple USING[ConsTupleObject, IsValidTuple, TIDOfTuple], DBStorageTupleset USING[TuplesetObject], DBStorageTuplesetScan USING[], DBStorageVec USING[VecPage, TypeOfSlot, HighSlotIndexOfPage]; DBStorageTuplesetScanImpl: CEDAR PROGRAM IMPORTS DB, DBSegment, DBStorageField, DBStoragePrivate, DBStoragePagetags, DBStorageTID, DBStorageVec, DBStorageTuple, DBStorageTSDict EXPORTS DBStorage, DBStorageTuplesetScan = BEGIN OPEN DBCommon, DBStorageTID, DBStorageTuple; <> TuplesetScanObject: PUBLIC TYPE = DBStorageConcrete.TuplesetScanObject; TuplesetScanHandle: TYPE = REF TuplesetScanObject; <> activeTuplesetScanList: TuplesetScanHandle; <<1st item on list is a permanent header node>> Init: PUBLIC PROC = { activeTuplesetScanList _ NEW[TuplesetScanObject _ [tupleset: NIL]]; }; OpenScanTupleset: PUBLIC PROC [ x: DBStorage.TupleHandle--tupleset--, start: DBStorage.FirstLast] RETURNS [TuplesetScanHandle] = { result: TuplesetScanHandle = NEW[TuplesetScanObject _ [tupleset: x]]; result.position _ SELECT start FROM First => beforeFirst, Last => afterLast, ENDCASE => ERROR; result.link _ activeTuplesetScanList.link; activeTuplesetScanList.link _ result; RETURN[result] }; NextScanTupleset: PUBLIC PROC [scan: TuplesetScanHandle] RETURNS [DBStorage.TupleHandle] = { IF scan=NIL THEN RETURN[NIL]; -- convenience feature DO--loop to simulate tail-recursion WHILE scan.position # middle DO SELECT scan.position FROM beforeFirst => {SetInitialPage[scan]; NewPage[scan, forward]};--makes position # beforeFirst afterLast => RETURN[NIL]; invalid => ERROR DB.InternalError; -- InvalidTuplesetScan ENDCASE => ERROR; ENDLOOP; FOR slotI: CARDINAL IN [scan.slotIndex + 1 .. DBStorageVec.HighSlotIndexOfPage[scan.pagePtr]] DO IF DBStorageVec.TypeOfSlot[scan.pagePtr, slotI] = scan.localTuplesetID THEN GOTO FoundNext; REPEAT FoundNext => {--return the tuple result: DBStorage.TupleHandle _ ConsTupleObject[tid: ConsTID[scan.page, slotI], cacheHint: scan.pageHint]; scan.slotIndex _ slotI; RETURN[result]; };--FoundNext FINISHED => {--try next page TRUSTED { scan.page _ DBStorageTSDict.EntryFromIndex[scan.pagePtr, scan.localTuplesetID].next; }; DBSegment.UnlockPage[scan.pageHint]; NewPage[scan, forward]; };--FINISHED ENDLOOP; ENDLOOP; };--NextScanTupleset PrevScanTupleset: PUBLIC PROC [scan: TuplesetScanHandle] RETURNS [DBStorage.TupleHandle] = { IF scan=NIL THEN RETURN[NIL]; -- convenience feature DO--loop to simulate tail-recursion WHILE scan.position # middle DO SELECT scan.position FROM beforeFirst => RETURN[NIL]; afterLast => {SetInitialPage[scan]; NewPage[scan, backward]};--makes position # afterLast invalid => ERROR DB.InternalError; -- InvalidTuplesetScan ENDCASE => ERROR; ENDLOOP; FOR slotI: CARDINAL DECREASING IN (DBStorageTSDict.TSDictSlotIndex .. MIN[scan.slotIndex, DBStorageVec.HighSlotIndexOfPage[scan.pagePtr]] ] DO IF DBStorageVec.TypeOfSlot[scan.pagePtr, slotI] = scan.localTuplesetID THEN GOTO FoundNext; REPEAT FoundNext => {--return the tuple result: DBStorage.TupleHandle _ ConsTupleObject[tid: ConsTID[scan.page, slotI], cacheHint: scan.pageHint]; scan.slotIndex _ slotI - 1; RETURN[result]; };--FoundNext FINISHED => {--try next page TRUSTED { scan.page _ DBStorageTSDict.EntryFromIndex[scan.pagePtr, scan.localTuplesetID].prev; }; DBSegment.UnlockPage[scan.pageHint]; NewPage[scan, backward]; };--FINISHED ENDLOOP; ENDLOOP; };--PrevScanTupleset SetInitialPage: PROC [scan: TuplesetScanHandle] = TRUSTED { <> <> tsObjPtr: LONG POINTER TO DBStorageTupleset.TuplesetObject; cacheHint: DBCommon.CacheHandle; [tsObjPtr, cacheHint] _ DBStoragePrivate.GetNWordBase[scan.tupleset, DBStorageField.TuplesetFieldHandle[]]; scan.page _ SELECT scan.position FROM beforeFirst => tsObjPtr.searchList.next, afterLast => tsObjPtr.searchList.prev, ENDCASE => ERROR; DBSegment.UnlockPage[cacheHint]; };--SetInitialPage ForwardBackward: TYPE = {forward, backward}; NewPage: PROC [scan: TuplesetScanHandle, direction: ForwardBackward] = TRUSTED { <> <> <> IF scan.page = NullDBPage THEN { scan.position _ SELECT direction FROM forward => afterLast, backward => beforeFirst, ENDCASE => ERROR; } ELSE { tsIsInDict: BOOLEAN; scan.slotIndex _ SELECT direction FROM forward => DBStorageTSDict.TSDictSlotIndex, backward => LAST[CARDINAL],--larger than the number of slots on a page ENDCASE => ERROR; [scan.pageHint, scan.pagePtr] _ DBSegment.ReadPage[scan.page, NIL]; DBStoragePagetags.AssertPageIsTuplePage[scan.pagePtr]; [scan.localTuplesetID, tsIsInDict] _ DBStorageTSDict.GetIndex[scan.pagePtr, TIDOfTuple[scan.tupleset]]; IF ~tsIsInDict THEN ERROR DB.InternalError; --[BadTuplesetSearchList]; scan.position _ middle; };--IF };--NewPage CloseScanTupleset: PUBLIC PROC [scan: TuplesetScanHandle] = { IF scan.position = middle THEN DBSegment.UnlockPage[scan.pageHint]; FOR scanPred: TuplesetScanHandle _ activeTuplesetScanList, scanPred.link UNTIL scanPred = NIL DO IF scanPred.link = scan THEN {scanPred.link _ scan.link; scan.link _ NIL; EXIT}; REPEAT FINISHED => ERROR DB.InternalError; --[TuplesetScanNotFound]; ENDLOOP; scan.position _ invalid; scan.pageHint _ NIL; scan.tupleset _ NIL; };--CloseScanTupleset CallAfterFinishTransaction: PUBLIC PROC [] = { rPrev: TuplesetScanHandle _ activeTuplesetScanList; UNTIL rPrev.link = NIL DO r: TuplesetScanHandle _ rPrev.link; IF NOT DBStorageTuple.IsValidTuple[r.tupleset] THEN { r.position _ invalid; r.pageHint _ NIL; r.tupleset _ NIL; rPrev.link _ r.link; r.link _ NIL; } ELSE rPrev _ r; ENDLOOP; }; NoticeDeletion: PUBLIC PROC [ dbPage: DBPage, tsID: TID, localTSID: CARDINAL, nextDBPage: DBPage] = { FOR scan: TuplesetScanHandle _ activeTuplesetScanList.link, scan.link UNTIL scan=NIL DO IF scan.position = middle AND scan.page = dbPage THEN { <> IF DBStorageTuple.TIDOfTuple[scan.tupleset] = tsID THEN { <> scan.page _ nextDBPage; DBSegment.UnlockPage[scan.pageHint]; NewPage[scan, forward]; } ELSE { <> IF scan.localTuplesetID > localTSID THEN scan.localTuplesetID _ scan.localTuplesetID - 1; };--IF };--IF ENDLOOP; };--NoticeDeletion END.--DBStorageTuplesetScanImpl CHANGE LOG Created by MBrown on June 14, 1980 12:26 PM <> Changed by MBrown on June 20, 1980 4:26 PM <> Changed by MBrown on July 9, 1980 6:25 PM <> Changed by MBrown on July 9, 1980 11:40 PM <> <> <> Changed by MBrown on July 11, 1980 2:47 PM <> Changed by MBrown on July 22, 1980 2:28 PM <> <> Changed by MBrown on August 1, 1980 10:59 PM <> <> Changed by MBrown on August 3, 1980 1:24 AM <> <> Changed by MBrown on August 4, 1980 10:34 PM <> Changed by MBrown on August 6, 1980 9:34 PM <> <> <> Changed by MBrown on September 12, 1980 2:09 PM <> Changed by MBrown on November 12, 1980 4:11 PM <> <> <> Changed by MBrown on December 11, 1980 2:39 PM <> <> <> Changed by MBrown on February 27, 1981 4:09 PM <> Changed by MBrown on 17-Jun-81 11:06:35 <> <> <> Changed by MBrown on December 2, 1982 3:05 pm <> Changed by Willie-Sue on February 15, 1985 <>