RecoverFromCache.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bob Hagmann August 7, 1985 8:18:55 am PDT
DIRECTORY
BasicTime,
Commander USING [CommandProc, Handle, Register],
CommandTool USING [ArgumentVector, Failed, Parse],
Convert,
File,
FS,
FSBackdoor,
FSRemoteFile,
IO,
Process USING [CheckForAbort],
RedBlackTree,
Rope;
RecoverFromCache: CEDAR PROGRAM
IMPORTS BasicTime, Commander, CommandTool, Convert, File, FS, FSBackdoor, FSRemoteFile, IO, Process, RedBlackTree, Rope
= BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
GNameToDate: TYPE = REF GNameToDateObj;
GNameToDateObj: TYPE = RECORD [
key: ROPE,
createTime: BasicTime.GMT
];
RecoverFromCacheProc: Commander.CommandProc = {
[cmd: REF CommandObject] RETURNS [result: REFNIL, msg: ROPENIL]
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: BOOLFALSE;
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;
};
local => {
};
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: BOOLFALSE;
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: BOOLTRUE;
foundOnServer: BOOLFALSE;
createdOnServer: BasicTime.GMT;
fullFNameOnServer: ROPE;
missingCreateDate: BOOLFALSE;
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 => {explanationerror.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: ROPENIL;
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: BOOLFALSE;
server: ROPENIL;
autoConfirm: BOOLFALSE;
listOnly: BOOLFALSE;
expectType: TYPE = {num, volName, switch};
expecting: expectType ← num;
volumeName: ROPENIL;
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} "];
};
GetTheKey: RedBlackTree.GetKey = {
myObj: GNameToDate = NARROW[data];
RETURN[myObj.key];
};
CompareStuff: RedBlackTree.Compare = {
myObj: GNameToDate = NARROW[data];
key: ROPE = NARROW[k];
RETURN[Rope.Compare[key, myObj.key]];
};
Init: PROCEDURE = {
Commander.Register[
"///Commands/RecoverFromCache", RecoverFromCacheProc,
"RecoverFromCache Volume {-c} {-l} {Server} -- Scan the FS file cache on the specified volume (e.g., 'Cedar') for files from Server (all files if Server omitted); for each file, check to see that there is a file by that name on the server that has a higher version number. If not, print file name, versions and date from the server and wait for confirmation. -c does autoconfirm. If confirmed, store the file from the cache. -l only does listing"];
};
Initialization
Init[];
END.
Bob Hagmann August 7, 1985 8:18:55 am PDT
changes to: acceptProc (local of RecoverFromCacheProc), confirm (local of acceptProc, local of RecoverFromCacheProc), DIRECTORY, RecoverFromCache