RecoverFromCacheProc: Commander.CommandProc = {
[cmd: REF CommandObject] RETURNS [result: REF ← NIL, msg: ROPE ← NIL]
CommandObject = [
in, out, err: STREAM, commandLine, command: ROPE,
propertyList: List.AList, procData: CommandProcHandle]
Enumerate the cache, and find the "count" largest files. Enumeration is fairly slow since the files must actually be opened to discover their size. We keep an unsorted sequence of the largest files found so far. This data structure is OK since we are so heavily disk bound.
out: STREAM ← cmd.out;
count: INT ← 10;
volume: File.Volume;
lastEntry: FSBackdoor.EntryPtr;
localCount, cachedCount, attachedCount: INT ← 0;
stopAttachmentsList: BOOL ← FALSE;
matchAttachmentsProc:
UNSAFE
PROC [entry: FSBackdoor.EntryPtr]
RETURNS [accept, stop:
BOOLEAN] ={
Process.CheckForAbort[];
lastEntry ← entry;
RETURN[TRUE, stopAttachmentsList];
};
acceptAttachmentsProc:
SAFE
PROC
RETURNS [stop:
BOOLEAN] =
TRUSTED {
thisFP: File.FP ← File.nullFP;
fileName: ROPE;
fileNameLessVersion: ROPE;
createTime: BasicTime.GMT;
attachedTo: ROPE;
stop ← FALSE;
fileNameLessVersion ← FSBackdoor.TextFromTextRep[@lastEntry[lastEntry.nameBody]];
fileName ← Rope.Cat[fileNameLessVersion, "!", Convert.RopeFromCard[from: lastEntry.version, showRadix: FALSE]];
WITH e: lastEntry^
SELECT
FROM
attached => {
node: RedBlackTree.Node;
createTime ← e.created;
attachedTo ← FSBackdoor.TextFromTextRep[@lastEntry[e.attachedTo]];
node ← RedBlackTree.LookupNode[lNameToGName, attachedTo];
IF node =
NIL
THEN {
myData: GNameToDate = NEW [GNameToDateObj ← [attachedTo, createTime]];
RedBlackTree.Insert[lNameToGName, myData, attachedTo];
};
};
cached => {
stopAttachmentsList ← TRUE;
};
ENDCASE ;
};
matchProc:
UNSAFE
PROC [entry: FSBackdoor.EntryPtr]
RETURNS [accept, stop:
BOOLEAN] ={
Process.CheckForAbort[];
lastEntry ← entry;
RETURN[TRUE, FALSE];
};
acceptProc:
SAFE
PROC
RETURNS [stop:
BOOLEAN] =
TRUSTED {
fileName: ROPE;
fileNameLessVersion: ROPE;
nameBodyRopeText: Rope.Text;
doTransfer: BOOL ← FALSE;
stop ← FALSE;
nameBodyRopeText ← FSBackdoor.TextFromTextRep[@lastEntry[lastEntry.nameBody]];
fileNameLessVersion ← IF nameBodyRopeText.InlineFetch[0] # '[ THEN Rope.Concat["[]<>", nameBodyRopeText] ELSE nameBodyRopeText;
fileName ← Rope.Cat[fileNameLessVersion, "!", Convert.RopeFromCard[from: lastEntry.version, showRadix: FALSE]];
WITH e: lastEntry^
SELECT
FROM
cached => {
lookForDateInfoProc:
FS.InfoProc =
CHECKED {
InfoProc: TYPE = PROC [ fullFName, attachedTo: ROPE, created: BasicTime.GMT, bytes: INT, keep: CARDINAL ] RETURNS [continue: BOOL];
IF BasicTime.Period[created, localCreateDate] = 0
THEN {
foundOnServer ← TRUE;
createdOnServer ← created;
fullFNameOnServer ← fullFName;
};
RETURN[TRUE];
};
node: RedBlackTree.Node;
errorFree: BOOL ← TRUE;
foundOnServer: BOOL ← FALSE;
createdOnServer: BasicTime.GMT;
fullFNameOnServer: ROPE;
missingCreateDate: BOOL ← FALSE;
file: FS.OpenFile ← FS.nullOpenFile;
localCreateDate: BasicTime.GMT ← BasicTime.nullGMT;
node ← RedBlackTree.LookupNode[lNameToGName, fileName];
IF node =
NIL
THEN {
explanation: ROPE;
file ← FS.Open[name: fileName, remoteCheck: FALSE ! FS.Error => {explanation ← error.explanation; CONTINUE;}];
IF file #
FS.nullOpenFile
THEN {
localCreateDate ← FS.GetInfo[file].created;
}
ELSE {
cmd.out.PutF["\n Open error %g during open of %g. Not processed.", IO.rope[explanation], IO.rope[fileName]];
RETURN;
}
}
ELSE {
myData: GNameToDate = NARROW[node.data];
localCreateDate ← myData.createTime;
};
FS.EnumerateForInfo[pattern: Rope.Cat[fileNameLessVersion, "!*"], proc: lookForDateInfoProc ! FS.Error => CONTINUE;];
IF listOnly
THEN {
IF ~foundOnServer THEN cmd.out.PutF["\n Copy %g.", IO.rope[fileName]];
}
ELSE {
IF autoConfirm
THEN {
IF ~foundOnServer THEN doTransfer ← TRUE ELSE doTransfer ← FALSE;
}
ELSE {
IF ~foundOnServer
THEN {
DO
line: ROPE ← NIL;
IF foundOnServer THEN cmd.out.PutF["\n File %g is on server, but there is a local version %g. Copy it? ", IO.rope[fullFNameOnServer], IO.int[lastEntry.version]]
ELSE cmd.out.PutF["\n File %g is on not on server. Copy it? ", IO.rope[fileName]];
line ← cmd.in.GetLineRope[];
cmd.out.PutRope["\n"];
IF Rope.IsEmpty[line] THEN LOOP;
IF line.Fetch[0] = 'y OR line.Fetch[0] = 'Y THEN {doTransfer ← TRUE; EXIT};
IF line.Fetch[0] = 'n OR line.Fetch[0] = 'N THEN {doTransfer ← FALSE; EXIT};
ENDLOOP;
};
};
};
IF doTransfer
THEN {
confirm: FSRemoteFile.ConfirmProc = CHECKED { RETURN[TRUE]};
fullFName: ROPE;
cp: FS.ComponentPositions;
IF file =
FS.nullOpenFile
THEN {
explanation: ROPE;
file ← FS.Open[name: fileName, remoteCheck: FALSE ! FS.Error => {explanation ← error.explanation; CONTINUE;}];
IF file =
FS.nullOpenFile
THEN {
cmd.out.PutF["\n Open error %g during open of %g. Can't copy.", IO.rope[explanation], IO.rope[fileName]];
RETURN;
};
};
[fullFName: fullFName, cp: cp] ← FS.ExpandName[name: fileName] ;
FSRemoteFile.Store[server: Rope.Substr[fullFName, cp.server.start, cp.server.length], file: Rope.Substr[fullFName, cp.dir.start-1, cp.ver.start-cp.dir.start], str: FS.StreamFromOpenFile[file], created: localCreateDate, proc: confirm];
[] ← FS.Copy[from: fileName, to: fileNameLessVersion, attach: FALSE];
cmd.out.PutF["\n %g copied\n", IO.rope[fileName]];
};
IF file = FS.nullOpenFile THEN FS.Close[file ! FS.Error => CONTINUE];
};
ENDCASE ;
};
lNameToGName: RedBlackTree.Table;
argv: CommandTool.ArgumentVector ← CommandTool.Parse[cmd
! CommandTool.Failed => {msg ← errorMsg; GO TO Usage}];
counter: INT ← 1;
gotVolume: BOOL ← FALSE;
server: ROPE ← NIL;
autoConfirm: BOOL ← FALSE;
listOnly: BOOL ← FALSE;
expectType: TYPE = {num, volName, switch};
expecting: expectType ← num;
volumeName: ROPE ← NIL;
pattern: Rope.Text;
IF argv.argc < 2 THEN GOTO Usage;
WHILE counter < argv.argc
DO
arg: ROPE ← argv[counter];
IF arg.InlineFetch[0] = '-
THEN {
c: CHAR;
IF arg.Length[] # 2 THEN GOTO Usage;
c ← arg.InlineFetch[1];
SELECT c
FROM
'c => autoConfirm ← TRUE;
'l => listOnly ← TRUE;
ENDCASE;
}
ELSE {
-- NOT '-
IF gotVolume THEN server ← arg ELSE {gotVolume ← TRUE; volumeName ← arg};
};
counter ← counter + 1;
ENDLOOP;
volume ← File.FindVolumeFromName[volumeName];
IF volume = NIL THEN GOTO Usage;
lNameToGName ← RedBlackTree.Create[getKey: GetTheKey, compare: CompareStuff];
cmd.out.PutRope["Starting enumerate of FS BTree for attachments.\n"];
FSBackdoor.Enumerate[volName: volumeName, nameBodyPattern: NIL, localOnly: TRUE, allVersions: TRUE, version: FSBackdoor.highestVersion, matchProc: matchAttachmentsProc, acceptProc: acceptAttachmentsProc];
cmd.out.PutRope["Starting enumerate of FS BTree for cached files.\n"];
pattern ← Rope.Flatten[Rope.Cat["[", server,"*"]];
FSBackdoor.Enumerate[volName: volumeName, nameBodyPattern: pattern, localOnly: FALSE, allVersions: FALSE, version: FSBackdoor.highestVersion, matchProc: matchProc, acceptProc: acceptProc];
RedBlackTree.DestroyTable[lNameToGName];
EXITS
Usage => RETURN[$Failure, "Usage: RecoverFromCache {-c} {Server} "];
};