-- FullBlownTestFilePageMgrImpl.mesa
-- Last edited by:
-- Kolling on November 9, 1983 5:00 pm
DIRECTORY
AlpineEnvironment
USING[FileID, PageCount, PageNumber, PageRun, VolumeID,
wordsPerPage],
AlpineInternal
USING[FileHandle],
CedarVersion
USING[machineType],
File
USING[Type],
FileIO
USING[Open],
FileTypes
USING[tUntypedFile],
FileMap
USING[GetNext, Handle, Initialize, Register],
FileMapPrivate
USING[FileHandle],
FilePageMgr
USING[CreateWithID, Delete, ExistingFile, FileInUse,
ForceOutEverything, ForceOutFile, ForceOutVMPageSet,
GetAttributes, GetSize, InitializeFilePageMgr, NoSuchFile,
PageRunArgIllegal, PageRunExtendsPastEof, ReadAheadPages,
ReadAheadLogPages, ReadLeaderPages, ReadPages, ReadLogPages,
ReleaseState, ReleaseVMPageSet, RestoreCacheToCleanState,
SetSize, ShareVMPageSet, UsePages, UseLogPages,VMPageSet],
IO
USING[card, Close, GetCard, Handle, PutF,
PutRope, rope],
Process
USING[priorityBackground, priorityNormal, SetPriority, Yield],
RandomCard
USING[Choose, Init],
Rope
USING[ROPE],
SafeStorage
USING[ReclaimCollectibleObjects],
System
USING[GetClockPulses, MicrosecondsToPulses, Pulses],
SystemInternal
USING[UniversalID],
Volume
USING[SystemID];
FullBlownTestFilePageMgrImpl: PROGRAM
IMPORTS AI: AlpineInternal, AE: AlpineEnvironment, CedarVersion, FileIO, FileMap, FPM:
FilePageMgr, IO, Process, RandomCard, SafeStorage, System, Volume =
BEGIN
GetParams: PROCEDURE =
BEGIN
paramStreamHandle: IO.Handle ← FileIO.Open["FullBlownTest.Params",
read, oldOnly];
NNormalProcesses ← paramStreamHandle.GetCard[];
NErrorProcesses ← paramStreamHandle.GetCard[];
NSharingProcesses ← paramStreamHandle.GetCard[];
IF (NNormalProcesses + NErrorProcesses + NSharingProcesses) = 0 THEN ERROR;
IF (NLoops ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
IF (MaxFilesPerProcess ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
IF (MaxFileSize ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
IF (MaxNPagesEachTime ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
IF (MaxOpsPerFileCycle ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
IF (NNormalChunksInCache ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
IF (NLogChunksInCache ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
IF (NLeaderChunksInCache ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
paramStreamHandle.Close[];
resultsStreamHandle.PutF["NNormalChunksInCache: %g NLogChunksInCache: %g NLeaderChunksInCache: %g*n*n", IO.card[NNormalChunksInCache],
IO.card[NLogChunksInCache], IO.card[NLeaderChunksInCache]];
resultsStreamHandle.PutF["NNormalProcesses: %g NLoops: %g MaxFilesPerProcess: %g MaxFileSize: %g MaxNPagesEachTime: %g", IO.card[NNormalProcesses],
IO.card[NLoops], IO.card[MaxFilesPerProcess],
IO.card[MaxFileSize], IO.card[MaxNPagesEachTime]];
resultsStreamHandle.PutF[" MaxOpsPerFileCycle: %g*n",
IO.card[MaxOpsPerFileCycle]];
resultsStreamHandle.PutF["NErrorProcesses: %g NSharingProcesses: %g*n",
IO.card[NErrorProcesses], IO.card[NSharingProcesses]];
END;
SetUpFileData: PROCEDURE[] =
BEGIN
myFilesIDsStreamHandle: IO.Handle ←
FileIO.Open["noFilesFiles.IDs", write, none];
fileHandle: FileMap.Handle;
IF myFilesIDsStreamHandle.GetCard[] < NFiles THEN ERROR;
FOR index: CARDINAL IN [0..NFiles)
DO size: CARDINAL;
files[index].fileID ← GetFileID[myFilesIDsStreamHandle];
fileHandle ← FileMap.Register[VolumeID,
files[index].fileID];
size ← FPM.GetSize[fileHandle ! FPM.NoSuchFile => CONTINUE];
FPM.Delete[fileHandle ! FPM.NoSuchFile => CONTINUE];
ENDLOOP;
myFilesIDsStreamHandle.Close[];
END;
GetFileID: PROCEDURE[stream: IO.Handle] RETURNS[fileID: AE.FileID] =
BEGIN
uid: SystemInternal.UniversalID;
a: CARDINAL ← stream.GetCard[];
b: CARDINAL ← stream.GetCard[];
c: CARDINAL ← stream.GetCard[];
uid ← [processor: [physical[a: a, b: b, c: c]], sequence: stream.GetCard[]];
RETURN[LOOPHOLE[uid, AE.FileID]];
END;
CleanCache: PROCEDURE =
BEGIN
FPM.RestoreCacheToCleanState[];
END;
AllSomeOrSomeRandom: TYPE = {allFixed, allRandom, someFixed, someRandom};
FileInterval: TYPE = RECORD[SELECT allOrSomeRandom: AllSomeOrSomeRandom FROM
allFixed => [nPagesEachTime: CARDINAL],
allRandom => NULL,
someFixed => [firstPage, lastPage, nPagesEachTime: CARDINAL],
someRandom => NULL,
ENDCASE];
IOMode: TYPE = {read, readWithReadAhead, write};
IOReadMode: TYPE = IOMode[read..readWithReadAhead];
MapAndSetSizeIllegal: PROCEDURE[fileHandle: FileMap.Handle, fileIndex: CARDINAL] =
BEGIN
pageRun: AE.PageRun;
vMPageSet: FPM.VMPageSet;
pages: LONG POINTER;
BEGIN
pageRun ← [firstPage: files[fileIndex].size - 1, count: 0];
vMPageSet ← (IF files[fileIndex].type = normal
THEN FPM.ReadPages ELSE FPM.ReadLogPages)[fileHandle, pageRun
! FPM.PageRunArgIllegal => GOTO okay];
ERROR;
EXITS okay => NULL;
END;
BEGIN
IF files[fileIndex].size = 0 THEN RETURN;
pageRun ← [firstPage: files[fileIndex].size - 1,
count: RandomCard.Choose[min: 2, max: 5]];
vMPageSet ← (IF files[fileIndex].type = normal
THEN FPM.ReadPages ELSE FPM.ReadLogPages)[fileHandle, pageRun
! FPM.PageRunExtendsPastEof => GOTO okay];
ERROR;
EXITS okay => NULL;
END;
BEGIN
firstPage: CARDINAL ← files[fileIndex].size/2;
count: CARDINAL ← RandomCard.Choose[min: 1, max: 14];
newSize: CARDINAL ← IF firstPage = 0 THEN 0 ELSE firstPage - 1;
IF firstPage + count > files[fileIndex].size THEN count ← 1;
pageRun ← [firstPage: firstPage, count: count];
vMPageSet ← (IF files[fileIndex].type = normal
THEN FPM.ReadPages ELSE FPM.ReadLogPages)[fileHandle, pageRun];
pages ← vMPageSet.pages;
FOR index: CARDINAL IN [0..vMPageSet.pageRun.count)
DO
ReadDataPage[fileIndex, pages, vMPageSet.pageRun.firstPage + index];
pages ← pages + AE.wordsPerPage;
ENDLOOP;
BEGIN
FPM.SetSize[fileHandle, newSize ! FPM.FileInUse => GOTO okay];
ERROR;
EXITS okay => NULL;
END;
BEGIN
FPM.Delete[fileHandle ! FPM.FileInUse => GOTO okay];
ERROR;
EXITS okay => NULL;
END;
END;
FPM.ReleaseVMPageSet[vMPageSet, clean, FALSE];
END;
SequentialIO: PROCEDURE[fileHandle: FileMap.Handle, fileIndex: CARDINAL, ioMode:
IOMode, releaseState: FPM.ReleaseState, keep: BOOLEAN, includeLeader: BOOLEAN,
fileInterval: FileInterval] =
BEGIN
RandomFirstPage: PROCEDURE RETURNS[CARDINAL] = INLINE
BEGIN RETURN[RandomCard.Choose[min: 0, max: files[fileIndex].size - 1]];
END;
RandomLastPage: PROCEDURE RETURNS[CARDINAL] = INLINE
BEGIN RETURN[RandomCard.Choose[min: firstPage, max:
files[fileIndex].size - 1]];
END;
RandomNPagesEachTime: PROCEDURE RETURNS[CARDINAL] = INLINE
BEGIN RETURN[MIN[RandomCard.Choose[min: 1, max: MaxNPagesEachTime],
totalPages]];
END;
totalPages: CARDINAL;
times: CARDINAL;
startPage, nPages: CARDINAL;
firstPage, lastPage, nPagesEachTime: CARDINAL;
IF includeLeader
THEN BEGIN vMPageSet: FPM.VMPageSet ← FPM.ReadLeaderPages[fileHandle];
(IF ioMode = write THEN WriteLeaderPage ELSE
ReadLeaderPage)[fileIndex, vMPageSet.pages];
FPM.ReleaseVMPageSet[vMPageSet, releaseState, keep];
END;
IF files[fileIndex].size = 0 THEN RETURN;
WITH fileInt: fileInterval SELECT FROM
allFixed => BEGIN firstPage ← 0; lastPage ← files[fileIndex].size - 1; END;
allRandom => BEGIN firstPage ← 0; lastPage ← files[fileIndex].size - 1; END;
someFixed => BEGIN firstPage ← fileInt.firstPage; lastPage ←
fileInt.lastPage; END;
someRandom => BEGIN firstPage ← RandomFirstPage[]; lastPage ←
RandomLastPage[];
END;
ENDCASE => ERROR;
totalPages ← lastPage - firstPage + 1;
nPagesEachTime ← (WITH fileInt: fileInterval SELECT FROM
allFixed => fileInt.nPagesEachTime,
allRandom => RandomNPagesEachTime[],
someFixed => fileInt.nPagesEachTime,
someRandom => RandomNPagesEachTime[],
ENDCASE => ERROR);
times ← (totalPages + (nPagesEachTime - 1))/nPagesEachTime;
startPage ← firstPage;
nPages ← nPagesEachTime;
FOR index: CARDINAL IN [0..times)
DO IF index = times - 1 THEN nPages ← lastPage - startPage + 1;
HandleNPages[fileHandle, fileIndex, ioMode, releaseState, keep, startPage,
nPages];
DelayForNPages[nPages];
startPage ← startPage + nPages;
ENDLOOP;
END;
HandleNPages: PROCEDURE[fileHandle: FileMap.Handle, fileIndex: CARDINAL,
ioMode: IOMode, releaseState: FPM.ReleaseState, keep: BOOLEAN, firstPage, nPages:
CARDINAL] =
BEGIN
pageRun: AE.PageRun ← [firstPage: firstPage, count: nPages];
vMPageSet: FPM.VMPageSet;
pages: LONG POINTER;
pageNumber: CARDINAL ← firstPage;
sharing: BOOLEAN ← FALSE;
DO
vMPageSet ← (SELECT TRUE FROM
ioMode IN IOReadMode => IF files[fileIndex].type = normal
THEN FPM.ReadPages ELSE FPM.ReadLogPages,
ENDCASE => IF files[fileIndex].type = normal THEN FPM.UsePages ELSE
FPM.UseLogPages)[fileHandle, pageRun];
pages ← vMPageSet.pages;
IF vMPageSet.pageRun.count > pageRun.count THEN ERROR;
IF RandomCard.Choose[min: 0, max: 10] = 1
THEN BEGIN sharing ← TRUE;
FPM.ShareVMPageSet[vMPageSet];
END;
FOR index: CARDINAL IN [0..vMPageSet.pageRun.count)
DO
(IF ioMode IN IOReadMode
THEN ReadDataPage ELSE WriteDataPage)[fileIndex, pages,
vMPageSet.pageRun.firstPage + index];
pageNumber ← pageNumber + 1;
pages ← pages + AE.wordsPerPage;
ENDLOOP;
IF RandomCard.Choose[min: 0, max: 10] = 1
THEN FPM.ForceOutVMPageSet[vMPageSet];
FPM.ReleaseVMPageSet[vMPageSet, releaseState, keep];
IF sharing THEN BEGIN FPM.ReleaseVMPageSet[vMPageSet, releaseState, keep];
sharing ← FALSE;
END;
pageRun.firstPage ← pageRun.firstPage + vMPageSet.pageRun.count;
pageRun.count ← pageRun.count - vMPageSet.pageRun.count;
IF pageRun.count = 0 THEN EXIT;
ENDLOOP;
IF ((ioMode = readWithReadAhead) AND (pageRun.firstPage <
files[fileIndex].size))
THEN BEGIN
pageRun.count ← MIN[nPages + nPages, files[fileIndex].size -
(firstPage + nPages)];
(IF files[fileIndex].type = normal THEN FPM.ReadAheadPages ELSE
FPM.ReadAheadLogPages)[fileHandle, pageRun];
END;
END;
Halfway: CARDINAL ← AE.wordsPerPage/2;
ReadLeaderPage: PROCEDURE[fileIndex: CARDINAL, pages: LONG POINTER] =
BEGIN
wordCount: CARDINAL ← RandomCard.Choose[min: 0, max: Halfway - 1];
IF LOOPHOLE[(pages + wordCount)^, CARDINAL] # leaderTouch[fileIndex]
THEN ERROR;
wordCount ← RandomCard.Choose[min: Halfway, max: AE.wordsPerPage - 1];
IF LOOPHOLE[(pages + wordCount)^, CARDINAL] # wordCount + fileIndex
THEN ERROR;
END;
OneThird: CARDINAL ← AE.wordsPerPage/3;
TwoThird: CARDINAL ← 2*OneThird; -- close enough.
WriteLeaderPage: PROCEDURE[fileIndex: CARDINAL, pages: LONG POINTER] =
BEGIN
leaderTouch[fileIndex] ← leaderTouch[fileIndex] + 1;
FOR wordCount: CARDINAL IN [0..Halfway)
DO (pages + wordCount)^ ← leaderTouch[fileIndex]; ENDLOOP;
FOR wordCount: CARDINAL IN [Halfway..AE.wordsPerPage)
DO (pages + wordCount)^ ← wordCount + fileIndex; ENDLOOP;
END;
ReadDataPage: PROCEDURE[fileIndex: CARDINAL, pages: LONG POINTER, pageNumber:
CARDINAL] =
BEGIN
IF LOOPHOLE[(pages + RandomCard.Choose[min: 0, max: OneThird - 1])^,
CARDINAL] # dataTouch[fileIndex][pageNumber] THEN ERROR;
IF LOOPHOLE[(pages + RandomCard.Choose[min: OneThird, max: TwoThird - 1])^,
CARDINAL] # fileIndex THEN ERROR;
IF LOOPHOLE[(pages + RandomCard.Choose[min: TwoThird, max: AE.wordsPerPage
- 1])^, CARDINAL] # pageNumber THEN ERROR;
END;
WriteDataPage: PROCEDURE[fileIndex: CARDINAL, pages: LONG POINTER, pageNumber:
CARDINAL] =
BEGIN
dataTouch[fileIndex][pageNumber] ← dataTouch[fileIndex][pageNumber] + 1;
FOR wordCount: CARDINAL IN [0..OneThird)
DO (pages + wordCount)^ ← dataTouch[fileIndex][pageNumber]; ENDLOOP;
FOR wordCount: CARDINAL IN [OneThird..TwoThird)
DO (pages + wordCount)^ ← fileIndex; ENDLOOP;
FOR wordCount: CARDINAL IN [TwoThird..AE.wordsPerPage)
DO (pages + wordCount)^ ← pageNumber; ENDLOOP;
END;
delayConst: LONG CARDINAL ← 4000;
DelayForNPages: PROCEDURE[nPages: CARDINAL] =
BEGIN
newPulseLimit: System.Pulses;
IF delayConst = 0 THEN RETURN;
newPulseLimit ← [System.GetClockPulses[] +
System.MicrosecondsToPulses[delayConst*LONG[nPages]]];
Process.SetPriority[Process.priorityBackground];
DO
Process.Yield[];
IF System.GetClockPulses[] >= newPulseLimit THEN EXIT;
ENDLOOP;
Process.SetPriority[Process.priorityNormal];
END;
GetSequenceID: PROCEDURE[fileHandle: FileMap.Handle] RETURNS[fileSequenceID: LONG
CARDINAL] =
BEGIN
uid: SystemInternal.UniversalID ← LOOPHOLE[LOOPHOLE[fileHandle,
FileMapPrivate.FileHandle].fileID];
RETURN[uid.sequence];
END;
BasicProcess: PROCEDURE [firstFileIndex, maxFileIndex: CARDINAL]=
BEGIN
debugArray: DebugArray;
debugArrayIndex: INTEGER ← 0;
debugSize: CARDINAL;
FOR indexLoops: CARDINAL IN[0..NLoops)
DO
FOR indexFiles: CARDINAL IN [firstFileIndex..maxFileIndex)
DO
oldSize: CARDINAL;
resets: CARDINAL ← 0;
attemptedBadCreate: BOOLEAN ← FALSE;
fileHandle: FileMap.Handle ← FileMap.Register[VolumeID,
files[indexFiles].fileID];
IF NOT files[indexFiles].exists
THEN BEGIN files[indexFiles].size ← RandomCard.Choose[min: 0, max:
MaxFileSize];
FPM.CreateWithID[fileHandle, files[indexFiles].size,
FileTypes.tUntypedFile];
debugArray[debugArrayIndex] ←
[GetSequenceID[fileHandle], create, files[indexFiles].size];
debugArrayIndex ← (IF debugArrayIndex = MaxDebugIndex - 1
THEN 0 ELSE debugArrayIndex + 1);
files[indexFiles].exists ← TRUE;
END;
files[indexFiles].nOps ← RandomCard.Choose[min: 0, max: MaxOpsPerFileCycle];
files[indexFiles].totalNOps ← files[indexFiles].totalNOps +
files[indexFiles].nOps;
IF RandomCard.Choose[min: 0, max: 1] = 1
THEN BEGIN attemptedBadCreate ← TRUE;
debugArray[debugArrayIndex] ←
[GetSequenceID[fileHandle], badCreate, files[indexFiles].size];
debugArrayIndex ← (IF debugArrayIndex = MaxDebugIndex - 1
THEN 0 ELSE debugArrayIndex + 1);
FPM.CreateWithID[fileHandle, files[indexFiles].size, FileTypes.tUntypedFile
! FPM.ExistingFile => GOTO okay];
ERROR;
EXITS okay => NULL;
END;
IF (debugSize ← FPM.GetSize[fileHandle]) # files[indexFiles].size
THEN ERROR;
BEGIN
chkType: File.Type;
chkVolID: AE.VolumeID;
[chkType, chkVolID] ← FPM.GetAttributes[fileHandle];
IF chkType # FileTypes.tUntypedFile THEN ERROR;
IF chkVolID # VolumeID THEN ERROR;
END;
IF files[indexFiles].nOps # 0
THEN SequentialIO[fileHandle, indexFiles, write, writeBatchedNoWait,
--keep--FALSE, --leader--TRUE, [allFixed[files[indexFiles].size]]];
FOR indexOps: CARDINAL IN [0..files[indexFiles].nOps)
DO
ioMode: IOMode ← (SELECT RandomCard.Choose[0, 2] FROM
0 => read, 1 => readWithReadAhead, 2 => write, ENDCASE => ERROR);
release: FPM.ReleaseState ← (SELECT RandomCard.Choose[0, 4] FROM
0 => writeIndividualWait, 1 => writeBatchedWait, 2 =>
writeIndividualNoWait, 3 => writeBatchedNoWait, 4 => clean,
ENDCASE => ERROR);
keep: BOOLEAN ← (RandomCard.Choose[0, 1] = 0);
leader: BOOLEAN ← (RandomCard.Choose[0, 1] = 0);
fileInterval: FileInterval ← (SELECT RandomCard.Choose[0, 2] FROM
0 => [allFixed[RandomCard.Choose[1, MaxNPagesEachTime]]],
1 => [allRandom[]],
2 => [someRandom[]],
ENDCASE => ERROR);
IF (RandomCard.Choose[0, files[indexFiles].nOps] MOD 10) = 0
THEN BEGIN resets ← resets + 1;
oldSize ← files[indexFiles].size;
files[indexFiles].size ← RandomCard.Choose[min: 0, max:
MaxFileSize];
debugArray[debugArrayIndex] ←
[GetSequenceID[fileHandle], setSize, files[indexFiles].size];
debugArrayIndex ← (IF debugArrayIndex = MaxDebugIndex - 1
THEN 0 ELSE debugArrayIndex + 1);
FPM.SetSize[fileHandle, files[indexFiles].size];
IF files[indexFiles].size > oldSize
THEN SequentialIO[fileHandle, indexFiles, write,
writeBatchedNoWait, --keep--FALSE, --leader--TRUE,
[someFixed[oldSize, files[indexFiles].size - 1,
RandomCard.Choose[1, MaxNPagesEachTime]]]];
END;
SequentialIO[fileHandle, indexFiles, ioMode, release, keep, leader,
fileInterval];
ENDLOOP;
IF RandomCard.Choose[min: 0, max: 10] = 1 THEN FPM.ForceOutFile[fileHandle];
IF RandomCard.Choose[min: 0, max: 1] = 1
THEN BEGIN
IF (debugSize ← FPM.GetSize[fileHandle]) # files[indexFiles].size
THEN ERROR;
debugArray[debugArrayIndex] ←
[GetSequenceID[fileHandle], delete, files[indexFiles].size];
debugArrayIndex ← (IF debugArrayIndex = MaxDebugIndex - 1
THEN 0 ELSE debugArrayIndex + 1);
FPM.Delete[fileHandle];
files[indexFiles].exists ← FALSE;
END;
ENDLOOP;
ENDLOOP;
FOR indexFiles: CARDINAL IN [firstFileIndex..maxFileIndex)
DO
IF files[indexFiles].exists
THEN BEGIN fileHandle: FileMap.Handle ← FileMap.Register[VolumeID,
files[indexFiles].fileID];
IF (debugSize ← FPM.GetSize[fileHandle]) # files[indexFiles].size
THEN ERROR;
debugArray[debugArrayIndex] ←
[GetSequenceID[fileHandle], delete, files[indexFiles].size];
debugArrayIndex ← (IF debugArrayIndex = MaxDebugIndex - 1
THEN 0 ELSE debugArrayIndex + 1);
FPM.Delete[fileHandle];
files[indexFiles].exists ← FALSE;
END;
ENDLOOP;
END;
ErrorProcess: PROCEDURE [firstFileIndex: CARDINAL]=
BEGIN
debugArray: DebugArray;
debugArrayIndex: INTEGER ← 0;
debugSize: CARDINAL;
FOR indexLoops: CARDINAL IN[0..100)
DO
FOR indexFiles: CARDINAL IN [firstFileIndex..firstFileIndex +
NFilesPerErrorProcess)
DO
fileHandle: FileMap.Handle ← FileMap.Register[VolumeID,
files[indexFiles].fileID];
IF RandomCard.Choose[min: 0, max: 1] = 1
THEN BEGIN tempSize: CARDINAL ← IF files[indexFiles].exists
THEN files[indexFiles].size ELSE RandomCard.Choose[min: 0, max:
MaxFileSize];
FPM.CreateWithID[fileHandle, tempSize, FileTypes.tUntypedFile
! FPM.ExistingFile => GOTO fileAlreadyExists];
IF files[indexFiles].exists THEN ERROR;
debugArray[debugArrayIndex] ←
[GetSequenceID[fileHandle], create, tempSize];
debugArrayIndex ← (IF debugArrayIndex = MaxDebugIndex - 1
THEN 0 ELSE debugArrayIndex + 1);
files[indexFiles].exists ← TRUE;
files[indexFiles].size ← tempSize;
EXITS fileAlreadyExists =>
IF (NOT files[indexFiles].exists) THEN ERROR;
END;
files[indexFiles].nOps ← RandomCard.Choose[min: 0, max: 4];
files[indexFiles].totalNOps ← files[indexFiles].totalNOps +
files[indexFiles].nOps;
BEGIN
debugSize ← FPM.GetSize[fileHandle ! FPM.NoSuchFile => GOTO noSuchFile];
IF NOT files[indexFiles].exists THEN ERROR;
IF debugSize # files[indexFiles].size THEN ERROR;
EXITS noSuchFile => IF files[indexFiles].exists THEN ERROR;
END;
BEGIN
chkType: File.Type;
chkVolID: AE.VolumeID;
[chkType, chkVolID] ← FPM.GetAttributes[fileHandle
! FPM.NoSuchFile => GOTO noSuchFile];
IF NOT files[indexFiles].exists THEN ERROR;
IF chkType # FileTypes.tUntypedFile THEN ERROR;
IF chkVolID # VolumeID THEN ERROR;
EXITS noSuchFile => IF files[indexFiles].exists THEN ERROR;
END;
BEGIN
SequentialIO[fileHandle, indexFiles, write, writeBatchedNoWait,
--keep--FALSE, --leader--TRUE, [allFixed[files[indexFiles].size]]
! FPM.NoSuchFile => GOTO noSuchFile];
IF NOT files[indexFiles].exists THEN ERROR;
EXITS noSuchFile => IF files[indexFiles].exists THEN ERROR;
END;
FOR indexOps: CARDINAL IN [0..files[indexFiles].nOps)
DO
ioMode: IOMode ← (SELECT RandomCard.Choose[0, 2] FROM
0 => read, 1 => readWithReadAhead, 2 => write, ENDCASE => ERROR);
release: FPM.ReleaseState ← (SELECT RandomCard.Choose[0, 4] FROM
0 => writeIndividualWait, 1 => writeBatchedWait, 2 =>
writeIndividualNoWait, 3 => writeBatchedNoWait, 4 => clean,
ENDCASE => ERROR);
keep: BOOLEAN ← (RandomCard.Choose[0, 1] = 0);
leader: BOOLEAN ← (RandomCard.Choose[0, 1] = 0);
fileInterval: FileInterval ← (SELECT RandomCard.Choose[0, 2] FROM
0 => [allFixed[RandomCard.Choose[1, MaxNPagesEachTime]]],
1 => [allRandom[]],
2 => [someRandom[]],
ENDCASE => ERROR);
IF (RandomCard.Choose[0, files[indexFiles].nOps] MOD 10) = 0
THEN BEGIN newSize: CARDINAL ← RandomCard.Choose[min: 0, max:
MaxFileSize];
oldSize: CARDINAL;
FPM.SetSize[fileHandle, newSize
! FPM.NoSuchFile => GOTO noSuchFile];
IF NOT files[indexFiles].exists THEN ERROR;
oldSize ← files[indexFiles].size;
files[indexFiles].size ← newSize;
IF newSize > oldSize
THEN SequentialIO[fileHandle, indexFiles, write,
writeBatchedNoWait, --keep--FALSE, --leader--TRUE,
[someFixed[oldSize, files[indexFiles].size - 1,
RandomCard.Choose[1, MaxNPagesEachTime]]]];
debugArray[debugArrayIndex] ←
[GetSequenceID[fileHandle], setSize, newSize];
debugArrayIndex ← (IF debugArrayIndex = MaxDebugIndex - 1
THEN 0 ELSE debugArrayIndex + 1);
EXITS noSuchFile => IF files[indexFiles].exists THEN ERROR;
END;
SequentialIO[fileHandle, indexFiles, ioMode, release, keep, leader,
fileInterval! FPM.NoSuchFile => GOTO noSuchFile];
REPEAT noSuchFile => IF files[indexFiles].exists THEN ERROR;
ENDLOOP;
IF RandomCard.Choose[min: 0, max: 10] = 1
THEN BEGIN FPM.ForceOutFile[fileHandle ! FPM.NoSuchFile => GOTO noSuchFile];
IF NOT files[indexFiles].exists THEN ERROR;
EXITS noSuchFile => IF files[indexFiles].exists THEN ERROR;
END;
IF ((RandomCard.Choose[min: 0, max: 6] >0) AND (files[indexFiles].exists))
THEN BEGIN -- map in illegal area.
MapAndSetSizeIllegal[fileHandle, indexFiles];
debugArray[debugArrayIndex] ← [GetSequenceID[fileHandle],
mapAndSetSize, files[indexFiles].size];
debugArrayIndex ← (IF debugArrayIndex = MaxDebugIndex - 1
THEN 0 ELSE debugArrayIndex + 1);
END;
IF RandomCard.Choose[min: 0, max: 1] = 1
THEN BEGIN
debugSize: CARDINAL;
BEGIN
debugSize ← FPM.GetSize[fileHandle
! FPM.NoSuchFile => GOTO noSuchFile];
IF NOT files[indexFiles].exists THEN ERROR;
IF debugSize # files[indexFiles].size THEN ERROR;
EXITS noSuchFile => IF files[indexFiles].exists THEN ERROR;
END;
FPM.Delete[fileHandle! FPM.NoSuchFile => GOTO noSuchFile];
IF NOT files[indexFiles].exists THEN ERROR;
debugArray[debugArrayIndex] ←
[GetSequenceID[fileHandle], delete, files[indexFiles].size];
debugArrayIndex ← (IF debugArrayIndex = MaxDebugIndex - 1
THEN 0 ELSE debugArrayIndex + 1);
files[indexFiles].exists ← FALSE;
EXITS noSuchFile => IF files[indexFiles].exists THEN ERROR;
END;
ENDLOOP;
ENDLOOP;
FOR indexFiles: CARDINAL IN [firstFileIndex..firstFileIndex +
NFilesPerErrorProcess)
DO
fileHandle: FileMap.Handle ← FileMap.Register[VolumeID,
files[indexFiles].fileID];
debugSize: CARDINAL;
BEGIN
debugSize ← FPM.GetSize[fileHandle
! FPM.NoSuchFile => GOTO noSuchFile];
IF NOT files[indexFiles].exists THEN ERROR;
IF debugSize # files[indexFiles].size THEN ERROR;
EXITS noSuchFile => IF files[indexFiles].exists THEN ERROR;
END;
BEGIN
FPM.Delete[fileHandle! FPM.NoSuchFile => GOTO noSuchFile];
IF NOT files[indexFiles].exists THEN ERROR;
files[indexFiles].exists ← FALSE;
EXITS noSuchFile => IF files[indexFiles].exists THEN ERROR;
END;
ENDLOOP;
END;
SubSharingProcess: PROCEDURE [firstFileIndex: CARDINAL] RETURNS [nOps:
ARRAY[0..NFilesPerSharingProcess) OF CARDINAL] =
BEGIN
debugSize: CARDINAL;
FOR index: CARDINAL IN [0..NFilesPerSharingProcess)
DO nOps[index] ← 0;
ENDLOOP;
FOR indexLoops: CARDINAL IN[0..NLoops)
DO
FOR indexFiles: CARDINAL IN [firstFileIndex..firstFileIndex +
NFilesPerSharingProcess)
DO
fileHandle: FileMap.Handle ← FileMap.Register[VolumeID,
files[indexFiles].fileID];
tempNOps: CARDINAL ← RandomCard.Choose[min: 0, max: MaxOpsPerFileCycle];
nOps[indexFiles - firstFileIndex] ← nOps[indexFiles - firstFileIndex] + tempNOps;
IF (debugSize ← FPM.GetSize[fileHandle]) # files[indexFiles].size
THEN ERROR;
BEGIN
chkType: File.Type;
chkVolID: AE.VolumeID;
[chkType, chkVolID] ← FPM.GetAttributes[fileHandle];
IF chkType # FileTypes.tUntypedFile THEN ERROR;
IF chkVolID # VolumeID THEN ERROR;
END;
FOR indexOps: CARDINAL IN [0..tempNOps)
DO
ioMode: IOMode ← (SELECT RandomCard.Choose[0, 1] FROM
0 => read, 1 => readWithReadAhead, ENDCASE => ERROR);
keep: BOOLEAN ← (RandomCard.Choose[0, 1] = 0);
leader: BOOLEAN ← (RandomCard.Choose[0, 1] = 0);
fileInterval: FileInterval ← (SELECT RandomCard.Choose[0, 2] FROM
0 => [allFixed[RandomCard.Choose[1, MaxNPagesEachTime]]],
1 => [allRandom[]],
2 => [someRandom[]],
ENDCASE => ERROR);
SequentialIO[fileHandle, indexFiles, ioMode, clean, keep, leader,
fileInterval];
ENDLOOP;
ENDLOOP;
ENDLOOP;
END;
SharingProcess: PROCEDURE [firstFileIndex: CARDINAL]=
BEGIN
NSubSharingProcesses: CARDINAL = 3;
mySubProcesses: ARRAY [0..NSubSharingProcesses) OF PROCESS RETURNS [nOps:
ARRAY[0..NFilesPerSharingProcess) OF CARDINAL];
FOR indexFiles: CARDINAL IN [firstFileIndex..firstFileIndex +
NFilesPerSharingProcess)
DO
fileHandle: FileMap.Handle ← FileMap.Register[VolumeID,
files[indexFiles].fileID];
files[indexFiles].size ← RandomCard.Choose[min: 0, max: MaxFileSize];
FPM.CreateWithID[fileHandle, files[indexFiles].size,
FileTypes.tUntypedFile];
files[indexFiles].exists ← TRUE;
SequentialIO[fileHandle, indexFiles, write, writeBatchedNoWait,
--keep--FALSE, --leader--TRUE, [allFixed[files[indexFiles].size]]];
ENDLOOP;
FOR indexProcesses: CARDINAL IN [0..NSubSharingProcesses)
DO
mySubProcesses[indexProcesses] ← FORK SubSharingProcess[firstFileIndex];
ENDLOOP;
FOR indexProcesses: CARDINAL IN [0..NSubSharingProcesses)
DO
tempNOps: ARRAY[0..NFilesPerSharingProcess) OF CARDINAL ←
JOIN mySubProcesses[indexProcesses];
FOR index: CARDINAL IN [0..NFilesPerSharingProcess)
DO files[firstFileIndex + index].totalNOps ← files[firstFileIndex +
index].totalNOps + tempNOps[index];
ENDLOOP;
ENDLOOP;
END;
VolumeID: AE.VolumeID = LOOPHOLE[Volume.SystemID[]];
Processes: TYPE = RECORD[SEQUENCE nProcesses: [0..LAST[CARDINAL]] OF
ProcessModel];
ProcessModel: TYPE = RECORD[process: PROCESS, nFiles: CARDINAL];
Files: TYPE = RECORD[SEQUENCE nFiles: [0..LAST[CARDINAL]] OF FileModel];
FileModel: TYPE = RECORD[fileID: AE.FileID, type: FileType, exists: BOOLEAN,
size: CARDINAL, totalNOps: CARDINAL, nOps: CARDINAL];
FileType: TYPE = {normal, log};
LeaderTouch: TYPE = RECORD[SEQUENCE nFiles: [0..LAST[CARDINAL]] OF CARDINAL];
DataTouch: TYPE = RECORD[SEQUENCE nFiles: [0..LAST[CARDINAL]] OF REF DataArray];
DataArray: TYPE = RECORD[SEQUENCE nPages: [0..LAST[CARDINAL]] OF CARDINAL];
processes: REF Processes;
files: REF Files;
leaderTouch: REF LeaderTouch;
dataTouch: REF DataTouch;
MaxDebugIndex: CARDINAL = 100;
DebugArray: TYPE = ARRAY [0..MaxDebugIndex) OF RECORD[fileSequenceID: LONG
CARDINAL, op: DebugOp ← inited, newSize: CARDINAL];
DebugOp: TYPE = {badCreate, create, setSize, delete, mapAndSetSize, inited};
PrintFileStats: PROCEDURE =
BEGIN
PutFileID: PROCEDURE[fileID: AE.FileID] =
BEGIN
uid: SystemInternal.UniversalID ← LOOPHOLE[fileID];
resultsStreamHandle.PutF[" %5g %5g %5g %10g ",
IO.card[uid.processor.a], IO.card[uid.processor.b],
IO.card[uid.processor.c], IO.card[uid.sequence]];
END;
FOR index: CARDINAL IN [0..NFiles)
DO
resultsStreamHandle.PutRope["file: "];
PutFileID[files[index].fileID];
resultsStreamHandle.PutF[" type: %g final size: %g totalNOps: %g*n",
IO.rope[(IF files[index].type = normal THEN "normal" ELSE "log")],
IO.card[files[index].size], IO.card[files[index].totalNOps]];
ENDLOOP;
FOR index: CARDINAL IN [0..NNormalProcesses)
DO
resultsStreamHandle.PutF["process: %g nFiles: %g*n",
IO.card[index], IO.card[processes[index].nFiles]];
ENDLOOP;
resultsStreamHandle.PutF["%g*n", IO.rope["For sharing processes: "]];
FOR index: CARDINAL IN [NNormalFiles..NNormalFiles +
NSharingProcesses*NFilesPerSharingProcess)
DO
resultsStreamHandle.PutRope["file: "];
PutFileID[files[index].fileID];
resultsStreamHandle.PutF[" type: %g final size: %g totalNOps: %g*n",
IO.rope[(IF files[index].type = normal THEN "normal" ELSE "log")],
IO.card[files[index].size], IO.card[files[index].totalNOps]];
ENDLOOP;
END;
Main: PROCEDURE =
BEGIN -- set up to call from CoPilot for debugging.
foo: CARDINAL ← 0;
BEGIN
ENABLE ANY => foo ← foo + 1; -- protect us from the tempcedarexec.
firstFileIndex, maxFileIndex: CARDINAL;
resultsStreamHandle ←
FileIO.Open["FullBlownTest.Results", overwrite, none];
resultsStreamHandle.PutF["*nMachine type: %g*n*n", IO.rope[SELECT
CedarVersion.machineType FROM dolphin => "Dolphin", dorado => "Dorado",
dandelion => "Dandelion", dicentra => "Dicentra", ENDCASE => "unknown"]];
[] ← RandomCard.Init[0];
GetParams[];
FPM.InitializeFilePageMgr[nNormalChunksInCache: NNormalChunksInCache,
nLogChunksInCache: NLogChunksInCache, nLeaderChunksInCache:
NLeaderChunksInCache];
resultsStreamHandle.PutRope["
Delay used is 4 milliseconds per page, after each transfer, unless superceeded.
"];
NProcesses ← NNormalProcesses + NErrorProcesses + NSharingProcesses;
processes ← NEW[Processes[NProcesses]];
NNormalFiles ← 0;
FOR indexProcesses: CARDINAL IN [0..NNormalProcesses)
DO
processes[indexProcesses].nFiles ← RandomCard.Choose[1, MaxFilesPerProcess];
NNormalFiles ← NNormalFiles + processes[indexProcesses].nFiles;
ENDLOOP;
NFiles ← NNormalFiles + (NFilesPerErrorProcess*NErrorProcesses) +
(NFilesPerSharingProcess*NSharingProcesses);
files ← NEW[Files[NFiles]];
leaderTouch ← NEW[LeaderTouch[NFiles]];
dataTouch ← NEW[DataTouch[NFiles]];
FOR index: CARDINAL IN [0..NFiles)
DO
files[index] ← [fileID: , type: IF
RandomCard.Choose[0,1] = 0 THEN normal ELSE log, exists: FALSE,
size: 0, totalNOps: 0, nOps: 0];
leaderTouch[index] ← 0;
dataTouch[index] ← NEW[DataArray[MaxFileSize]];
FOR index1: CARDINAL IN [0..MaxFileSize)
DO dataTouch[index][index1] ← 0;
ENDLOOP;
ENDLOOP;
IF NFiles > 100 THEN ERROR;
SetUpFileData[];
--SafeStorage.ReclaimCollectibleObjects[TRUE, TRUE];
--SafeStorage.ReclaimCollectibleObjects[TRUE, TRUE];
--IF FileMap.GetNext[NIL] # NIL THEN ERROR;
CleanCache[];
firstFileIndex ← 0;
FOR indexProcesses: CARDINAL IN [0..NNormalProcesses)
DO
maxFileIndex ← firstFileIndex + processes[indexProcesses].nFiles;
processes[indexProcesses].process ← FORK BasicProcess[firstFileIndex,
maxFileIndex];
firstFileIndex ← maxFileIndex;
ENDLOOP;
FOR indexProcesses: CARDINAL IN [NNormalProcesses..NNormalProcesses +
NSharingProcesses)
DO
processes[indexProcesses].process ← FORK SharingProcess[firstFileIndex];
firstFileIndex ← firstFileIndex + NFilesPerSharingProcess;
ENDLOOP;
FOR indexProcesses: CARDINAL IN [NNormalProcesses +
NSharingProcesses..NNormalProcesses + NSharingProcesses + NErrorProcesses)
DO
processes[indexProcesses].process ← FORK ErrorProcess[firstFileIndex];
firstFileIndex ← firstFileIndex + NFilesPerErrorProcess;
ENDLOOP;
FOR indexProcesses: CARDINAL IN [0..NProcesses)
DO
JOIN processes[indexProcesses].process;
IF (indexProcesses MOD 4) = 0 THEN FPM.ForceOutEverything[];
ENDLOOP;
FPM.ForceOutEverything[];
CleanCache[];
--SafeStorage.ReclaimCollectibleObjects[TRUE, TRUE];
--SafeStorage.ReclaimCollectibleObjects[TRUE, TRUE];
--IF FileMap.GetNext[NIL] # NIL THEN ERROR;
PrintFileStats[];
resultsStreamHandle.Close[];
END;
END;
-- main line code:
resultsStreamHandle: IO.Handle;
NNormalProcesses, NLoops: CARDINAL;
NErrorProcesses, NSharingProcesses: CARDINAL;
MaxFilesPerProcess, MaxFileSize, MaxNPagesEachTime, MaxOpsPerFileCycle: CARDINAL;
NFilesPerSharingProcess: CARDINAL = 3;
NFilesPerErrorProcess: CARDINAL ← 2;
NFiles: CARDINAL;
NProcesses: CARDINAL;
NNormalChunksInCache: CARDINAL;
NLogChunksInCache: CARDINAL;
NLeaderChunksInCache: CARDINAL;
NNormalFiles: CARDINAL;
FileMap.Initialize[101, 1000];
END.
Edit Log
Initial: Kolling: May 20, 1982 4:15 pm: general test for FilePageManager.