private void testFindMemStoresEligibleForFlush(AbstractFSWAL<?> wal) throws IOException {
    String cf1 = "cf1";
    String cf2 = "cf2";
    String cf3 = "cf3";
    TableDescriptor t1 = TableDescriptorBuilder.newBuilder(TableName.valueOf("t1"))
      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf1)).build();
    TableDescriptor t2 = TableDescriptorBuilder.newBuilder(TableName.valueOf("t2"))
      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf1)).build();
    RegionInfo hri1 = RegionInfoBuilder.newBuilder(t1.getTableName()).build();
    RegionInfo hri2 = RegionInfoBuilder.newBuilder(t2.getTableName()).build();

    List<ColumnFamilyDescriptor> cfs = new ArrayList<>();
    cfs.add(ColumnFamilyDescriptorBuilder.of(cf1));
    cfs.add(ColumnFamilyDescriptorBuilder.of(cf2));
    TableDescriptor t3 =
      TableDescriptorBuilder.newBuilder(TableName.valueOf("t3")).setColumnFamilies(cfs).build();
    RegionInfo hri3 = RegionInfoBuilder.newBuilder(t3.getTableName()).build();

    // add edits and roll the wal
    MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl();
    NavigableMap<byte[], Integer> scopes1 = new TreeMap<>(Bytes.BYTES_COMPARATOR);
    for (byte[] fam : t1.getColumnFamilyNames()) {
      scopes1.put(fam, 0);
    }
    NavigableMap<byte[], Integer> scopes2 = new TreeMap<>(Bytes.BYTES_COMPARATOR);
    for (byte[] fam : t2.getColumnFamilyNames()) {
      scopes2.put(fam, 0);
    }
    NavigableMap<byte[], Integer> scopes3 = new TreeMap<>(Bytes.BYTES_COMPARATOR);
    for (byte[] fam : t3.getColumnFamilyNames()) {
      scopes3.put(fam, 0);
    }
    addEdits(wal, hri1, t1, 2, mvcc, scopes1, cf1);
    wal.rollWriter();
    // add some more edits and roll the wal. This would reach the log number threshold
    addEdits(wal, hri1, t1, 2, mvcc, scopes1, cf1);
    wal.rollWriter();
    // with above rollWriter call, the max logs limit is reached.
    waitNumRolledLogFiles(wal, 2);

    // get the regions to flush; since there is only one region in the oldest wal, it should
    // return only one region.
    Map<byte[], List<byte[]>> regionsToFlush = wal.findRegionsToForceFlush();
    assertEquals(1, regionsToFlush.size());
    assertEquals(hri1.getEncodedNameAsBytes(), (byte[]) regionsToFlush.keySet().toArray()[0]);
    // insert edits in second region
    addEdits(wal, hri2, t2, 2, mvcc, scopes2, cf1);
    // get the regions to flush, it should still read region1.
    regionsToFlush = wal.findRegionsToForceFlush();
    assertEquals(1, regionsToFlush.size());
    assertEquals(hri1.getEncodedNameAsBytes(), (byte[]) regionsToFlush.keySet().toArray()[0]);
    // flush region 1, and roll the wal file. Only last wal which has entries for region1 should
    // remain.
    flushRegion(wal, hri1.getEncodedNameAsBytes(), t1.getColumnFamilyNames());
    wal.rollWriter();
    // only one wal should remain now (that is for the second region).
    waitNumRolledLogFiles(wal, 1);
    // flush the second region
    flushRegion(wal, hri2.getEncodedNameAsBytes(), t2.getColumnFamilyNames());
    wal.rollWriter(true);
    // no wal should remain now.
    waitNumRolledLogFiles(wal, 0);
    // add edits both to region 1 and region 2, and roll.
    addEdits(wal, hri1, t1, 2, mvcc, scopes1, cf1);
    addEdits(wal, hri2, t2, 2, mvcc, scopes2, cf1);
    wal.rollWriter();
    // add edits and roll the writer, to reach the max logs limit.
    waitNumRolledLogFiles(wal, 1);
    addEdits(wal, hri1, t1, 2, mvcc, scopes1, cf1);
    wal.rollWriter();
    // it should return two regions to flush, as the oldest wal file has entries
    // for both regions.
    regionsToFlush = wal.findRegionsToForceFlush();
    assertEquals(2, regionsToFlush.size());
    // flush both regions
    flushRegion(wal, hri1.getEncodedNameAsBytes(), t1.getColumnFamilyNames());
    flushRegion(wal, hri2.getEncodedNameAsBytes(), t2.getColumnFamilyNames());
    wal.rollWriter(true);
    waitNumRolledLogFiles(wal, 0);
    // Add an edit to region1, and roll the wal.
    addEdits(wal, hri1, t1, 2, mvcc, scopes1, cf1);
    // tests partial flush: roll on a partial flush, and ensure that wal is not archived.
    wal.startCacheFlush(hri1.getEncodedNameAsBytes(), t1.getColumnFamilyNames());
    wal.rollWriter();
    wal.completeCacheFlush(hri1.getEncodedNameAsBytes(), HConstants.NO_SEQNUM);
    waitNumRolledLogFiles(wal, 1);

    // clear test data
    flushRegion(wal, hri1.getEncodedNameAsBytes(), t1.getColumnFamilyNames());
    wal.rollWriter(true);
    // add edits for three familes
    addEdits(wal, hri3, t3, 2, mvcc, scopes3, cf1);
    addEdits(wal, hri3, t3, 2, mvcc, scopes3, cf2);
    addEdits(wal, hri3, t3, 2, mvcc, scopes3, cf3);
    wal.rollWriter();
    addEdits(wal, hri3, t3, 2, mvcc, scopes3, cf1);
    wal.rollWriter();
    waitNumRolledLogFiles(wal, 2);
    // flush one family before archive oldest wal
    Set<byte[]> flushedFamilyNames = new HashSet<>();
    flushedFamilyNames.add(Bytes.toBytes(cf1));
    flushRegion(wal, hri3.getEncodedNameAsBytes(), flushedFamilyNames);
    regionsToFlush = wal.findRegionsToForceFlush();
    // then only two family need to be flushed when archive oldest wal
    assertEquals(1, regionsToFlush.size());
    assertEquals(hri3.getEncodedNameAsBytes(), (byte[]) regionsToFlush.keySet().toArray()[0]);
    assertEquals(2, regionsToFlush.get(hri3.getEncodedNameAsBytes()).size());
  }
tests the log comparator. Ensure that we are not mixing meta logs with non-meta logs (throws
exception if we do). Comparison is based on the timestamp present in the wal name.
hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/wal/AbstractTestFSWAL.java