View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.regionserver.wal;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertNotEquals;
23  import static org.junit.Assert.assertNotNull;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.io.IOException;
28  import java.lang.reflect.Field;
29  import java.util.ArrayList;
30  import java.util.Comparator;
31  import java.util.List;
32  import java.util.Set;
33  import java.util.UUID;
34  import java.util.concurrent.CountDownLatch;
35  import java.util.concurrent.ExecutorService;
36  import java.util.concurrent.Executors;
37  import java.util.concurrent.atomic.AtomicBoolean;
38  
39  import org.apache.commons.lang.mutable.MutableBoolean;
40  import org.apache.commons.logging.Log;
41  import org.apache.commons.logging.LogFactory;
42  import org.apache.hadoop.conf.Configuration;
43  import org.apache.hadoop.fs.FileStatus;
44  import org.apache.hadoop.fs.FileSystem;
45  import org.apache.hadoop.fs.Path;
46  import org.apache.hadoop.hbase.CellScanner;
47  import org.apache.hadoop.hbase.Coprocessor;
48  import org.apache.hadoop.hbase.HBaseConfiguration;
49  import org.apache.hadoop.hbase.HBaseTestingUtility;
50  import org.apache.hadoop.hbase.HColumnDescriptor;
51  import org.apache.hadoop.hbase.HConstants;
52  import org.apache.hadoop.hbase.HRegionInfo;
53  import org.apache.hadoop.hbase.HTableDescriptor;
54  import org.apache.hadoop.hbase.KeyValue;
55  import org.apache.hadoop.hbase.TableName;
56  import org.apache.hadoop.hbase.client.Get;
57  import org.apache.hadoop.hbase.client.Put;
58  import org.apache.hadoop.hbase.client.Result;
59  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
60  import org.apache.hadoop.hbase.coprocessor.SampleRegionWALObserver;
61  import org.apache.hadoop.hbase.regionserver.HRegion;
62  import org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl;
63  import org.apache.hadoop.hbase.regionserver.Region;
64  import org.apache.hadoop.hbase.testclassification.MediumTests;
65  import org.apache.hadoop.hbase.util.Bytes;
66  import org.apache.hadoop.hbase.util.EnvironmentEdge;
67  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
68  import org.apache.hadoop.hbase.util.Threads;
69  import org.apache.hadoop.hbase.wal.DefaultWALProvider;
70  import org.apache.hadoop.hbase.wal.WAL;
71  import org.apache.hadoop.hbase.wal.WALKey;
72  import org.junit.After;
73  import org.junit.AfterClass;
74  import org.junit.Before;
75  import org.junit.BeforeClass;
76  import org.junit.Rule;
77  import org.junit.Test;
78  import org.junit.experimental.categories.Category;
79  import org.junit.rules.TestName;
80  
81  /**
82   * Provides FSHLog test cases.
83   */
84  @Category(MediumTests.class)
85  public class TestFSHLog {
86    private static final Log LOG = LogFactory.getLog(TestFSHLog.class);
87  
88    protected static Configuration conf;
89    protected static FileSystem fs;
90    protected static Path dir;
91    protected static Path rootDir;
92    protected static Path walRootDir;
93    protected final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
94  
95    @Rule
96    public final TestName currentTest = new TestName();
97  
98    @Before
99    public void setUp() throws Exception {
100     FileStatus[] entries = fs.listStatus(new Path("/"));
101     for (FileStatus dir : entries) {
102       fs.delete(dir.getPath(), true);
103     }
104     rootDir = TEST_UTIL.createRootDir();
105     walRootDir = TEST_UTIL.createWALRootDir();
106     dir = new Path(walRootDir, currentTest.getMethodName());
107     assertNotEquals(rootDir, walRootDir);
108   }
109 
110   @After
111   public void tearDown() throws Exception {
112   }
113 
114   @BeforeClass
115   public static void setUpBeforeClass() throws Exception {
116     // Make block sizes small.
117     TEST_UTIL.getConfiguration().setInt("dfs.blocksize", 1024 * 1024);
118     // quicker heartbeat interval for faster DN death notification
119     TEST_UTIL.getConfiguration().setInt("dfs.namenode.heartbeat.recheck-interval", 5000);
120     TEST_UTIL.getConfiguration().setInt("dfs.heartbeat.interval", 1);
121     TEST_UTIL.getConfiguration().setInt("dfs.client.socket-timeout", 5000);
122 
123     // faster failover with cluster.shutdown();fs.close() idiom
124     TEST_UTIL.getConfiguration()
125         .setInt("hbase.ipc.client.connect.max.retries", 1);
126     TEST_UTIL.getConfiguration().setInt(
127         "dfs.client.block.recovery.retries", 1);
128     TEST_UTIL.getConfiguration().setInt(
129       "hbase.ipc.client.connection.maxidletime", 500);
130     TEST_UTIL.getConfiguration().set(CoprocessorHost.WAL_COPROCESSOR_CONF_KEY,
131         SampleRegionWALObserver.class.getName());
132     TEST_UTIL.startMiniDFSCluster(3);
133 
134     conf = TEST_UTIL.getConfiguration();
135     fs = TEST_UTIL.getDFSCluster().getFileSystem();
136   }
137 
138   @AfterClass
139   public static void tearDownAfterClass() throws Exception {
140     fs.delete(rootDir, true);
141     fs.delete(walRootDir, true);
142     TEST_UTIL.shutdownMiniCluster();
143   }
144 
145   /**
146    * A loaded WAL coprocessor won't break existing WAL test cases.
147    */
148   @Test
149   public void testWALCoprocessorLoaded() throws Exception {
150     // test to see whether the coprocessor is loaded or not.
151     FSHLog log = null;
152     try {
153       log = new FSHLog(fs, walRootDir, dir.toString(),
154           HConstants.HREGION_OLDLOGDIR_NAME, conf, null, true, null, null);
155       WALCoprocessorHost host = log.getCoprocessorHost();
156       Coprocessor c = host.findCoprocessor(SampleRegionWALObserver.class.getName());
157       assertNotNull(c);
158     } finally {
159       if (log != null) {
160         log.close();
161       }
162     }
163   }
164 
165   protected void addEdits(WAL log,
166                           HRegionInfo hri,
167                           HTableDescriptor htd,
168                           int times,
169                           MultiVersionConcurrencyControl mvcc)
170       throws IOException {
171     final byte[] row = Bytes.toBytes("row");
172     for (int i = 0; i < times; i++) {
173       long timestamp = System.currentTimeMillis();
174       WALEdit cols = new WALEdit();
175       cols.add(new KeyValue(row, row, row, timestamp, row));
176       WALKey key = new WALKey(hri.getEncodedNameAsBytes(), htd.getTableName(),
177           WALKey.NO_SEQUENCE_ID, timestamp, WALKey.EMPTY_UUIDS, HConstants.NO_NONCE,
178           HConstants.NO_NONCE, mvcc);
179       log.append(htd, hri, key, cols, true);
180     }
181     log.sync();
182   }
183 
184   /**
185    * helper method to simulate region flush for a WAL.
186    * @param wal
187    * @param regionEncodedName
188    */
189   protected void flushRegion(WAL wal, byte[] regionEncodedName, Set<byte[]> flushedFamilyNames) {
190     wal.startCacheFlush(regionEncodedName, flushedFamilyNames);
191     wal.completeCacheFlush(regionEncodedName);
192   }
193 
194   /**
195    * tests the log comparator. Ensure that we are not mixing meta logs with non-meta logs (throws
196    * exception if we do). Comparison is based on the timestamp present in the wal name.
197    * @throws Exception
198    */
199   @Test 
200   public void testWALComparator() throws Exception {
201     FSHLog wal1 = null;
202     FSHLog walMeta = null;
203     try {
204       wal1 = new FSHLog(fs, walRootDir, dir.toString(),
205           HConstants.HREGION_OLDLOGDIR_NAME, conf, null, true, null, null);
206       LOG.debug("Log obtained is: " + wal1);
207       Comparator<Path> comp = wal1.LOG_NAME_COMPARATOR;
208       Path p1 = wal1.computeFilename(11);
209       Path p2 = wal1.computeFilename(12);
210       // comparing with itself returns 0
211       assertTrue(comp.compare(p1, p1) == 0);
212       // comparing with different filenum.
213       assertTrue(comp.compare(p1, p2) < 0);
214       walMeta = new FSHLog(fs, walRootDir, dir.toString(),
215           HConstants.HREGION_OLDLOGDIR_NAME, conf, null, true, null,
216           DefaultWALProvider.META_WAL_PROVIDER_ID);
217       Comparator<Path> compMeta = walMeta.LOG_NAME_COMPARATOR;
218 
219       Path p1WithMeta = walMeta.computeFilename(11);
220       Path p2WithMeta = walMeta.computeFilename(12);
221       assertTrue(compMeta.compare(p1WithMeta, p1WithMeta) == 0);
222       assertTrue(compMeta.compare(p1WithMeta, p2WithMeta) < 0);
223       // mixing meta and non-meta logs gives error
224       boolean ex = false;
225       try {
226         comp.compare(p1WithMeta, p2);
227       } catch (IllegalArgumentException e) {
228         ex = true;
229       }
230       assertTrue("Comparator doesn't complain while checking meta log files", ex);
231       boolean exMeta = false;
232       try {
233         compMeta.compare(p1WithMeta, p2);
234       } catch (IllegalArgumentException e) {
235         exMeta = true;
236       }
237       assertTrue("Meta comparator doesn't complain while checking log files", exMeta);
238     } finally {
239       if (wal1 != null) {
240         wal1.close();
241       }
242       if (walMeta != null) {
243         walMeta.close();
244       }
245     }
246   }
247 
248   /**
249    * On rolling a wal after reaching the threshold, {@link WAL#rollWriter()} returns the
250    * list of regions which should be flushed in order to archive the oldest wal file.
251    * <p>
252    * This method tests this behavior by inserting edits and rolling the wal enough times to reach
253    * the max number of logs threshold. It checks whether we get the "right regions" for flush on
254    * rolling the wal.
255    * @throws Exception
256    */
257   @Test 
258   public void testFindMemStoresEligibleForFlush() throws Exception {
259     LOG.debug("testFindMemStoresEligibleForFlush");
260     Configuration conf1 = HBaseConfiguration.create(conf);
261     conf1.setInt("hbase.regionserver.maxlogs", 1);
262     FSHLog wal = new FSHLog(fs, walRootDir, dir.toString(),
263         HConstants.HREGION_OLDLOGDIR_NAME, conf1, null, true, null, null);
264     HTableDescriptor t1 =
265         new HTableDescriptor(TableName.valueOf("t1")).addFamily(new HColumnDescriptor("row"));
266     HTableDescriptor t2 =
267         new HTableDescriptor(TableName.valueOf("t2")).addFamily(new HColumnDescriptor("row"));
268     HRegionInfo hri1 =
269         new HRegionInfo(t1.getTableName(), HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW);
270     HRegionInfo hri2 =
271         new HRegionInfo(t2.getTableName(), HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW);
272     // add edits and roll the wal
273     MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl();
274     try {
275       addEdits(wal, hri1, t1, 2, mvcc);
276       wal.rollWriter();
277       // add some more edits and roll the wal. This would reach the log number threshold
278       addEdits(wal, hri1, t1, 2, mvcc);
279       wal.rollWriter();
280       // with above rollWriter call, the max logs limit is reached.
281       assertTrue(wal.getNumRolledLogFiles() == 2);
282 
283       // get the regions to flush; since there is only one region in the oldest wal, it should
284       // return only one region.
285       byte[][] regionsToFlush = wal.findRegionsToForceFlush();
286       assertEquals(1, regionsToFlush.length);
287       assertTrue(Bytes.equals(hri1.getEncodedNameAsBytes(), regionsToFlush[0]));
288       // insert edits in second region
289       addEdits(wal, hri2, t2, 2, mvcc);
290       // get the regions to flush, it should still read region1.
291       regionsToFlush = wal.findRegionsToForceFlush();
292       assertEquals(regionsToFlush.length, 1);
293       assertTrue(Bytes.equals(hri1.getEncodedNameAsBytes(), regionsToFlush[0]));
294       // flush region 1, and roll the wal file. Only last wal which has entries for region1 should
295       // remain.
296       flushRegion(wal, hri1.getEncodedNameAsBytes(), t1.getFamiliesKeys());
297       wal.rollWriter();
298       // only one wal should remain now (that is for the second region).
299       assertEquals(1, wal.getNumRolledLogFiles());
300       // flush the second region
301       flushRegion(wal, hri2.getEncodedNameAsBytes(), t2.getFamiliesKeys());
302       wal.rollWriter(true);
303       // no wal should remain now.
304       assertEquals(0, wal.getNumRolledLogFiles());
305       // add edits both to region 1 and region 2, and roll.
306       addEdits(wal, hri1, t1, 2, mvcc);
307       addEdits(wal, hri2, t2, 2, mvcc);
308       wal.rollWriter();
309       // add edits and roll the writer, to reach the max logs limit.
310       assertEquals(1, wal.getNumRolledLogFiles());
311       addEdits(wal, hri1, t1, 2, mvcc);
312       wal.rollWriter();
313       // it should return two regions to flush, as the oldest wal file has entries
314       // for both regions.
315       regionsToFlush = wal.findRegionsToForceFlush();
316       assertEquals(2, regionsToFlush.length);
317       // flush both regions
318       flushRegion(wal, hri1.getEncodedNameAsBytes(), t1.getFamiliesKeys());
319       flushRegion(wal, hri2.getEncodedNameAsBytes(), t2.getFamiliesKeys());
320       wal.rollWriter(true);
321       assertEquals(0, wal.getNumRolledLogFiles());
322       // Add an edit to region1, and roll the wal.
323       addEdits(wal, hri1, t1, 2, mvcc);
324       // tests partial flush: roll on a partial flush, and ensure that wal is not archived.
325       wal.startCacheFlush(hri1.getEncodedNameAsBytes(), t1.getFamiliesKeys());
326       wal.rollWriter();
327       wal.completeCacheFlush(hri1.getEncodedNameAsBytes());
328       assertEquals(1, wal.getNumRolledLogFiles());
329     } finally {
330       if (wal != null) {
331         wal.close();
332       }
333     }
334   }
335 
336   @Test(expected=IOException.class)
337   public void testFailedToCreateWALIfParentRenamed() throws IOException {
338     final String name = "testFailedToCreateWALIfParentRenamed";
339     FSHLog log = new FSHLog(fs, walRootDir, name, HConstants.HREGION_OLDLOGDIR_NAME,
340         conf, null, true, null, null);
341     long filenum = System.currentTimeMillis();
342     Path path = log.computeFilename(filenum);
343     log.createWriterInstance(path);
344     Path parent = path.getParent();
345     path = log.computeFilename(filenum + 1);
346     Path newPath = new Path(parent.getParent(), parent.getName() + "-splitting");
347     fs.rename(parent, newPath);
348     log.createWriterInstance(path);
349     fail("It should fail to create the new WAL");
350   }
351 
352   /**
353    * Test flush for sure has a sequence id that is beyond the last edit appended.  We do this
354    * by slowing appends in the background ring buffer thread while in foreground we call
355    * flush.  The addition of the sync over HRegion in flush should fix an issue where flush was
356    * returning before all of its appends had made it out to the WAL (HBASE-11109).
357    * see HBASE-11109
358    * @throws IOException
359    */
360   @Test
361   public void testFlushSequenceIdIsGreaterThanAllEditsInHFile() throws IOException {
362     String testName = "testFlushSequenceIdIsGreaterThanAllEditsInHFile";
363     final TableName tableName = TableName.valueOf(testName);
364     final HRegionInfo hri = new HRegionInfo(tableName);
365     final byte[] rowName = tableName.getName();
366     final HTableDescriptor htd = new HTableDescriptor(tableName);
367     htd.addFamily(new HColumnDescriptor("f"));
368     HRegion r = HRegion.createHRegion(hri, rootDir,
369       TEST_UTIL.getConfiguration(), htd);
370     HRegion.closeHRegion(r);
371     final int countPerFamily = 10;
372     final MutableBoolean goslow = new MutableBoolean(false);
373     // subclass and doctor a method.
374     FSHLog wal = new FSHLog(FileSystem.get(conf), walRootDir,
375         testName, conf) {
376       @Override
377       void atHeadOfRingBufferEventHandlerAppend() {
378         if (goslow.isTrue()) {
379           Threads.sleep(100);
380           LOG.debug("Sleeping before appending 100ms");
381         }
382         super.atHeadOfRingBufferEventHandlerAppend();
383       }
384     };
385     HRegion region = HRegion.openHRegion(TEST_UTIL.getConfiguration(),
386       TEST_UTIL.getTestFileSystem(), rootDir, hri, htd, wal);
387     EnvironmentEdge ee = EnvironmentEdgeManager.getDelegate();
388     try {
389       List<Put> puts = null;
390       for (HColumnDescriptor hcd: htd.getFamilies()) {
391         puts =
392           TestWALReplay.addRegionEdits(rowName, hcd.getName(), countPerFamily, ee, region, "x");
393       }
394 
395       // Now assert edits made it in.
396       final Get g = new Get(rowName);
397       Result result = region.get(g);
398       assertEquals(countPerFamily * htd.getFamilies().size(), result.size());
399 
400       // Construct a WALEdit and add it a few times to the WAL.
401       WALEdit edits = new WALEdit();
402       for (Put p: puts) {
403         CellScanner cs = p.cellScanner();
404         while (cs.advance()) {
405           edits.add(cs.current());
406         }
407       }
408       // Add any old cluster id.
409       List<UUID> clusterIds = new ArrayList<UUID>();
410       clusterIds.add(UUID.randomUUID());
411       // Now make appends run slow.
412       goslow.setValue(true);
413       for (int i = 0; i < countPerFamily; i++) {
414         final HRegionInfo info = region.getRegionInfo();
415         final WALKey logkey = new WALKey(info.getEncodedNameAsBytes(), tableName,
416             System.currentTimeMillis(), clusterIds, -1, -1, region.getMVCC());
417         wal.append(htd, info, logkey, edits, true);
418         region.getMVCC().completeAndWait(logkey.getWriteEntry());
419       }
420       region.flush(true);
421       // FlushResult.flushSequenceId is not visible here so go get the current sequence id.
422       long currentSequenceId = region.getSequenceId();
423       // Now release the appends
424       goslow.setValue(false);
425       synchronized (goslow) {
426         goslow.notifyAll();
427       }
428       assertTrue(currentSequenceId >= region.getSequenceId());
429     } finally {
430       region.close(true);
431       wal.close();
432     }
433   }
434 
435   @Test
436   public void testSyncRunnerIndexOverflow() throws IOException, NoSuchFieldException,
437       SecurityException, IllegalArgumentException, IllegalAccessException {
438     final String name = "testSyncRunnerIndexOverflow";
439     FSHLog log =
440         new FSHLog(fs, walRootDir, name, HConstants.HREGION_OLDLOGDIR_NAME, conf,
441             null, true, null, null);
442     try {
443       Field ringBufferEventHandlerField = FSHLog.class.getDeclaredField("ringBufferEventHandler");
444       ringBufferEventHandlerField.setAccessible(true);
445       FSHLog.RingBufferEventHandler ringBufferEventHandler =
446           (FSHLog.RingBufferEventHandler) ringBufferEventHandlerField.get(log);
447       Field syncRunnerIndexField =
448           FSHLog.RingBufferEventHandler.class.getDeclaredField("syncRunnerIndex");
449       syncRunnerIndexField.setAccessible(true);
450       syncRunnerIndexField.set(ringBufferEventHandler, Integer.MAX_VALUE - 1);
451       HTableDescriptor htd =
452           new HTableDescriptor(TableName.valueOf("t1")).addFamily(new HColumnDescriptor("row"));
453       HRegionInfo hri =
454           new HRegionInfo(htd.getTableName(), HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW);
455       MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl();
456       for (int i = 0; i < 10; i++) {
457         addEdits(log, hri, htd, 1, mvcc);
458       }
459     } finally {
460       log.close();
461     }
462   }
463 
464   /**
465    * Test case for https://issues.apache.org/jira/browse/HBASE-16721
466    */
467   @Test (timeout = 30000)
468   public void testUnflushedSeqIdTracking() throws IOException, InterruptedException {
469     final String name = "testSyncRunnerIndexOverflow";
470     final byte[] b = Bytes.toBytes("b");
471 
472     final AtomicBoolean startHoldingForAppend = new AtomicBoolean(false);
473     final CountDownLatch holdAppend = new CountDownLatch(1);
474     final CountDownLatch flushFinished = new CountDownLatch(1);
475     final CountDownLatch putFinished = new CountDownLatch(1);
476 
477     try (FSHLog log =
478         new FSHLog(fs, walRootDir, name, HConstants.HREGION_OLDLOGDIR_NAME, conf,
479             null, true, null, null)) {
480 
481       log.registerWALActionsListener(new WALActionsListener.Base() {
482         @Override
483         public void visitLogEntryBeforeWrite(HTableDescriptor htd, WALKey logKey, WALEdit logEdit)
484             throws IOException {
485           if (startHoldingForAppend.get()) {
486             try {
487               holdAppend.await();
488             } catch (InterruptedException e) {
489               LOG.error(e);
490             }
491           }
492         }
493       });
494 
495       // open a new region which uses this WAL
496       HTableDescriptor htd =
497           new HTableDescriptor(TableName.valueOf("t1")).addFamily(new HColumnDescriptor(b));
498       HRegionInfo hri =
499           new HRegionInfo(htd.getTableName(), HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW);
500 
501       final HRegion region = TEST_UTIL.createLocalHRegion(hri, htd, log);
502       ExecutorService exec = Executors.newFixedThreadPool(2);
503 
504       // do a regular write first because of memstore size calculation.
505       region.put(new Put(b).addColumn(b, b,b));
506 
507       startHoldingForAppend.set(true);
508       exec.submit(new Runnable() {
509         @Override
510         public void run() {
511           try {
512             region.put(new Put(b).addColumn(b, b,b));
513             putFinished.countDown();
514           } catch (IOException e) {
515             LOG.error(e);
516           }
517         }
518       });
519 
520       // give the put a chance to start
521       Threads.sleep(3000);
522 
523       exec.submit(new Runnable() {
524         @Override
525         public void run() {
526           try {
527             Region.FlushResult flushResult = region.flush(true);
528             LOG.info("Flush result:" +  flushResult.getResult());
529             LOG.info("Flush succeeded:" +  flushResult.isFlushSucceeded());
530             flushFinished.countDown();
531           } catch (IOException e) {
532             LOG.error(e);
533           }
534         }
535       });
536 
537       // give the flush a chance to start. Flush should have got the region lock, and
538       // should have been waiting on the mvcc complete after this.
539       Threads.sleep(3000);
540 
541       // let the append to WAL go through now that the flush already started
542       holdAppend.countDown();
543       putFinished.await();
544       flushFinished.await();
545 
546       // check whether flush went through
547       assertEquals("Region did not flush?", 1, region.getStoreFileList(new byte[][]{b}).size());
548 
549       // now check the region's unflushed seqIds.
550       long seqId = log.getEarliestMemstoreSeqNum(hri.getEncodedNameAsBytes());
551       assertEquals("Found seqId for the region which is already flushed",
552           HConstants.NO_SEQNUM, seqId);
553 
554       region.close();
555     }
556   }
557 }