SELECT rand
FROM
IN [0..1) => {
-- look up all old files
lofs: LIST OF FileStuff;
lodin: LIST OF REF DirectoryINode;
skipMax: INT ← 1;
skipCnt: INT ← 0;
IF NumberOfKnownFiles <= 0 THEN LOOP;
SELECT loopCount
FROM
IN [250..500) => skipMax ← RandomChooseInt[randomStream, 1, 3];
IN [500..1000) => skipMax ← RandomChooseInt[randomStream, 1, 7];
IN [1000..2000) => skipMax ← RandomChooseInt[randomStream, 1, 15];
IN [2000..4000) => skipMax ← RandomChooseInt[randomStream, 1, 33];
IN [4000..8000) => skipMax ← RandomChooseInt[randomStream, 1, 67];
IN [8000..16000) => skipMax ← RandomChooseInt[randomStream, 1, 155];
ENDCASE;
IF loopCount = noTests THEN skipMax ← 1;
IF noisy
THEN {
out.PutF["\n"];
PrintTimeOnOut[startTime, out];
out.PutF["Start Look Up All Old files/directories, loopCount= %g, skipMax= %g\n", IO.int[loopCount], IO.int[skipMax]];
};
FOR lofs ← KnownFiles, lofs.rest
UNTIL lofs =
NIL
DO
skipCnt ← skipCnt + 1;
IF skipCnt >= skipMax THEN skipCnt ← 0 ELSE LOOP;
CheckAFile[lofs];
ENDLOOP;
FOR lodin ← KnownDirectoryINodes, lodin.rest
UNTIL lodin =
NIL
DO
skipCnt ← skipCnt + 1;
IF skipCnt >= skipMax THEN skipCnt ← 0 ELSE LOOP;
CheckADirectory[lodin];
ENDLOOP;
IF noisy
THEN {
PrintTimeOnOut[startTime, out];
out.PutF["Look Up All Old files/directories Done\n\n"];
};
};
IN [1..13) => {
-- make new file with a contents; sometimes the file is a symbolic link
rand2: INT;
lodin: LIST OF REF DirectoryINode;
now: SunNFS.TimeVal;
symbolicLink: BOOL ← FALSE;
mode: CARD;
uid: CARD;
gid: CARD;
oldFree: INT;
newFileName: REF TEXT;
contents: REF TEXT;
reply: SunNFS.DirOpRes;
replyAttr: SunNFS.AttrStat;
status: SunNFS.Stat;
now ← SunTimeFromGMT[BasicTime.Now[]];
rand2 ← RandomChooseInt[randomStream, 0, NumberOfKnownDirectoryINodess];
FOR lodin ← KnownDirectoryINodes, lodin.rest
UNTIL lodin =
NIL
DO
rand2 ← rand2 - 1;
IF rand2 <= 0 AND ~lodin.first.rmOnly THEN EXIT;
ENDLOOP;
IF lodin = NIL THEN LOOP;
IF lodin.first.isRoot AND NumberOfKnownDirectoryINodess # 0 THEN LOOP; -- root directory, and there are others
newFileName ← PickAName[lodin];
uid ← PickUID[];
gid ← PickGID[];
oldFree ← YggFile.ServerInfo[].secondaryBlocksFree;
IF RandomChooseInt[randomStream, 0, 6] = 3
THEN {
lookupStat: SunNFS.DirOpRes;
symbolicLink ← TRUE;
mode ← PickMode[] + YggNFS.symbolicLinkModeBits;
contents ← PickAName[NIL];
status ← YggNFS.Symlink[from: [dir: lodin.first.fHandle, name: newFileName], to: contents, attributes: [mode: mode, uid: uid, gid: gid, size: RefText.Length[contents], atime: now, mtime: now]];
IF status # ok THEN ERROR;
lookupStat ← YggNFS.Lookup[which: [dir: lodin.first.fHandle, name: newFileName]];
IF lookupStat.status # ok THEN ERROR;
reply.file ← lookupStat.file;
}
ELSE {
contents ← MakeUpContents[];
mode ← PickMode[] + YggNFS.regularModeBits;
reply ← YggNFS.Create[where: [dir: lodin.first.fHandle, name: newFileName], attributes: [mode: mode, uid: uid, gid: gid, size: RefText.Length[contents], atime: now, mtime: now]];
IF reply.status # ok THEN ERROR;
replyAttr ← YggNFS.Write[file: reply.file, offset: 0, count: RefText.Length[contents], block: contents];
IF replyAttr.status # ok THEN ERROR;
};
NumberOfKnownFiles ← NumberOfKnownFiles + 1;
lodin.first.filesInDirectory ← CONS[[newFileName, NEW[INodeStuff ← [fHandle: reply.file, inDirectory: LIST[lodin.first], contents: contents, mode: mode, uid: uid, gid: gid]]], lodin.first.filesInDirectory];
KnownFiles ← CONS[lodin.first.filesInDirectory.first, KnownFiles];
IF noisy
THEN {
newFree: INT ← YggFile.ServerInfo[].secondaryBlocksFree;
newDID: DID ← DIDFromFHandle[reply.file];
preferedPrintName: Rope.ROPE;
preferedPrintName ← MakePreferedPrintName[lodin.first.filesInDirectory];
IF symbolicLink THEN out.PutF["Make new symbolic link: name= %g, did: %g, took %g pages\n", IO.rope[preferedPrintName], IO.card[newDID.didLow], IO.int[oldFree - newFree] ]
ELSE out.PutF["Make new file: name= %g, did: %g, took %g pages\n", IO.rope[preferedPrintName], IO.card[newDID.didLow], IO.int[oldFree - newFree] ];
};
};
IN [13..19) => {
-- delete a file
rand2: INT;
fileCount: INT ← 0;
lodin: LIST OF REF DirectoryINode;
lofiles: LIST OF FileStuff;
allKnownFiles: LIST OF FileStuff ← NIL;
prevAllKnownFiles: LIST OF FileStuff ← NIL;
prevFiles: LIST OF FileStuff ← NIL;
lordin: LIST OF REF DirectoryINode;
prevDir: LIST OF REF DirectoryINode;
dirINode: REF DirectoryINode;
status: SunNFS.Stat;
oldFree: INT;
IF NumberOfKnownFiles = 0 THEN LOOP;
rand2 ← RandomChooseInt[randomStream, 0, NumberOfKnownDirectoryINodess];
FOR lodin ← KnownDirectoryINodes, lodin.rest
UNTIL lodin =
NIL
DO
rand2 ← rand2 - 1;
IF rand2 <= 0 THEN EXIT;
ENDLOOP;
IF lodin = NIL THEN LOOP;
dirINode ← lodin.first;
FOR lofs:
LIST
OF FileStuff ← dirINode.filesInDirectory, lofs.rest
UNTIL lofs =
NIL
DO
fileCount ← fileCount + 1;
ENDLOOP;
IF fileCount = 0 THEN LOOP;
rand2 ← RandomChooseInt[randomStream, 0, fileCount-1];
FOR lofiles ← dirINode.filesInDirectory, lofiles.rest
UNTIL lofiles =
NIL
DO
rand2 ← rand2 -1;
IF rand2 <= 0 THEN EXIT;
prevFiles ← lofiles;
ENDLOOP;
IF lofiles = NIL THEN LOOP;
oldFree ← YggFile.ServerInfo[].secondaryBlocksFree;
status ← YggNFS.Remove[which: [dir: dirINode.fHandle, name: lofiles.first.fileName]];
IF status # ok THEN ERROR;
NumberOfKnownFiles ← NumberOfKnownFiles - 1;
FOR allKnownFiles ← KnownFiles, allKnownFiles.rest
UNTIL allKnownFiles =
NIL
DO
IF RefText.Equal[lofiles.first.fileName, allKnownFiles.first.fileName] AND (lofiles.first.inode = allKnownFiles.first.inode) THEN EXIT;
prevAllKnownFiles ← allKnownFiles;
REPEAT FINISHED => ERROR;
ENDLOOP;
IF prevAllKnownFiles = NIL THEN KnownFiles ← allKnownFiles.rest
ELSE prevAllKnownFiles.rest ← allKnownFiles.rest;
IF prevFiles = NIL THEN dirINode.filesInDirectory ← lofiles.rest
ELSE prevFiles.rest ← lofiles.rest;
FOR lordin ← lofiles.first.inode.inDirectory, lordin.rest
UNTIL lordin =
NIL
DO
IF lordin.first = dirINode
THEN {
EXIT;
};
prevDir ← lordin;
REPEAT FINISHED => ERROR;
ENDLOOP;
IF prevDir = NIL THEN lofiles.first.inode.inDirectory ← lordin.rest
ELSE prevDir.rest ← lordin.rest;
IF lofiles.first.inode.inDirectory #
NIL
THEN {
-- multi-hard link file has had one of it's links deleted. Does the other one still work?
FOR files:
LIST
OF FileStuff ← lofiles.first.inode.inDirectory.first.filesInDirectory, files.rest
UNTIL files =
NIL
DO
IF files.first.inode = lofiles.first.inode
THEN {
CheckAFile[files];
EXIT;
};
REPEAT FINISHED => ERROR;
ENDLOOP;
CheckADirectory[lofiles.first.inode.inDirectory]; -- check the directory too
};
IF noisy
THEN {
newFree: INT ← YggFile.ServerInfo[].secondaryBlocksFree;
out.PutF["Delete file: name= %g in directory name= %g, got %g pages\n", IO.rope[RefText.TrustTextAsRope[lofiles.first.fileName]], IO.rope[MakePreferedDirPrintName[dirINode]], IO.int[newFree - oldFree] ];
};
};
IN [19..21) => {
-- make new directory
rand2: INT;
lodin: LIST OF REF DirectoryINode;
now: SunNFS.TimeVal;
mode: CARD;
uid: CARD;
gid: CARD;
oldFree: INT;
newDirName: REF TEXT;
reply: SunNFS.DirOpRes;
now ← SunTimeFromGMT[BasicTime.Now[]];
rand2 ← RandomChooseInt[randomStream, 0, NumberOfKnownDirectoryINodess];
FOR lodin ← KnownDirectoryINodes, lodin.rest
UNTIL lodin =
NIL
DO
rand2 ← rand2 - 1;
IF rand2 <= 0 AND ~lodin.first.rmOnly THEN EXIT;
ENDLOOP;
IF lodin = NIL THEN LOOP;
IF lodin.first.isRoot AND NumberOfKnownDirectoryINodess # 0 THEN LOOP; -- root directory, and there are others
newDirName ← PickAName[lodin];
mode ← PickMode[];
uid ← PickUID[];
gid ← PickGID[];
oldFree ← YggFile.ServerInfo[].secondaryBlocksFree;
reply ← YggNFS.Mkdir[where: [dir: lodin.first.fHandle, name: newDirName], attributes: [mode: mode, uid: uid, gid: gid, size: 0, atime: now, mtime: now]];
IF reply.status # ok THEN ERROR;
NumberOfKnownDirectoryINodess ← NumberOfKnownDirectoryINodess + 1;
lodin.first.directoriesInDirectory ← CONS[[newDirName, NEW[DirectoryINode ← [fHandle: reply.file, inDirectory: LIST[lodin.first], filesInDirectory: NIL, directoriesInDirectory: NIL, isRoot: FALSE]]], lodin.first.directoriesInDirectory];
KnownDirectoryINodes ← CONS[lodin.first.directoriesInDirectory.first.dirINode, KnownDirectoryINodes];
IF noisy
THEN {
newFree: INT ← YggFile.ServerInfo[].secondaryBlocksFree;
newDID: DID ← DIDFromFHandle[reply.file];
preferedPrintName: Rope.ROPE;
preferedPrintName ← MakePreferedDirPrintName[lodin.first.directoriesInDirectory.first.dirINode];
out.PutF["Make new directory: name= %g, did: %g, took %g pages\n", IO.rope[preferedPrintName], IO.card[newDID.didLow], IO.int[oldFree - newFree] ];
};
};
IN [21..22) => {
-- remove a directory
lodin: LIST OF REF DirectoryINode;
See if dirs are empty
FOR lodin ← KnownDirectoryINodes, lodin.rest
UNTIL lodin =
NIL
DO
IF lodin.first.isRoot THEN LOOP;
IF ~lodin.first.rmOnly THEN LOOP;
IF lodin.first.filesInDirectory =
NIL
AND lodin.first.directoriesInDirectory =
NIL
THEN {
FailedToRMDirCount ← 0;
RemoveDirectory[lodin, noisy, out];
EXIT;
};
ENDLOOP;
IF lodin #
NIL
THEN {
LOOP;
};
If it looks like we need another
IF NumberOfRMDirectories * 5 < NumberOfKnownDirectoryINodess
OR FailedToRMDirCount > 5
THEN {
FailedToRMDirCount ← 0;
FOR lodin ← KnownDirectoryINodes, lodin.rest
UNTIL lodin =
NIL
DO
IF lodin.first.isRoot THEN LOOP;
IF lodin.first.rmOnly THEN LOOP;
lodin.first.rmOnly ← TRUE;
IF noisy
THEN {
preferedPrintName: Rope.ROPE;
preferedPrintName ← MakePreferedDirPrintName[lodin.first];
out.PutF["Flag directory for RmDir: name= %g\n", IO.rope[preferedPrintName] ];
};
NumberOfRMDirectories ← NumberOfRMDirectories + 1;
EXIT;
ENDLOOP;
}
ELSE {
FailedToRMDirCount ← FailedToRMDirCount + 1;
};
};
IN [22..24) => {
-- change a file's attrs
rand2: INT;
dirINode: REF DirectoryINode;
prevFiles: LIST OF FileStuff ← NIL;
fileCount: INT ← 0;
lofiles: LIST OF FileStuff;
lodin: LIST OF REF DirectoryINode;
mode: CARD;
uid: CARD;
gid: CARD;
oldFree: INT ← YggFile.ServerInfo[].secondaryBlocksFree;
reply: SunNFS.AttrStat;
IF NumberOfKnownFiles = 0 THEN LOOP;
rand2 ← RandomChooseInt[randomStream, 0, NumberOfKnownDirectoryINodess];
FOR lodin ← KnownDirectoryINodes, lodin.rest
UNTIL lodin =
NIL
DO
rand2 ← rand2 - 1;
IF rand2 <= 0 THEN EXIT;
ENDLOOP;
IF lodin = NIL THEN LOOP;
dirINode ← lodin.first;
FOR lofs:
LIST
OF FileStuff ← dirINode.filesInDirectory, lofs.rest
UNTIL lofs =
NIL
DO
fileCount ← fileCount + 1;
ENDLOOP;
IF fileCount = 0 THEN LOOP;
rand2 ← RandomChooseInt[randomStream, 0, fileCount-1];
FOR lofiles ← dirINode.filesInDirectory, lofiles.rest
UNTIL lofiles =
NIL
DO
rand2 ← rand2 -1;
IF rand2 <= 0 THEN EXIT;
prevFiles ← lofiles;
ENDLOOP;
IF lofiles = NIL THEN LOOP;
mode ← PickMode[] + CARD[Basics.BITAND[lofiles.first.inode.mode, YggNFS.typeBits]];
uid ← PickUID[];
gid ← PickGID[];
reply ← YggNFS.Setattr[file: lofiles.first.inode.fHandle, attributes: [mode: mode, uid: uid, gid: gid, size: CARD.LAST, atime: [CARD.LAST, CARD.LAST], mtime: [CARD.LAST, CARD.LAST]]];
IF reply.status # ok THEN ERROR;
lofiles.first.inode.mode ← mode;
lofiles.first.inode.uid ← uid;
lofiles.first.inode.gid ← gid;
IF noisy
THEN {
newFree: INT ← YggFile.ServerInfo[].secondaryBlocksFree;
preferedPrintName: Rope.ROPE;
preferedPrintName ← MakePreferedPrintName[lofiles];
out.PutF["Changed attributes on file: name= %g\n", IO.rope[preferedPrintName] ];
IF newFree # oldFree THEN out.PutF[" ---- Change attributes took %g pages\n", IO.int[newFree - oldFree] ];
};
};
IN [24..29) => {
-- make a hard link
rand2: INT;
lodin: LIST OF REF DirectoryINode;
loallFileStuff: LIST OF FileStuff;
mode: CARD;
uid: CARD;
gid: CARD;
oldFree: INT ← YggFile.ServerInfo[].secondaryBlocksFree;
newFileName: REF TEXT;
oldPreferedPrintName: Rope.ROPE;
fileFHandle: SunNFS.FHandle;
status: SunNFS.Stat;
IF NumberOfKnownFiles = 0 THEN LOOP;
rand2 ← RandomChooseInt[randomStream, 0, NumberOfKnownDirectoryINodess];
FOR lodin ← KnownDirectoryINodes, lodin.rest
UNTIL lodin =
NIL
DO
rand2 ← rand2 - 1;
IF rand2 <= 0 AND ~lodin.first.rmOnly THEN EXIT;
ENDLOOP;
IF lodin = NIL THEN LOOP;
IF lodin.first.isRoot AND NumberOfKnownDirectoryINodess # 0 THEN LOOP; -- root directory, and there are others
rand2 ← RandomChooseInt[randomStream, 0, NumberOfKnownFiles-1];
FOR loallFileStuff ← KnownFiles, loallFileStuff.rest
UNTIL loallFileStuff =
NIL
DO
rand2 ← rand2 - 1;
IF rand2 <= 0 AND CARD[Basics.BITAND[loallFileStuff.first.inode.mode, YggNFS.typeBits]] # YggNFS.symbolicLinkModeBits THEN EXIT;
ENDLOOP;
IF loallFileStuff = NIL THEN LOOP;
oldPreferedPrintName ← MakePreferedPrintName[loallFileStuff];
fileFHandle ← loallFileStuff.first.inode.fHandle;
newFileName ← PickAName[lodin];
mode ← PickMode[];
uid ← PickUID[];
gid ← PickGID[];
status ← YggNFS.Link[to: fileFHandle, as: [dir: lodin.first.fHandle, name: newFileName]];
lodin.first.filesInDirectory ← CONS[[newFileName, loallFileStuff.first.inode], lodin.first.filesInDirectory];
loallFileStuff.first.inode.inDirectory ← CONS[lodin.first, loallFileStuff.first.inode.inDirectory];
KnownFiles ← CONS[lodin.first.filesInDirectory.first, KnownFiles];
NumberOfKnownFiles ← NumberOfKnownFiles + 1;
IF noisy
THEN {
newFree: INT ← YggFile.ServerInfo[].secondaryBlocksFree;
preferedPrintName: Rope.ROPE;
preferedPrintName ← MakePreferedPrintName[lodin.first.filesInDirectory];
out.PutF["Make new hard link: name= %g (one other name is %g)\n", IO.rope[preferedPrintName], IO.rope[oldPreferedPrintName] ];
IF newFree # oldFree THEN out.PutF[" ---- New hard link took %g pages\n", IO.int[newFree - oldFree] ];
};
};
IN [29..35) => {
-- rename file
rand2: INT;
fileCount: INT ← 0;
fromDir: LIST OF REF DirectoryINode;
lofiles: LIST OF FileStuff;
allKnownFiles: LIST OF FileStuff ← NIL;
prevAllKnownFiles: LIST OF FileStuff ← NIL;
prevFiles: LIST OF FileStuff ← NIL;
lordin: LIST OF REF DirectoryINode;
prevDir: LIST OF REF DirectoryINode;
dirINode: REF DirectoryINode;
status: SunNFS.Stat;
toDir: LIST OF REF DirectoryINode;
now: SunNFS.TimeVal;
symbolicLink: BOOL ← FALSE;
newFileName: REF TEXT;
oldPreferedPrintName: Rope.ROPE;
oldFree: INT ← YggFile.ServerInfo[].secondaryBlocksFree;
IF NumberOfKnownFiles = 0 THEN LOOP;
rand2 ← RandomChooseInt[randomStream, 0, NumberOfKnownDirectoryINodess];
FOR fromDir ← KnownDirectoryINodes, fromDir.rest
UNTIL fromDir =
NIL
DO
rand2 ← rand2 - 1;
IF rand2 <= 0 THEN EXIT;
ENDLOOP;
IF fromDir = NIL THEN LOOP;
dirINode ← fromDir.first;
FOR lofs:
LIST
OF FileStuff ← dirINode.filesInDirectory, lofs.rest
UNTIL lofs =
NIL
DO
fileCount ← fileCount + 1;
ENDLOOP;
IF fileCount = 0 THEN LOOP;
rand2 ← RandomChooseInt[randomStream, 0, fileCount-1];
FOR lofiles ← dirINode.filesInDirectory, lofiles.rest
UNTIL lofiles =
NIL
DO
rand2 ← rand2 -1;
IF rand2 <= 0 THEN EXIT;
prevFiles ← lofiles;
ENDLOOP;
IF lofiles = NIL THEN LOOP;
oldPreferedPrintName ← MakePreferedPrintName[lofiles];
lofiles.first is the file to rename
now ← SunTimeFromGMT[BasicTime.Now[]];
rand2 ← RandomChooseInt[randomStream, 0, NumberOfKnownDirectoryINodess];
FOR toDir ← KnownDirectoryINodes, toDir.rest
UNTIL toDir =
NIL
DO
rand2 ← rand2 - 1;
IF rand2 <= 0 AND ~toDir.first.rmOnly THEN EXIT;
ENDLOOP;
IF toDir = NIL THEN LOOP;
IF toDir.first.isRoot AND NumberOfKnownDirectoryINodess # 0 THEN LOOP; -- root directory, and there are others
newFileName ← PickAName[toDir];
status ← YggNFS.Rename[from: [dir: fromDir.first.fHandle, name: lofiles.first.fileName], to: [dir: toDir.first.fHandle, name: newFileName]];
IF status # ok THEN ERROR;
IF prevFiles = NIL THEN dirINode.filesInDirectory ← lofiles.rest
ELSE prevFiles.rest ← lofiles.rest;
FOR lordin ← lofiles.first.inode.inDirectory, lordin.rest
UNTIL lordin =
NIL
DO
IF lordin.first = dirINode
THEN {
EXIT;
};
prevDir ← lordin;
REPEAT FINISHED => ERROR;
ENDLOOP;
IF prevDir = NIL THEN lofiles.first.inode.inDirectory ← lordin.rest
ELSE prevDir.rest ← lordin.rest;
toDir.first.filesInDirectory ← CONS[[newFileName, lofiles.first.inode], toDir.first.filesInDirectory];
lofiles.first.inode.inDirectory ← CONS[toDir.first, lofiles.first.inode.inDirectory];
FOR allKnownFiles ← KnownFiles, allKnownFiles.rest
UNTIL allKnownFiles =
NIL
DO
IF RefText.Equal[lofiles.first.fileName, allKnownFiles.first.fileName]
AND (lofiles.first.inode = allKnownFiles.first.inode)
THEN
{
allKnownFiles.first.fileName ← newFileName;
EXIT;
};
REPEAT FINISHED => ERROR;
ENDLOOP;
IF noisy
THEN {
newFree: INT ← YggFile.ServerInfo[].secondaryBlocksFree;
newPreferedPrintName: Rope.ROPE;
newPreferedPrintName ← MakePreferedPrintName[toDir.first.filesInDirectory];
out.PutF["Rename: from = %g to = %g\n", IO.rope[oldPreferedPrintName], IO.rope[newPreferedPrintName] ];
IF newFree # oldFree THEN out.PutF[" ---- Rename took %g pages\n", IO.int[newFree - oldFree] ];
};
};
ENDCASE;