/**
  * Load data to a table, flush it to disk, trigger compaction, confirm the compaction state is
  * right and wait till it is done.
  *
  * @param tableName
  * @param flushes
  * @param expectedState
  * @param singleFamily otherwise, run compaction on all cfs
  * @throws IOException
  * @throws InterruptedException
  */
 private void compaction(
     final String tableName,
     final int flushes,
     final CompactionState expectedState,
     boolean singleFamily)
     throws IOException, InterruptedException {
   // Create a table with regions
   TableName table = TableName.valueOf(tableName);
   byte[] family = Bytes.toBytes("family");
   byte[][] families = {
     family, Bytes.add(family, Bytes.toBytes("2")), Bytes.add(family, Bytes.toBytes("3"))
   };
   Table ht = null;
   try {
     ht = TEST_UTIL.createTable(table, families);
     loadData(ht, families, 3000, flushes);
     HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
     List<HRegion> regions = rs.getOnlineRegions(table);
     int countBefore = countStoreFilesInFamilies(regions, families);
     int countBeforeSingleFamily = countStoreFilesInFamily(regions, family);
     assertTrue(countBefore > 0); // there should be some data files
     HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
     if (expectedState == CompactionState.MINOR) {
       if (singleFamily) {
         admin.compact(table.getName(), family);
       } else {
         admin.compact(table.getName());
       }
     } else {
       if (singleFamily) {
         admin.majorCompact(table.getName(), family);
       } else {
         admin.majorCompact(table.getName());
       }
     }
     long curt = System.currentTimeMillis();
     long waitTime = 5000;
     long endt = curt + waitTime;
     CompactionState state = admin.getCompactionState(table.getName());
     while (state == CompactionState.NONE && curt < endt) {
       Thread.sleep(10);
       state = admin.getCompactionState(table.getName());
       curt = System.currentTimeMillis();
     }
     // Now, should have the right compaction state,
     // otherwise, the compaction should have already been done
     if (expectedState != state) {
       for (HRegion region : regions) {
         state = region.getCompactionState();
         assertEquals(CompactionState.NONE, state);
       }
     } else {
       // Wait until the compaction is done
       state = admin.getCompactionState(table.getName());
       while (state != CompactionState.NONE && curt < endt) {
         Thread.sleep(10);
         state = admin.getCompactionState(table.getName());
       }
       // Now, compaction should be done.
       assertEquals(CompactionState.NONE, state);
     }
     int countAfter = countStoreFilesInFamilies(regions, families);
     int countAfterSingleFamily = countStoreFilesInFamily(regions, family);
     assertTrue(countAfter < countBefore);
     if (!singleFamily) {
       if (expectedState == CompactionState.MAJOR) assertTrue(families.length == countAfter);
       else assertTrue(families.length < countAfter);
     } else {
       int singleFamDiff = countBeforeSingleFamily - countAfterSingleFamily;
       // assert only change was to single column family
       assertTrue(singleFamDiff == (countBefore - countAfter));
       if (expectedState == CompactionState.MAJOR) {
         assertTrue(1 == countAfterSingleFamily);
       } else {
         assertTrue(1 < countAfterSingleFamily);
       }
     }
   } finally {
     if (ht != null) {
       TEST_UTIL.deleteTable(table);
     }
   }
 }