YggFilePageMgrLruImpl.mesa
Copyright © 1985, 1988 by Xerox Corporation. All rights reserved.
Last edited by
Kolling on January 24, 1984 12:59:22 pm PST
Hauser, March 8, 1985 10:24:00 am PST
Bob Hagmann May 12, 1988 4:07:41 pm PDT
DIRECTORY
YggDummyProcess USING[Detach, MsecToTicks, SetTimeout, Ticks],
YggEnvironment USING[PageNumber],
YggDIDMap USING[VerifyFilePageMgrHandle, Document],
YggFilePageMgrLru USING[LruListPlace, SweepItem],
YggFilePageMgrPrivateChunk USING[Chunk, ChunkAllocator, ChunkIsDirty, ChunkType, ListChunkType, InternalFilePageMgrLogicError, RefChunk, Sweeper],
YggFilePageMgrPrivateFile USING[FPMFileObject, FPMFileHandle],
YggFilePageMgrLruImpl:
CEDAR
MONITOR
IMPORTS YggDIDMap, YggFilePageMgrPrivateChunk, YggDummyProcess
EXPORTS YggInternal, YggFilePageMgrLru =
BEGIN
FPMFileObject: PUBLIC TYPE = YggFilePageMgrPrivateFile.FPMFileObject;
FPMFileHandle: PUBLIC TYPE = YggFilePageMgrPrivateFile.FPMFileHandle;
Chunk: PUBLIC TYPE = YggFilePageMgrPrivateChunk.Chunk;
RefChunk: PUBLIC TYPE = YggFilePageMgrPrivateChunk.RefChunk;
ListChunkType: TYPE = YggFilePageMgrPrivateChunk.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 YggFilePageMgrPrivateChunk.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 YggFilePageMgrPrivateChunk.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 YggFilePageMgrPrivateChunk.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:
YggFilePageMgrLru.LruListPlace] =
BEGIN
-- non system fatal errors: none.
ErrorProc:
PROCEDURE
RETURNS[fpmFileHandle: FPMFileHandle] =
BEGIN
ERROR UnexpectedHorror;
END;
fPMFileHandle: FPMFileHandle ← YggDIDMap.VerifyFilePageMgrHandle[refChunk.doc,
ErrorProc];
(IF lruListPlace = mru THEN AddAsMru ELSE AddAsLru)[refChunk];
fPMFileHandle.nLruListChunks ← fPMFileHandle.nLruListChunks + 1;
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 ← YggDIDMap.VerifyFilePageMgrHandle[refChunk.doc,
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: YggInternal.FileHandle,
startFilePageNumber: YggEnvironment.PageNumber] =
BEGIN
-- non system fatal errors: none.
IF (refChunk ← lruList[chunkType].next) = lruList[chunkType]
THEN ERROR NoMoreChunksAvailable; -- fatal.
Unlink[refChunk];
IF (mapped ← (refChunk.doc #
NIL))
THEN
BEGIN
AddAsMru[refChunk];
RETURN[mapped, refChunk, --refChunk.doc-- NIL, refChunk.startFilePageNumber];
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)];
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.doc # NIL THEN RETURN[FALSE];
ENDLOOP;
IF initialLruListChunks[chunkType] # nLruListChunks[chunkType]
THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE];
END;
timeToSleepBetweenSweeps:
ARRAY ListChunkType
OF YggDummyProcess.Ticks ←
ALL[YggDummyProcess.MsecToTicks[1000]];
MaxTimeToSleepBetweenSweeps:
ARRAY ListChunkType
OF YggDummyProcess.Ticks =
ALL[YggDummyProcess.MsecToTicks[1000]];
MinTimeToSleepBetweenSweeps:
ARRAY ListChunkType
OF YggDummyProcess.Ticks =
ALL[YggDummyProcess.MsecToTicks[100]];
SweepNeeded:
ARRAY ListChunkType
OF
CONDITION;
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, currentEpoch:
NAT, chunkType: ListChunkType]
RETURNS[needToHurry:
BOOLEAN, sweepList:
LIST
OF YggFilePageMgrLru.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
YggDummyProcess.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.doc #
NIL)
AND (YggFilePageMgrPrivateChunk.ChunkIsDirty[refChunk]))
THEN sweepList ← CONS[[refChunk.doc, refChunk.startFilePageNumber], sweepList];
refChunk ← refChunk.prev;
ENDLOOP;
needToHurry ← hurryUp[chunkType];
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] ← YggFilePageMgrPrivateChunk.ChunkAllocator[lruHeader, TRUE];
lruList[chunkType].prev ← lruList[chunkType].next ← lruList[chunkType];
THROUGH [0..nChunks[chunkType])
DO
AddAsMru[YggFilePageMgrPrivateChunk.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 YggDummyProcess.Detach[FORK YggFilePageMgrPrivateChunk.Sweeper[chunkType]]; END;
ENDLOOP;
moduleInitialized ← TRUE;
END;
module initialization.
moduleInitialized: BOOLEAN ← FALSE;
TRUSTED
BEGIN
YggDummyProcess.SetTimeout[@SweepNeeded[normal], timeToSleepBetweenSweeps[normal]];
YggDummyProcess.SetTimeout[@SweepNeeded[log], timeToSleepBetweenSweeps[log]];
END;
END.