You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by te...@apache.org on 2013/07/08 16:52:00 UTC

svn commit: r1500780 - in /hbase/trunk: hbase-client/src/main/java/org/apache/hadoop/hbase/client/ hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ hbase-common/src/main/java/org/apache/hadoop/hbase/ hbase-protocol/src/main/java/org/apache/...

Author: tedyu
Date: Mon Jul  8 14:52:00 2013
New Revision: 1500780

URL: http://svn.apache.org/r1500780
Log:
HBASE-8753 Provide new delete flag which can delete all cells under a column-family which have designated timestamp (Honghua)


Modified:
    hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Delete.java
    hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java
    hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java
    hbase/trunk/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java
    hbase/trunk/hbase-protocol/src/main/protobuf/Client.proto
    hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/DeleteTracker.java
    hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ScanDeleteTracker.java
    hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java
    hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java
    hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java
    hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
    hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestScanDeleteTracker.java

Modified: hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Delete.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Delete.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Delete.java (original)
+++ hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Delete.java Mon Jul  8 14:52:00 2013
@@ -212,6 +212,25 @@ public class Delete extends Mutation imp
   }
 
   /**
+   * Delete all columns of the specified family with a timestamp equal to
+   * the specified timestamp.
+   * @param family family name
+   * @param timestamp version timestamp
+   * @return this for invocation chaining
+   */
+  public Delete deleteFamilyVersion(byte [] family, long timestamp) {
+    List<? extends Cell> list = familyMap.get(family);
+    if(list == null) {
+      list = new ArrayList<Cell>();
+    }
+    ((List<KeyValue>)list).add(new KeyValue(row, family, null, timestamp,
+          KeyValue.Type.DeleteFamilyVersion));
+    familyMap.put(family, list);
+    return this;
+  }
+
+
+  /**
    * Delete all versions of the specified column.
    * @param family family name
    * @param qualifier column qualifier

Modified: hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java (original)
+++ hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java Mon Jul  8 14:52:00 2013
@@ -548,6 +548,8 @@ public final class ProtobufUtil {
             delete.deleteColumn(family, qualifier, ts);
           } else if (deleteType == DeleteType.DELETE_MULTIPLE_VERSIONS) {
             delete.deleteColumns(family, qualifier, ts);
+          } else if (deleteType == DeleteType.DELETE_FAMILY_VERSION) {
+            delete.deleteFamilyVersion(family, ts);
           } else {
             delete.deleteFamily(family, ts);
           }
@@ -1187,7 +1189,9 @@ public final class ProtobufUtil {
       return DeleteType.DELETE_MULTIPLE_VERSIONS;
     case DeleteFamily:
       return DeleteType.DELETE_FAMILY;
-      default:
+    case DeleteFamilyVersion:
+      return DeleteType.DELETE_FAMILY_VERSION;
+    default:
         throw new IOException("Unknown delete type: " + type);
     }
   }

Modified: hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java (original)
+++ hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java Mon Jul  8 14:52:00 2013
@@ -205,6 +205,7 @@ public class KeyValue implements Cell, H
     Put((byte)4),
 
     Delete((byte)8),
+    DeleteFamilyVersion((byte)10),
     DeleteColumn((byte)12),
     DeleteFamily((byte)14),
 
@@ -1372,6 +1373,13 @@ public class KeyValue implements Cell, H
   }
 
   /**
+   * @return True if this KV is a delete family-version type.
+   */
+  public boolean isDeleteFamilyVersion() {
+    return getType() == Type.DeleteFamilyVersion.getCode();
+  }
+
+  /**
    *
    * @return True if this KV is a delete family or column type.
    */

