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.jupiter.api.Assertions.assertEquals;
021
022import org.apache.hadoop.hbase.CellComparatorImpl;
023import org.apache.hadoop.hbase.KeyValue;
024import org.apache.hadoop.hbase.regionserver.querymatcher.DeleteTracker.DeleteResult;
025import org.apache.hadoop.hbase.testclassification.RegionServerTests;
026import org.apache.hadoop.hbase.testclassification.SmallTests;
027import org.apache.hadoop.hbase.util.Bytes;
028import org.junit.jupiter.api.BeforeEach;
029import org.junit.jupiter.api.Tag;
030import org.junit.jupiter.api.Test;
031
032@Tag(RegionServerTests.TAG)
033@Tag(SmallTests.TAG)
034public class TestScanDeleteTracker {
035
036  private ScanDeleteTracker sdt;
037
038  private long timestamp = 10L;
039
040  @BeforeEach
041  public void setUp() throws Exception {
042    sdt = new ScanDeleteTracker(CellComparatorImpl.COMPARATOR);
043  }
044
045  @Test
046  public void testDeletedByDelete() {
047    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), Bytes.toBytes("qualifier"),
048      timestamp, KeyValue.Type.Delete);
049    sdt.add(kv);
050    DeleteResult ret = sdt.isDeleted(kv);
051    assertEquals(DeleteResult.VERSION_DELETED, ret);
052  }
053
054  @Test
055  public void testDeletedByDeleteColumn() {
056    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), Bytes.toBytes("qualifier"),
057      timestamp, KeyValue.Type.DeleteColumn);
058    sdt.add(kv);
059    timestamp -= 5;
060    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), Bytes.toBytes("qualifier"),
061      timestamp, KeyValue.Type.DeleteColumn);
062    DeleteResult ret = sdt.isDeleted(kv);
063    assertEquals(DeleteResult.COLUMN_DELETED, ret);
064  }
065
066  @Test
067  public void testDeletedByDeleteFamily() {
068    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), Bytes.toBytes("qualifier"),
069      timestamp, KeyValue.Type.DeleteFamily);
070    sdt.add(kv);
071    timestamp -= 5;
072    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), Bytes.toBytes("qualifier"),
073      timestamp, KeyValue.Type.DeleteColumn);
074    DeleteResult ret = sdt.isDeleted(kv);
075    assertEquals(DeleteResult.FAMILY_DELETED, ret);
076  }
077
078  @Test
079  public void testDeletedByDeleteFamilyVersion() {
080    byte[] qualifier1 = Bytes.toBytes("qualifier1");
081    byte[] qualifier2 = Bytes.toBytes("qualifier2");
082    byte[] qualifier3 = Bytes.toBytes("qualifier3");
083    byte[] qualifier4 = Bytes.toBytes("qualifier4");
084    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), null, timestamp,
085      KeyValue.Type.DeleteFamilyVersion);
086    sdt.add(kv);
087    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier1, timestamp,
088      KeyValue.Type.DeleteFamilyVersion);
089    DeleteResult ret = sdt.isDeleted(kv);
090    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
091    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier2, timestamp,
092      KeyValue.Type.DeleteFamilyVersion);
093    ret = sdt.isDeleted(kv);
094    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
095    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier3, timestamp,
096      KeyValue.Type.DeleteFamilyVersion);
097    ret = sdt.isDeleted(kv);
098    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
099    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier4, timestamp,
100      KeyValue.Type.DeleteFamilyVersion);
101    ret = sdt.isDeleted(kv);
102    assertEquals(DeleteResult.FAMILY_VERSION_DELETED, ret);
103    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier1, timestamp + 3,
104      KeyValue.Type.DeleteFamilyVersion);
105    ret = sdt.isDeleted(kv);
106    assertEquals(DeleteResult.NOT_DELETED, ret);
107    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier2, timestamp - 2,
108      KeyValue.Type.DeleteFamilyVersion);
109    ret = sdt.isDeleted(kv);
110    assertEquals(DeleteResult.NOT_DELETED, ret);
111    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier3, timestamp - 5,
112      KeyValue.Type.DeleteFamilyVersion);
113    ret = sdt.isDeleted(kv);
114    assertEquals(DeleteResult.NOT_DELETED, ret);
115    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier4, timestamp + 8,
116      KeyValue.Type.DeleteFamilyVersion);
117    ret = sdt.isDeleted(kv);
118    assertEquals(DeleteResult.NOT_DELETED, ret);
119  }
120
121  @Test
122  public void testDeleteDeleteColumn() {
123    byte[] qualifier = Bytes.toBytes("qualifier");
124    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
125      KeyValue.Type.Delete);
126    sdt.add(kv);
127
128    timestamp -= 5;
129    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
130      KeyValue.Type.DeleteColumn);
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    DeleteResult ret = sdt.isDeleted(kv);
137    assertEquals(DeleteResult.COLUMN_DELETED, ret);
138  }
139
140  @Test
141  public void testDeleteColumnDelete() {
142    byte[] qualifier = Bytes.toBytes("qualifier");
143    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
144      KeyValue.Type.DeleteColumn);
145    sdt.add(kv);
146
147    qualifier = Bytes.toBytes("qualifier1");
148    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
149      KeyValue.Type.Delete);
150    sdt.add(kv);
151
152    DeleteResult ret = sdt.isDeleted(kv);
153    assertEquals(DeleteResult.VERSION_DELETED, ret);
154  }
155
156  // Testing new way where we save the Delete in case of a Delete for specific
157  // ts, could have just added the last line to the first test, but rather keep
158  // them separated
159  @Test
160  public void testDeleteKeepDelete() {
161    byte[] qualifier = Bytes.toBytes("qualifier");
162    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, timestamp,
163      KeyValue.Type.Delete);
164    sdt.add(kv);
165    sdt.isDeleted(kv);
166    assertEquals(false, sdt.isEmpty());
167  }
168
169  @Test
170  public void testDeleteKeepVersionZero() {
171    byte[] qualifier = Bytes.toBytes("qualifier");
172
173    long deleteTimestamp = 10;
174    long valueTimestamp = 0;
175
176    sdt.reset();
177    KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, deleteTimestamp,
178      KeyValue.Type.Delete);
179    sdt.add(kv);
180    kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("f"), qualifier, valueTimestamp,
181      KeyValue.Type.Delete);
182    DeleteResult ret = sdt.isDeleted(kv);
183    assertEquals(DeleteResult.NOT_DELETED, ret);
184  }
185}