-- PilotBTreeSupportImpl.mesa -- last edited by Levin, August 18, 1982 10:08 am -- Schmidt, October 4, 1982 11:47 am -- Schroeder, July 21, 1982 4:28 pm DIRECTORY BTreeSupportDefs USING [PageHandle, PageNumber], BTreeSupportExtraDefs USING [], DCSFileTypes USING [tLeaderPage], Directory: TYPE USING[PutProperty], Environment USING [bytesPerPage, wordsPerPage], File USING [ Capability, GetAttributes, GetSize, PageCount, PageNumber, SetSize, ShowCapability], FileStream USING [-- Create, GetLength, SetLength, -- SetLeaderPropertiesForCapability], Heap USING [systemZone], Inline USING [LongCOPY, LongDivMod, LowHalf], PropertyTypes: TYPE USING[tByteLength], Space USING [ Create, CreateUniformSwapUnits, Deactivate, Delete, ForceOut, GetHandle, GetWindow, Handle, LongPointer, Map, PageCount, PageFromLongPointer, Unmap, virtualMemory, WindowOrigin], -- Stream USING [Delete, Handle], System: TYPE USING [GetGreenwichMeanTime, GreenwichMeanTime]; PilotBTreeSupportImpl: PROGRAM IMPORTS Directory, File, FileStream, Heap, Inline, Space, -- Stream, -- System EXPORTS BTreeSupportDefs, BTreeSupportExtraDefs = BEGIN OPEN BTreeSupportDefs; -- Caller Bugs IllegalPageHandle: ERROR = CODE; IllegalPageNumber: ERROR = CODE; NonTrivialRemap: ERROR = CODE; -- Implementation Bugs HandleIndexingBotch: ERROR = CODE; -- BTreeSupportExtraDefs implementation pageSize: CARDINAL = Environment.wordsPerPage; FileHandle: PUBLIC TYPE = LONG POINTER TO FileDesc; FileDesc: TYPE = RECORD [ cap: File.Capability, bias: [0..1], written: BOOLEAN, fileSize: File.PageCount, spaces: LONG POINTER TO SpaceHandles]; SpaceHandles: TYPE = RECORD [ nSpaces: HandleIndex ← 0, spaceHandles: SEQUENCE maxHandles: CARDINAL OF Space.Handle ← NULL]; HandleIndex: TYPE = CARDINAL; mappingIncrement: Space.PageCount = 32; minTableSize: CARDINAL = 30; tableSizeIncrement: CARDINAL = 15; OpenFile: PUBLIC PROCEDURE [cap: File.Capability] RETURNS [fileH: FileHandle] = BEGIN bias: [0..1] = IF File.GetAttributes[cap].type = DCSFileTypes.tLeaderPage THEN 1 ELSE 0; fileSize: File.PageCount = File.GetSize[cap]; window: Space.WindowOrigin ← [cap, bias]; tableSize: CARDINAL = MAX[Inline.LowHalf[(fileSize-bias+mappingIncrement)/mappingIncrement], minTableSize]; fileH ← Heap.systemZone.NEW[FileDesc ← [cap: cap, bias: bias, written: FALSE, fileSize: fileSize, spaces: Heap.systemZone.NEW[SpaceHandles[tableSize] ← []]]]; UNTIL window.base >= fileSize DO space: Space.Handle = Space.Create[size: mappingIncrement, parent: Space.virtualMemory]; index: HandleIndex = fileH.spaces.nSpaces; Space.CreateUniformSwapUnits[1, space]; Space.Map[space, window]; window.base ← window.base + mappingIncrement; fileH.spaces.spaceHandles[index] ← space; fileH.spaces.nSpaces ← index + 1; ENDLOOP; END; CloseFile: PUBLIC PROCEDURE [fileH: FileHandle] = BEGIN FOR i: HandleIndex IN [0..fileH.spaces.nSpaces) DO Space.Delete[fileH.spaces.spaceHandles[i]]; ENDLOOP; Heap.systemZone.FREE[@fileH.spaces]; Heap.systemZone.FREE[@fileH]; END; -- BTreeSupportDefs implementation ReadPage: PUBLIC PROCEDURE [fileH: FileHandle, pageN: PageNumber] RETURNS [pageH: PageHandle] = BEGIN IF pageN + fileH.bias >= fileH.fileSize THEN ERROR IllegalPageNumber; RETURN[PageNumberToPageHandle[fileH, pageN]] END; UsePage: PUBLIC PROCEDURE [fileH: FileHandle, pageN: PageNumber] RETURNS [pageH: PageHandle] = BEGIN requiredFileSize: CARDINAL = pageN + fileH.bias + 1; IF fileH.fileSize < requiredFileSize THEN BEGIN index: HandleIndex ← fileH.spaces.nSpaces; space: Space.Handle ← fileH.spaces.spaceHandles[index-1]; window: Space.WindowOrigin ← Space.GetWindow[space]; Space.Unmap[space]; File.SetSize[fileH.cap, fileH.fileSize ← requiredFileSize]; SetLengthInLeaderPage[fileH]; Space.Map[space, window]; UNTIL LONG[index]*mappingIncrement + fileH.bias >= requiredFileSize DO space: Space.Handle = Space.Create[size: mappingIncrement, parent: Space.virtualMemory]; Space.CreateUniformSwapUnits[1, space]; window.base ← window.base + mappingIncrement; Space.Map[space, window]; IF index = fileH.spaces.maxHandles THEN BEGIN newTable: LONG POINTER TO SpaceHandles = Heap.systemZone.NEW[SpaceHandles[fileH.spaces.maxHandles+tableSizeIncrement] ← []]; Inline.LongCOPY[from: @fileH.spaces.spaceHandles[0], to: @newTable.spaceHandles[0], nwords: fileH.spaces.nSpaces*SIZE[Space.Handle]]; Heap.systemZone.FREE[@fileH.spaces]; fileH.spaces ← newTable; END; fileH.spaces.spaceHandles[index] ← space; index ← index + 1; ENDLOOP; fileH.spaces.nSpaces ← index; END; RETURN[PageNumberToPageHandle[fileH, pageN]] END; WritePage: PUBLIC PROCEDURE[fileH: FileHandle, pageN: PageNumber, pageH: PageHandle] = BEGIN space: Space.Handle = Space.GetHandle[Space.PageFromLongPointer[pageH]]; IF File.ShowCapability[Space.GetWindow[space].file].fID ~= File.ShowCapability[fileH.cap].fID THEN ERROR IllegalPageHandle; IF pageN >= fileH.fileSize - fileH.bias THEN ERROR IllegalPageNumber; IF PageNumberToPageHandle[fileH, pageN] ~= pageH THEN ERROR NonTrivialRemap; IF NOT fileH.written THEN { IF fileH.bias = 1 THEN { now: System.GreenwichMeanTime = System.GetGreenwichMeanTime[]; FileStream.SetLeaderPropertiesForCapability[cap: fileH.cap, create: now, write: now]; }; fileH.written ← TRUE; }; Space.ForceOut[space]; END; ReleasePage: PUBLIC PROCEDURE [pageH: PageHandle] = {Space.Deactivate[Space.GetHandle[Space.PageFromLongPointer[pageH]]]}; SetLength: PUBLIC PROCEDURE [fileH: FileHandle, pageN: PageNumber] = BEGIN newSize: File.PageCount = pageN + fileH.bias; SELECT newSize FROM > fileH.fileSize => ReleasePage[UsePage[fileH, pageN]]; < fileH.fileSize => BEGIN handleIndex: HandleIndex; relPage: CARDINAL; window: Space.WindowOrigin; [handleIndex, relPage] ← Inline.LongDivMod[pageN, mappingIncrement]; FOR i: HandleIndex IN (handleIndex..fileH.spaces.nSpaces) DO Space.Delete[fileH.spaces.spaceHandles[i]]; ENDLOOP; window ← Space.GetWindow[fileH.spaces.spaceHandles[handleIndex]]; Space.Unmap[fileH.spaces.spaceHandles[handleIndex]]; File.SetSize[fileH.cap, fileH.fileSize ← newSize]; SetLengthInLeaderPage[fileH]; Space.Map[fileH.spaces.spaceHandles[handleIndex], window]; END; ENDCASE; END; PageSize: PUBLIC PROCEDURE RETURNS [nWords: CARDINAL] = {RETURN[pageSize]}; RawStorage: TYPE = RECORD [SEQUENCE COMPUTED CARDINAL OF WORD]; AllocateWords: PUBLIC PROCEDURE [nWords: CARDINAL] RETURNS [LONG POINTER] = {RETURN[LOOPHOLE[Heap.systemZone.NEW[RawStorage[nWords]]]]}; FreeWords: PUBLIC PROCEDURE [p: LONG POINTER] = {Heap.systemZone.FREE[@p]}; -- Internal Stuff SetLengthInLeaderPage: PROC [fileH: FileHandle] = BEGIN newLength: LONG CARDINAL; -- sH: Stream.Handle; IF fileH.bias # 1 THEN RETURN; newLength ← (fileH.fileSize-1)*Environment.bytesPerPage; Directory.PutProperty[file: fileH.cap, property: PropertyTypes.tByteLength, propertyValue: DESCRIPTOR[@newLength, SIZE[LONG CARDINAL]]]; -- sH ← FileStream.Create[fileH.cap]; -- IF FileStream.GetLength[sH] # newLength -- THEN FileStream.SetLength[sH, newLength]; -- Stream.Delete[sH]; END; --SetLengthInLeaderPage-- PageNumberToPageHandle: PROCEDURE [fileH: FileHandle, pageN: PageNumber] RETURNS [pageH: PageHandle] = BEGIN handleIndex: HandleIndex; relPage: CARDINAL; [handleIndex, relPage] ← Inline.LongDivMod[pageN, mappingIncrement]; IF handleIndex >= fileH.spaces.nSpaces THEN ERROR HandleIndexingBotch; RETURN[Space.LongPointer[fileH.spaces.spaceHandles[handleIndex]]+LONG[relPage]*pageSize] END; END.