45
45
import com .evolvedbinary .j8fu .function .SupplierE ;
46
46
import org .exist .util .sanity .SanityCheck ;
47
47
48
+ import javax .annotation .Nullable ;
49
+
48
50
/**
49
51
* Database recovery. This class is used once during startup to check
50
52
* if the database is in a consistent state. If not, the class attempts to recover
@@ -59,11 +61,13 @@ public class RecoveryManager {
59
61
private final DBBroker broker ;
60
62
private final JournalRecoveryAccessor journalRecovery ;
61
63
private final boolean restartOnError ;
64
+ private final boolean hideProgressBar ;
62
65
63
66
public RecoveryManager (final DBBroker broker , final JournalManager journalManager , final boolean restartOnError ) {
64
67
this .broker = broker ;
65
68
this .journalRecovery = journalManager .getRecoveryAccessor (this );
66
69
this .restartOnError = restartOnError ;
70
+ this .hideProgressBar = Boolean .getBoolean ("exist.recovery.progressbar.hide" );
67
71
}
68
72
69
73
/**
@@ -120,10 +124,10 @@ public boolean recover() throws LogException {
120
124
Lsn lastLsn = Lsn .LSN_INVALID ;
121
125
Loggable next ;
122
126
try {
123
- final ProgressBar progress = new ProgressBar ("Scanning journal " , FileUtils .sizeQuietly (last ));
127
+ final long lastSize = FileUtils .sizeQuietly (last );
128
+ @ Nullable final ProgressBar scanProgressBar = hideProgressBar ? null : new ProgressBar ("Scanning journal " , lastSize );
124
129
while ((next = reader .nextEntry ()) != null ) {
125
130
// LOG.debug(next.dump());
126
- progress .set (next .getLsn ().getOffset ());
127
131
if (next .getLogType () == LogEntryTypes .TXN_START ) {
128
132
// new transaction starts: add it to the transactions table
129
133
txnsStarted .put (next .getTransactionId (), next );
@@ -135,6 +139,14 @@ public boolean recover() throws LogException {
135
139
lastCheckpoint = (Checkpoint ) next ;
136
140
}
137
141
lastLsn = next .getLsn ();
142
+
143
+ if (scanProgressBar != null ) {
144
+ scanProgressBar .set (next .getLsn ().getOffset ());
145
+ }
146
+ }
147
+
148
+ if (scanProgressBar != null ) {
149
+ scanProgressBar .set (lastSize ); // 100%
138
150
}
139
151
} catch (final LogException e ) {
140
152
if (LOG .isDebugEnabled ()) {
@@ -146,7 +158,7 @@ public boolean recover() throws LogException {
146
158
// if the last checkpoint record is not the last record in the file
147
159
// we need a recovery.
148
160
if ((lastCheckpoint == null || !lastCheckpoint .getLsn ().equals (lastLsn )) &&
149
- txnsStarted .size () > 0 ) {
161
+ ! txnsStarted .isEmpty () ) {
150
162
LOG .info ("Dirty transactions: {}" , txnsStarted .size ());
151
163
// starting recovery: reposition the log reader to the last checkpoint
152
164
if (lastCheckpoint == null ) {
@@ -250,10 +262,11 @@ private void doRecovery(final int txnCount, final Path last, final JournalReader
250
262
if (LOG .isInfoEnabled ())
251
263
{
252
264
LOG .info ("First pass: redoing {} transactions..." , txnCount );}
253
- final ProgressBar progress = new ProgressBar ("Redo " , FileUtils .sizeQuietly (last ));
254
265
Loggable next = null ;
255
266
int redoCnt = 0 ;
256
267
try {
268
+ final long lastSize = FileUtils .sizeQuietly (last );
269
+ @ Nullable final ProgressBar redoProgressBar = hideProgressBar ? null : new ProgressBar ("Redo " , lastSize );
257
270
while ((next = reader .nextEntry ()) != null ) {
258
271
SanityCheck .ASSERT (next .getLogType () != LogEntryTypes .CHECKPOINT ,
259
272
"Found a checkpoint during recovery run! This should not ever happen." );
@@ -271,9 +284,19 @@ private void doRecovery(final int txnCount, final Path last, final JournalReader
271
284
// LOG.debug("Redo: " + next.dump());
272
285
// redo the log entry
273
286
next .redo ();
274
- progress .set (next .getLsn ().getOffset ());
275
- if (next .getLsn ().equals (lastLsn ))
276
- {break ;} // last readable entry reached. Stop here.
287
+
288
+ if (redoProgressBar != null ) {
289
+ redoProgressBar .set (next .getLsn ().getOffset ());
290
+ }
291
+
292
+ if (next .getLsn ().equals (lastLsn )) {
293
+ // last readable entry reached. Stop here.
294
+ break ;
295
+ }
296
+ }
297
+
298
+ if (redoProgressBar != null ) {
299
+ redoProgressBar .set (lastSize ); // 100% done
277
300
}
278
301
} catch (final Exception e ) {
279
302
LOG .error ("Exception caught while redoing transactions. Aborting recovery to avoid possible damage. " +
@@ -291,16 +314,19 @@ private void doRecovery(final int txnCount, final Path last, final JournalReader
291
314
{
292
315
LOG .info ("Second pass: undoing dirty transactions. Uncommitted transactions: {}" , runningTxns .size ());}
293
316
// see if there are uncommitted transactions pending
294
- if (runningTxns .size () > 0 ) {
317
+ if (! runningTxns .isEmpty () ) {
295
318
// do a reverse scan of the log, undoing all uncommitted transactions
296
319
try {
297
- while ((next = reader .previousEntry ()) != null ) {
320
+ final long lastSize = FileUtils .sizeQuietly (last );
321
+ final ProgressBar undoProgressBar = hideProgressBar ? null : new ProgressBar ("Undo " , lastSize );
322
+ while ((next = reader .previousEntry ()) != null ) {
298
323
if (next .getLogType () == LogEntryTypes .TXN_START ) {
299
324
if (runningTxns .get (next .getTransactionId ()) != null ) {
300
325
runningTxns .remove (next .getTransactionId ());
301
- if (runningTxns .size () == 0 )
326
+ if (runningTxns .isEmpty ()) {
302
327
// all dirty transactions undone
303
- {break ;}
328
+ break ;
329
+ }
304
330
}
305
331
} else if (next .getLogType () == LogEntryTypes .TXN_COMMIT ) {
306
332
// ignore already committed transaction
@@ -314,6 +340,14 @@ private void doRecovery(final int txnCount, final Path last, final JournalReader
314
340
// LOG.debug("Undo: " + next.dump());
315
341
next .undo ();
316
342
}
343
+
344
+ if (undoProgressBar != null ) {
345
+ undoProgressBar .set (lastSize - next .getLsn ().getOffset ());
346
+ }
347
+ }
348
+
349
+ if (undoProgressBar != null ) {
350
+ undoProgressBar .set (lastSize ); // 100% done
317
351
}
318
352
} catch (final Exception e ) {
319
353
LOG .warn ("Exception caught while undoing dirty transactions. Remaining transactions to be undone: {}. Aborting recovery to avoid possible damage. Before starting again, make sure to run a check via the emergency export tool." , runningTxns .size (), e );
0 commit comments