<> <> <> DIRECTORY FS USING [PagesForBytes], IO, 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 [CloseTransaction, CommitAndContinue, Open, RegisterStatsProc, StartTransaction, SwapLogs, UnregisterStatsProc]; FixLog: CEDAR PROGRAM IMPORTS FS, IO, ViewerIO, ViewerOps, WalnutDefs, WalnutLog, WalnutLogExpunge, WalnutRoot = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; out: STREAM _ NIL; DebugStream: PROC RETURNS [IO.STREAM] = BEGIN v: ViewerClasses.Viewer_ ViewerOps.FindViewer["NewWalnut FixLog"]; out: IO.STREAM_ ViewerIO.CreateViewerStreams["NewWalnut FixLog", v].out; IF v#NIL THEN IF v.iconic THEN ViewerOps.OpenIcon[v]; RETURN[out]; END; debugging: BOOL _ FALSE; 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 _ DebugStream[]; 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]]; 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 secoond 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 }; [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.CloseTransaction[]; out.PutF["\n The old log was %g bytes, the new log is %g bytes", IO.int[logLength], IO.int[newLen]]; out.PutF["\nThe log file contains %g messages", IO.int[num]]; EXITS error => { WalnutLogExpunge.EndExpunge[]; WalnutRoot.UnregisterStatsProc[Report]; WalnutLogExpunge.Shutdown[]; WalnutLog.ShutdownLog[]; WalnutRoot.CloseTransaction[]; }; END; }; Report: PROC[r: ROPE] = { out.PutF["\n %g @ %g\n", IO.rope[r], IO.time[]] }; END.