-- FilePageMgrLruImpl.mesa
-- Last edited by
-- Kolling on January 24, 1984 12:59:22 pm PST
DIRECTORY
AlpineInternal,
AlpineEnvironment
USING[PageNumber],
FileMap
USING[VerifyFilePageMgrHandle, Handle],
FilePageMgrLru
USING[LruListPlace, SweepItem],
FilePageMgrPrivateChunk
USING[Chunk, ChunkAllocator, ChunkIsDirty, ChunkType, ListChunkType,
InternalFilePageMgrLogicError, RefChunk, Sweeper],
FilePageMgrPrivateFile
USING[FPMFileObject, FPMFileHandle],
Process
USING[Detach, MsecToTicks, SetTimeout, Ticks];
FilePageMgrLruImpl: CEDAR MONITOR
IMPORTS FileMap, FpmPC: FilePageMgrPrivateChunk, Process
EXPORTS AlpineInternal, FilePageMgrLru =
BEGIN OPEN AE: AlpineEnvironment, FpmL: FilePageMgrLru, FpmPF: FilePageMgrPrivateFile;
FPMFileObject: PUBLIC TYPE = FpmPF.FPMFileObject;
FPMFileHandle: PUBLIC TYPE = FpmPF.FPMFileHandle;
Chunk: PUBLIC TYPE = FpmPC.Chunk;
RefChunk: PUBLIC TYPE = FpmPC.RefChunk;
ListChunkType: TYPE = FpmPC.ListChunkType;
lruList: ARRAY ListChunkType OF RefChunk ← ALL[NIL];
nLruListChunks: ARRAY ListChunkType OF NAT ← ALL[0];
initialLruListChunks: ARRAY ListChunkType OF NAT ← ALL[0];
lruListLimit: NAT;
LruListParamsTooSmall: ERROR = CODE;
-- we let system fatal errors keep the monitor locked up.
AddAsLru: INTERNAL PROCEDURE[refChunk: RefChunk] =
BEGIN -- non system fatal errors: none.
chunkType: ListChunkType = refChunk.chunkType;
refHeaderChunk: RefChunk = lruList[chunkType];
IF ((refChunk.next # NIL) OR (refChunk.prev # NIL))
THEN ERROR FpmPC.InternalFilePageMgrLogicError;
nLruListChunks[chunkType] ← nLruListChunks[chunkType] + 1;
refHeaderChunk.next.prev ← refChunk;
refChunk.next ← refHeaderChunk.next;
refChunk.prev ← refHeaderChunk;
refHeaderChunk.next ← refChunk;
END;
AddAsMru: INTERNAL PROCEDURE[refChunk: RefChunk] =
BEGIN -- non system fatal errors: none.
chunkType: ListChunkType = refChunk.chunkType;
refHeaderChunk: RefChunk = lruList[chunkType];
IF ((refChunk.next # NIL) OR (refChunk.prev # NIL))
THEN ERROR FpmPC.InternalFilePageMgrLogicError;
nLruListChunks[chunkType] ← nLruListChunks[chunkType] + 1;
refHeaderChunk.prev.next ← refChunk;
refChunk.next ← refHeaderChunk;
refChunk.prev ← refHeaderChunk.prev;
refHeaderChunk.prev ← refChunk;
END;
Unlink: INTERNAL PROCEDURE[refChunk: RefChunk] =
BEGIN -- non system fatal errors: none.
chunkType: ListChunkType = refChunk.chunkType;
IF (nLruListChunks[chunkType] ← nLruListChunks[chunkType] - 1) < 0
THEN ERROR FpmPC.InternalFilePageMgrLogicError;
refChunk.prev.next ← refChunk.next;
refChunk.next.prev ← refChunk.prev;
refChunk.prev ← NIL; -- for
refChunk.next ← NIL; -- debugging.
END;
UnexpectedHorror: ERROR = CODE;
PutMappedChunkOnLruList: PUBLIC ENTRY PROCEDURE[refChunk: RefChunk, lruListPlace:
FpmL.LruListPlace] =
BEGIN -- non system fatal errors: none.
ErrorProc: PROCEDURE RETURNS[fpmFileHandle: FPMFileHandle] =
BEGIN ERROR UnexpectedHorror; END;
fPMFileHandle: FPMFileHandle ← FileMap.VerifyFilePageMgrHandle[refChunk.fileHandle,
ErrorProc];
(IF lruListPlace = mru THEN AddAsMru ELSE AddAsLru)[refChunk];
fPMFileHandle.nLruListChunks ← fPMFileHandle.nLruListChunks + 1;
END;
PutUnmappedChunkOnLruList: PUBLIC ENTRY PROCEDURE[refChunk: RefChunk] =
BEGIN -- non system fatal errors: none.
AddAsLru[refChunk];
END;
GetOurChunkFromLruList: PUBLIC ENTRY PROCEDURE [refChunk: RefChunk,
tellSweeperToHurry: BOOLEAN] =
BEGIN -- non system fatal errors: none.
ErrorProc: PROCEDURE RETURNS[fpmFileHandle: FPMFileHandle] =
BEGIN ERROR UnexpectedHorror; END;
fPMFileHandle: FPMFileHandle ← FileMap.VerifyFilePageMgrHandle[refChunk.fileHandle,
ErrorProc];
Unlink[refChunk];
fPMFileHandle.nLruListChunks ← fPMFileHandle.nLruListChunks - 1;
IF tellSweeperToHurry THEN HurryUpSweeper[refChunk.chunkType];
END;
-- Note, if the chunk is mapped, we can only hint that it's the one to get, and we have to return a lot of stuff because it may change out from under us; we move it to the mru end of the list however; this does no harm and it prevents some conflicts.
NoMoreChunksAvailable: ERROR = CODE; -- all the chunks of a given type are in use when another is requested.
GetOtherChunkFromLruList: PUBLIC ENTRY PROCEDURE [chunkType: ListChunkType]
RETURNS [mapped: BOOLEAN, refChunk: RefChunk, fileHandle: FileMap.Handle,
startFilePageNumber: AE.PageNumber] =
BEGIN -- non system fatal errors: none.
IF (refChunk ← lruList[chunkType].next) = lruList[chunkType]
THEN ERROR NoMoreChunksAvailable; -- fatal.
Unlink[refChunk];
IF (mapped ← (refChunk.fileHandle # NIL))
THEN BEGIN
AddAsMru[refChunk];
RETURN[mapped, refChunk, refChunk.fileHandle, refChunk.startFilePageNumber];
END;
END;
RelinkChunkAsLruOnLruList: PUBLIC ENTRY PROCEDURE[refChunk: RefChunk] =
BEGIN -- non system fatal errors: none.
Unlink[refChunk];
AddAsLru[refChunk];
END;
checkDuringNotDebugging: BOOLEAN ← TRUE;
UsingTooMuchOfCache: PUBLIC ENTRY PROCEDURE[fPMFileHandle: FPMFileHandle]
RETURNS [yes: BOOLEAN] =
BEGIN -- non system fatal errors: none.
RETURN[(checkDuringNotDebugging) AND (nLruListChunks[normal] # 0)
AND (fPMFileHandle.nLruListChunks > lruListLimit)];
END;
CheckCacheInCleanState: PUBLIC ENTRY PROCEDURE RETURNS [clean: BOOLEAN] =
BEGIN -- non system fatal errors: none.
FOR chunkType: ListChunkType IN ListChunkType
DO
FOR refChunk: RefChunk ← lruList[chunkType].next, refChunk.next
UNTIL refChunk = lruList[chunkType]
DO IF refChunk.fileHandle # NIL THEN RETURN[FALSE];
ENDLOOP;
IF initialLruListChunks[chunkType] # nLruListChunks[chunkType]
THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE];
END;
timeToSleepBetweenSweeps: ARRAY ListChunkType OF Process.Ticks ←
ALL[Process.MsecToTicks[1000]];
MaxTimeToSleepBetweenSweeps: ARRAY ListChunkType OF Process.Ticks =
ALL[Process.MsecToTicks[1000]];
MinTimeToSleepBetweenSweeps: ARRAY ListChunkType OF Process.Ticks =
ALL[Process.MsecToTicks[100]];
SweepNeeded: ARRAY ListChunkType OF CONDITION ← [normal: [timeout:
timeToSleepBetweenSweeps[normal]], log: [timeout: timeToSleepBetweenSweeps[log]], leader:
[timeout: timeToSleepBetweenSweeps[leader]]];
hurryUp: ARRAY ListChunkType OF BOOLEAN ← ALL[FALSE];
HurryUpSweeper: INTERNAL PROCEDURE[chunkType: ListChunkType] =
BEGIN -- non system fatal errors: none.
hurryUp[chunkType] ← TRUE;
NOTIFY SweepNeeded[chunkType];
END;
WaitToSweep: PUBLIC ENTRY PROCEDURE [oldNeedToHurry: BOOLEAN, chunkType:
ListChunkType] RETURNS[needToHurry: BOOLEAN, sweepList: LIST OF FpmL.SweepItem] =
BEGIN -- non system fatal errors: none.
refChunk: RefChunk;
timeToSleepBetweenSweeps[chunkType] ← IF oldNeedToHurry
THEN MAX[timeToSleepBetweenSweeps[chunkType]/2,
MinTimeToSleepBetweenSweeps[chunkType]]
ELSE MIN[(timeToSleepBetweenSweeps[chunkType] +
timeToSleepBetweenSweeps[chunkType]), MaxTimeToSleepBetweenSweeps[chunkType]];
hurryUp[chunkType] ← FALSE;
TRUSTED BEGIN Process.SetTimeout[@SweepNeeded[chunkType],
timeToSleepBetweenSweeps[chunkType]]; END;
WAIT SweepNeeded[chunkType];
refChunk ← lruList[chunkType].prev; -- mru.
sweepList ← NIL;
DO
IF refChunk = lruList[chunkType] THEN EXIT;
IF ((refChunk.fileHandle # NIL) AND (FpmPC.ChunkIsDirty[refChunk]))
THEN sweepList ← CONS[[refChunk.fileHandle, refChunk.startFilePageNumber], sweepList];
refChunk ← refChunk.prev;
ENDLOOP;
needToHurry ← hurryUp[chunkType];
END;
InitializeLruLists: PUBLIC ENTRY PROCEDURE[nChunks: ARRAY ListChunkType OF NAT] =
BEGIN -- non system fatal errors: none.
IF moduleInitialized THEN ERROR;
FOR chunkType: ListChunkType IN ListChunkType
DO
IF nChunks[chunkType] = 0 THEN RETURN WITH ERROR LruListParamsTooSmall;
lruList[chunkType] ← FpmPC.ChunkAllocator[lruHeader, TRUE];
lruList[chunkType].prev ← lruList[chunkType].next ← lruList[chunkType];
THROUGH [0..nChunks[chunkType])
DO AddAsMru[FpmPC.ChunkAllocator[chunkType, TRUE]];
ENDLOOP;
initialLruListChunks[chunkType] ← nChunks[chunkType];
ENDLOOP;
IF ((checkDuringNotDebugging) AND ((lruListLimit ← nLruListChunks[normal]/10)
= 0)) THEN RETURN WITH ERROR LruListParamsTooSmall;
FOR chunkType: ListChunkType IN ListChunkType
DO TRUSTED BEGIN Process.Detach[FORK FpmPC.Sweeper[chunkType]]; END;
ENDLOOP;
moduleInitialized ← TRUE;
END;
-- module initialization.
moduleInitialized: BOOLEAN ← FALSE;
END.
Edit Log
Initial: Kolling: 23-Feb-82 12:34:40: manager of the lru structure for the File Page Manager.