<> <> <> <> <> <> <> <> <> DIRECTORY DBCommon USING[DBPage, NullDBPage, CacheHandle, TID, ConsTID, InternalError], DBSegment USING[ReadPage, UnlockPage], DBStorage USING[TupleHandle, FirstLast], DBStorageConcrete USING[TuplesetScanObject], DBStorageField USING[TuplesetFieldHandle], DBStoragePage, DBStoragePrivate USING[GetNWordBase], DBStorageTuple USING[ConsTupleObject, IsValidTuple, TIDOfTuple], DBStorageTuplesetScan USING[]; DBStorageTuplesetScanImpl: CEDAR PROGRAM IMPORTS DBCommon, DBSegment, DBStorageField, DBStoragePrivate, DBStoragePage, DBStorageTuple EXPORTS DBStorage, DBStorageTuplesetScan = BEGIN OPEN DBCommon, 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]]; tempTuplesetScanHandle _ NEW[TuplesetScanObject _ [tupleset: NIL]]; }; OpenScanTupleset: PUBLIC PROC [x: DBStorage.TupleHandle, 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] }; tempTuplesetScanHandle: TuplesetScanHandle; EmptyTupleSet: PUBLIC PROC [x: DBStorage.TupleHandle] RETURNS[yes: BOOL] = { tempTuplesetScanHandle.tupleset _ x; tempTuplesetScanHandle.position _ beforeFirst; SetInitialPage[tempTuplesetScanHandle]; NewPage[tempTuplesetScanHandle, forward]; yes _ tempTuplesetScanHandle.position = afterLast; IF tempTuplesetScanHandle.position = middle THEN DBSegment.UnlockPage[tempTuplesetScanHandle.pageHint] }; FirstTuple: PUBLIC PROC [x: DBStorage.TupleHandle] RETURNS[tuple: DBStorage.TupleHandle] = { tempTuplesetScanHandle.tupleset _ x; tempTuplesetScanHandle.position _ beforeFirst; SetInitialPage[tempTuplesetScanHandle]; tuple _ NextScanTupleset[tempTuplesetScanHandle]; IF tempTuplesetScanHandle.position = middle THEN DBSegment.UnlockPage[tempTuplesetScanHandle.pageHint] }; 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 DBCommon.InternalError; -- InvalidTuplesetScan ENDCASE => ERROR; ENDLOOP; FOR slotI: CARDINAL IN [scan.slotIndex + 1 .. DBStoragePage.HighSlotIndexOfPage[scan.pagePtr]] DO IF DBStoragePage.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 _ DBStoragePage.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 DBCommon.InternalError; -- InvalidTuplesetScan ENDCASE => ERROR; ENDLOOP; FOR slotI: CARDINAL DECREASING IN (DBStoragePage.TSDictSlotIndex .. MIN[scan.slotIndex, DBStoragePage.HighSlotIndexOfPage[scan.pagePtr]] ] DO IF DBStoragePage.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 _ DBStoragePage.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 DBStoragePage.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 => DBStoragePage.TSDictSlotIndex, backward => LAST[CARDINAL],--larger than the number of slots on a page ENDCASE => ERROR; [scan.pageHint, scan.pagePtr] _ DBSegment.ReadPage[scan.page, NIL]; DBStoragePage.AssertPageIsTuplePage[scan.pagePtr]; [scan.localTuplesetID, tsIsInDict] _ DBStoragePage.GetIndex[scan.pagePtr, TIDOfTuple[scan.tupleset]]; IF ~tsIsInDict THEN ERROR DBCommon.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 DBCommon.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 <>