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],
YggInternal;
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 NATALL[0];
initialLruListChunks: ARRAY ListChunkType OF NATALL[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;
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 ← 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;
END;
RelinkChunkAsLruOnLruList: PUBLIC ENTRY PROCEDURE[refChunk: RefChunk] =
BEGIN -- non system fatal errors: none.
Unlink[refChunk];
AddAsLru[refChunk];
END;
checkDuringNotDebugging: BOOLEANTRUE;
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.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 BOOLEANALL[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];
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] ← 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: BOOLEANFALSE;
TRUSTED BEGIN
YggDummyProcess.SetTimeout[@SweepNeeded[normal], timeToSleepBetweenSweeps[normal]];
YggDummyProcess.SetTimeout[@SweepNeeded[log], timeToSleepBetweenSweeps[log]];
END;
END.
Edit Log