Modified: hbase/trunk/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java (original)
+++ hbase/trunk/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java Mon Jul  8 14:52:00 2013
@@ -6600,11 +6600,13 @@ public final class ClientProtos {
       DELETE_ONE_VERSION(0, 0),
       DELETE_MULTIPLE_VERSIONS(1, 1),
       DELETE_FAMILY(2, 2),
+      DELETE_FAMILY_VERSION(3, 3),
       ;
       
       public static final int DELETE_ONE_VERSION_VALUE = 0;
       public static final int DELETE_MULTIPLE_VERSIONS_VALUE = 1;
       public static final int DELETE_FAMILY_VALUE = 2;
+      public static final int DELETE_FAMILY_VERSION_VALUE = 3;
       
       
       public final int getNumber() { return value; }
@@ -6614,6 +6616,7 @@ public final class ClientProtos {
           case 0: return DELETE_ONE_VERSION;
           case 1: return DELETE_MULTIPLE_VERSIONS;
           case 2: return DELETE_FAMILY;
+          case 3: return DELETE_FAMILY_VERSION;
           default: return null;
         }
       }
@@ -6644,7 +6647,7 @@ public final class ClientProtos {
       }
       
       private static final DeleteType[] VALUES = {
-        DELETE_ONE_VERSION, DELETE_MULTIPLE_VERSIONS, DELETE_FAMILY, 
+        DELETE_ONE_VERSION, DELETE_MULTIPLE_VERSIONS, DELETE_FAMILY, DELETE_FAMILY_VERSION, 
       };
       
       public static DeleteType valueOf(
@@ -21576,7 +21579,7 @@ public final class ClientProtos {
       "\177\n\tCondition\022\013\n\003row\030\001 \002(\014\022\016\n\006family\030\002 \002(",
       "\014\022\021\n\tqualifier\030\003 \002(\014\022!\n\013compareType\030\004 \002(" +
       "\0162\014.CompareType\022\037\n\ncomparator\030\005 \002(\0132\013.Co" +
-      "mparator\"\365\005\n\rMutationProto\022\013\n\003row\030\001 \001(\014\022" +
+      "mparator\"\220\006\n\rMutationProto\022\013\n\003row\030\001 \001(\014\022" +
       "/\n\nmutateType\030\002 \001(\0162\033.MutationProto.Muta" +
       "tionType\022/\n\013columnValue\030\003 \003(\0132\032.Mutation" +
       "Proto.ColumnValue\022\021\n\ttimestamp\030\004 \001(\004\022!\n\t" +
@@ -21593,61 +21596,61 @@ public final class ClientProtos {
       "\014\n\010SKIP_WAL\020\001\022\r\n\tASYNC_WAL\020\002\022\014\n\010SYNC_WAL" +
       "\020\003\022\r\n\tFSYNC_WAL\020\004\">\n\014MutationType\022\n\n\006APP" +
       "END\020\000\022\r\n\tINCREMENT\020\001\022\007\n\003PUT\020\002\022\n\n\006DELETE\020" +
-      "\003\"U\n\nDeleteType\022\026\n\022DELETE_ONE_VERSION\020\000\022",
+      "\003\"p\n\nDeleteType\022\026\n\022DELETE_ONE_VERSION\020\000\022",
       "\034\n\030DELETE_MULTIPLE_VERSIONS\020\001\022\021\n\rDELETE_" +
-      "FAMILY\020\002\"r\n\rMutateRequest\022 \n\006region\030\001 \002(" +
-      "\0132\020.RegionSpecifier\022 \n\010mutation\030\002 \002(\0132\016." +
-      "MutationProto\022\035\n\tcondition\030\003 \001(\0132\n.Condi" +
-      "tion\"<\n\016MutateResponse\022\027\n\006result\030\001 \001(\0132\007" +
-      ".Result\022\021\n\tprocessed\030\002 \001(\010\"\362\002\n\004Scan\022\027\n\006c" +
-      "olumn\030\001 \003(\0132\007.Column\022!\n\tattribute\030\002 \003(\0132" +
-      "\016.NameBytesPair\022\020\n\010startRow\030\003 \001(\014\022\017\n\007sto" +
-      "pRow\030\004 \001(\014\022\027\n\006filter\030\005 \001(\0132\007.Filter\022\035\n\tt" +
-      "imeRange\030\006 \001(\0132\n.TimeRange\022\026\n\013maxVersion",
-      "s\030\007 \001(\r:\0011\022\031\n\013cacheBlocks\030\010 \001(\010:\004true\022\021\n" +
-      "\tbatchSize\030\t \001(\r\022\025\n\rmaxResultSize\030\n \001(\004\022" +
-      "\022\n\nstoreLimit\030\013 \001(\r\022\023\n\013storeOffset\030\014 \001(\r" +
-      "\022\"\n\032loadColumnFamiliesOnDemand\030\r \001(\010\022\024\n\014" +
-      "cachingCount\030\016 \001(\r\022\023\n\013prefetching\030\017 \001(\010\"" +
-      "\230\001\n\013ScanRequest\022 \n\006region\030\001 \001(\0132\020.Region" +
-      "Specifier\022\023\n\004scan\030\002 \001(\0132\005.Scan\022\021\n\tscanne" +
-      "rId\030\003 \001(\004\022\024\n\014numberOfRows\030\004 \001(\r\022\024\n\014close" +
-      "Scanner\030\005 \001(\010\022\023\n\013nextCallSeq\030\006 \001(\004\"l\n\014Sc" +
-      "anResponse\022\'\n\016resultCellMeta\030\001 \001(\0132\017.Res",
-      "ultCellMeta\022\021\n\tscannerId\030\002 \001(\004\022\023\n\013moreRe" +
-      "sults\030\003 \001(\010\022\013\n\003ttl\030\004 \001(\r\"%\n\016ResultCellMe" +
-      "ta\022\023\n\013cellsLength\030\001 \003(\r\"\260\001\n\024BulkLoadHFil" +
-      "eRequest\022 \n\006region\030\001 \002(\0132\020.RegionSpecifi" +
-      "er\0224\n\nfamilyPath\030\002 \003(\0132 .BulkLoadHFileRe" +
-      "quest.FamilyPath\022\024\n\014assignSeqNum\030\003 \001(\010\032*" +
-      "\n\nFamilyPath\022\016\n\006family\030\001 \002(\014\022\014\n\004path\030\002 \002" +
-      "(\t\"\'\n\025BulkLoadHFileResponse\022\016\n\006loaded\030\001 " +
-      "\002(\010\"_\n\026CoprocessorServiceCall\022\013\n\003row\030\001 \002" +
-      "(\014\022\023\n\013serviceName\030\002 \002(\t\022\022\n\nmethodName\030\003 ",
-      "\002(\t\022\017\n\007request\030\004 \002(\014\"d\n\031CoprocessorServi" +
-      "ceRequest\022 \n\006region\030\001 \002(\0132\020.RegionSpecif" +
-      "ier\022%\n\004call\030\002 \002(\0132\027.CoprocessorServiceCa" +
-      "ll\"]\n\032CoprocessorServiceResponse\022 \n\006regi" +
-      "on\030\001 \002(\0132\020.RegionSpecifier\022\035\n\005value\030\002 \002(" +
-      "\0132\016.NameBytesPair\"B\n\013MultiAction\022 \n\010muta" +
-      "tion\030\001 \001(\0132\016.MutationProto\022\021\n\003get\030\002 \001(\0132" +
-      "\004.Get\"I\n\014ActionResult\022\026\n\005value\030\001 \001(\0132\007.R" +
-      "esult\022!\n\texception\030\002 \001(\0132\016.NameBytesPair" +
-      "\"^\n\014MultiRequest\022 \n\006region\030\001 \002(\0132\020.Regio",
-      "nSpecifier\022\034\n\006action\030\002 \003(\0132\014.MultiAction" +
-      "\022\016\n\006atomic\030\003 \001(\010\".\n\rMultiResponse\022\035\n\006res" +
-      "ult\030\001 \003(\0132\r.ActionResult2\342\002\n\rClientServi" +
-      "ce\022 \n\003get\022\013.GetRequest\032\014.GetResponse\022/\n\010" +
-      "multiGet\022\020.MultiGetRequest\032\021.MultiGetRes" +
-      "ponse\022)\n\006mutate\022\016.MutateRequest\032\017.Mutate" +
-      "Response\022#\n\004scan\022\014.ScanRequest\032\r.ScanRes" +
-      "ponse\022>\n\rbulkLoadHFile\022\025.BulkLoadHFileRe" +
-      "quest\032\026.BulkLoadHFileResponse\022F\n\013execSer" +
-      "vice\022\032.CoprocessorServiceRequest\032\033.Copro",
-      "cessorServiceResponse\022&\n\005multi\022\r.MultiRe" +
-      "quest\032\016.MultiResponseBB\n*org.apache.hado" +
-      "op.hbase.protobuf.generatedB\014ClientProto" +
-      "sH\001\210\001\001\240\001\001"
+      "FAMILY\020\002\022\031\n\025DELETE_FAMILY_VERSION\020\003\"r\n\rM" +
+      "utateRequest\022 \n\006region\030\001 \002(\0132\020.RegionSpe" +
+      "cifier\022 \n\010mutation\030\002 \002(\0132\016.MutationProto" +
+      "\022\035\n\tcondition\030\003 \001(\0132\n.Condition\"<\n\016Mutat" +
+      "eResponse\022\027\n\006result\030\001 \001(\0132\007.Result\022\021\n\tpr" +
+      "ocessed\030\002 \001(\010\"\362\002\n\004Scan\022\027\n\006column\030\001 \003(\0132\007" +
+      ".Column\022!\n\tattribute\030\002 \003(\0132\016.NameBytesPa" +
+      "ir\022\020\n\010startRow\030\003 \001(\014\022\017\n\007stopRow\030\004 \001(\014\022\027\n" +
+      "\006filter\030\005 \001(\0132\007.Filter\022\035\n\ttimeRange\030\006 \001(",
+      "\0132\n.TimeRange\022\026\n\013maxVersions\030\007 \001(\r:\0011\022\031\n" +
+      "\013cacheBlocks\030\010 \001(\010:\004true\022\021\n\tbatchSize\030\t " +
+      "\001(\r\022\025\n\rmaxResultSize\030\n \001(\004\022\022\n\nstoreLimit" +
+      "\030\013 \001(\r\022\023\n\013storeOffset\030\014 \001(\r\022\"\n\032loadColum" +
+      "nFamiliesOnDemand\030\r \001(\010\022\024\n\014cachingCount\030" +
+      "\016 \001(\r\022\023\n\013prefetching\030\017 \001(\010\"\230\001\n\013ScanReque" +
+      "st\022 \n\006region\030\001 \001(\0132\020.RegionSpecifier\022\023\n\004" +
+      "scan\030\002 \001(\0132\005.Scan\022\021\n\tscannerId\030\003 \001(\004\022\024\n\014" +
+      "numberOfRows\030\004 \001(\r\022\024\n\014closeScanner\030\005 \001(\010" +
+      "\022\023\n\013nextCallSeq\030\006 \001(\004\"l\n\014ScanResponse\022\'\n",
+      "\016resultCellMeta\030\001 \001(\0132\017.ResultCellMeta\022\021" +
+      "\n\tscannerId\030\002 \001(\004\022\023\n\013moreResults\030\003 \001(\010\022\013" +
+      "\n\003ttl\030\004 \001(\r\"%\n\016ResultCellMeta\022\023\n\013cellsLe" +
+      "ngth\030\001 \003(\r\"\260\001\n\024BulkLoadHFileRequest\022 \n\006r" +
+      "egion\030\001 \002(\0132\020.RegionSpecifier\0224\n\nfamilyP" +
+      "ath\030\002 \003(\0132 .BulkLoadHFileRequest.FamilyP" +
+      "ath\022\024\n\014assignSeqNum\030\003 \001(\010\032*\n\nFamilyPath\022" +
+      "\016\n\006family\030\001 \002(\014\022\014\n\004path\030\002 \002(\t\"\'\n\025BulkLoa" +
+      "dHFileResponse\022\016\n\006loaded\030\001 \002(\010\"_\n\026Coproc" +
+      "essorServiceCall\022\013\n\003row\030\001 \002(\014\022\023\n\013service",
+      "Name\030\002 \002(\t\022\022\n\nmethodName\030\003 \002(\t\022\017\n\007reques" +
+      "t\030\004 \002(\014\"d\n\031CoprocessorServiceRequest\022 \n\006" +
+      "region\030\001 \002(\0132\020.RegionSpecifier\022%\n\004call\030\002" +
+      " \002(\0132\027.CoprocessorServiceCall\"]\n\032Coproce" +
+      "ssorServiceResponse\022 \n\006region\030\001 \002(\0132\020.Re" +
+      "gionSpecifier\022\035\n\005value\030\002 \002(\0132\016.NameBytes" +
+      "Pair\"B\n\013MultiAction\022 \n\010mutation\030\001 \001(\0132\016." +
+      "MutationProto\022\021\n\003get\030\002 \001(\0132\004.Get\"I\n\014Acti" +
+      "onResult\022\026\n\005value\030\001 \001(\0132\007.Result\022!\n\texce" +
+      "ption\030\002 \001(\0132\016.NameBytesPair\"^\n\014MultiRequ",
+      "est\022 \n\006region\030\001 \002(\0132\020.RegionSpecifier\022\034\n" +
+      "\006action\030\002 \003(\0132\014.MultiAction\022\016\n\006atomic\030\003 " +
+      "\001(\010\".\n\rMultiResponse\022\035\n\006result\030\001 \003(\0132\r.A" +
+      "ctionResult2\342\002\n\rClientService\022 \n\003get\022\013.G" +
+      "etRequest\032\014.GetResponse\022/\n\010multiGet\022\020.Mu" +
+      "ltiGetRequest\032\021.MultiGetResponse\022)\n\006muta" +
+      "te\022\016.MutateRequest\032\017.MutateResponse\022#\n\004s" +
+      "can\022\014.ScanRequest\032\r.ScanResponse\022>\n\rbulk" +
+      "LoadHFile\022\025.BulkLoadHFileRequest\032\026.BulkL" +
+      "oadHFileResponse\022F\n\013execService\022\032.Coproc",
+      "essorServiceRequest\032\033.CoprocessorService" +
+      "Response\022&\n\005multi\022\r.MultiRequest\032\016.Multi" +
+      "ResponseBB\n*org.apache.hadoop.hbase.prot" +
+      "obuf.generatedB\014ClientProtosH\001\210\001\001\240\001\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {

Modified: hbase/trunk/hbase-protocol/src/main/protobuf/Client.proto
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-protocol/src/main/protobuf/Client.proto?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-protocol/src/main/protobuf/Client.proto (original)
+++ hbase/trunk/hbase-protocol/src/main/protobuf/Client.proto Mon Jul  8 14:52:00 2013
@@ -175,6 +175,7 @@ message MutationProto {
     DELETE_ONE_VERSION = 0;
     DELETE_MULTIPLE_VERSIONS = 1;
     DELETE_FAMILY = 2;
+    DELETE_FAMILY_VERSION = 3;
   }
 
   message ColumnValue {

Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/DeleteTracker.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/DeleteTracker.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/DeleteTracker.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/DeleteTracker.java Mon Jul  8 14:52:00 2013
@@ -104,6 +104,7 @@ public interface DeleteTracker {
    */
   public static enum DeleteResult {
     FAMILY_DELETED, // The KeyValue is deleted by a delete family.
+    FAMILY_VERSION_DELETED, // The KeyValue is deleted by a delete family version.
     COLUMN_DELETED, // The KeyValue is deleted by a delete column.
     VERSION_DELETED, // The KeyValue is deleted by a version delete.
     NOT_DELETED

Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ScanDeleteTracker.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ScanDeleteTracker.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ScanDeleteTracker.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ScanDeleteTracker.java Mon Jul  8 14:52:00 2013
@@ -19,6 +19,9 @@
 
 package org.apache.hadoop.hbase.regionserver;
 
+import java.util.SortedSet;
+import java.util.TreeSet;
+
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.util.Bytes;
@@ -43,6 +46,7 @@ public class ScanDeleteTracker implement
 
   private boolean hasFamilyStamp = false;
   private long familyStamp = 0L;
+  private SortedSet<Long> familyVersionStamps = new TreeSet<Long>();
   private byte [] deleteBuffer = null;
   private int deleteOffset = 0;
   private int deleteLength = 0;
@@ -75,6 +79,9 @@ public class ScanDeleteTracker implement
         hasFamilyStamp = true;
         familyStamp = timestamp;
         return;
+      } else if (type == KeyValue.Type.DeleteFamilyVersion.getCode()) {
+        familyVersionStamps.add(timestamp);
+        return;
       }
 
       if (deleteBuffer != null && type < deleteType) {
@@ -111,6 +118,10 @@ public class ScanDeleteTracker implement
       return DeleteResult.FAMILY_DELETED;
     }
 
+    if (familyVersionStamps.contains(Long.valueOf(timestamp))) {
+        return DeleteResult.FAMILY_VERSION_DELETED;
+    }
+
     if (deleteBuffer != null) {
       int ret = Bytes.compareTo(deleteBuffer, deleteOffset, deleteLength,
           buffer, qualifierOffset, qualifierLength);
@@ -146,7 +157,8 @@ public class ScanDeleteTracker implement
 
   @Override
   public boolean isEmpty() {
-    return deleteBuffer == null && !hasFamilyStamp;
+    return deleteBuffer == null && !hasFamilyStamp &&
+           familyVersionStamps.isEmpty();
   }
 
   @Override
@@ -154,6 +166,7 @@ public class ScanDeleteTracker implement
   public void reset() {
     hasFamilyStamp = false;
     familyStamp = 0L;
+    familyVersionStamps.clear();
     deleteBuffer = null;
   }
 

Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ScanQueryMatcher.java Mon Jul  8 14:52:00 2013
@@ -352,6 +352,7 @@ public class ScanQueryMatcher {
         case COLUMN_DELETED:
           return columns.getNextRowOrNextColumn(bytes, offset, qualLength);
         case VERSION_DELETED:
+        case FAMILY_VERSION_DELETED:
           return MatchCode.SKIP;
         case NOT_DELETED:
           break;

Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java Mon Jul  8 14:52:00 2013
@@ -950,7 +950,7 @@ public class StoreFile {
 
     private void appendDeleteFamilyBloomFilter(final KeyValue kv)
         throws IOException {
-      if (!kv.isDeleteFamily()) {
+      if (!kv.isDeleteFamily() && !kv.isDeleteFamilyVersion()) {
         return;
       }
 

Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java Mon Jul  8 14:52:00 2013
@@ -292,7 +292,7 @@ public class StoreFileScanner implements
             kv.getRowOffset(), kv.getRowLength(), kv.getBuffer(),
             kv.getQualifierOffset(), kv.getQualifierLength());
       } else if (this.matcher != null && !matcher.hasNullColumnInQuery() &&
-          kv.isDeleteFamily()) {
+          (kv.isDeleteFamily() || kv.isDeleteFamilyVersion())) {
         // if there is no such delete family kv in the store file,
         // then no need to seek.
         haveToSeek = reader.passesDeleteFamilyBloomFilter(kv.getBuffer(),

Modified: hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java (original)
+++ hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java Mon Jul  8 14:52:00 2013
@@ -1723,6 +1723,160 @@ public class TestFromClientSide {
   }
 
   @Test
+  public void testDeleteFamilyVersion() throws Exception {
+    HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
+    byte [] TABLE = Bytes.toBytes("testDeleteFamilyVersion");
+
+    byte [][] QUALIFIERS = makeNAscii(QUALIFIER, 1);
+    byte [][] VALUES = makeN(VALUE, 5);
+    long [] ts = {1000, 2000, 3000, 4000, 5000};
+
+    HTable ht = TEST_UTIL.createTable(TABLE, FAMILY, 5);
+
+    Put put = new Put(ROW);
+    for (int q = 0; q < 1; q++)
+      for (int t = 0; t < 5; t++)
+        put.add(FAMILY, QUALIFIERS[q], ts[t], VALUES[t]);
+    ht.put(put);
+    admin.flush(TABLE);
+
+    Delete delete = new Delete(ROW);
+    delete.deleteFamilyVersion(FAMILY, ts[1]);  // delete version '2000'
+    delete.deleteFamilyVersion(FAMILY, ts[3]);  // delete version '4000'
+    ht.delete(delete);
+    admin.flush(TABLE);
+
+    for (int i = 0; i < 1; i++) {
+      Get get = new Get(ROW);
+      get.addColumn(FAMILY, QUALIFIERS[i]);
+      get.setMaxVersions(Integer.MAX_VALUE);
+      Result result = ht.get(get);
+      // verify version '1000'/'3000'/'5000' remains for all columns
+      assertNResult(result, ROW, FAMILY, QUALIFIERS[i],
+          new long [] {ts[0], ts[2], ts[4]},
+          new byte[][] {VALUES[0], VALUES[2], VALUES[4]},
+          0, 2);
+    }
+    ht.close();
+    admin.close();
+  }
+
+  @Test
+  public void testDeleteFamilyVersionWithOtherDeletes() throws Exception {
+    byte [] TABLE = Bytes.toBytes("testDeleteFamilyVersionWithOtherDeletes");
+
+    byte [][] QUALIFIERS = makeNAscii(QUALIFIER, 5);
+    byte [][] VALUES = makeN(VALUE, 5);
+    long [] ts = {1000, 2000, 3000, 4000, 5000};
+
+    HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
+    HTable ht = TEST_UTIL.createTable(TABLE, FAMILY, 5);
+    Put put = null;
+    Result result = null;
+    Get get = null;
+    Delete delete = null;
+
+    // 1. put on ROW
+    put = new Put(ROW);
+    for (int q = 0; q < 5; q++)
+      for (int t = 0; t < 5; t++)
+        put.add(FAMILY, QUALIFIERS[q], ts[t], VALUES[t]);
+    ht.put(put);
+    admin.flush(TABLE);
+
+    // 2. put on ROWS[0]
+    byte [] ROW2 = Bytes.toBytes("myRowForTest");
+    put = new Put(ROW2);
+    for (int q = 0; q < 5; q++)
+      for (int t = 0; t < 5; t++)
+        put.add(FAMILY, QUALIFIERS[q], ts[t], VALUES[t]);
+    ht.put(put);
+    admin.flush(TABLE);
+
+    // 3. delete on ROW
+    delete = new Delete(ROW);
+    // delete version <= 2000 of all columns
+    // note: deleteFamily must be the first since it will mask
+    // the subsequent other type deletes!
+    delete.deleteFamily(FAMILY, ts[1]);
+    // delete version '4000' of all columns
+    delete.deleteFamilyVersion(FAMILY, ts[3]);
+   // delete version <= 3000 of column 0
+    delete.deleteColumns(FAMILY, QUALIFIERS[0], ts[2]);
+    // delete version <= 5000 of column 2
+    delete.deleteColumns(FAMILY, QUALIFIERS[2], ts[4]);
+    // delete version 5000 of column 4
+    delete.deleteColumn(FAMILY, QUALIFIERS[4], ts[4]);
+    ht.delete(delete);
+    admin.flush(TABLE);
+
+     // 4. delete on ROWS[0]
+    delete = new Delete(ROW2);
+    delete.deleteFamilyVersion(FAMILY, ts[1]);  // delete version '2000'
+    delete.deleteFamilyVersion(FAMILY, ts[3]);  // delete version '4000'
+    ht.delete(delete);
+    admin.flush(TABLE);
+
+    // 5. check ROW
+    get = new Get(ROW);
+    get.addColumn(FAMILY, QUALIFIERS[0]);
+    get.setMaxVersions(Integer.MAX_VALUE);
+    result = ht.get(get);
+    assertNResult(result, ROW, FAMILY, QUALIFIERS[0],
+        new long [] {ts[4]},
+        new byte[][] {VALUES[4]},
+        0, 0);
+
+    get = new Get(ROW);
+    get.addColumn(FAMILY, QUALIFIERS[1]);
+    get.setMaxVersions(Integer.MAX_VALUE);
+    result = ht.get(get);
+    assertNResult(result, ROW, FAMILY, QUALIFIERS[1],
+        new long [] {ts[2], ts[4]},
+        new byte[][] {VALUES[2], VALUES[4]},
+        0, 1);
+
+    get = new Get(ROW);
+    get.addColumn(FAMILY, QUALIFIERS[2]);
+    get.setMaxVersions(Integer.MAX_VALUE);
+    result = ht.get(get);
+    assertEquals(0, result.size());
+
+    get = new Get(ROW);
+    get.addColumn(FAMILY, QUALIFIERS[3]);
+    get.setMaxVersions(Integer.MAX_VALUE);
+    result = ht.get(get);
+    assertNResult(result, ROW, FAMILY, QUALIFIERS[3],
+        new long [] {ts[2], ts[4]},
+        new byte[][] {VALUES[2], VALUES[4]},
+        0, 1);
+
+    get = new Get(ROW);
+    get.addColumn(FAMILY, QUALIFIERS[4]);
+    get.setMaxVersions(Integer.MAX_VALUE);
+    result = ht.get(get);
+    assertNResult(result, ROW, FAMILY, QUALIFIERS[4],
+        new long [] {ts[2]},
+        new byte[][] {VALUES[2]},
+        0, 0);
+
+    // 6. check ROWS[0]
+    for (int i = 0; i < 5; i++) {
+      get = new Get(ROW2);
+      get.addColumn(FAMILY, QUALIFIERS[i]);
+      get.setMaxVersions(Integer.MAX_VALUE);
+      result = ht.get(get);
+      // verify version '1000'/'3000'/'5000' remains for all columns
+      assertNResult(result, ROW2, FAMILY, QUALIFIERS[i],
+          new long [] {ts[0], ts[2], ts[4]},
+          new byte[][] {VALUES[0], VALUES[2], VALUES[4]},
+          0, 2);
+    }
+    ht.close();
+    admin.close();
+  }
+
+  @Test
   public void testDeletes() throws Exception {
     byte [] TABLE = Bytes.toBytes("testDeletes");
 

Modified: hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestScanDeleteTracker.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestScanDeleteTracker.java?rev=1500780&r1=1500779&r2=1500780&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestScanDeleteTracker.java (original)
+++ hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestScanDeleteTracker.java Mon Jul  8 14:52:00 2013
@@ -67,6 +67,35 @@ public class TestScanDeleteTracker exten
     assertEquals(DeleteResult.FAMILY_DELETED, ret);
   }
 
+  public void testDeletedBy_DeleteFamilyVersion() {
+    byte [] qualifier1 = Bytes.toBytes("qualifier1");
+    byte [] qualifier2 = Bytes.toBytes("qualifier2");
+    byte [] qualifier3 = Bytes.toBytes("qualifier3");
+    byte [] qualifier4 = Bytes.toBytes("qualifier4");
+    deleteType = KeyValue.Type.DeleteFamilyVersion.getCode();
+
+    sdt.add(null, 0, 0, timestamp, deleteType);
+
+    DeleteResult ret = sdt.isDeleted(qualifier1, 0, qualifier1.length, timestamp);
+    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
+    ret = sdt.isDeleted(qualifier2, 0, qualifier2.length, timestamp);
+    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
+    ret = sdt.isDeleted(qualifier3, 0, qualifier3.length, timestamp);
+    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
+    ret = sdt.isDeleted(qualifier4, 0, qualifier4.length, timestamp);
+    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
+
+    ret = sdt.isDeleted(qualifier1, 0, qualifier1.length, timestamp + 3);
+    assertEquals(DeleteResult.NOT_DELETED, ret);
+    ret = sdt.isDeleted(qualifier2, 0, qualifier2.length, timestamp - 2);
+    assertEquals(DeleteResult.NOT_DELETED, ret);
+    ret = sdt.isDeleted(qualifier3, 0, qualifier3.length, timestamp - 5);
+    assertEquals(DeleteResult.NOT_DELETED, ret);
+    ret = sdt.isDeleted(qualifier4, 0, qualifier4.length, timestamp + 8);
+    assertEquals(DeleteResult.NOT_DELETED, ret);
+  }
+
+
   public void testDelete_DeleteColumn() {
     byte [] qualifier = Bytes.toBytes("qualifier");
     deleteType = KeyValue.Type.Delete.getCode();