-- File: DBIndexScanImpl.mesa
-- Implements: DBIndexScan
-- Created by: Suzuki, November 20, 1980 10:29 AM
-- Last edited by:
-- Suzuki, November 20, 1980 10:29 AM
-- MBrown, February 27, 1981 9:41 PM
-- Cattell, September 21, 1982 9:58 pm
DIRECTORY
DBCommon,
DBStorage,
DBStorageConcrete,
DBIndexFilePage USING[CreateIndexKey, FreeKey, GreaterEq, Key, LessEq],
DBIndex,
DBIndexScan;
DBIndexScanImpl: PROGRAM
IMPORTS
DBIndexFilePage
EXPORTS
DBStorage,
DBIndexScan
= BEGIN OPEN DBIndexFilePage;
-- Types
IndexScanObject: PUBLIC TYPE = DBStorageConcrete.IndexScanObject;
IndexScanHandle: TYPE = REF IndexScanObject;
-- global vars
PriorityScanList: IndexScanHandle;
CloseScanIndex: PUBLIC PROC [x: DBStorage.IndexScanHandle] =
BEGIN
y: IndexScanHandle ← LOOPHOLE[x, IndexScanHandle];
IF y.tree=NIL THEN RETURN; -- Already freed or transaction closed
FreeKey[y.lowerBound];
FreeKey[y.upperBound];
IF y.front = y THEN NULL
ELSE
IF y = PriorityScanList THEN PriorityScanList ← PriorityScanList.back
ELSE {
y.front.back ← y.back;
y.back.front ← y.front;
y.front ← PriorityScanList.front;
y.back ← PriorityScanList;
y.front.back ← y;
PriorityScanList.front ← y};
y.free ← TRUE;
END;
InitScan: PUBLIC PROC =
BEGIN
PriorityScanList ← NEW[IndexScanObject];
PriorityScanList.front ← PriorityScanList.back ← PriorityScanList;
PriorityScanList.free ← TRUE;
END;
FreeScan: PUBLIC PROC =
BEGIN
s: IndexScanHandle;
FreeOne: PROC =
BEGIN
s.tree ← NIL; s.this← DBCommon.NullDBPage;
IF NOT s.free THEN {
FreeKey[s.lowerBound]; FreeKey[s.upperBound];
s.lowerBound← NIL; s.upperBound← NIL };
s.free← TRUE;
END;
FOR s ← PriorityScanList, s.back UNTIL s.back = PriorityScanList DO
FreeOne[];
REPEAT FINISHED => FreeOne[];
ENDLOOP;
END;
CreateScanHandle: PUBLIC PROC [
r: DBIndex.RealIndexHandle, y: DBStorage.Selection, start: DBStorage.FirstLast, page: DBCommon.DBPage,
index: CARDINAL] RETURNS [DBStorage.IndexScanHandle] =
BEGIN
IF NOT PriorityScanList.front.free THEN {
temp: IndexScanHandle ← NEW[IndexScanObject];
temp.front ← PriorityScanList.front;
temp.back ← PriorityScanList;
PriorityScanList.front.back ← temp;
PriorityScanList.front ← temp;
PriorityScanList ← temp}
ELSE PriorityScanList ← PriorityScanList.front;
-- now PriorityScanList points to a free object.
PriorityScanList↑ ←
[front: PriorityScanList.front, back: PriorityScanList.back, tree: r,
this: page, index: index, free: FALSE,
start: start,
lowerBound: CreateIndexKey[y.lowerBound],
upperBound: CreateIndexKey[y.upperBound],
includeLowerBound: y.includeLowerBound,
includeUpperBound: y.includeUpperBound,
lowerBoundInfinity: y.lowerBoundInfinity,
upperBoundInfinity: y.upperBoundInfinity];
RETURN[LOOPHOLE[PriorityScanList, DBStorage.IndexScanHandle]];
END;
FreeScanHandle: PUBLIC PROC [s: IndexScanHandle] =
-- Maintains the LIFO queue
BEGIN
temp: IndexScanHandle;
s.free ← TRUE;
IF s.front = s THEN RETURN;
-- remove it from the list
s.front.back ← s.back;
s.back.front ← s.front;
-- put it in front of PriorityScanList
temp ← PriorityScanList.front;
temp.back ← s;
s.front ← temp;
PriorityScanList.front ← s;
s.back ← PriorityScanList;
END;
ManipulateScanIndex: PUBLIC PROC [
page: DBIndex.Page, after: CARDINAL, f: PROC [IndexScanHandle]] =
BEGIN
db: DBCommon.DBPage ← page.db;
temp: IndexScanHandle ← PriorityScanList;
UNTIL temp.free DO
IF temp.this = db AND temp.index >= after THEN f[temp];
temp ← temp.back;
IF temp = PriorityScanList THEN RETURN;
ENDLOOP;
END;
PutScanIndex: PUBLIC PROC[r: DBIndex.RealIndexHandle, p: DBIndex.Page] =
-- "r" was an empty tree, and just became to have one entry. "p" points to the first page.
-- If there is a IndexScanHandle, change values.
BEGIN
temp: IndexScanHandle ← PriorityScanList;
UNTIL temp.free DO
IF temp.tree=r THEN {
temp.this ← p.db;
IF temp.start=First THEN
IF temp.lowerBoundInfinity THEN temp.index ← 0
ELSE IF temp.includeLowerBound THEN
IF LessEq[temp.lowerBound, Key[p,0]]
THEN temp.index ← 0
ELSE temp.index ← 1
ELSE temp.index ← 1
ELSE IF temp.upperBoundInfinity THEN temp.index ← 1
ELSE IF temp.includeUpperBound THEN
IF GreaterEq[temp.upperBound, Key[p,0]]
THEN temp.index ← 1
ELSE temp.index ← 0
ELSE temp.index ← 0};
temp ← temp.back;
IF temp=PriorityScanList THEN RETURN
ENDLOOP;
END;
ScanForNullTree: PUBLIC PROC [q: DBIndex.RealIndexHandle] =
-- The tree pointed to by q because empty. Change all the IndexRealHandle
--so that if they point to this index, their page fields are Null
BEGIN
temp: IndexScanHandle ← PriorityScanList;
UNTIL temp.free DO
IF temp.tree=q THEN {
temp.this ← DBCommon.NullDBPage;
temp.index ← 0};
temp ← temp.back;
IF temp=PriorityScanList THEN RETURN
ENDLOOP;
END;
END.
Change Log
Added PutScanIndex and ScanForNullTree
Suzuki: November 24, 1980 11:01 AM
Alloc storage from DBHeapStorage; use Inline; define FreeIndexKey
MBrown: February 27, 1981 6:26 PM
CopyIndexKey -> CreateIndexKey.
Cattell: June 20, 1982 6:41 pm
Removed FreeIndexKey defined by Mark above, we should call DBIndexFilePageImpl.FreeKey instead to centralize this. No longer need DBHeapStorage or Inline as a result.
Cattell: August 19, 1982 7:39 pm
Re-organization of DBIndex level
Cattell: September 21, 1982 9:56 pm