@@ -276,7 +276,7 @@ public Integer run() throws Exception {
276276 * log entry. Does its writing as an alternate user in another filesystem instance to simulate
277277 * better it being a regionserver.
278278 */
279- class ZombieLastLogWriterRegionServer extends Thread {
279+ private class ZombieLastLogWriterRegionServer extends Thread {
280280 final AtomicLong editsCount ;
281281 final AtomicBoolean stop ;
282282 final int numOfWriters ;
@@ -402,10 +402,6 @@ public void testOldRecoveredEditsFileSidelined() throws IOException {
402402
403403 private Path createRecoveredEditsPathForRegion () throws IOException {
404404 byte [] encoded = RegionInfoBuilder .FIRST_META_REGIONINFO .getEncodedNameAsBytes ();
405- long now = EnvironmentEdgeManager .currentTime ();
406- Entry entry = new Entry (
407- new WALKeyImpl (encoded , TableName .META_TABLE_NAME , 1 , now , HConstants .DEFAULT_CLUSTER_ID ),
408- new WALEdit ());
409405 Path p = WALSplitUtil .getRegionSplitEditsPath (TableName .META_TABLE_NAME , encoded , 1 ,
410406 FILENAME_BEING_SPLIT , TMPDIRNAME , conf );
411407 return p ;
@@ -491,10 +487,10 @@ public void testSplitLeavesCompactionEventsEdits() throws IOException {
491487 assertEquals (11 , countWAL (splitLog [0 ]));
492488 }
493489
494- /*
490+ /**
495491 * Tests that WalSplitter ignores replication marker edits.
496492 */
497- @ Test ( timeout = 30000 )
493+ @ Test
498494 public void testSplitRemovesReplicationMarkerEdits () throws IOException {
499495 RegionInfo regionInfo = ReplicationMarkerChore .REGION_INFO ;
500496 Path path = new Path (WALDIR , WAL_FILE_PREFIX + "1" );
@@ -1206,7 +1202,44 @@ public void testRecoveredEditsStoragePolicy() throws IOException {
12061202 } finally {
12071203 conf .unset (HConstants .WAL_STORAGE_POLICY );
12081204 }
1205+ }
1206+
1207+ /**
1208+ * See HBASE-27644, typically we should not have empty WALEdit but we should be able to process
1209+ * it, instead of losing data after it.
1210+ */
1211+ @ Test
1212+ public void testEmptyWALEdit () throws IOException {
1213+ final String region = "region__5" ;
1214+ REGIONS .clear ();
1215+ REGIONS .add (region );
1216+ makeRegionDirs (REGIONS );
1217+ fs .mkdirs (WALDIR );
1218+ Path path = new Path (WALDIR , WAL_FILE_PREFIX + 5 );
1219+ generateEmptyEditWAL (path , Bytes .toBytes (region ));
1220+ useDifferentDFSClient ();
1221+
1222+ Path regiondir = new Path (TABLEDIR , region );
1223+ fs .mkdirs (regiondir );
1224+ List <Path > splitPaths = WALSplitter .split (HBASELOGDIR , WALDIR , OLDLOGDIR , fs , conf , wals );
1225+ // Make sure that WALSplitter generate the split file
1226+ assertEquals (1 , splitPaths .size ());
1227+
1228+ Path originalLog = (fs .listStatus (OLDLOGDIR ))[0 ].getPath ();
1229+ assertEquals (11 , countWAL (originalLog ));
1230+ // we will skip the empty WAL when splitting
1231+ assertEquals (10 , countWAL (splitPaths .get (0 )));
1232+ }
12091233
1234+ private void generateEmptyEditWAL (Path path , byte [] region ) throws IOException {
1235+ fs .mkdirs (WALDIR );
1236+ try (Writer writer = wals .createWALWriter (fs , path )) {
1237+ long seq = 0 ;
1238+ appendEmptyEntry (writer , TABLE_NAME , region , seq ++);
1239+ for (int i = 0 ; i < 10 ; i ++) {
1240+ appendEntry (writer , TABLE_NAME , region , Bytes .toBytes (i ), FAMILY , QUALIFIER , VALUE , seq ++);
1241+ }
1242+ }
12101243 }
12111244
12121245 private Writer generateWALs (int leaveOpen ) throws IOException {
@@ -1399,7 +1432,7 @@ private static void appendRegionEvent(Writer w, String region) throws IOExceptio
13991432 w .sync (false );
14001433 }
14011434
1402- public static long appendEntry (Writer writer , TableName table , byte [] region , byte [] row ,
1435+ private static long appendEntry (Writer writer , TableName table , byte [] region , byte [] row ,
14031436 byte [] family , byte [] qualifier , byte [] value , long seq ) throws IOException {
14041437 LOG .info (Thread .currentThread ().getName () + " append" );
14051438 writer .append (createTestEntry (table , region , row , family , qualifier , value , seq ));
@@ -1412,13 +1445,27 @@ private static Entry createTestEntry(TableName table, byte[] region, byte[] row,
14121445 byte [] qualifier , byte [] value , long seq ) {
14131446 long time = System .nanoTime ();
14141447
1415- seq ++;
14161448 final KeyValue cell = new KeyValue (row , family , qualifier , time , KeyValue .Type .Put , value );
14171449 WALEdit edit = new WALEdit ();
14181450 edit .add (cell );
14191451 return new Entry (new WALKeyImpl (region , table , seq , time , HConstants .DEFAULT_CLUSTER_ID ), edit );
14201452 }
14211453
1454+ private static long appendEmptyEntry (Writer writer , TableName table , byte [] region , long seq )
1455+ throws IOException {
1456+ LOG .info (Thread .currentThread ().getName () + " append" );
1457+ writer .append (createEmptyEntry (table , region , seq ));
1458+ LOG .info (Thread .currentThread ().getName () + " sync" );
1459+ writer .sync (false );
1460+ return seq ;
1461+ }
1462+
1463+ private static Entry createEmptyEntry (TableName table , byte [] region , long seq ) {
1464+ long time = System .nanoTime ();
1465+ return new Entry (new WALKeyImpl (region , table , seq , time , HConstants .DEFAULT_CLUSTER_ID ),
1466+ new WALEdit ());
1467+ }
1468+
14221469 private void injectEmptyFile (String suffix , boolean closeFile ) throws IOException {
14231470 Writer writer =
14241471 WALFactory .createWALWriter (fs , new Path (WALDIR , WAL_FILE_PREFIX + suffix ), conf );
@@ -1428,22 +1475,19 @@ private void injectEmptyFile(String suffix, boolean closeFile) throws IOExceptio
14281475 }
14291476
14301477 private boolean logsAreEqual (Path p1 , Path p2 ) throws IOException {
1431- Reader in1 , in2 ;
1432- in1 = wals .createReader (fs , p1 );
1433- in2 = wals .createReader (fs , p2 );
1434- Entry entry1 ;
1435- Entry entry2 ;
1436- while ((entry1 = in1 .next ()) != null ) {
1437- entry2 = in2 .next ();
1438- if (
1439- (entry1 .getKey ().compareTo (entry2 .getKey ()) != 0 )
1440- || (!entry1 .getEdit ().toString ().equals (entry2 .getEdit ().toString ()))
1441- ) {
1442- return false ;
1478+ try (Reader in1 = wals .createReader (fs , p1 ); Reader in2 = wals .createReader (fs , p2 )) {
1479+ Entry entry1 ;
1480+ Entry entry2 ;
1481+ while ((entry1 = in1 .next ()) != null ) {
1482+ entry2 = in2 .next ();
1483+ if (
1484+ (entry1 .getKey ().compareTo (entry2 .getKey ()) != 0 )
1485+ || (!entry1 .getEdit ().toString ().equals (entry2 .getEdit ().toString ()))
1486+ ) {
1487+ return false ;
1488+ }
14431489 }
14441490 }
1445- in1 .close ();
1446- in2 .close ();
14471491 return true ;
14481492 }
14491493}
0 commit comments