DIRECTORY DBCommon USING[WordsPerPage, TIDSlotMask, InternalError], DBStats, DBStoragePage, PrincOpsUtils; DBStoragePageImpl: CEDAR PROGRAM IMPORTS DBCommon, DBStats, DBStoragePage, I: PrincOpsUtils EXPORTS DBStoragePage SHARES DBStoragePage = BEGIN VecPage: TYPE = DBStoragePage.VecPage; Slot: TYPE = DBStoragePage.Slot; VecHeader: TYPE = DBStoragePage.VecHeader; FreeSlotIndex: DBStoragePage.SlotIndexField = 0; NonsenseSlotIndex: CARDINAL = LAST[CARDINAL]; ValidateInput: BOOL = TRUE; CheckPage: BOOL = TRUE; ExhaustivelyCheckPage: BOOL = FALSE; VecOfOffset: PROC[p: LONG POINTER TO VecPage, offset: CARDINAL] RETURNS[LONG POINTER TO VecHeader] = TRUSTED INLINE BEGIN RETURN[LOOPHOLE[p+offset, LONG POINTER TO VecHeader]]; END;--VecOfOffset FreeVecOffset: PROC[p: LONG POINTER TO VecPage] RETURNS[CARDINAL] = TRUSTED INLINE BEGIN RETURN[LOOPHOLE[p + (DBCommon.WordsPerPage-SIZE[Slot]), LONG POINTER TO Slot].vecOffset]; END;--FreeVecOffset FreeVecPtr: PROC[p: LONG POINTER TO VecPage] RETURNS[LONG POINTER TO VecHeader] = TRUSTED INLINE BEGIN RETURN[VecOfOffset[p, FreeVecOffset[p]]]; END;--FreeVecPtr InitializeVecPage: PUBLIC PROC[p: LONG POINTER TO VecPage, pageTag: CARDINAL] = TRUSTED BEGIN WordsFree: CARDINAL = DBCommon.WordsPerPage - SIZE[VecPage] - SIZE[Slot]; DBStats.Inc[StorageInitVecPage]; p^ _ VecPage[tag: pageTag, highSlot: 0, nFreeSlots: 0, nWordsInFreeVecs: WordsFree]; LOOPHOLE[p+SIZE[VecPage], LONG POINTER TO VecHeader]^ _ VecHeader[slotIndex: FreeSlotIndex, length: WordsFree]; LOOPHOLE[p+DBCommon.WordsPerPage-SIZE[Slot], LONG POINTER TO Slot]^ _ Slot[type: DBStoragePage.UnFreeType, vecOffset: SIZE[VecPage]]; END;--InitializeVecPage CheckVecPage: PUBLIC PROC[p: LONG POINTER TO VecPage, pageTag: CARDINAL] = TRUSTED BEGIN OPEN pageHdr: p; Assert: PROC[condition: BOOL] = CHECKED BEGIN IF ~condition THEN ERROR DBCommon.InternalError; -- CheckVecPageFailed END;--Assert DBStats.Inc[StorageCheckVecPage]; Assert[pageTag = DBStoragePage.TagOfPage[p]]; BEGIN nFreeSlots: CARDINAL _ 0; curSlot: CARDINAL; FOR curSlot IN [1..DBStoragePage.HighSlotIndexOfPage[p]] DO IF DBStoragePage.TypeOfSlot[p, curSlot] = DBStoragePage.FreeType THEN nFreeSlots _ nFreeSlots + 1; ENDLOOP; Assert[nFreeSlots = pageHdr.nFreeSlots]; END; BEGIN freeVecPtr: LONG POINTER TO VecHeader _ FreeVecPtr[p]; Assert[LOOPHOLE[p+DBCommon.WordsPerPage-SIZE[Slot], LONG POINTER TO Slot].type = DBStoragePage.UnFreeType]; Assert[freeVecPtr.slotIndex = FreeSlotIndex]; Assert[LOOPHOLE[freeVecPtr + freeVecPtr.length, LONG POINTER TO Slot] = DBStoragePage.IndexToSlot[p, DBStoragePage.HighSlotIndexOfPage[p]]]; END; BEGIN freeWords: CARDINAL _ FreeVecPtr[p].length; nonFreeVecs: CARDINAL _ 0; curVecPtr: LONG POINTER TO VecHeader _ VecOfOffset[p, SIZE[VecPage]]; WHILE curVecPtr # FreeVecPtr[p] DO IF curVecPtr.slotIndex = FreeSlotIndex THEN freeWords _ freeWords + curVecPtr.length ELSE BEGIN Assert[DBStoragePage.TypeOfSlot[p, curVecPtr.slotIndex] # DBStoragePage.FreeType]; Assert[DBStoragePage.VecOfSlot[p, curVecPtr.slotIndex] = curVecPtr]; nonFreeVecs _ nonFreeVecs + 1; END;--IF curVecPtr _ curVecPtr + curVecPtr.length; ENDLOOP; Assert[freeWords = pageHdr.nWordsInFreeVecs]; Assert[nonFreeVecs + pageHdr.nFreeSlots = pageHdr.highSlot]; END; END;--CheckVecPage AllocVec: PUBLIC PROC[p: LONG POINTER TO VecPage, nWords: CARDINAL] RETURNS[--slotIndex-- CARDINAL, --success-- BOOL] = TRUSTED BEGIN OPEN pageHdr: p; newSlotIndex: CARDINAL; BEGIN--block for exit GOTOs newSlotPtr: LONG POINTER TO Slot; freeVecPtr: LONG POINTER TO VecHeader _ FreeVecPtr[p]; oldFreeVecLength: CARDINAL; DBStats.Inc[StorageAllocVec]; IF ExhaustivelyCheckPage THEN DBStoragePage.CheckVecPage[p, pageHdr.tag]; IF ValidateInput AND (nWords < SIZE[VecHeader]) THEN ERROR DBCommon.InternalError; -- NWordsTooSmall IF pageHdr.nFreeSlots = 0 THEN BEGIN IF pageHdr.nWordsInFreeVecs < nWords+SIZE[VecHeader]+SIZE[Slot] THEN GOTO Failure; IF pageHdr.highSlot = DBCommon.TIDSlotMask THEN GOTO Failure; IF freeVecPtr.length = SIZE[VecHeader] THEN BEGIN CompactPage[p]; freeVecPtr _ FreeVecPtr[p]; END;--IF newSlotIndex _ pageHdr.highSlot _ pageHdr.highSlot + 1; newSlotPtr _ DBStoragePage.IndexToSlot[p, newSlotIndex]; IF CheckPage AND (freeVecPtr + freeVecPtr.length-1 # LOOPHOLE[newSlotPtr, LONG POINTER TO VecHeader]) THEN ERROR DBCommon.InternalError; -- FreeVecSmashed freeVecPtr.length _ freeVecPtr.length - SIZE[Slot]; IF CheckPage AND (freeVecPtr.length < SIZE[VecHeader]) THEN ERROR DBCommon.InternalError; -- FreeVecSmashed pageHdr.nWordsInFreeVecs _ pageHdr.nWordsInFreeVecs - SIZE[Slot]; END ELSE BEGIN--pageHdr.nFreeSlots > 0 IF pageHdr.nWordsInFreeVecs < nWords+SIZE[VecHeader] THEN GOTO Failure; FOR newSlotIndex IN [1..pageHdr.highSlot] DO IF DBStoragePage.TypeOfSlot[p, newSlotIndex] = DBStoragePage.FreeType THEN EXIT; REPEAT FINISHED => ERROR DBCommon.InternalError; -- FreeSlotsSmashed ENDLOOP; newSlotPtr _ DBStoragePage.IndexToSlot[p, newSlotIndex]; pageHdr.nFreeSlots _ pageHdr.nFreeSlots - 1; END;--IF IF freeVecPtr.length < nWords+SIZE[VecHeader] THEN BEGIN CompactPage[p]; freeVecPtr _ FreeVecPtr[p]; END;--IF oldFreeVecLength _ freeVecPtr.length; IF CheckPage AND (oldFreeVecLength < nWords+SIZE[VecHeader]) THEN ERROR DBCommon.InternalError; -- FreeVecSmashed freeVecPtr^ _ [slotIndex: newSlotIndex, length: nWords]; newSlotPtr^ _ [type: DBStoragePage.UnFreeType, vecOffset: FreeVecOffset[p]]; freeVecPtr _ freeVecPtr + nWords; freeVecPtr^ _ [slotIndex: FreeSlotIndex, length: oldFreeVecLength-nWords]; newSlotPtr _ LOOPHOLE[p + (DBCommon.WordsPerPage - SIZE[Slot]), LONG POINTER TO Slot]; -- point to freeSlot newSlotPtr.vecOffset _ newSlotPtr.vecOffset + nWords; pageHdr.nWordsInFreeVecs _ pageHdr.nWordsInFreeVecs - nWords; GOTO Success; EXITS Success => BEGIN IF ExhaustivelyCheckPage THEN DBStoragePage.CheckVecPage[p, pageHdr.tag]; RETURN[newSlotIndex, TRUE]; END;--Success Failure => BEGIN IF ExhaustivelyCheckPage THEN DBStoragePage.CheckVecPage[p, pageHdr.tag]; RETURN[NonsenseSlotIndex, FALSE]; END;--Failure END; END;--AllocVec WordsInLargestAllocableVec: PUBLIC PROC[p: LONG POINTER TO VecPage] RETURNS[--nWords-- CARDINAL] = TRUSTED { OPEN pageHdr: p; wordsOfVecSpace: CARDINAL = pageHdr.nWordsInFreeVecs - SIZE[VecHeader]; wordsNeededForSlots: CARDINAL = IF pageHdr.nFreeSlots = 0 THEN SIZE[Slot] ELSE 0; RETURN[IF wordsOfVecSpace <= wordsNeededForSlots THEN 0 ELSE wordsOfVecSpace-wordsNeededForSlots]; };--WordsInLargestAllocableVec FreeVec: PUBLIC PROC[p: LONG POINTER TO VecPage, slotIndex: CARDINAL] = TRUSTED BEGIN OPEN pageHdr: p; slotPtr: LONG POINTER TO Slot; DBStats.Inc[StorageFreeVec]; IF ExhaustivelyCheckPage THEN DBStoragePage.CheckVecPage[p, pageHdr.tag]; IF ValidateInput AND (slotIndex = 0 OR slotIndex > pageHdr.highSlot) THEN ERROR DBCommon.InternalError; -- NotASlot slotPtr _ DBStoragePage.IndexToSlot[p, slotIndex]; IF ValidateInput AND (slotPtr.type = DBStoragePage.FreeType) THEN ERROR DBCommon.InternalError; -- SlotIsFree BEGIN vecPtr: LONG POINTER TO VecHeader _ LOOPHOLE[p + slotPtr.vecOffset, LONG POINTER TO VecHeader]; vecPtr.slotIndex _ FreeSlotIndex; pageHdr.nWordsInFreeVecs _ pageHdr.nWordsInFreeVecs + vecPtr.length; END; IF slotIndex # pageHdr.highSlot THEN BEGIN slotPtr^ _ Slot[type: DBStoragePage.FreeType, vecOffset: 0]; pageHdr.nFreeSlots _ pageHdr.nFreeSlots + 1; END ELSE BEGIN freeWordsReclaimed: CARDINAL _ 1; IF CheckPage AND (DBStoragePage.IndexToSlot[p, FreeSlotIndex].type # DBStoragePage.UnFreeType) THEN ERROR DBCommon.InternalError; -- FreeVecSmashed DO IF (slotPtr+freeWordsReclaimed).type # DBStoragePage.FreeType THEN EXIT; freeWordsReclaimed _ freeWordsReclaimed + 1; ENDLOOP; pageHdr.highSlot _ pageHdr.highSlot - freeWordsReclaimed; pageHdr.nFreeSlots _ pageHdr.nFreeSlots - (freeWordsReclaimed-1); BEGIN freeVecPtr: LONG POINTER TO VecHeader _ FreeVecPtr[p]; freeVecPtr.length _ freeVecPtr.length + freeWordsReclaimed; pageHdr.nWordsInFreeVecs _ pageHdr.nWordsInFreeVecs + freeWordsReclaimed; END; END;--IF IF ExhaustivelyCheckPage THEN DBStoragePage.CheckVecPage[p, pageHdr.tag]; RETURN; END;--FreeVec ModifyVec: PUBLIC PROC [p: LONG POINTER TO VecPage, slotIndex: CARDINAL, deltaWords: INTEGER, preserveContents: BOOL] RETURNS[--success-- BOOL] = TRUSTED BEGIN OPEN pageHdr: LOOPHOLE[p, LONG POINTER TO VecPage]; BEGIN -- Block for EXITS GOTOs slotPtr: LONG POINTER TO Slot; -- points to slot whose vec we're modifying vecPtr: LONG POINTER TO VecHeader; -- points to vec we're modifying vecLen: CARDINAL; -- original length of vec we're modifying newVecLen: CARDINAL; -- length after modification DBStats.Inc[StorageModifyVec]; IF ExhaustivelyCheckPage THEN DBStoragePage.CheckVecPage[p, pageHdr.tag]; IF ValidateInput AND (slotIndex = 0 OR slotIndex > pageHdr.highSlot) THEN ERROR DBCommon.InternalError; -- NotASlot slotPtr _ DBStoragePage.IndexToSlot[p, slotIndex]; IF ValidateInput AND (slotPtr.type = DBStoragePage.FreeType) THEN ERROR DBCommon.InternalError; -- SlotIsFree vecPtr _ LOOPHOLE[p + slotPtr.vecOffset, LONG POINTER TO VecHeader]; vecLen _ vecPtr.length; IF deltaWords > 0 THEN BEGIN valPtr: LONG POINTER; valPtrRef: REF Block; Block: TYPE = RECORD [SEQUENCE length: CARDINAL OF CARDINAL]; valWasAllocated: BOOL _ FALSE; -- TRUE later if valPtr points to heap storage IF deltaWords + SIZE[VecHeader] > pageHdr.nWordsInFreeVecs THEN--it just won't fit GOTO Failure; newVecLen _ vecLen + deltaWords; IF newVecLen + SIZE[VecHeader] > pageHdr.nWordsInFreeVecs THEN BEGIN IF preserveContents THEN BEGIN -- copy current value to temp storage DBStats.Inc[StorageModifyDifficultVec]; valPtrRef _ NEW[Block[vecLen-SIZE[VecHeader]]]; valPtr_ LOOPHOLE[valPtrRef, LONG POINTER]+SIZE[Block[0]]; I.LongCopy[ from: vecPtr+SIZE[VecHeader], nwords: vecLen-SIZE[VecHeader], to: valPtr]; valWasAllocated _ TRUE; END;--IF vecPtr.slotIndex _ FreeSlotIndex; pageHdr.nWordsInFreeVecs _ pageHdr.nWordsInFreeVecs + vecLen; CompactPage[p]; END ELSE BEGIN IF ~preserveContents THEN BEGIN --free old vec now, before possible compaction vecPtr.slotIndex _ FreeSlotIndex; pageHdr.nWordsInFreeVecs _ pageHdr.nWordsInFreeVecs + vecLen; END;--IF IF newVecLen + SIZE[VecHeader] > FreeVecPtr[p].length THEN BEGIN CompactPage[p]; vecPtr _ LOOPHOLE[p + slotPtr.vecOffset, LONG POINTER TO VecHeader]; END;--IF IF preserveContents THEN BEGIN valPtr _ vecPtr + SIZE[VecHeader]; -- safe because no compaction can happen now. vecPtr.slotIndex _ FreeSlotIndex; pageHdr.nWordsInFreeVecs _ pageHdr.nWordsInFreeVecs + vecLen; END;--IF END;--IF IF CheckPage AND newVecLen + SIZE[VecHeader] > FreeVecPtr[p].length THEN ERROR DBCommon.InternalError; -- Unknown slotPtr.vecOffset _ FreeVecOffset[p]; vecPtr _ LOOPHOLE[p + slotPtr.vecOffset, LONG POINTER TO VecHeader]; IF preserveContents THEN BEGIN -- Copy preserved value back I.LongCopy[from: valPtr, nwords: vecLen-SIZE[VecHeader], to: vecPtr+SIZE[VecHeader]]; END;--IF vecLen _ vecPtr.length; -- Length of freeVec before allocation vecPtr^ _ VecHeader[slotIndex: slotIndex, length: newVecLen]; vecPtr _ vecPtr + newVecLen; -- Point to freeVec vecPtr^ _ VecHeader[slotIndex: FreeSlotIndex, length: vecLen - newVecLen]; slotPtr _ LOOPHOLE[ p + (DBCommon.WordsPerPage - SIZE[Slot]), LONG POINTER TO Slot]; -- point to FreeSlot slotPtr.vecOffset _ slotPtr.vecOffset + newVecLen; pageHdr.nWordsInFreeVecs _ pageHdr.nWordsInFreeVecs - newVecLen; END ELSE BEGIN--deltaWords<=0 IF deltaWords = 0 THEN GOTO Success; deltaWords _ -deltaWords; IF ValidateInput AND LOOPHOLE[deltaWords, CARDINAL] > vecLen THEN DBCommon.InternalError; -- DeltaTooSmall newVecLen _ LOOPHOLE[vecLen - deltaWords, CARDINAL]; vecPtr.length _ newVecLen; vecPtr _ vecPtr + newVecLen; --point to the fragment we're freeing vecPtr^ _ VecHeader[slotIndex: FreeSlotIndex, length: deltaWords]; pageHdr.nWordsInFreeVecs _ pageHdr.nWordsInFreeVecs + deltaWords; END;--IF GOTO Success; EXITS Success => BEGIN IF ExhaustivelyCheckPage THEN DBStoragePage.CheckVecPage[p, pageHdr.tag]; RETURN[TRUE]; END;--Success Failure => BEGIN IF ExhaustivelyCheckPage THEN DBStoragePage.CheckVecPage[p, pageHdr.tag]; RETURN[FALSE]; END;--Failure END; END;--ModifyVec CompactPage: PROC[p: LONG POINTER TO VecPage] = TRUSTED BEGIN OPEN pageHdr: p; highSlotOff: CARDINAL _ DBStoragePage.IndexToOffset[DBStoragePage.HighSlotIndexOfPage[p]]; curSrc: CARDINAL _ SIZE[VecPage]; curDst: CARDINAL; s, l: CARDINAL; nAllocVecs: CARDINAL _ 0; BEGIN-- block for exit GOTOs DBStats.Inc[StorageCompactPage]; DO IF VecOfOffset[p, curSrc].slotIndex = FreeSlotIndex THEN EXIT; nAllocVecs _ nAllocVecs + 1; curSrc _ curSrc + VecOfOffset[p, curSrc].length; IF CheckPage AND (curSrc >= highSlotOff) THEN GOTO NoFreeVecs; REPEAT NoFreeVecs => ERROR DBCommon.InternalError; -- FreeVecSmashed, freeVec should be present ENDLOOP; curDst _ curSrc; curSrc _ curSrc + VecOfOffset[p, curSrc].length; IF curSrc >= highSlotOff THEN BEGIN IF ~CheckPage OR (curSrc = highSlotOff) THEN GOTO Compacted ELSE ERROR DBCommon.InternalError; -- Unknown END;--IF DO DO IF VecOfOffset[p, curSrc].slotIndex # FreeSlotIndex THEN EXIT; curSrc _ curSrc + VecOfOffset[p, curSrc].length; IF curSrc >= highSlotOff THEN GOTO SeenAllVecs; ENDLOOP; nAllocVecs _ nAllocVecs + 1; s _ VecOfOffset[p, curSrc].slotIndex; l _ VecOfOffset[p, curSrc].length; I.LongCopy[from: p+curSrc, nwords: l, to: p+curDst]; DBStoragePage.IndexToSlot[p, s].vecOffset _ curDst; curDst _ curDst + l; curSrc _ curSrc + l; IF curSrc >= highSlotOff THEN GOTO SeenAllVecs; REPEAT SeenAllVecs => BEGIN IF ~CheckPage OR (curSrc=highSlotOff) THEN BEGIN DBStoragePage.IndexToSlot[p, FreeSlotIndex].vecOffset _ curDst; VecOfOffset[p, curDst]^ _ VecHeader[slotIndex: FreeSlotIndex, length: curSrc - curDst]; GOTO Compacted; END ELSE ERROR DBCommon.InternalError; END;--SeenAllVecs ENDLOOP; EXITS Compacted => BEGIN IF CheckPage AND (VecOfOffset[p, curDst].length # pageHdr.nWordsInFreeVecs) THEN ERROR DBCommon.InternalError; RETURN; END;--Compacted END;--EXITS END;--CompactPage END.--StorageVecImpl Created by MBrown on February 15, 1980 10:39 PM Changed by MBrown on February 17, 1980 4:58 PM Changed by MBrown on February 17, 1980 10:25 PM Changed by MBrown on February 18, 1980 10:46 AM Changed by MBrown on February 18, 1980 6:30 PM Changed by MBrown on February 19, 1980 3:41 PM Changed by MBrown on 20-Feb-80 11:52 Changed by MBrown on February 20, 1980 3:07 PM Changed by MBrown on February 24, 1980 11:55 AM Changed by MBrown on June 11, 1980 4:29 PM Changed by MBrown on August 22, 1980 4:37 PM Changed by MBrown on August 24, 1980 10:51 AM Changed by MBrown on September 26, 1980 4:18 PM Changed by MBrown on December 6, 1980 11:28 PM Changed by MBrown on February 27, 1981 5:28 PM Changed by MBrown on August 7, 1982 9:56 pm Changed by Willie-Sue on February 15, 1985 ŠFile: DBStoragePageImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last edited by: MBrown on August 7, 1982 9:55 pm Cattell, November 8, 1983 1:10 pm Willie-Sue, March 19, 1985 6:07:13 pm PST Widom, July 16, 1985 5:35:35 pm PDT Donahue, May 23, 1986 10:04:53 am PDT This module implements all of DBStoragePage. Constants relating to persistent structure (some others are in DBStoragePage). Distinguished values for VecHeader.slotIndex: In a VecHeader, this means that the vec is free. This slot points to freeVec. Returned by failing AllocVec as the slot result; should trap if used later. Switches to control the amount of redundant checking compiled in. Compile code to check the nWords input to AllocVec, slotIndex to FreeVec, etc. (Don't exhaustively check input pages). Compile code to check properties of the page structure during AllocVec, FreeVec, etc. (Don't exhaustively check input pages). Compile code to exhaustively check input pages, and recheck before returning, for AllocVec, FreeVec, ModifyVec. PrincOpsUtils Returns the offset of freeVec. Returns a pointer to freeVec. Creates an empty page in page p of the cache, ready to store vecs using the procedures below. The new page has tag = pageTag. Number of words free after the page header and free slot are created. Verifies that the internal structure of the page is consistent, and that it has tag = pageTag. This proc clearly cannot check that the data stored in the vecs themselves is correct. May die horribly if the page is really bad. Tag is correct. The nFreeSlots is correct. FreeSlot is UnFree, freeVec is free and immediately above highSlot. The non-slot area is full of vecs. Non-free vecs point to (unique) non-free slots, that point back. (We use the pigeonhole principle to test uniqueness by counting non-free vecs). Makes a new vec of total length nWords (including vec header), a slot to hold it, and returns the index of the slot. If ~success, then the call failed for lack of space, and slotIndex is garbage. Create a new slot numbered one higher than the highest existing slot. Shrink freeVec by one Slot's worth of words. If it weren't for paranoia, we could just use a WHILE loop here; there must be a free slot. If freeVec is too small, compact it now. It is large enough now, so do it. Frees the vec held in the slot at slotIndex, and the slot also. Check integrity of sentinel (FreeSlot). Changes the length of the vec at slotIndex by deltaWords. If deltaWords<0, the final deltaWords words of data in the vec are lost forever. If deltaWords>0 and preserveContents, then the old contents of the vec will be found in the initial words of the new vec; the new words are not initialized. If ~success, then the call failed for lack of space. (The call cannot fail if deltaWords<0). We use the following "simplified" strategy: If the page does not contain enough free words to hold the entire expanded vec without deleting the old copy, we save the old value in heap storage (if it needs to be preserved), delete the old vec, and compact. Else if the page has enough space but freeVec doesn't, we compact. If the old value needn't be preserved, we free it before compaction; otherwise it is freed after the value is copied out (and hence does not join freeVec). Possible elaborations: extending the vec by looking for a free vec behind it. (Not too hard, but may require coalescing several free vecs). In-place permutation during compaction (MUCH harder). Possible simplifications: always preserveContents (not so good for long strings). Allocate fixed storage in global frame for a buffer area, to eliminate heap node allocation. With a suitable algorithm, this area needs only contain as much storage as the maximum number of slots, or maybe less... WARNING: We are loopholing valPtrRef (a REF) into a LONG POINTER (valPtr) here, in the case when we need auxiliary storage to copy into (since compaction will move the data and PrincOpsUtils.LongCopy won't work). Both the long pointer and ref are local to this block, and the space will be garbage collected sometime later. It will fit only after the original vec's storage has been reclaimed Note: we assume that a request for a node of size 0 is ok. It will fit in the current free storage, but compaction may still be needed... At this point, the following is true: vecLen, newVecLen,and slotPtr have values as described in their respective declarations above. The slot at slotPtr may point to garbage, but its type is ok. If preserveContents, then valPtr points to the old contents (which may go away if CompactPage is called). If valWasAllocated, then valPtr points to a vector gotten from AllocFieldValue. FreeVec is long enough to hold newVecLen words for the new vec, plus a minimum freeVec. Fixup freeVec We depend on SIZE[VecHeader] = 1 here; otherwise we must do something else when a piece smaller than a VecHeader is freed. (Compacting would NOT suffice). Collects all free storage on page p into a single free vec, and returns the size of the vec. p is a tuple page in the cache, open for writing. Called from: AllocVec, ModifyVec. all three quantities are p-relative loop to find the first free vec, if any move past the first free vec Loop to move each allocated vec down loop to find the next allocated vec, if any Found an allocated vec; move it Module History AllocVec and CompactPage copied from preliminary versions done on February 2 (before design was "debugged" and documented, interface formalized). Recoded AllocVec to match new interface (it now allocates slots also). Simplified it by forcing freeVec to always exist, and by having redundant information in header. Coded CheckVecPage. Converted CompactPage to new primitives and made it compact upward. Coded FreeVec. Bug fixes: CompactPage set freeVec length to the negative of its true value. AllocVec didn't update FreeSlot after allocating a vec from freeVec. First test program runs to completion. (This took 1 hr of debugging; all other bugs were in testing code). Coded ModifyVec. Two bugs found in ModifyVec. First was a logic bug in case ~preserveContents and ~compact. {This was due to insufficient analysis in coding a complex problem; a symptom was the deeply nested IF-THEN-ELSE structure. The fix caused a considerable simplification of this.} Second was in the case preserveContents and ~valWasAllocated, the length of freeVec was wrong. {This was due to coding one of two cases, noting that the tail of the second could be unified with the first, but using the already written code in the unification without reexamining it for hidden assumptions.} A bug in one of the redundant checks. Expanded VecTest now runs to completion. Minor changes to conform to changes in inteface. TIDSlotMask now comes from DBStorageTID. Implemented WordsInLargestAllocableVec. WordsInLargestAllocableVec returned 177777B when called on an empty page. This was another CARDINAL subtraction bug. We really need true CARDINAL arithmetic! Converted to new DBException. Added DBStats counter events StorageInitVecPage, StorageCheckVecPage, StorageAllocVec, StorageFreeVec, StorageModifyVec, StorageModifyDifficultVec, StorageCompactPage. Pre-Pilot changes. Set ExhaustivelyCheckPage = FALSE. made Cedar, added tioga formatting Κ‡˜šœ™Jšœ Οmœ1™<—Jšœ™Jšœ ™ Jšœ!™!Jšœ)™)™#Icode™%—J˜šΟk ˜ Jšœ žœ+˜9J˜J˜J˜J˜—šœžœž˜ Jšžœ"žœ˜:Jšžœ˜Jšžœ˜J˜Jšœž˜J˜Jšœ žœ˜&Jšœžœ˜ Jšœ žœ˜*J˜Jšœ,™,J˜JšœN™NJ˜Jšœ-™-˜0JšœN™N—šœžœžœžœ˜-JšœK™KJ˜J˜—JšœA™Ašœžœžœ˜JšœN™NJšœ'™'—šœ žœžœ˜JšœU™UJšœ'™'—šœžœžœ˜$JšœM™MJšœ!™!J˜J˜—Jšœ ™ J˜J˜š Οn œžœžœžœžœžœ˜?š žœžœžœžœžœžœž˜9Jš žœžœ žœžœžœ ˜6—JšžœΟc ˜—J˜šŸ œžœžœžœžœ žœžœžœžœž˜Xšœ™Jš žœžœžœ žœžœžœ˜Y—Jšžœ ˜—J˜šŸ œžœžœžœžœ žœžœžœžœžœžœž˜fšœ™Jšžœ#˜)—Jšžœ  ˜—J˜šŸœžœžœžœžœžœžœžœž˜]šœ~™~šœ žœžœ žœ˜IJšœE™E—J˜ J˜Tš žœžœ žœžœžœ˜8J˜7—š žœžœžœžœžœ ˜FJšœ0žœ ˜?——Jšžœ ˜J˜J˜—šŸ œžœžœžœžœžœžœžœž˜XJšœγ™γJ˜Jšžœ ˜J˜š Ÿœžœ žœžœž˜-Jšžœ žœžœ ˜F—Jšžœ ˜ J˜Jšœ™J˜!J˜-Jšœ™Jšžœ žœžœ˜3šžœ žœ+ž˜;šžœ?ž˜EJ˜——Jšžœ˜J˜(Jšžœ˜JšœC™CJšžœ žœžœžœ˜<š œžœžœžœžœžœ ˜PJ˜—J˜-š œžœ!žœžœžœ˜GJ˜D—Jšžœ˜JšœΆ™ΆJšžœ žœ'žœ˜MJš œ žœžœžœžœ ˜Ešžœž˜"Jšžœ%žœ)˜Tšžœž˜ J˜RJ˜DJ˜—Jšžœ ˜J˜)—Jšžœ˜J˜-J˜Jšœžœžœ .˜Mšžœžœ'ž ˜RJšžœ ˜ —Jšœβ™βJšœΓ™ΓJšœ©™©JšœΔ™ΔJ˜ šžœ žœ'žœž˜DJšœD™Dšžœžœžœ %˜DJ˜'Jšœ žœžœ˜/š œžœ žœžœžœ ˜9Jšœ:™:—šžœ ˜ Jšœ žœžœ˜J—Jšœžœ˜—Jšžœ ˜J˜!J˜=Jšœž˜—šžœž˜ JšœN™Nšžœžœžœ .˜NJ˜!J˜=—Jšžœ ˜šžœ žœ#žœž˜@J˜Jš œ žœžœžœžœ ˜D—Jšžœ ˜šžœžœž˜Jšœžœ  -˜PJ˜!J˜=—Jšžœ ˜—Jšžœ ˜JšœΨ™Ψšžœ žœ žœ#ž˜HJšžœžœ  ˜(—J˜%Jš œ žœžœžœžœ ˜Dšžœžœžœ ˜;Jšžœ'žœžœ ˜UJšžœ ˜—Jšœ &˜>J˜=Jšœ ™ Jšœ ˜0J˜Jšœ žœ˜Jš œžœ žœžœžœ ˜U—J˜2JšœBž˜E—šžœž ˜Jšžœžœžœ ˜$Jšœœ™œJ˜š žœžœžœ žœ ž˜AJšžœ ˜(—Jšœ žœžœ˜5J˜Jšœ %˜BJ˜BJ˜A—Jšžœ ˜Jšžœ ˜ šž˜šœ ž˜Jšžœžœ,˜IJšžœžœ˜ —Jšžœ  ˜ šœ ž˜Jšžœžœ,˜IJšžœžœ˜—Jšžœ  ˜ —Jšžœ˜Jšžœ  ˜—J˜š Ÿ œžœžœžœžœ žœž˜=Jšœ™Jšœ!™!J˜Jšžœ ˜šœ žœ˜J˜B—Jšœžœžœ ˜!šœžœ˜Jšœ#™#—Jšœžœ˜Jšœ žœ˜J˜Jšž ˜J˜ šž˜Jšœ'™'Jšžœ2žœžœ˜>J˜J˜0Jšžœ žœžœžœ ˜>—šž˜Jšœžœžœ ,˜X—Jšžœ˜Jšœ™J˜J˜0šžœžœž˜#Jšžœ žœžœžœ ˜;Jšžœžœžœ  ˜-—Jšžœ ˜šž˜Jšœ$™$šž˜Jšœ+™+Jšžœ2žœžœ˜>J˜0Jšžœžœžœ ˜/—Jšžœ˜Jšœ™J˜J˜IJšžœ3˜4J˜3J˜J˜Jšžœžœžœ ˜/—šž˜šœž˜šžœ žœžœž˜0J˜?J˜WJšžœ ˜—Jšž˜Jšžœžœžœ˜"—Jšžœ  ˜—Jšžœ˜šž˜šœ ž˜šžœ žœ<ž˜PJšžœžœ˜—Jšžœ˜—Jšžœ  ˜—Jšžœ ˜ Jšžœ  ˜—J˜—Jšžœ ˜J˜Jšœ™J˜Jšœ.ž˜0JšœL™LJšœD™DJ˜Jšœ-ž˜/JšœX™XJšœO™OJ˜Jšœ.ž˜0JšœX™XJ˜Jšœ.ž˜0Jšœ™J˜Jšœ-ž˜/JšœL™LJšœP™PJšœQ™QJšœ™J˜Jšœ-ž˜/Jšœ™J˜J˜$JšœL™LJšœQ™QJšœV™VJšœW™WJšœQ™QJšœR™RJšœO™OJ˜Jšœ-ž˜/JšœO™OJ˜Jšœ.ž˜0Jšœ0™0J˜Jšœ)ž˜+Jšœ(™(J˜Jšœ+ž˜-Jšœ'™'J˜Jšœ,ž˜.Jšœ[™[JšœC™CJ˜Jšœ.ž˜0Jšœ™J˜Jšœ-ž˜/JšœV™VJšœP™PJ˜Jšœ-ž˜/Jšœ™J˜J˜+Jšœ"™"J™J˜*J™"J˜—…—9Ψiι