001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.regionserver.querymatcher;
019
020import static org.junit.Assert.*;
021
022import org.apache.hadoop.hbase.CellComparatorImpl;
023import org.apache.hadoop.hbase.HBaseClassTestRule;
024import org.apache.hadoop.hbase.KeyValue;
025import org.apache.hadoop.hbase.regionserver.querymatcher.DeleteTracker.DeleteResult;
026import org.apache.hadoop.hbase.testclassification.RegionServerTests;
027import org.apache.hadoop.hbase.testclassification.SmallTests;
028import org.apache.hadoop.hbase.util.Bytes;
029import org.junit.Before;
030import org.junit.ClassRule;
031import org.junit.Test;
032import org.junit.experimental.categories.Category;
033
034@Category({ RegionServerTests.class, SmallTests.class })
035public class TestScanDeleteTracker {
036
037  @ClassRule
038  public static final HBaseClassTestRule CLASS_RULE =
039    HBaseClassTestRule.forClass(TestScanDeleteTracker.class);
040
041  private ScanDeleteTracker sdt;
042
043  private long timestamp = 10L;
044
045  @Before
046  public void setUp() throws Exception {
047    sdt = new ScanDeleteTracker(CellComparatorImpl.COMPARATOR);
048  }
049
050  @Test
051  public void testDeletedByDelete() {
052    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), Bytes.toBytes("qualifier"),
053      timestamp, KeyValue.Type.Delete);
054    sdt.add(kv);
055    DeleteResult ret = sdt.isDeleted(kv);
056    assertEquals(DeleteResult.VERSION_DELETED, ret);
057  }
058
059  @Test
060  public void testDeletedByDeleteColumn() {
061    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), Bytes.toBytes("qualifier"),
062      timestamp, KeyValue.Type.DeleteColumn);
063    sdt.add(kv);
064    timestamp -= 5;
065    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), Bytes.toBytes("qualifier"),
066      timestamp, KeyValue.Type.DeleteColumn);
067    DeleteResult ret = sdt.isDeleted(kv);
068    assertEquals(DeleteResult.COLUMN_DELETED, ret);
069  }
070
071  @Test
072  public void testDeletedByDeleteFamily() {
073    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), Bytes.toBytes("qualifier"),
074      timestamp, KeyValue.Type.DeleteFamily);
075    sdt.add(kv);
076    timestamp -= 5;
077    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), Bytes.toBytes("qualifier"),
078      timestamp, KeyValue.Type.DeleteColumn);
079    DeleteResult ret = sdt.isDeleted(kv);
080    assertEquals(DeleteResult.FAMILY_DELETED, ret);
081  }
082
083  @Test
084  public void testDeletedByDeleteFamilyVersion() {
085    byte[] qualifier1 = Bytes.toBytes("qualifier1");
086    byte[] qualifier2 = Bytes.toBytes("qualifier2");
087    byte[] qualifier3 = Bytes.toBytes("qualifier3");
088    byte[] qualifier4 = Bytes.toBytes("qualifier4");
089    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), null, timestamp,
090      KeyValue.Type.DeleteFamilyVersion);
091    sdt.add(kv);
092    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier1, timestamp,
093      KeyValue.Type.DeleteFamilyVersion);
094    DeleteResult ret = sdt.isDeleted(kv);
095    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
096    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier2, timestamp,
097      KeyValue.Type.DeleteFamilyVersion);
098    ret = sdt.isDeleted(kv);
099    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
100    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier3, timestamp,
101      KeyValue.Type.DeleteFamilyVersion);
102    ret = sdt.isDeleted(kv);
103    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
104    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier4, timestamp,
105      KeyValue.Type.DeleteFamilyVersion);
106    ret = sdt.isDeleted(kv);
107    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
108    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier1, timestamp + 3,
109      KeyValue.Type.DeleteFamilyVersion);
110    ret = sdt.isDeleted(kv);
111    assertEquals(DeleteResult.NOT_DELETED, ret);
112    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier2, timestamp - 2,
113      KeyValue.Type.DeleteFamilyVersion);
114    ret = sdt.isDeleted(kv);
115    assertEquals(DeleteResult.NOT_DELETED, ret);
116    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier3, timestamp - 5,
117      KeyValue.Type.DeleteFamilyVersion);
118    ret = sdt.isDeleted(kv);
119    assertEquals(DeleteResult.NOT_DELETED, ret);
120    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier4, timestamp + 8,
121      KeyValue.Type.DeleteFamilyVersion);
122    ret = sdt.isDeleted(kv);
123    assertEquals(DeleteResult.NOT_DELETED, ret);
124  }
125
126  @Test
127  public void testDeleteDeleteColumn() {
128    byte[] qualifier = Bytes.toBytes("qualifier");
129    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
130      KeyValue.Type.Delete);
131    sdt.add(kv);
132
133    timestamp -= 5;
134    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
135      KeyValue.Type.DeleteColumn);
136    sdt.add(kv);
137
138    timestamp -= 5;
139    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
140      KeyValue.Type.DeleteColumn);
141    DeleteResult ret = sdt.isDeleted(kv);
142    assertEquals(DeleteResult.COLUMN_DELETED, ret);
143  }
144
145  @Test
146  public void testDeleteColumnDelete() {
147    byte[] qualifier = Bytes.toBytes("qualifier");
148    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
149      KeyValue.Type.DeleteColumn);
150    sdt.add(kv);
151
152    qualifier = Bytes.toBytes("qualifier1");
153    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
154      KeyValue.Type.Delete);
155    sdt.add(kv);
156
157    DeleteResult ret = sdt.isDeleted(kv);
158    assertEquals(DeleteResult.VERSION_DELETED, ret);
159  }
160
161  // Testing new way where we save the Delete in case of a Delete for specific
162  // ts, could have just added the last line to the first test, but rather keep
163  // them separated
164  @Test
165  public void testDeleteKeepDelete() {
166    byte[] qualifier = Bytes.toBytes("qualifier");
167    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
168      KeyValue.Type.Delete);
169    sdt.add(kv);
170    sdt.isDeleted(kv);
171    assertEquals(false, sdt.isEmpty());
172  }
173
174  @Test
175  public void testDeleteKeepVersionZero() {
176    byte[] qualifier = Bytes.toBytes("qualifier");
177
178    long deleteTimestamp = 10;
179    long valueTimestamp = 0;
180
181    sdt.reset();
182    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, deleteTimestamp,
183      KeyValue.Type.Delete);
184    sdt.add(kv);
185    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, valueTimestamp,
186      KeyValue.Type.Delete);
187    DeleteResult ret = sdt.isDeleted(kv);
188    assertEquals(DeleteResult.NOT_DELETED, ret);
189  }
190}