@@ -297,6 +297,52 @@ private JournalChannel writeV4Journal(File journalDir, int numEntries, byte[] ma
297297 return jc ;
298298 }
299299
300+ private JournalChannel writeV4JournalWithInvalidRecord (File journalDir ,
301+ int numEntries , byte [] masterKey ) throws Exception {
302+ long logId = System .currentTimeMillis ();
303+ JournalChannel jc = new JournalChannel (journalDir , logId );
304+
305+ moveToPosition (jc , JournalChannel .VERSION_HEADER_SIZE );
306+
307+ BufferedChannel bc = jc .getBufferedChannel ();
308+
309+ byte [] data = new byte [1024 ];
310+ Arrays .fill (data , (byte ) 'X' );
311+ long lastConfirmed = LedgerHandle .INVALID_ENTRY_ID ;
312+ for (int i = 0 ; i <= numEntries ; i ++) {
313+ ByteBuf packet ;
314+ if (i == 0 ) {
315+ packet = generateMetaEntry (1 , masterKey );
316+ } else {
317+ packet = ClientUtil .generatePacket (1 , i , lastConfirmed , i * data .length , data );
318+ }
319+ lastConfirmed = i ;
320+ ByteBuffer lenBuff = ByteBuffer .allocate (4 );
321+ if (i == numEntries - 1 ) {
322+ //mock when flush data to file ,it writes an invalid entry to journal
323+ lenBuff .putInt (-1 );
324+ } else {
325+ lenBuff .putInt (packet .readableBytes ());
326+ }
327+ lenBuff .flip ();
328+ bc .write (Unpooled .wrappedBuffer (lenBuff ));
329+ bc .write (packet );
330+ packet .release ();
331+ }
332+
333+ // write fence key
334+ ByteBuf packet = generateFenceEntry (1 );
335+ ByteBuf lenBuf = Unpooled .buffer ();
336+ lenBuf .writeInt (packet .readableBytes ());
337+ //mock
338+ bc .write (lenBuf );
339+ bc .write (packet );
340+ bc .flushAndForceWrite (false );
341+ updateJournalVersion (jc , JournalChannel .V4 );
342+
343+ return jc ;
344+ }
345+
300346 static JournalChannel writeV5Journal (File journalDir , int numEntries ,
301347 byte [] masterKey ) throws Exception {
302348 return writeV5Journal (journalDir , numEntries , masterKey , false );
@@ -838,7 +884,7 @@ public void testJournalScanIOException() throws Exception {
838884 assertEquals (journalIds .size (), 1 );
839885
840886 try {
841- journal .scanJournal (journalIds .get (0 ), Long .MAX_VALUE , journalScanner );
887+ journal .scanJournal (journalIds .get (0 ), Long .MAX_VALUE , journalScanner , false );
842888 fail ("Should not have been able to scan the journal" );
843889 } catch (Exception e ) {
844890 // Expected
@@ -848,7 +894,74 @@ public void testJournalScanIOException() throws Exception {
848894 b .shutdown ();
849895 }
850896
851- private class DummyJournalScan implements Journal .JournalScanner {
897+ /**
898+ * Test for invalid record data during read of Journal.
899+ */
900+ @ Test
901+ public void testJournalScanInvalidRecordWithSkipFlag () throws Exception {
902+ File journalDir = createTempDir ("bookie" , "journal" );
903+ Bookie .checkDirectoryStructure (Bookie .getCurrentDirectory (journalDir ));
904+
905+ File ledgerDir = createTempDir ("bookie" , "ledger" );
906+ Bookie .checkDirectoryStructure (Bookie .getCurrentDirectory (ledgerDir ));
907+
908+ try {
909+ writeV4JournalWithInvalidRecord (Bookie .getCurrentDirectory (journalDir ),
910+ 100 , "testPasswd" .getBytes ());
911+ } catch (Exception e ) {
912+ fail ();
913+ }
914+
915+
916+ ServerConfiguration conf = TestBKConfiguration .newServerConfiguration ();
917+ // Disabled skip broken journal files by default
918+ conf .setJournalDirName (journalDir .getPath ())
919+ .setLedgerDirNames (new String [] { ledgerDir .getPath () })
920+ .setMetadataServiceUri (null )
921+ .setSkipReplayJournalInvalidRecord (true );
922+
923+ Journal .JournalScanner journalScanner = new DummyJournalScan ();
924+
925+ Bookie b = new Bookie (conf );
926+
927+ for (Journal journal : b .journals ) {
928+ List <Long > journalIds = Journal .listJournalIds (journal .getJournalDirectory (), null );
929+ assertEquals (journalIds .size (), 1 );
930+ try {
931+ journal .scanJournal (journalIds .get (0 ), 0 , journalScanner , conf .isSkipReplayJournalInvalidRecord ());
932+ } catch (Exception e ) {
933+ fail ("Should pass the journal scanning because we enabled skip flag by default." );
934+ }
935+ }
936+
937+ b .shutdown ();
938+
939+ // Disabled skip broken journal files by default
940+ conf = TestBKConfiguration .newServerConfiguration ();
941+ conf .setJournalDirName (journalDir .getPath ())
942+ .setLedgerDirNames (new String [] { ledgerDir .getPath () })
943+ .setMetadataServiceUri (null );
944+
945+ journalScanner = new DummyJournalScan ();
946+
947+ b = new Bookie (conf );
948+
949+ for (Journal journal : b .journals ) {
950+ List <Long > journalIds = Journal .listJournalIds (journal .getJournalDirectory (), null );
951+ assertEquals (journalIds .size (), 1 );
952+ try {
953+ journal .scanJournal (journalIds .get (0 ), 0 , journalScanner , conf .isSkipReplayJournalInvalidRecord ());
954+ fail ("Should fail the journal scanning because of disabled skip flag" );
955+ } catch (Exception e ) {
956+ // expected.
957+ }
958+ }
959+
960+ b .shutdown ();
961+ }
962+
963+
964+ static class DummyJournalScan implements Journal .JournalScanner {
852965
853966 @ Override
854967 public void process (int journalVersion , long offset , ByteBuffer entry ) throws IOException {
0 commit comments