2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.regionserver
;
20 import static org
.apache
.hadoop
.hbase
.HBaseTestingUtility
.COLUMNS
;
21 import static org
.junit
.Assert
.assertEquals
;
22 import static org
.junit
.Assert
.assertTrue
;
23 import java
.util
.ArrayList
;
24 import java
.util
.List
;
25 import org
.apache
.hadoop
.hbase
.Cell
;
26 import org
.apache
.hadoop
.hbase
.CellUtil
;
27 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
28 import org
.apache
.hadoop
.hbase
.HBaseTestingUtility
;
29 import org
.apache
.hadoop
.hbase
.KeepDeletedCells
;
30 import org
.apache
.hadoop
.hbase
.TableName
;
31 import org
.apache
.hadoop
.hbase
.client
.ColumnFamilyDescriptor
;
32 import org
.apache
.hadoop
.hbase
.client
.ColumnFamilyDescriptorBuilder
;
33 import org
.apache
.hadoop
.hbase
.client
.Delete
;
34 import org
.apache
.hadoop
.hbase
.client
.Get
;
35 import org
.apache
.hadoop
.hbase
.client
.Put
;
36 import org
.apache
.hadoop
.hbase
.client
.Result
;
37 import org
.apache
.hadoop
.hbase
.client
.TableDescriptor
;
38 import org
.apache
.hadoop
.hbase
.client
.TableDescriptorBuilder
;
39 import org
.apache
.hadoop
.hbase
.filter
.TimestampsFilter
;
40 import org
.apache
.hadoop
.hbase
.testclassification
.MediumTests
;
41 import org
.apache
.hadoop
.hbase
.testclassification
.RegionServerTests
;
42 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
43 import org
.apache
.hadoop
.hbase
.util
.EnvironmentEdgeManager
;
44 import org
.apache
.hadoop
.hbase
.util
.ManualEnvironmentEdge
;
45 import org
.junit
.Assert
;
46 import org
.junit
.ClassRule
;
47 import org
.junit
.Rule
;
48 import org
.junit
.Test
;
49 import org
.junit
.experimental
.categories
.Category
;
50 import org
.junit
.rules
.TestName
;
53 * Test Minimum Versions feature (HBASE-4071).
55 @Category({RegionServerTests
.class, MediumTests
.class})
56 public class TestMinVersions
{
59 public static final HBaseClassTestRule CLASS_RULE
=
60 HBaseClassTestRule
.forClass(TestMinVersions
.class);
62 HBaseTestingUtility hbu
= new HBaseTestingUtility();
63 private final byte[] T0
= Bytes
.toBytes("0");
64 private final byte[] T1
= Bytes
.toBytes("1");
65 private final byte[] T2
= Bytes
.toBytes("2");
66 private final byte[] T3
= Bytes
.toBytes("3");
67 private final byte[] T4
= Bytes
.toBytes("4");
68 private final byte[] T5
= Bytes
.toBytes("5");
70 private final byte[] c0
= COLUMNS
[0];
72 @Rule public TestName name
= new TestName();
75 * Verify behavior of getClosestBefore(...)
78 public void testGetClosestBefore() throws Exception
{
80 ColumnFamilyDescriptor cfd
=
81 ColumnFamilyDescriptorBuilder
.newBuilder(c0
)
82 .setMinVersions(1).setMaxVersions(1000).setTimeToLive(1).
83 setKeepDeletedCells(KeepDeletedCells
.FALSE
).build();
85 TableDescriptor htd
= TableDescriptorBuilder
.
86 newBuilder(TableName
.valueOf(name
.getMethodName())).setColumnFamily(cfd
).build();
87 HRegion region
= hbu
.createLocalHRegion(htd
, null, null);
91 long ts
= EnvironmentEdgeManager
.currentTime() - 2000;
93 Put p
= new Put(T1
, ts
);
94 p
.addColumn(c0
, c0
, T1
);
97 p
= new Put(T1
, ts
+1);
98 p
.addColumn(c0
, c0
, T4
);
102 p
.addColumn(c0
, c0
, T3
);
105 // now make sure that getClosestBefore(...) get can
106 // rows that would be expired without minVersion.
107 // also make sure it gets the latest version
108 Result r
= hbu
.getClosestRowBefore(region
, T1
, c0
);
109 checkResult(r
, c0
, T4
);
111 r
= hbu
.getClosestRowBefore(region
, T2
, c0
);
112 checkResult(r
, c0
, T4
);
116 region
.compact(true);
118 r
= hbu
.getClosestRowBefore(region
, T1
, c0
);
119 checkResult(r
, c0
, T4
);
121 r
= hbu
.getClosestRowBefore(region
, T2
, c0
);
122 checkResult(r
, c0
, T4
);
124 HBaseTestingUtility
.closeRegionAndWAL(region
);
129 * Test mixed memstore and storefile scanning
130 * with minimum versions.
133 public void testStoreMemStore() throws Exception
{
134 // keep 3 versions minimum
136 ColumnFamilyDescriptor cfd
=
137 ColumnFamilyDescriptorBuilder
.newBuilder(c0
)
138 .setMinVersions(3).setMaxVersions(1000).setTimeToLive(1).
139 setKeepDeletedCells(KeepDeletedCells
.FALSE
).build();
141 TableDescriptor htd
= TableDescriptorBuilder
.
142 newBuilder(TableName
.valueOf(name
.getMethodName())).setColumnFamily(cfd
).build();
144 HRegion region
= hbu
.createLocalHRegion(htd
, null, null);
146 long ts
= EnvironmentEdgeManager
.currentTime() - 2000;
149 Put p
= new Put(T1
, ts
-1);
150 p
.addColumn(c0
, c0
, T2
);
153 p
= new Put(T1
, ts
-3);
154 p
.addColumn(c0
, c0
, T0
);
159 region
.compact(true);
162 p
.addColumn(c0
, c0
, T3
);
165 p
= new Put(T1
, ts
-2);
166 p
.addColumn(c0
, c0
, T1
);
169 p
= new Put(T1
, ts
-3);
170 p
.addColumn(c0
, c0
, T0
);
173 // newest version in the memstore
174 // the 2nd oldest in the store file
175 // and the 3rd, 4th oldest also in the memstore
179 Result r
= region
.get(g
); // this'll use ScanWildcardColumnTracker
180 checkResult(r
, c0
, T3
,T2
,T1
);
185 r
= region
.get(g
); // this'll use ExplicitColumnTracker
186 checkResult(r
, c0
, T3
,T2
,T1
);
188 HBaseTestingUtility
.closeRegionAndWAL(region
);
193 * Make sure the Deletes behave as expected with minimum versions
196 public void testDelete() throws Exception
{
197 ColumnFamilyDescriptor cfd
=
198 ColumnFamilyDescriptorBuilder
.newBuilder(c0
)
199 .setMinVersions(3).setMaxVersions(1000).setTimeToLive(1).
200 setKeepDeletedCells(KeepDeletedCells
.FALSE
).build();
202 TableDescriptor htd
= TableDescriptorBuilder
.
203 newBuilder(TableName
.valueOf(name
.getMethodName())).setColumnFamily(cfd
).build();
205 HRegion region
= hbu
.createLocalHRegion(htd
, null, null);
208 long ts
= EnvironmentEdgeManager
.currentTime() - 2000;
211 Put p
= new Put(T1
, ts
-2);
212 p
.addColumn(c0
, c0
, T1
);
215 p
= new Put(T1
, ts
-1);
216 p
.addColumn(c0
, c0
, T2
);
220 p
.addColumn(c0
, c0
, T3
);
223 Delete d
= new Delete(T1
, ts
-1);
228 Result r
= region
.get(g
); // this'll use ScanWildcardColumnTracker
229 checkResult(r
, c0
, T3
);
234 r
= region
.get(g
); // this'll use ExplicitColumnTracker
235 checkResult(r
, c0
, T3
);
239 region
.compact(true);
244 r
= region
.get(g
); // this'll use ScanWildcardColumnTracker
245 checkResult(r
, c0
, T3
);
250 r
= region
.get(g
); // this'll use ExplicitColumnTracker
251 checkResult(r
, c0
, T3
);
253 HBaseTestingUtility
.closeRegionAndWAL(region
);
258 * Make sure the memstor behaves correctly with minimum versions
261 public void testMemStore() throws Exception
{
262 ColumnFamilyDescriptor cfd
=
263 ColumnFamilyDescriptorBuilder
.newBuilder(c0
)
264 .setMinVersions(2).setMaxVersions(1000).setTimeToLive(1).
265 setKeepDeletedCells(KeepDeletedCells
.FALSE
).build();
267 TableDescriptor htd
= TableDescriptorBuilder
.
268 newBuilder(TableName
.valueOf(name
.getMethodName())).setColumnFamily(cfd
).build();
269 HRegion region
= hbu
.createLocalHRegion(htd
, null, null);
272 long ts
= EnvironmentEdgeManager
.currentTime() - 2000;
276 Put p
= new Put(T1
, ts
-2);
277 p
.addColumn(c0
, c0
, T2
);
281 p
= new Put(T1
, ts
-1);
282 p
.addColumn(c0
, c0
, T3
);
287 p
.addColumn(c0
, c0
, T4
);
292 region
.compact(true);
294 // now put the first version (backdated)
295 p
= new Put(T1
, ts
-3);
296 p
.addColumn(c0
, c0
, T1
);
299 // now the latest change is in the memstore,
300 // but it is not the latest version
302 Result r
= region
.get(new Get(T1
));
303 checkResult(r
, c0
, T4
);
307 r
= region
.get(g
); // this'll use ScanWildcardColumnTracker
308 checkResult(r
, c0
, T4
,T3
);
313 r
= region
.get(g
); // this'll use ExplicitColumnTracker
314 checkResult(r
, c0
, T4
,T3
);
316 p
= new Put(T1
, ts
+1);
317 p
.addColumn(c0
, c0
, T5
);
320 // now the latest version is in the memstore
324 r
= region
.get(g
); // this'll use ScanWildcardColumnTracker
325 checkResult(r
, c0
, T5
,T4
);
330 r
= region
.get(g
); // this'll use ExplicitColumnTracker
331 checkResult(r
, c0
, T5
,T4
);
333 HBaseTestingUtility
.closeRegionAndWAL(region
);
338 * Verify basic minimum versions functionality
341 public void testBaseCase() throws Exception
{
342 // 2 version minimum, 1000 versions maximum, ttl = 1s
343 ColumnFamilyDescriptor cfd
=
344 ColumnFamilyDescriptorBuilder
.newBuilder(c0
)
345 .setMinVersions(2).setMaxVersions(1000).setTimeToLive(1).
346 setKeepDeletedCells(KeepDeletedCells
.FALSE
).build();
348 TableDescriptor htd
= TableDescriptorBuilder
.
349 newBuilder(TableName
.valueOf(name
.getMethodName())).setColumnFamily(cfd
).build();
350 HRegion region
= hbu
.createLocalHRegion(htd
, null, null);
354 long ts
= EnvironmentEdgeManager
.currentTime() - 2000;
357 Put p
= new Put(T1
, ts
-3);
358 p
.addColumn(c0
, c0
, T1
);
362 p
= new Put(T1
, ts
-2);
363 p
.addColumn(c0
, c0
, T2
);
367 p
= new Put(T1
, ts
-1);
368 p
.addColumn(c0
, c0
, T3
);
373 p
.addColumn(c0
, c0
, T4
);
376 Result r
= region
.get(new Get(T1
));
377 checkResult(r
, c0
, T4
);
380 g
.setTimeRange(0L, ts
+1);
382 checkResult(r
, c0
, T4
);
384 // oldest version still exists
385 g
.setTimeRange(0L, ts
-2);
387 checkResult(r
, c0
, T1
);
389 // gets see only available versions
390 // even before compactions
393 r
= region
.get(g
); // this'll use ScanWildcardColumnTracker
394 checkResult(r
, c0
, T4
,T3
);
399 r
= region
.get(g
); // this'll use ExplicitColumnTracker
400 checkResult(r
, c0
, T4
,T3
);
405 // with HBASE-4241 a flush will eliminate the expired rows
407 g
.setTimeRange(0L, ts
-2);
409 assertTrue(r
.isEmpty());
412 region
.compact(true);
414 // after compaction the 4th version is still available
416 g
.setTimeRange(0L, ts
+1);
418 checkResult(r
, c0
, T4
);
421 g
.setTimeRange(0L, ts
);
423 checkResult(r
, c0
, T3
);
425 // but the 2nd and earlier versions are gone
426 g
.setTimeRange(0L, ts
-1);
428 assertTrue(r
.isEmpty());
430 HBaseTestingUtility
.closeRegionAndWAL(region
);
435 * Verify that basic filters still behave correctly with
436 * minimum versions enabled.
439 public void testFilters() throws Exception
{
440 final byte [] c1
= COLUMNS
[1];
441 ColumnFamilyDescriptor cfd
=
442 ColumnFamilyDescriptorBuilder
.newBuilder(c0
)
443 .setMinVersions(2).setMaxVersions(1000).setTimeToLive(1).
444 setKeepDeletedCells(KeepDeletedCells
.FALSE
).build();
446 ColumnFamilyDescriptor cfd2
=
447 ColumnFamilyDescriptorBuilder
.newBuilder(c1
)
448 .setMinVersions(2).setMaxVersions(1000).setTimeToLive(1).
449 setKeepDeletedCells(KeepDeletedCells
.FALSE
).build();
450 List
<ColumnFamilyDescriptor
> cfdList
= new ArrayList();
454 TableDescriptor htd
= TableDescriptorBuilder
.
455 newBuilder(TableName
.valueOf(name
.getMethodName())).setColumnFamilies(cfdList
).build();
456 HRegion region
= hbu
.createLocalHRegion(htd
, null, null);
459 long ts
= EnvironmentEdgeManager
.currentTime() - 2000;
462 Put p
= new Put(T1
, ts
-3);
463 p
.addColumn(c0
, c0
, T0
);
464 p
.addColumn(c1
, c1
, T0
);
467 p
= new Put(T1
, ts
-2);
468 p
.addColumn(c0
, c0
, T1
);
469 p
.addColumn(c1
, c1
, T1
);
472 p
= new Put(T1
, ts
-1);
473 p
.addColumn(c0
, c0
, T2
);
474 p
.addColumn(c1
, c1
, T2
);
478 p
.addColumn(c0
, c0
, T3
);
479 p
.addColumn(c1
, c1
, T3
);
482 List
<Long
> tss
= new ArrayList
<>();
486 // Sholud only get T2, versions is 2, so T1 is gone from user view.
489 g
.setFilter(new TimestampsFilter(tss
));
491 Result r
= region
.get(g
);
492 checkResult(r
, c1
, T2
);
494 // Sholud only get T2, versions is 2, so T1 is gone from user view.
497 g
.setFilter(new TimestampsFilter(tss
));
500 checkResult(r
, c0
, T2
);
504 region
.compact(true);
506 // After flush/compact, the result should be consistent with previous result
509 g
.setFilter(new TimestampsFilter(tss
));
512 checkResult(r
, c1
, T2
);
514 // After flush/compact, the result should be consistent with previous result
517 g
.setFilter(new TimestampsFilter(tss
));
520 checkResult(r
, c0
, T2
);
522 HBaseTestingUtility
.closeRegionAndWAL(region
);
527 public void testMinVersionsWithKeepDeletedCellsTTL() throws Exception
{
529 ColumnFamilyDescriptor cfd
=
530 ColumnFamilyDescriptorBuilder
.newBuilder(c0
)
531 .setMinVersions(2).setMaxVersions(Integer
.MAX_VALUE
).setTimeToLive(ttl
).
532 setKeepDeletedCells(KeepDeletedCells
.TTL
).build();
534 TableDescriptor htd
= TableDescriptorBuilder
.
535 newBuilder(TableName
.valueOf(name
.getMethodName())).setColumnFamily(cfd
).build();
537 HRegion region
= hbu
.createLocalHRegion(htd
, null, null);
539 long startTS
= EnvironmentEdgeManager
.currentTime();
540 ManualEnvironmentEdge injectEdge
= new ManualEnvironmentEdge();
541 injectEdge
.setValue(startTS
);
542 EnvironmentEdgeManager
.injectEdge(injectEdge
);
544 long ts
= startTS
- 2000;
546 Put p
= new Put(T1
, ts
-3);
547 p
.addColumn(c0
, c0
, T1
);
551 p
= new Put(T1
, ts
-2);
552 p
.addColumn(c0
, c0
, T2
);
556 p
= new Put(T1
, ts
-1);
557 p
.addColumn(c0
, c0
, T3
);
563 //check we can still see all versions before compaction
566 g
.setTimeRange(0, ts
);
568 checkResult(r
, c0
, T3
, T2
, T1
);
571 region
.compact(true);
572 Assert
.assertEquals(startTS
, EnvironmentEdgeManager
.currentTime());
573 long expiredTime
= EnvironmentEdgeManager
.currentTime() - ts
- 3;
574 Assert
.assertTrue("TTL for T1 has expired", expiredTime
< (ttl
* 1000));
575 //check that nothing was purged yet
578 g
.setTimeRange(0, ts
);
580 checkResult(r
, c0
, T3
, T2
, T1
);
584 g
.setTimeRange(0, ts
-1);
586 checkResult(r
, c0
, T2
, T1
);
588 injectEdge
.incValue(ttl
* 1000);
591 region
.compact(true);
593 //check that after compaction (which is after TTL) that only T1 was purged
596 g
.setTimeRange(0, ts
);
598 checkResult(r
, c0
, T3
, T2
);
602 g
.setTimestamp(ts
-2);
604 checkResult(r
, c0
, T2
);
607 private void checkResult(Result r
, byte[] col
, byte[] ... vals
) {
608 assertEquals(vals
.length
, r
.size());
609 List
<Cell
> kvs
= r
.getColumnCells(col
, col
);
610 assertEquals(kvs
.size(), vals
.length
);
611 for (int i
=0;i
<vals
.length
;i
++) {
612 String expected
= Bytes
.toString(vals
[i
]);
613 String actual
= Bytes
.toString(CellUtil
.cloneValue(kvs
.get(i
)));
614 assertTrue(expected
+ " was expected but doesn't match " + actual
,
615 CellUtil
.matchingValue(kvs
.get(i
), vals
[i
]));