@Test
  public void testDeleteMarkerVersioning() throws Exception {
    TableDescriptor htd = hbu.createTableDescriptor(TableName.valueOf(name.getMethodName()), 0, 1,
      HConstants.FOREVER, KeepDeletedCells.TRUE);
    HRegion region = hbu.createLocalHRegion(htd, null, null);

    long ts = EnvironmentEdgeManager.currentTime();
    Put p = new Put(T1, ts);
    p.addColumn(c0, c0, T1);
    region.put(p);

    // this prevents marker collection based on earliestPut
    // (cannot keep earliest put per column in the store file)
    p = new Put(T1, ts - 10);
    p.addColumn(c0, c1, T1);
    region.put(p);

    Delete d = new Delete(T1, ts);
    // test corner case (Put and Delete have same TS)
    d.addColumns(c0, c0, ts);
    region.delete(d);

    d = new Delete(T1, ts + 1);
    d.addColumn(c0, c0, ts + 1);
    region.delete(d);

    d = new Delete(T1, ts + 3);
    d.addColumn(c0, c0, ts + 3);
    region.delete(d);

    region.flush(true);
    region.compact(true);
    region.compact(true);
    assertEquals(3, countDeleteMarkers(region));

    // add two more puts, since max version is 1
    // the 2nd put (and all delete markers following)
    // will be removed.
    p = new Put(T1, ts + 2);
    p.addColumn(c0, c0, T2);
    region.put(p);

    // delete, put, delete, delete, put
    assertEquals(3, countDeleteMarkers(region));

    p = new Put(T1, ts + 3);
    p.addColumn(c0, c0, T3);
    region.put(p);

    // This is potentially questionable behavior.
    // This could be changed by not letting the ScanQueryMatcher
    // return SEEK_NEXT_COL if a put is past VERSIONS, but instead
    // return SKIP if the store has KEEP_DELETED_CELLS set.
    //
    // As it stands, the 1 here is correct here.
    // There are two puts, VERSIONS is one, so after the 1st put the scanner
    // knows that there can be no more KVs (put or delete) that have any effect.
    //
    // delete, put, put | delete, delete
    assertEquals(1, countDeleteMarkers(region));

    // flush cache only sees what is in the memstore
    region.flush(true);

    // Here we have the three markers again, because the flush above
    // removed the 2nd put before the file is written.
    // So there's only one put, and hence the deletes already in the store
    // files cannot be removed safely.
    // delete, put, delete, delete
    assertEquals(3, countDeleteMarkers(region));

    region.compact(true);
    assertEquals(3, countDeleteMarkers(region));

    // add one more put
    p = new Put(T1, ts + 4);
    p.addColumn(c0, c0, T4);
    region.put(p);

    region.flush(true);
    // one trailing delete marker remains (but only one)
    // because delete markers do not increase the version count
    assertEquals(1, countDeleteMarkers(region));
    region.compact(true);
    region.compact(true);
    assertEquals(1, countDeleteMarkers(region));

    HBaseTestingUtil.closeRegionAndWAL(region);
  }
Verify that column/version delete makers are sorted with their respective puts and removed
correctly by versioning (i.e. not relying on the store earliestPutTS).
hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestKeepDeletes.java