-- File: DBIndexPageImpl.mesa -- Last edited by: -- Suzuki: December 16, 1980 5:15 PM -- MBrown: May 23, 1983 10:58 am -- Cattell: September 21, 1982 9:27 pm DIRECTORY DBCache, DBCommon, DBSegment USING[AllocPage, FreePage, ReadPage, UnlockPage, WriteLockedPage], DBStoragePagetags USING [BTree], DBIndex, DBIndexPage; DBIndexPageImpl: PROGRAM IMPORTS DBSegment EXPORTS DBIndexPage = BEGIN Core: TYPE = DBIndex.Core; Page: TYPE = DBIndex.Page; PageObject: TYPE = DBIndex.PageObject; RealIndexHandle: TYPE = DBIndex.RealIndexHandle; -- global vars PageList: Page; TakeALookAtThis: SIGNAL = CODE; BadPage: PUBLIC SIGNAL = CODE; -- Public procs DestroyPageList: PUBLIC PROC = BEGIN p: Page; p ← PageList; DO IF NOT p.free THEN UnlockPage[p]; -- unlock page p.tree← NIL; p.cache← NIL; p.db← 0; p.pointer← NIL; p.depth← 0; -- erase invalid data p ← p.front; IF p=PageList THEN EXIT; ENDLOOP; END; DestroyPage: PUBLIC PROC [ segment: DBCommon.DBPage, p: Page, db: DBCommon.DBPage] = -- Deallocates the Page and DBPage; it should have a lock count of 1 BEGIN DBSegment.FreePage[segment, db, p.cache]; p.free ← TRUE; END; UnlockPage: PUBLIC PROC [p: Page] = BEGIN CheckTag[p.pointer]; DBSegment.UnlockPage[p.cache]; p.free ← TRUE; END; WriteAndUnlockPage: PUBLIC PROC [p: Page] = BEGIN CheckTag[p.pointer]; DBSegment.WriteLockedPage[p.cache]; DBSegment.UnlockPage[p.cache]; p.free ← TRUE; END; WritePage: PUBLIC PROC [p: DBIndex.Page] = -- Mark page p as having been written, but keep locked. BEGIN CheckTag[p.pointer]; DBSegment.WriteLockedPage[p.cache]; END; AllocatePage: PROC RETURNS [Page] = -- Just allocates the DBIndex.Page, i.e. the HANDLE for the DBCommon.Page -- returns a "free" page; caller is responsible for marking it not free. BEGIN ret: Page; p: Page ← PageList; UNTIL p.free = TRUE DO p ← p.front; IF p=PageList THEN GOTO NoFreePage; REPEAT NoFreePage => {ret ← NEW[PageObject]; PageList.front.back ← ret; ret↑ ← [NIL, DBCommon.NullDBPage, NIL, 0, NIL, TRUE, PageList.front, PageList]; PageList.front ← ret; RETURN[ret]}; FINISHED => {RETURN[p]} ENDLOOP; END; CreateEmptyPage: PUBLIC PROC [ tree: RealIndexHandle, level: CARDINAL, s: DBCommon.DBPage] RETURNS [Page] = -- level = 1 if it is a leaf BEGIN cache: DBCache.CacheHandle; db: DBCommon.DBPage; h: Page; p: LONG POINTER TO Core; [db, cache, p] ← DBSegment.AllocPage[s]; p.tag.pageTag ← DBStoragePagetags.BTree; p.left ← p.right ← DBCommon.NullDBPage; p.size ← 0; h ← AllocatePage[]; h.tree ← tree; h.db ← db; h.cache ← cache; h.depth ← level; h.pointer ← p; h.free ← FALSE; RETURN[h]; END; GetPage: PUBLIC PROC [ tree: RealIndexHandle, db: DBCommon.DBPage, level: CARDINAL] RETURNS [Page] = BEGIN p: Page ← AllocatePage[]; cache: DBCache.CacheHandle; pointer: LONG POINTER TO Core; [cache, pointer] ← DBSegment.ReadPage[db, p.cache]; CheckTag[pointer]; p.tree ← tree; p.db ← db; p.cache ← cache; p.depth ← level; p.pointer ← pointer; p.free ← FALSE; RETURN[p] END; CheckTag: PUBLIC PROC[p: LONG POINTER TO Core] = { IF p.tag.pageTag#DBStoragePagetags.BTree THEN SIGNAL BadPage}; -- Main part PageList ← NEW[PageObject]; PageList.front ← PageList.back ← PageList; PageList.free ← TRUE; END. Change Log: Added to check page tag in CreateOldPage by Suzuki November 24, 1980 9:06 AM Changed FreePage. Now Unlocks the page by Suzuki November 24, 1980 1:33 PM Changed AllocatePage. Now initializes the page if it was obtained via AllocateHeapNode by MBrown December 13, 1980 12:41 AM Allocate storage from heap storage mdsZone by MBrown February 27, 1981 6:18 PM Convert to Cedar by Cattell 7-Jun-81 11:24:59 Fixed bug in DestroyPageList: it didn't deallocate the PageObjects, and later code was trying to treat the cache hints to non-existent storage as real! by Cattell June 24, 1982 11:18 am Changed PageObjects from POINTERs to REFs. by Cattell August 6, 1982 5:10 pm Eliminated import of heap storage allocator. by MBrown August 7, 1982 9:38 pm Added BadPage signal. by Cattell August 25, 1982 5:21 pm The following invariant of the "page" data structure was getting messed up: NOT p.free iff DBSegment.LockCount[p.db, p.cache] > 0. The problem was that p.free was assigned FALSE, then a DBSegment call was made that can raise transaction aborted, then p.cache was assigned. Fix is to have AllocatePage return a page with p.free = TRUE, then make DBSegment call. by MBrown May 23, 1983 10:58 am