<> <> <> <> <<>> <> <<>> DIRECTORY FS USING [Error, ErrorFromStream], IO, Rope, WalnutDB -- using lots -- , WalnutDefs USING [Error, VersionMismatch, MsgSet], WalnutLog -- using lots -- , WalnutMiscLog USING [walnutItemFixedLength, CreateReadArchiveLog], WalnutOps USING [], WalnutOpsInternal USING [CarefullyApply, CheckInProgress, CheckReport, LongRunningApply, ParseLog], WalnutOpsMonitorImpl, WalnutStream USING [Open], WalnutRoot USING [CommitAndContinue]; WalnutOpsArchiveFileImpl: CEDAR MONITOR LOCKS walnutOpsMonitorImpl IMPORTS FS, IO, Rope, walnutOpsMonitorImpl: WalnutOpsMonitorImpl, WalnutDB, WalnutDefs, WalnutLog, WalnutMiscLog, WalnutOpsInternal, WalnutStream, WalnutRoot EXPORTS WalnutOps SHARES WalnutOpsMonitorImpl = BEGIN OPEN WalnutOpsInternal; <> ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; <> <> <> <> <<>> ReadArchiveFile: PUBLIC ENTRY PROC[file: ROPE, msgSet: WalnutDefs.MsgSet _ [NIL, -1]] RETURNS[numNew: INT] = { <> 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] RETURNS[ok: BOOL]= { <> 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]; }; ok _ FALSE; 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[]; ok _ TRUE; CheckReport["\n Finished writing archive file\n"]; }; END.