@@ -101,6 +101,12 @@ public void testBrokenMVVs() throws Exception {
101101 final IntegrityCheck icheck = icheck ();
102102 icheck .checkTree (ex .getTree ());
103103 assertTrue (icheck .getFaults ().length > 0 );
104+ /*
105+ * A structurally corrupt MVV must not inflate the marked-version
106+ * counter: the leftover-mark scan runs only after visitAllVersions
107+ * has validated the record.
108+ */
109+ assertEquals (0 , icheck .getMarkedVersionCount ());
104110 }
105111
106112 /**
@@ -185,6 +191,34 @@ public void testPruneAndClearWithLeftoverMarkBits() throws Exception {
185191 assertFalse (output .toString (), output .toString ().contains ("PruneAndClear failed" ));
186192 }
187193
194+ /**
195+ * The -P gate must compare fault counts, not the MAX_FAULTS-capped fault
196+ * list: with more than MAX_FAULTS marked-version faults the list holds
197+ * only them, and a genuine fault found later (here a corrupt garbage
198+ * chain, checked after the trees) is not recorded in the list - it must
199+ * still block clearing the TransactionIndex.
200+ */
201+ @ Test
202+ public void testPruneAndClearBlockedByFaultBeyondFaultCap () throws Exception {
203+ final Exchange ex = _persistit .getExchange (_volumeName , "mvv" , true );
204+ disableBackgroundCleanup ();
205+ transactionalStore (ex );
206+ _persistit .getTransactionIndex ().updateActiveTransactionCache ();
207+
208+ assertTrue (corrupt5 (ex , 0 , IntegrityCheck .MAX_FAULTS + 1 )[0 ] > IntegrityCheck .MAX_FAULTS );
209+ corrupt4 (ex );
210+
211+ final IntegrityCheck icheck = (IntegrityCheck ) CLI .parseTask (_persistit , "icheck trees=* -u -P" );
212+ final StringWriter output = new StringWriter ();
213+ icheck .setMessageWriter (new PrintWriter (output ));
214+ icheck .setup (1 , "icheck" , "cli" , 0 , 5 );
215+ icheck .run ();
216+
217+ assertTrue (icheck .getMarkedVersionCount () > 0 );
218+ assertTrue (output .toString (), output .toString ().contains ("PruneAndClear failed" ));
219+ assertFalse (output .toString (), output .toString ().contains ("aborted transactions were cleared by pruning" ));
220+ }
221+
188222 @ Test
189223 public void testIndexFixHoles () throws Exception {
190224 final Exchange ex = _persistit .getExchange (_volumeName , "mvv" , true );
@@ -376,6 +410,7 @@ private interface MVVCorruption {
376410
377411 /**
378412 * Applies a corruption to the raw bytes of up to ten stored MVV values
413+ * following key 500
379414 *
380415 * @param ex
381416 * @param corruption
@@ -384,12 +419,29 @@ private interface MVVCorruption {
384419 * @throws PersistitException
385420 */
386421 private int [] corruptMVVs (final Exchange ex , final MVVCorruption corruption ) throws PersistitException {
422+ return corruptMVVs (ex , 500 , 10 , corruption );
423+ }
424+
425+ /**
426+ * Applies a corruption to the raw bytes of up to <code>limit</code>
427+ * stored MVV values following <code>startKey</code>
428+ *
429+ * @param ex
430+ * @param startKey
431+ * @param limit
432+ * @param corruption
433+ * @return the number of values corrupted and the summed corruption
434+ * contributions, as a two-element array
435+ * @throws PersistitException
436+ */
437+ private int [] corruptMVVs (final Exchange ex , final int startKey , final int limit , final MVVCorruption corruption )
438+ throws PersistitException {
387439 ex .ignoreMVCCFetch (true );
388440 try {
389- ex .clear ().to (key (500 ));
441+ ex .clear ().to (key (startKey ));
390442 int corrupted = 0 ;
391443 int total = 0 ;
392- while (corrupted < 10 && ex .next ()) {
444+ while (corrupted < limit && ex .next ()) {
393445 final byte [] bytes = ex .getValue ().getEncodedBytes ();
394446 final int length = ex .getValue ().getEncodedSize ();
395447 if (MVV .isArrayMVV (bytes , 0 , length )) {
@@ -460,7 +512,15 @@ private void corrupt4(final Exchange ex) throws PersistitException {
460512 * @throws PersistitException
461513 */
462514 private int [] corrupt5 (final Exchange ex ) throws PersistitException {
463- return corruptMVVs (ex , (bytes , length ) -> {
515+ return corrupt5 (ex , 500 , 10 );
516+ }
517+
518+ /**
519+ * Same as {@link #corrupt5(Exchange)} for up to <code>limit</code> values
520+ * following <code>startKey</code>
521+ */
522+ private int [] corrupt5 (final Exchange ex , final int startKey , final int limit ) throws PersistitException {
523+ return corruptMVVs (ex , startKey , limit , (bytes , length ) -> {
464524 int marked = 0 ;
465525 int from = 1 ;
466526 while (from + MVV .LENGTH_PER_VERSION <= length ) {
0 commit comments