<> <> <> DIRECTORY FS USING [PagesForBytes], IO, RefTab USING [EachPairAction, Ref, Val, Create, Fetch, Store, Pairs], Rope USING [ROPE], ViewerClasses USING [Viewer], ViewerIO USING [CreateViewerStreams], ViewerOps USING [FindViewer, OpenIcon], WalnutDefs USING [Error], WalnutLog USING [LogLength, OpenLogStreams, ReturnCurrentLogStreams, ShutdownLog], WalnutLogExpunge USING [CopyEntry, EndExpunge, GetExpungeProgress, PeekEntry, SetPosition, Shutdown, SkipEntry, StartExpunge], WalnutRoot USING [CommitAndContinue, Open, RegisterStatsProc, Shutdown, StartTransaction, SwapLogs, UnregisterStatsProc], WalnutStream USING [Open, PeekEntry]; LogInfo: CEDAR PROGRAM IMPORTS FS, IO, RefTab, ViewerIO, ViewerOps, WalnutDefs, WalnutLog, WalnutLogExpunge, WalnutRoot, WalnutStream = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; out: STREAM _ NIL; debugging: BOOL _ FALSE; Xyz: TYPE = REF ValueObject; ValueObject: TYPE = RECORD[num, bytes: INT _ 0]; TSStream: PROC[name: ROPE] RETURNS [in, out: STREAM] = { v: ViewerClasses.Viewer _ ViewerOps.FindViewer[name]; [in, out] _ ViewerIO.CreateViewerStreams[name, v]; IF v#NIL THEN IF v.iconic THEN ViewerOps.OpenIcon[v]; }; Scan: PROC[logFile: ROPE] = { strm: STREAM; out _ TSStream["Walnut ScanLog"].out; strm _ WalnutStream.Open[name: logFile, readOnly: TRUE]; out.PutF["\n Scanning the logfile: %g\n\n(0)", IO.rope[logFile]]; strm.SetIndex[0]; DoScan[strm]; strm.Close[]; }; Fix: PROC[rootFile: ROPE, entriesToIgonore: LIST OF REF ANY] = { previousAt, at: INT _ -1; ident: ATOM; logLength, newLen: INT; expungeID: INT; num, numSinceFlush: INT _ 0; bytesBetweenFlushes: INT = 200000; toBeIgnored: LIST OF ATOM; pagesNeeded: INT; FOR ei: LIST OF REF ANY _ entriesToIgonore, ei.rest UNTIL ei = NIL DO ax: ATOM _ NARROW[ei.first]; toBeIgnored _ CONS[ax, toBeIgnored]; ENDLOOP; out _ TSStream["Walnut FixLog"].out; WalnutRoot.RegisterStatsProc[Report]; [] _ WalnutRoot.Open[rootFile]; [] _ WalnutRoot.StartTransaction[]; [] _ WalnutLog.OpenLogStreams[]; pagesNeeded _ FS.PagesForBytes[logLength _ WalnutLog.LogLength[]]; WalnutLog.ReturnCurrentLogStreams[]; expungeID _ WalnutLogExpunge.StartExpunge[pagesNeeded]; out.PutF["\n Fixing, using the rootfile: %g\n", IO.rope[rootFile]]; IF toBeIgnored = NIL THEN out.PutRope[" No entries will be ignored\n"] ELSE { out.PutRope["\n Ignoring the following entries: "]; FOR ignore: LIST OF ATOM _ toBeIgnored, ignore.rest UNTIL ignore = NIL DO out.PutF[" %g,", IO.atom[ignore.first]]; ENDLOOP; out.PutChar['\n]; }; [] _ WalnutLogExpunge.SetPosition[0]; BEGIN ENABLE WalnutDefs.Error => { out.PutF["WalnutDefs Error: code: %g, info: %g at %g", IO.atom[code], IO.rope[explanation], IO.time[] ]; GOTO error; }; DO bytesThisCopy, newPos: INT; didSkip: BOOL _ FALSE; previousAt _ at; [ident, , at]_ WalnutLogExpunge.PeekEntry[]; IF ident = NIL AND at # -1 THEN EXIT; IF at = previousAt THEN { -- probably transAbort [] _ WalnutLogExpunge.SkipEntry[]; out.PutF["\n At pos %g a second time\n", IO.int[at]]; LOOP }; FOR ignore: LIST OF ATOM _ toBeIgnored, ignore.rest UNTIL ignore = NIL DO IF ident = ignore.first THEN { [] _ WalnutLogExpunge.SkipEntry[]; didSkip _ TRUE; EXIT; }; ENDLOOP; IF didSkip THEN LOOP; IF ident = $LogFileInfo THEN { [] _ WalnutLogExpunge.SkipEntry[]; LOOP }; IF ~ValidIdent[ident, at] THEN { [] _ WalnutLogExpunge.SkipEntry[]; LOOP }; [newPos, bytesThisCopy] _ WalnutLogExpunge.CopyEntry[]; IF debugging THEN out.PutF[" - copied to %g", IO.int[newPos]]; IF ident = $CreateMsg THEN { IF (num_ num + 1) MOD 10 = 0 THEN IF num MOD 100 = 0 THEN out.PutF["(%g)", IO.int[num]] ELSE out.PutChar['.]; }; numSinceFlush _ numSinceFlush + bytesThisCopy; IF numSinceFlush >= bytesBetweenFlushes THEN { [] _ WalnutLogExpunge.GetExpungeProgress[]; WalnutRoot.CommitAndContinue[]; numSinceFlush _ 0; }; ENDLOOP; [] _ WalnutLogExpunge.GetExpungeProgress[]; WalnutLogExpunge.EndExpunge[]; WalnutRoot.CommitAndContinue[]; [ , newLen] _ WalnutRoot.SwapLogs[expungeID]; WalnutRoot.UnregisterStatsProc[Report]; WalnutRoot.Shutdown[]; out.PutF["\n The old log was %g bytes, the new log is %g bytes", IO.int[logLength], IO.int[newLen]]; out.PutF["\n The log file contains %g messages", IO.int[num]]; EXITS error => { WalnutLogExpunge.EndExpunge[]; WalnutRoot.UnregisterStatsProc[Report]; WalnutLogExpunge.Shutdown[]; WalnutLog.ShutdownLog[]; WalnutRoot.Shutdown[]; }; END; }; ValidIdent: PROC[ident: ATOM, at: INT] RETURNS[valid: BOOL] = { <> SELECT ident FROM $LogFileInfo => RETURN[TRUE]; $CreateMsg => RETURN[TRUE]; $ExpungeMsgs => RETURN[TRUE]; $WriteExpungeLog => RETURN[TRUE]; $CreateMsgSet => RETURN[TRUE]; $DestroyMsgSet => RETURN[TRUE]; $EmptyMsgSet => RETURN[TRUE]; $HasBeenRead => RETURN[TRUE]; $AddMsg => RETURN[TRUE]; $RemoveMsg => RETURN[TRUE]; $MoveMsg => RETURN[TRUE]; $RecordNewMailInfo => RETURN[TRUE]; $StartCopyNewMail => RETURN[TRUE]; $EndCopyNewMailInfo => RETURN[TRUE]; $AcceptNewMail => RETURN[TRUE]; $StartReadArchiveFile => RETURN[TRUE]; $EndReadArchiveFile => RETURN[TRUE]; $StartCopyReadArchive => RETURN[TRUE]; $EndCopyReadArchiveInfo => RETURN[TRUE]; ENDCASE => NULL; out.PutF["\n~~~~ Invalid Entry with identifier $%g at log pos %g\n", IO.atom[ident], IO.int[at] ]; RETURN[FALSE] }; DoScan: PROC[strm: STREAM] = { ident: ATOM; length: INT; table: RefTab.Ref _ RefTab.Create[]; found: BOOL; val: RefTab.Val; count: INT _ 0; at : INT _ strm.GetIndex[]; ForPrinting: RefTab.EachPairAction = { ident: ATOM _ NARROW[key]; this: Xyz _ NARROW[val]; out.PutF["Ident: %g, num: %g, bytes: %g\n", IO.atom[ident], IO.int[this.num], IO.int[this.bytes] ]; RETURN[FALSE]; -- don't quit }; DO this: Xyz; [ident, , length] _ WalnutStream.PeekEntry[strm]; IF ident = NIL THEN EXIT; strm.SetIndex[at _ at + length]; [found, val] _ RefTab.Fetch[table, ident]; IF found THEN { this _ NARROW[val]; this.num _ this.num + 1; this.bytes _ this.bytes + length; } ELSE this _ NEW[ValueObject _ [1, length]]; [] _ RefTab.Store[table, ident, this]; IF (count _ count + 1) MOD 10 = 0 THEN { IF count MOD 100 = 0 THEN out.PutF["(%g)", IO.int[count]] ELSE out.PutChar['~]; }; ENDLOOP; out.PutF["\n\n\t\tThe log contained the following %g entries:\n", IO.int[count]]; [] _ RefTab.Pairs[table, ForPrinting]; }; Report: PROC[msg: ROPE] = { out.PutF["\n %g @ %g\n", IO.rope[msg], IO.time[]] }; END.