ReadArchiveFile:
PUBLIC
ENTRY
PROC[file:
ROPE, msgSet: WalnutDefs.MsgSet ← [
NIL, -1]]
RETURNS[numNew: INT] = {
Write a "readArchiveFile" log entry; if the archiveFile exists, parses it and writes the appropriate entries (new msgs and moves if msgSet is not "Active" (NIL defaults to categories specified in the file). Then replays the log. If the file couldn't be read, numNew = -1;
ENABLE UNWIND => NULL;
ok: BOOL ← FALSE;
fStream: STREAM;
reason: ROPE;
Raf:
PROC = {
at: INT;
IF msgSet.name # NIL THEN [] ← WalnutDB.VerifyMsgSet[msgSet];
at ← WalnutLog.StartReadArchiveFile[file, msgSet.name].at;
WalnutDB.SetReadArchivePos[at];
};
Raf2:
PROC = {
[] ← WalnutLog.EndReadArchiveFile[];
WalnutDB.SetReadArchivePos[0];
};
Caf:
PROC[inProgress:
BOOL] = {
fromPos: INT ← 0;
IF ~inProgress
THEN {
at: INT;
ok ← WalnutLog.PrepareToCopyTempLog[ which: readArchive, pagesAlreadyCopied: 0, reportProc: WalnutOpsInternal.CheckReport];
IF ~ok THEN RETURN;
at ← WalnutLog.StartCopyReadArchive[].at;
WalnutDB.SetCopyReadArchivePos[at];
WalnutDB.SetOpInProgressPos[at];
WalnutRoot.CommitAndContinue[];
}
ELSE {
-- calculate fromPos
logLen: INT ← WalnutLog.LogLength[];
startedCopyAt, startCopyPos: INT;
startCopyPos ← WalnutDB.GetCopyReadArchivePos[];
IF WalnutLog.SetPosition[startCopyPos] # 0
THEN
ERROR WalnutDefs.Error[$log, $BadLog,
IO.PutFR["no entry at %g",
IO.int[startCopyPos]]];
[] ← WalnutLog.NextEntry[]; -- skip the copy entry
startedCopyAt ← WalnutLog.NextAt[];
fromPos ← logLen - startedCopyAt;
};
CheckReport[
IO.PutFR["\nCopying the ReadArchiveTempLog, starting at bytePos %g\n",
IO.int[fromPos]]];
WalnutLog.CopyTempLog[
readArchive, WalnutDB.GetCopyReadArchivePos[], fromPos, CheckReport];
CheckReport["\n"];
WalnutDB.SetParseLogInProgress[TRUE];
WalnutDB.SetParseLogPos[WalnutDB.GetOpInProgressPos[]];
WalnutDB.SetOpInProgressPos[-1];
};
WalnutOpsInternal.CheckInProgress[];
fStream ← WalnutStream.Open[name: file, readOnly:
TRUE !
FS.Error =>
{ CheckReport[error.explanation]; fStream ← NIL; CONTINUE} ].strm;
IF fStream = NIL THEN RETURN[-1];
WalnutOpsInternal.CarefullyApply[proc: Raf, didUpdate: TRUE];
BEGIN
ENABLE
BEGIN
FS.Error => { reason ← error.explanation; GOTO exit };
IO.Error => {
reason ← FS.ErrorFromStream[stream].explanation;
IF reason = NIL THEN reason ← "IO Error creating readArchiveLog";
GOTO exit
};
END;
[ok, reason] ←
WalnutMiscLog.CreateReadArchiveLog[fStream, msgSet.name, CheckReport];
EXITS
exit => ok ← FALSE;
END;
fStream.Close[ ! IO.Error, FS.Error => CONTINUE];
IF ~ok
THEN {
CheckReport[IO.PutFR[" Archive Read of %g failed", IO.rope[file]]];
IF reason # NIL THEN CheckReport[" Error reported as: ", reason];
RETURN[-1];
}
ELSE Raf2[];
WalnutOpsInternal.LongRunningApply[Caf];
IF ~ok
THEN {
CheckReport[
IO.PutFR[" Out of space trying to copy readArchiveLog for file %g",
IO.rope[file]]];
RETURN[-1];
};
CheckReport["\nAdding messages to database\n"];
numNew ← WalnutOpsInternal.ParseLog[TRUE];
};
WriteArchiveFile:
PUBLIC ENTRY PROC[
file: ROPE, msgSetList: LIST OF WalnutDefs.MsgSet, append: BOOL] = {
Write an archive file that contains the messages from the given message sets. No log entry is written and no updates are made to the database (we just hold the monitor to guarantee that no changes to the message sets occur).
ENABLE UNWIND => NULL;
wStream: STREAM;
someMsgWasTooBig: BOOL ← FALSE;
walnutItemForm: ROPE = "@%05d 00525 %05d\n"; -- 20 chars, tioga formatting
startHeaderForm: ROPE = "*start*\n%05d %05d US \n";
thisMsgSet, exp: ROPE;
startHeaderFixedLen: INT = 24;
first: BOOL ← TRUE;
WriteProc:
PROC[msg, TOCentry:
ROPE, hasBeenRead:
BOOL, startOfSubject:
INT] = {
textStart, textLen, formatLen, prefixLen: INT;
length, walnutItemLen: INT ← 0;
walnutItem: ROPE;
[textStart, textLen, formatLen, , ] ← WalnutDB.GetMsgText[msg];
walnutItem ← Rope.Cat[msg, "\n", thisMsgSet, "\n"];
walnutItemLen ←
WalnutMiscLog.walnutItemFixedLength + walnutItem.Length[] + formatLen;
IF formatLen # 0 THEN walnutItemLen ← walnutItemLen + 1; -- for extra CR after formatting
prefixLen ← startHeaderFixedLen + walnutItemLen;
length ← prefixLen + textLen + 1; -- extra CR after text
IF length > 99999
THEN {
CheckReport[
IO.PutFR["\nLength of msg %g is too big (%g bytes) - skipping",
IO.rope[msg], IO.int[length]] ];
someMsgWasTooBig ← TRUE;
RETURN
};
-- the -2 below are because the bytecount within the prefix item does not include the surrounding @'s
wStream.PutRope[
IO.PutFR[startHeaderForm, IO.int[length], IO.int[prefixLen]] ];
wStream.PutRope[
IO.PutFR[walnutItemForm, IO.int[walnutItemLen-2], IO.int[formatLen] ]];
wStream.PutRope[walnutItem];
IF formatLen # 0
THEN {
WalnutLog.CopyBytesToArchive[wStream, textStart+textLen, formatLen];
wStream.PutChar['\n];
};
wStream.PutChar['@];
WalnutLog.CopyBytesToArchive[wStream, textStart, textLen];
wStream.PutChar['\n];
};
WalnutOpsInternal.CheckInProgress[];
BEGIN
ENABLE
BEGIN
WalnutDefs.Error => {
IF wStream # NIL THEN wStream.Close[ ! IO.Error, FS.Error => CONTINUE];
REJECT;
};
WalnutDefs.VersionMismatch => {
IF wStream # NIL THEN wStream.Close[ ! IO.Error, FS.Error => CONTINUE];
REJECT;
};
IO.Error => { CheckReport[exp ← FS.ErrorFromStream[stream].explanation]; GOTO err };
FS.Error => { CheckReport[exp ← error.explanation]; GOTO err };
END;
BEGIN
wStream ← WalnutStream.Open[
name: file, useOldIfFound: append, exclusive: TRUE ! FS.Error =>
{ CheckReport[error.explanation]; GOTO none }].strm;
EXITS
none => wStream ← NIL;
END;
IF wStream =
NIL
THEN {
CheckReport[IO.PutFR["\nCould not open %g", IO.rope[file]]];
RETURN
};
IF append
THEN wStream.SetIndex[wStream.GetLength[]]
ELSE {
wStream.SetIndex[0];
wStream.SetLength[0];
};
CheckReport["\n Archiving: "];
FOR mL:
LIST
OF WalnutDefs.MsgSet ← msgSetList, mL.rest
UNTIL mL=
NIL
DO
thisMsgSet ← mL.first.name;
IF ~WalnutDB.VerifyMsgSet[mL.first]
THEN {
CheckReport["\n MsgSet ", thisMsgSet, " doesn't exist - continuing"];
LOOP;
};
IF first THEN first ← FALSE ELSE CheckReport[", "];
CheckReport[thisMsgSet];
[] ← WalnutDB.EnumerateMsgsInSet[name: thisMsgSet, proc: WriteProc];
ENDLOOP;
EXITS
err => {
wStream.Close[];
ERROR WalnutDefs.Error[$log, $ErrorDuringWriteArchive, exp];
};
END;
wStream.Close[];
CheckReport["\n Finished writing archive file\n"];
};