blob: 475993d3eefdc6a1b7cd86e2f9949f146315ae5f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.client;
import static org.apache.hadoop.hbase.HBaseTestingUtility.countRows;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.CompareOperator;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeepDeletedCells;
import org.apache.hadoop.hbase.PrivateCellUtil;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNameTestRule;
import org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.KeyOnlyFilter;
import org.apache.hadoop.hbase.filter.LongComparator;
import org.apache.hadoop.hbase.filter.QualifierFilter;
import org.apache.hadoop.hbase.filter.RegexStringComparator;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.testclassification.ClientTests;
import org.apache.hadoop.hbase.testclassification.LargeTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.AfterClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Run tests that use the HBase clients; {@link Table}.
* Sets up the HBase mini cluster once at start and runs through all client tests.
* Each creates a table named for the method and does its stuff against that.
*
* Parameterized to run with different registry implementations.
*
* This class was split in three because it got too big when parameterized. Other classes
* are below.
*
* @see TestFromClientSide4
* @see TestFromClientSide5
*/
// NOTE: Increment tests were moved to their own class, TestIncrementsFromClientSide.
@Category({LargeTests.class, ClientTests.class})
@SuppressWarnings ("deprecation")
@RunWith(Parameterized.class)
public class TestFromClientSide extends FromClientSideBase {
private static final Logger LOG = LoggerFactory.getLogger(TestFromClientSide.class);
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestFromClientSide.class);
@Rule
public TableNameTestRule name = new TableNameTestRule();
// To keep the child classes happy.
TestFromClientSide() {
}
public TestFromClientSide(Class registry, int numHedgedReqs) throws Exception {
initialize(registry, numHedgedReqs, MultiRowMutationEndpoint.class);
}
@Parameterized.Parameters public static Collection parameters() {
return Arrays.asList(new Object[][] { { MasterRegistry.class, 1 }, { MasterRegistry.class, 2 },
{ ZKConnectionRegistry.class, 1 } });
}
@AfterClass public static void tearDownAfterClass() throws Exception {
afterClass();
}
/**
* Test append result when there are duplicate rpc request.
*/
@Test
public void testDuplicateAppend() throws Exception {
HTableDescriptor hdt = TEST_UTIL
.createTableDescriptor(name.getTableName(), HColumnDescriptor.DEFAULT_MIN_VERSIONS, 3,
HConstants.FOREVER, HColumnDescriptor.DEFAULT_KEEP_DELETED);
Map<String, String> kvs = new HashMap<>();
kvs.put(SleepAtFirstRpcCall.SLEEP_TIME_CONF_KEY, "2000");
hdt.addCoprocessor(SleepAtFirstRpcCall.class.getName(), null, 1, kvs);
TEST_UTIL.createTable(hdt, new byte[][] { ROW }).close();
Configuration c = new Configuration(TEST_UTIL.getConfiguration());
c.setInt(HConstants.HBASE_CLIENT_PAUSE, 50);
// Client will retry because rpc timeout is small than the sleep time of first rpc call
c.setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, 1500);
try (Connection connection = ConnectionFactory.createConnection(c);
Table table = connection.getTableBuilder(name.getTableName(), null).
setOperationTimeout(3 * 1000).build()) {
Append append = new Append(ROW);
append.addColumn(HBaseTestingUtility.fam1, QUALIFIER, VALUE);
Result result = table.append(append);
// Verify expected result
Cell[] cells = result.rawCells();
assertEquals(1, cells.length);
assertKey(cells[0], ROW, HBaseTestingUtility.fam1, QUALIFIER, VALUE);
// Verify expected result again
Result readResult = table.get(new Get(ROW));
cells = readResult.rawCells();
assertEquals(1, cells.length);
assertKey(cells[0], ROW, HBaseTestingUtility.fam1, QUALIFIER, VALUE);
}
}
/**
* Basic client side validation of HBASE-4536
*/
@Test public void testKeepDeletedCells() throws Exception {
final TableName tableName = name.getTableName();
final byte[] FAMILY = Bytes.toBytes("family");
final byte[] C0 = Bytes.toBytes("c0");
final byte[] T1 = Bytes.toBytes("T1");
final byte[] T2 = Bytes.toBytes("T2");
final byte[] T3 = Bytes.toBytes("T3");
ColumnFamilyDescriptor familyDescriptor =
new ColumnFamilyDescriptorBuilder.ModifyableColumnFamilyDescriptor(FAMILY)
.setKeepDeletedCells(KeepDeletedCells.TRUE).setMaxVersions(3);
TableDescriptorBuilder.ModifyableTableDescriptor tableDescriptor =
new TableDescriptorBuilder.ModifyableTableDescriptor(tableName);
tableDescriptor.setColumnFamily(familyDescriptor);
TEST_UTIL.getAdmin().createTable(tableDescriptor);
try (Table h = TEST_UTIL.getConnection().getTable(tableName)) {
long ts = System.currentTimeMillis();
Put p = new Put(T1, ts);
p.addColumn(FAMILY, C0, T1);
h.put(p);
p = new Put(T1, ts + 2);
p.addColumn(FAMILY, C0, T2);
h.put(p);
p = new Put(T1, ts + 4);
p.addColumn(FAMILY, C0, T3);
h.put(p);
Delete d = new Delete(T1, ts + 3);
h.delete(d);
d = new Delete(T1, ts + 3);
d.addColumns(FAMILY, C0, ts + 3);
h.delete(d);
Get g = new Get(T1);
// does *not* include the delete
g.setTimeRange(0, ts + 3);
Result r = h.get(g);
assertArrayEquals(T2, r.getValue(FAMILY, C0));
Scan s = new Scan().withStartRow(T1);
s.setTimeRange(0, ts + 3);
s.readAllVersions();
ResultScanner scanner = h.getScanner(s);
Cell[] kvs = scanner.next().rawCells();
assertArrayEquals(T2, CellUtil.cloneValue(kvs[0]));
assertArrayEquals(T1, CellUtil.cloneValue(kvs[1]));
scanner.close();
s = new Scan().withStartRow(T1);
s.setRaw(true);
s.readAllVersions();
scanner = h.getScanner(s);
kvs = scanner.next().rawCells();
assertTrue(PrivateCellUtil.isDeleteFamily(kvs[0]));
assertArrayEquals(T3, CellUtil.cloneValue(kvs[1]));
assertTrue(CellUtil.isDelete(kvs[2]));
assertArrayEquals(T2, CellUtil.cloneValue(kvs[3]));
assertArrayEquals(T1, CellUtil.cloneValue(kvs[4]));
scanner.close();
}
}
/**
* Basic client side validation of HBASE-10118
*/
@Test public void testPurgeFutureDeletes() throws Exception {
final TableName tableName = name.getTableName();
final byte[] ROW = Bytes.toBytes("row");
final byte[] FAMILY = Bytes.toBytes("family");
final byte[] COLUMN = Bytes.toBytes("column");
final byte[] VALUE = Bytes.toBytes("value");
try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) {
// future timestamp
long ts = System.currentTimeMillis() * 2;
Put put = new Put(ROW, ts);
put.addColumn(FAMILY, COLUMN, VALUE);
table.put(put);
Get get = new Get(ROW);
Result result = table.get(get);
assertArrayEquals(VALUE, result.getValue(FAMILY, COLUMN));
Delete del = new Delete(ROW);
del.addColumn(FAMILY, COLUMN, ts);
table.delete(del);
get = new Get(ROW);
result = table.get(get);
assertNull(result.getValue(FAMILY, COLUMN));
// major compaction, purged future deletes
TEST_UTIL.getAdmin().flush(tableName);
TEST_UTIL.getAdmin().majorCompact(tableName);
// waiting for the major compaction to complete
TEST_UTIL.waitFor(6000,
() -> TEST_UTIL.getAdmin().getCompactionState(tableName) == CompactionState.NONE);
put = new Put(ROW, ts);
put.addColumn(FAMILY, COLUMN, VALUE);
table.put(put);
get = new Get(ROW);
result = table.get(get);
assertArrayEquals(VALUE, result.getValue(FAMILY, COLUMN));
}
}
/**
* Verifies that getConfiguration returns the same Configuration object used
* to create the HTable instance.
*/
@Test public void testGetConfiguration() throws Exception {
final TableName tableName = name.getTableName();
byte[][] FAMILIES = new byte[][] { Bytes.toBytes("foo") };
Configuration conf = TEST_UTIL.getConfiguration();
try (Table table = TEST_UTIL.createTable(tableName, FAMILIES)) {
assertSame(conf, table.getConfiguration());
}
}
/**
* Test from client side of an involved filter against a multi family that
* involves deletes.
*/
@Test public void testWeirdCacheBehaviour() throws Exception {
final TableName tableName = name.getTableName();
byte[][] FAMILIES = new byte[][] {
Bytes.toBytes("trans-blob"),
Bytes.toBytes("trans-type"),
Bytes.toBytes("trans-date"),
Bytes.toBytes("trans-tags"),
Bytes.toBytes("trans-group")
};
try (Table ht = TEST_UTIL.createTable(tableName, FAMILIES)) {
String value = "this is the value";
String value2 = "this is some other value";
String keyPrefix1 = HBaseTestingUtility.getRandomUUID().toString();
String keyPrefix2 = HBaseTestingUtility.getRandomUUID().toString();
String keyPrefix3 = HBaseTestingUtility.getRandomUUID().toString();
putRows(ht, 3, value, keyPrefix1);
putRows(ht, 3, value, keyPrefix2);
putRows(ht, 3, value, keyPrefix3);
putRows(ht, 3, value2, keyPrefix1);
putRows(ht, 3, value2, keyPrefix2);
putRows(ht, 3, value2, keyPrefix3);
try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
System.out.println("Checking values for key: " + keyPrefix1);
assertEquals("Got back incorrect number of rows from scan", 3,
getNumberOfRows(keyPrefix1, value2, table));
System.out.println("Checking values for key: " + keyPrefix2);
assertEquals("Got back incorrect number of rows from scan", 3,
getNumberOfRows(keyPrefix2, value2, table));
System.out.println("Checking values for key: " + keyPrefix3);
assertEquals("Got back incorrect number of rows from scan", 3,
getNumberOfRows(keyPrefix3, value2, table));
deleteColumns(ht, value2, keyPrefix1);
deleteColumns(ht, value2, keyPrefix2);
deleteColumns(ht, value2, keyPrefix3);
System.out.println("Starting important checks.....");
assertEquals("Got back incorrect number of rows from scan: " + keyPrefix1, 0,
getNumberOfRows(keyPrefix1, value2, table));
assertEquals("Got back incorrect number of rows from scan: " + keyPrefix2, 0,
getNumberOfRows(keyPrefix2, value2, table));
assertEquals("Got back incorrect number of rows from scan: " + keyPrefix3, 0,
getNumberOfRows(keyPrefix3, value2, table));
}
}
}
/**
* Test filters when multiple regions. It does counts. Needs eye-balling of
* logs to ensure that we're not scanning more regions that we're supposed to.
* Related to the TestFilterAcrossRegions over in the o.a.h.h.filter package.
*/
@Test public void testFilterAcrossMultipleRegions() throws IOException {
final TableName tableName = name.getTableName();
try (Table t = TEST_UTIL.createTable(tableName, FAMILY)) {
int rowCount = TEST_UTIL.loadTable(t, FAMILY, false);
assertRowCount(t, rowCount);
// Split the table. Should split on a reasonable key; 'lqj'
List<HRegionLocation> regions = splitTable(t);
assertRowCount(t, rowCount);
// Get end key of first region.
byte[] endKey = regions.get(0).getRegion().getEndKey();
// Count rows with a filter that stops us before passed 'endKey'.
// Should be count of rows in first region.
int endKeyCount = countRows(t, createScanWithRowFilter(endKey));
assertTrue(endKeyCount < rowCount);
// How do I know I did not got to second region? Thats tough. Can't really
// do that in client-side region test. I verified by tracing in debugger.
// I changed the messages that come out when set to DEBUG so should see
// when scanner is done. Says "Finished with scanning..." with region name.
// Check that its finished in right region.
// New test. Make it so scan goes into next region by one and then two.
// Make sure count comes out right.
byte[] key = new byte[] { endKey[0], endKey[1], (byte) (endKey[2] + 1) };
int plusOneCount = countRows(t, createScanWithRowFilter(key));
assertEquals(endKeyCount + 1, plusOneCount);
key = new byte[] { endKey[0], endKey[1], (byte) (endKey[2] + 2) };
int plusTwoCount = countRows(t, createScanWithRowFilter(key));
assertEquals(endKeyCount + 2, plusTwoCount);
// New test. Make it so I scan one less than endkey.
key = new byte[] { endKey[0], endKey[1], (byte) (endKey[2] - 1) };
int minusOneCount = countRows(t, createScanWithRowFilter(key));
assertEquals(endKeyCount - 1, minusOneCount);
// For above test... study logs. Make sure we do "Finished with scanning.."
// in first region and that we do not fall into the next region.
key = new byte[] { 'a', 'a', 'a' };
int countBBB = countRows(t, createScanWithRowFilter(key, null, CompareOperator.EQUAL));
assertEquals(1, countBBB);
int countGreater =
countRows(t, createScanWithRowFilter(endKey, null, CompareOperator.GREATER_OR_EQUAL));
// Because started at start of table.
assertEquals(0, countGreater);
countGreater =
countRows(t, createScanWithRowFilter(endKey, endKey, CompareOperator.GREATER_OR_EQUAL));
assertEquals(rowCount - endKeyCount, countGreater);
}
}
@Test public void testSuperSimple() throws Exception {
final TableName tableName = name.getTableName();
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
Put put = new Put(ROW);
put.addColumn(FAMILY, QUALIFIER, VALUE);
ht.put(put);
Scan scan = new Scan();
scan.addColumn(FAMILY, tableName.toBytes());
ResultScanner scanner = ht.getScanner(scan);
Result result = scanner.next();
assertNull("Expected null result", result);
scanner.close();
}
}
@Test public void testMaxKeyValueSize() throws Exception {
final TableName tableName = name.getTableName();
Configuration conf = TEST_UTIL.getConfiguration();
String oldMaxSize = conf.get(ConnectionConfiguration.MAX_KEYVALUE_SIZE_KEY);
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
byte[] value = new byte[4 * 1024 * 1024];
Put put = new Put(ROW);
put.addColumn(FAMILY, QUALIFIER, value);
ht.put(put);
try {
TEST_UTIL.getConfiguration().setInt(ConnectionConfiguration.MAX_KEYVALUE_SIZE_KEY,
2 * 1024 * 1024);
// Create new table so we pick up the change in Configuration.
try (Connection connection =
ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) {
try (Table t = connection.getTable(TableName.valueOf(FAMILY))) {
put = new Put(ROW);
put.addColumn(FAMILY, QUALIFIER, value);
t.put(put);
}
}
fail("Inserting a too large KeyValue worked, should throw exception");
} catch (Exception ignored) {
}
}
conf.set(ConnectionConfiguration.MAX_KEYVALUE_SIZE_KEY, oldMaxSize);
}
@Test public void testFilters() throws Exception {
final TableName tableName = name.getTableName();
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
byte[][] ROWS = makeN(ROW, 10);
byte[][] QUALIFIERS =
{ Bytes.toBytes("col0-<d2v1>-<d3v2>"), Bytes.toBytes("col1-<d2v1>-<d3v2>"),
Bytes.toBytes("col2-<d2v1>-<d3v2>"), Bytes.toBytes("col3-<d2v1>-<d3v2>"),
Bytes.toBytes("col4-<d2v1>-<d3v2>"), Bytes.toBytes("col5-<d2v1>-<d3v2>"),
Bytes.toBytes("col6-<d2v1>-<d3v2>"), Bytes.toBytes("col7-<d2v1>-<d3v2>"),
Bytes.toBytes("col8-<d2v1>-<d3v2>"), Bytes.toBytes("col9-<d2v1>-<d3v2>") };
for (int i = 0; i < 10; i++) {
Put put = new Put(ROWS[i]);
put.setDurability(Durability.SKIP_WAL);
put.addColumn(FAMILY, QUALIFIERS[i], VALUE);
ht.put(put);
}
Scan scan = new Scan();
scan.addFamily(FAMILY);
Filter filter = new QualifierFilter(CompareOperator.EQUAL,
new RegexStringComparator("col[1-5]"));
scan.setFilter(filter);
try (ResultScanner scanner = ht.getScanner(scan)) {
int expectedIndex = 1;
for (Result result : scanner) {
assertEquals(1, result.size());
assertTrue(Bytes.equals(CellUtil.cloneRow(result.rawCells()[0]), ROWS[expectedIndex]));
assertTrue(Bytes.equals(CellUtil.cloneQualifier(result.rawCells()[0]),
QUALIFIERS[expectedIndex]));
expectedIndex++;
}
assertEquals(6, expectedIndex);
}
}
}
@Test public void testFilterWithLongCompartor() throws Exception {
final TableName tableName = name.getTableName();
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
byte[][] ROWS = makeN(ROW, 10);
byte[][] values = new byte[10][];
for (int i = 0; i < 10; i++) {
values[i] = Bytes.toBytes(100L * i);
}
for (int i = 0; i < 10; i++) {
Put put = new Put(ROWS[i]);
put.setDurability(Durability.SKIP_WAL);
put.addColumn(FAMILY, QUALIFIER, values[i]);
ht.put(put);
}
Scan scan = new Scan();
scan.addFamily(FAMILY);
Filter filter = new SingleColumnValueFilter(FAMILY, QUALIFIER, CompareOperator.GREATER,
new LongComparator(500));
scan.setFilter(filter);
try (ResultScanner scanner = ht.getScanner(scan)) {
int expectedIndex = 0;
for (Result result : scanner) {
assertEquals(1, result.size());
assertTrue(Bytes.toLong(result.getValue(FAMILY, QUALIFIER)) > 500);
expectedIndex++;
}
assertEquals(4, expectedIndex);
}
}
}
@Test public void testKeyOnlyFilter() throws Exception {
final TableName tableName = name.getTableName();
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
byte[][] ROWS = makeN(ROW, 10);
byte[][] QUALIFIERS =
{ Bytes.toBytes("col0-<d2v1>-<d3v2>"), Bytes.toBytes("col1-<d2v1>-<d3v2>"),
Bytes.toBytes("col2-<d2v1>-<d3v2>"), Bytes.toBytes("col3-<d2v1>-<d3v2>"),
Bytes.toBytes("col4-<d2v1>-<d3v2>"), Bytes.toBytes("col5-<d2v1>-<d3v2>"),
Bytes.toBytes("col6-<d2v1>-<d3v2>"), Bytes.toBytes("col7-<d2v1>-<d3v2>"),
Bytes.toBytes("col8-<d2v1>-<d3v2>"), Bytes.toBytes("col9-<d2v1>-<d3v2>") };
for (int i = 0; i < 10; i++) {
Put put = new Put(ROWS[i]);
put.setDurability(Durability.SKIP_WAL);
put.addColumn(FAMILY, QUALIFIERS[i], VALUE);
ht.put(put);
}
Scan scan = new Scan();
scan.addFamily(FAMILY);
Filter filter = new KeyOnlyFilter(true);
scan.setFilter(filter);
try (ResultScanner scanner = ht.getScanner(scan)) {
int count = 0;
for (Result result : scanner) {
assertEquals(1, result.size());
assertEquals(Bytes.SIZEOF_INT, result.rawCells()[0].getValueLength());
assertEquals(VALUE.length, Bytes.toInt(CellUtil.cloneValue(result.rawCells()[0])));
count++;
}
assertEquals(10, count);
}
}
}
/**
* Test simple table and non-existent row cases.
*/
@Test public void testSimpleMissing() throws Exception {
final TableName tableName = name.getTableName();
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
byte[][] ROWS = makeN(ROW, 4);
// Try to get a row on an empty table
Get get = new Get(ROWS[0]);
Result result = ht.get(get);
assertEmptyResult(result);
get = new Get(ROWS[0]);
get.addFamily(FAMILY);
result = ht.get(get);
assertEmptyResult(result);
get = new Get(ROWS[0]);
get.addColumn(FAMILY, QUALIFIER);
result = ht.get(get);
assertEmptyResult(result);
Scan scan = new Scan();
result = getSingleScanResult(ht, scan);
assertNullResult(result);
scan = new Scan().withStartRow(ROWS[0]);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
scan = new Scan().withStartRow(ROWS[0]).withStopRow(ROWS[1]);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
scan = new Scan();
scan.addFamily(FAMILY);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
scan = new Scan();
scan.addColumn(FAMILY, QUALIFIER);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
// Insert a row
Put put = new Put(ROWS[2]);
put.addColumn(FAMILY, QUALIFIER, VALUE);
ht.put(put);
// Try to get empty rows around it
get = new Get(ROWS[1]);
result = ht.get(get);
assertEmptyResult(result);
get = new Get(ROWS[0]);
get.addFamily(FAMILY);
result = ht.get(get);
assertEmptyResult(result);
get = new Get(ROWS[3]);
get.addColumn(FAMILY, QUALIFIER);
result = ht.get(get);
assertEmptyResult(result);
// Try to scan empty rows around it
scan = new Scan().withStartRow(ROWS[3]);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
scan = new Scan().withStartRow(ROWS[0]).withStopRow(ROWS[2]);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
// Make sure we can actually get the row
get = new Get(ROWS[2]);
result = ht.get(get);
assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE);
get = new Get(ROWS[2]);
get.addFamily(FAMILY);
result = ht.get(get);
assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE);
get = new Get(ROWS[2]);
get.addColumn(FAMILY, QUALIFIER);
result = ht.get(get);
assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE);
// Make sure we can scan the row
scan = new Scan();
result = getSingleScanResult(ht, scan);
assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE);
scan = new Scan().withStartRow(ROWS[0]).withStopRow(ROWS[3]);
result = getSingleScanResult(ht, scan);
assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE);
scan = new Scan().withStartRow(ROWS[2]).withStopRow(ROWS[3]);
result = getSingleScanResult(ht, scan);
assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE);
}
}
/**
* Test basic puts, gets, scans, and deletes for a single row
* in a multiple family table.
*/
@SuppressWarnings("checkstyle:MethodLength")
@Test
public void testSingleRowMultipleFamily() throws Exception {
final TableName tableName = name.getTableName();
byte[][] ROWS = makeN(ROW, 3);
byte[][] FAMILIES = makeNAscii(FAMILY, 10);
byte[][] QUALIFIERS = makeN(QUALIFIER, 10);
byte[][] VALUES = makeN(VALUE, 10);
try (Table ht = TEST_UTIL.createTable(tableName, FAMILIES)) {
////////////////////////////////////////////////////////////////////////////
// Insert one column to one family
////////////////////////////////////////////////////////////////////////////
Put put = new Put(ROWS[0]);
put.addColumn(FAMILIES[4], QUALIFIERS[0], VALUES[0]);
ht.put(put);
// Get the single column
getVerifySingleColumn(ht, ROWS, 0, FAMILIES, 4, QUALIFIERS, 0, VALUES, 0);
// Scan the single column
scanVerifySingleColumn(ht, ROWS, 0, FAMILIES, 4, QUALIFIERS, 0, VALUES, 0);
// Get empty results around inserted column
getVerifySingleEmpty(ht, ROWS, 0, FAMILIES, 4, QUALIFIERS, 0);
// Scan empty results around inserted column
scanVerifySingleEmpty(ht, ROWS, 0, FAMILIES, 4, QUALIFIERS, 0);
////////////////////////////////////////////////////////////////////////////
// Flush memstore and run same tests from storefiles
////////////////////////////////////////////////////////////////////////////
TEST_UTIL.flush();
// Redo get and scan tests from storefile
getVerifySingleColumn(ht, ROWS, 0, FAMILIES, 4, QUALIFIERS, 0, VALUES, 0);
scanVerifySingleColumn(ht, ROWS, 0, FAMILIES, 4, QUALIFIERS, 0, VALUES, 0);
getVerifySingleEmpty(ht, ROWS, 0, FAMILIES, 4, QUALIFIERS, 0);
scanVerifySingleEmpty(ht, ROWS, 0, FAMILIES, 4, QUALIFIERS, 0);
////////////////////////////////////////////////////////////////////////////
// Now, Test reading from memstore and storefiles at once
////////////////////////////////////////////////////////////////////////////
// Insert multiple columns to two other families
put = new Put(ROWS[0]);
put.addColumn(FAMILIES[2], QUALIFIERS[2], VALUES[2]);
put.addColumn(FAMILIES[2], QUALIFIERS[4], VALUES[4]);
put.addColumn(FAMILIES[4], QUALIFIERS[4], VALUES[4]);
put.addColumn(FAMILIES[6], QUALIFIERS[6], VALUES[6]);
put.addColumn(FAMILIES[6], QUALIFIERS[7], VALUES[7]);
put.addColumn(FAMILIES[7], QUALIFIERS[7], VALUES[7]);
put.addColumn(FAMILIES[9], QUALIFIERS[0], VALUES[0]);
ht.put(put);
// Get multiple columns across multiple families and get empties around it
singleRowGetTest(ht, ROWS, FAMILIES, QUALIFIERS, VALUES);
// Scan multiple columns across multiple families and scan empties around it
singleRowScanTest(ht, ROWS, FAMILIES, QUALIFIERS, VALUES);
////////////////////////////////////////////////////////////////////////////
// Flush the table again
////////////////////////////////////////////////////////////////////////////
TEST_UTIL.flush();
// Redo tests again
singleRowGetTest(ht, ROWS, FAMILIES, QUALIFIERS, VALUES);
singleRowScanTest(ht, ROWS, FAMILIES, QUALIFIERS, VALUES);
// Insert more data to memstore
put = new Put(ROWS[0]);
put.addColumn(FAMILIES[6], QUALIFIERS[5], VALUES[5]);
put.addColumn(FAMILIES[6], QUALIFIERS[8], VALUES[8]);
put.addColumn(FAMILIES[6], QUALIFIERS[9], VALUES[9]);
put.addColumn(FAMILIES[4], QUALIFIERS[3], VALUES[3]);
ht.put(put);
////////////////////////////////////////////////////////////////////////////
// Delete a storefile column
////////////////////////////////////////////////////////////////////////////
Delete delete = new Delete(ROWS[0]);
delete.addColumns(FAMILIES[6], QUALIFIERS[7]);
ht.delete(delete);
// Try to get deleted column
Get get = new Get(ROWS[0]);
get.addColumn(FAMILIES[6], QUALIFIERS[7]);
Result result = ht.get(get);
assertEmptyResult(result);
// Try to scan deleted column
Scan scan = new Scan();
scan.addColumn(FAMILIES[6], QUALIFIERS[7]);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
// Make sure we can still get a column before it and after it
get = new Get(ROWS[0]);
get.addColumn(FAMILIES[6], QUALIFIERS[6]);
result = ht.get(get);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[6], VALUES[6]);
get = new Get(ROWS[0]);
get.addColumn(FAMILIES[6], QUALIFIERS[8]);
result = ht.get(get);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[8], VALUES[8]);
// Make sure we can still scan a column before it and after it
scan = new Scan();
scan.addColumn(FAMILIES[6], QUALIFIERS[6]);
result = getSingleScanResult(ht, scan);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[6], VALUES[6]);
scan = new Scan();
scan.addColumn(FAMILIES[6], QUALIFIERS[8]);
result = getSingleScanResult(ht, scan);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[8], VALUES[8]);
////////////////////////////////////////////////////////////////////////////
// Delete a memstore column
////////////////////////////////////////////////////////////////////////////
delete = new Delete(ROWS[0]);
delete.addColumns(FAMILIES[6], QUALIFIERS[8]);
ht.delete(delete);
// Try to get deleted column
get = new Get(ROWS[0]);
get.addColumn(FAMILIES[6], QUALIFIERS[8]);
result = ht.get(get);
assertEmptyResult(result);
// Try to scan deleted column
scan = new Scan();
scan.addColumn(FAMILIES[6], QUALIFIERS[8]);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
// Make sure we can still get a column before it and after it
get = new Get(ROWS[0]);
get.addColumn(FAMILIES[6], QUALIFIERS[6]);
result = ht.get(get);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[6], VALUES[6]);
get = new Get(ROWS[0]);
get.addColumn(FAMILIES[6], QUALIFIERS[9]);
result = ht.get(get);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[9], VALUES[9]);
// Make sure we can still scan a column before it and after it
scan = new Scan();
scan.addColumn(FAMILIES[6], QUALIFIERS[6]);
result = getSingleScanResult(ht, scan);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[6], VALUES[6]);
scan = new Scan();
scan.addColumn(FAMILIES[6], QUALIFIERS[9]);
result = getSingleScanResult(ht, scan);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[9], VALUES[9]);
////////////////////////////////////////////////////////////////////////////
// Delete joint storefile/memstore family
////////////////////////////////////////////////////////////////////////////
delete = new Delete(ROWS[0]);
delete.addFamily(FAMILIES[4]);
ht.delete(delete);
// Try to get storefile column in deleted family
get = new Get(ROWS[0]);
get.addColumn(FAMILIES[4], QUALIFIERS[4]);
result = ht.get(get);
assertEmptyResult(result);
// Try to get memstore column in deleted family
get = new Get(ROWS[0]);
get.addColumn(FAMILIES[4], QUALIFIERS[3]);
result = ht.get(get);
assertEmptyResult(result);
// Try to get deleted family
get = new Get(ROWS[0]);
get.addFamily(FAMILIES[4]);
result = ht.get(get);
assertEmptyResult(result);
// Try to scan storefile column in deleted family
scan = new Scan();
scan.addColumn(FAMILIES[4], QUALIFIERS[4]);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
// Try to scan memstore column in deleted family
scan = new Scan();
scan.addColumn(FAMILIES[4], QUALIFIERS[3]);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
// Try to scan deleted family
scan = new Scan();
scan.addFamily(FAMILIES[4]);
result = getSingleScanResult(ht, scan);
assertNullResult(result);
// Make sure we can still get another family
get = new Get(ROWS[0]);
get.addColumn(FAMILIES[2], QUALIFIERS[2]);
result = ht.get(get);
assertSingleResult(result, ROWS[0], FAMILIES[2], QUALIFIERS[2], VALUES[2]);
get = new Get(ROWS[0]);
get.addColumn(FAMILIES[6], QUALIFIERS[9]);
result = ht.get(get);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[9], VALUES[9]);
// Make sure we can still scan another family
scan = new Scan();
scan.addColumn(FAMILIES[6], QUALIFIERS[6]);
result = getSingleScanResult(ht, scan);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[6], VALUES[6]);
scan = new Scan();
scan.addColumn(FAMILIES[6], QUALIFIERS[9]);
result = getSingleScanResult(ht, scan);
assertSingleResult(result, ROWS[0], FAMILIES[6], QUALIFIERS[9], VALUES[9]);
////////////////////////////////////////////////////////////////////////////
// Flush everything and rerun delete tests
////////////////////////////////////////////////////////////////////////////
TEST_UTIL.flush();
// Try to get storefile column in deleted family
assertEmptyResult(ht.get(new Get(ROWS[0]).addColumn(FAMILIES[4], QUALIFIERS[4])));
// Try to get memstore column in deleted family
assertEmptyResult(ht.get(new Get(ROWS[0]).addColumn(FAMILIES[4], QUALIFIERS[3])));
// Try to get deleted family
assertEmptyResult(ht.get(new Get(ROWS[0]).addFamily(FAMILIES[4])));
// Try to scan storefile column in deleted family
assertNullResult(getSingleScanResult(ht, new Scan().addColumn(FAMILIES[4], QUALIFIERS[4])));
// Try to scan memstore column in deleted family
assertNullResult(getSingleScanResult(ht, new Scan().addColumn(FAMILIES[4], QUALIFIERS[3])));
// Try to scan deleted family
assertNullResult(getSingleScanResult(ht, new Scan().addFamily(FAMILIES[4])));
// Make sure we can still get another family
assertSingleResult(ht.get(new Get(ROWS[0]).addColumn(FAMILIES[2], QUALIFIERS[2])),
ROWS[0], FAMILIES[2], QUALIFIERS[2], VALUES[2]);
assertSingleResult(ht.get(new Get(ROWS[0]).addColumn(FAMILIES[6], QUALIFIERS[9])),
ROWS[0], FAMILIES[6], QUALIFIERS[9], VALUES[9]);
// Make sure we can still scan another family
assertSingleResult(getSingleScanResult(ht, new Scan().addColumn(FAMILIES[6], QUALIFIERS[6])),
ROWS[0], FAMILIES[6], QUALIFIERS[6], VALUES[6]);
assertSingleResult(getSingleScanResult(ht, new Scan().addColumn(FAMILIES[6], QUALIFIERS[9])),
ROWS[0], FAMILIES[6], QUALIFIERS[9], VALUES[9]);
}
}
@Test(expected = NullPointerException.class) public void testNullTableName() throws IOException {
// Null table name (should NOT work)
TEST_UTIL.createTable(null, FAMILY);
fail("Creating a table with null name passed, should have failed");
}
@Test(expected = IllegalArgumentException.class) public void testNullFamilyName()
throws IOException {
final TableName tableName = name.getTableName();
// Null family (should NOT work)
TEST_UTIL.createTable(tableName, new byte[][] { null });
fail("Creating a table with a null family passed, should fail");
}
@Test public void testNullRowAndQualifier() throws Exception {
final TableName tableName = name.getTableName();
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
// Null row (should NOT work)
try {
Put put = new Put((byte[]) null);
put.addColumn(FAMILY, QUALIFIER, VALUE);
ht.put(put);
fail("Inserting a null row worked, should throw exception");
} catch (Exception ignored) {
}
// Null qualifier (should work)
{
Put put = new Put(ROW);
put.addColumn(FAMILY, null, VALUE);
ht.put(put);
getTestNull(ht, ROW, FAMILY, VALUE);
scanTestNull(ht, ROW, FAMILY, VALUE);
Delete delete = new Delete(ROW);
delete.addColumns(FAMILY, null);
ht.delete(delete);
Get get = new Get(ROW);
Result result = ht.get(get);
assertEmptyResult(result);
}
}
}
@Test public void testNullEmptyQualifier() throws Exception {
final TableName tableName = name.getTableName();
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
// Empty qualifier, byte[0] instead of null (should work)
try {
Put put = new Put(ROW);
put.addColumn(FAMILY, HConstants.EMPTY_BYTE_ARRAY, VALUE);
ht.put(put);
getTestNull(ht, ROW, FAMILY, VALUE);
scanTestNull(ht, ROW, FAMILY, VALUE);
// Flush and try again
TEST_UTIL.flush();
getTestNull(ht, ROW, FAMILY, VALUE);
scanTestNull(ht, ROW, FAMILY, VALUE);
Delete delete = new Delete(ROW);
delete.addColumns(FAMILY, HConstants.EMPTY_BYTE_ARRAY);
ht.delete(delete);
Get get = new Get(ROW);
Result result = ht.get(get);
assertEmptyResult(result);
} catch (Exception e) {
throw new IOException("Using a row with null qualifier should not throw exception");
}
}
}
@Test public void testNullValue() throws IOException {
final TableName tableName = name.getTableName();
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
// Null value
try {
Put put = new Put(ROW);
put.addColumn(FAMILY, QUALIFIER, null);
ht.put(put);
Get get = new Get(ROW);
get.addColumn(FAMILY, QUALIFIER);
Result result = ht.get(get);
assertSingleResult(result, ROW, FAMILY, QUALIFIER, null);
Scan scan = new Scan();
scan.addColumn(FAMILY, QUALIFIER);
result = getSingleScanResult(ht, scan);
assertSingleResult(result, ROW, FAMILY, QUALIFIER, null);
Delete delete = new Delete(ROW);
delete.addColumns(FAMILY, QUALIFIER);
ht.delete(delete);
get = new Get(ROW);
result = ht.get(get);
assertEmptyResult(result);
} catch (Exception e) {
throw new IOException("Null values should be allowed, but threw exception");
}
}
}
@Test public void testNullQualifier() throws Exception {
final TableName tableName = name.getTableName();
try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) {
// Work for Put
Put put = new Put(ROW);
put.addColumn(FAMILY, null, VALUE);
table.put(put);
// Work for Get, Scan
getTestNull(table, ROW, FAMILY, VALUE);
scanTestNull(table, ROW, FAMILY, VALUE);
// Work for Delete
Delete delete = new Delete(ROW);
delete.addColumns(FAMILY, null);
table.delete(delete);
Get get = new Get(ROW);
Result result = table.get(get);
assertEmptyResult(result);
// Work for Increment/Append
Increment increment = new Increment(ROW);
increment.addColumn(FAMILY, null, 1L);
table.increment(increment);
getTestNull(table, ROW, FAMILY, 1L);
table.incrementColumnValue(ROW, FAMILY, null, 1L);
getTestNull(table, ROW, FAMILY, 2L);
delete = new Delete(ROW);
delete.addColumns(FAMILY, null);
table.delete(delete);
Append append = new Append(ROW);
append.addColumn(FAMILY, null, VALUE);
table.append(append);
getTestNull(table, ROW, FAMILY, VALUE);
// Work for checkAndMutate using thenPut, thenMutate and thenDelete
put = new Put(ROW);
put.addColumn(FAMILY, null, Bytes.toBytes("checkAndPut"));
table.put(put);
table.checkAndMutate(ROW, FAMILY).ifEquals(VALUE).thenPut(put);
RowMutations mutate = new RowMutations(ROW);
mutate.add(new Put(ROW).addColumn(FAMILY, null, Bytes.toBytes("checkAndMutate")));
table.checkAndMutate(ROW, FAMILY).ifEquals(Bytes.toBytes("checkAndPut")).thenMutate(mutate);
delete = new Delete(ROW);
delete.addColumns(FAMILY, null);
table.checkAndMutate(ROW, FAMILY).
ifEquals(Bytes.toBytes("checkAndMutate")).thenDelete(delete);
}
}
@Test
@SuppressWarnings("checkstyle:MethodLength")
public void testVersions() throws Exception {
final TableName tableName = name.getTableName();
long[] STAMPS = makeStamps(20);
byte[][] VALUES = makeNAscii(VALUE, 20);
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 10)) {
// Insert 4 versions of same column
Put put = new Put(ROW);
put.addColumn(FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
put.addColumn(FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
put.addColumn(FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
put.addColumn(FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
ht.put(put);
// Verify we can get each one properly
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
// Verify we don't accidentally get others
getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[3]);
getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[6]);
scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[3]);
scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[6]);
// Ensure maxVersions in query is respected
Get get = new Get(ROW);
get.addColumn(FAMILY, QUALIFIER);
get.readVersions(2);
Result result = ht.get(get);
assertNResult(result, ROW, FAMILY, QUALIFIER, new long[] { STAMPS[4], STAMPS[5] },
new byte[][] { VALUES[4], VALUES[5] }, 0, 1);
Scan scan = new Scan().withStartRow(ROW);
scan.addColumn(FAMILY, QUALIFIER);
scan.readVersions(2);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILY, QUALIFIER, new long[] { STAMPS[4], STAMPS[5] },
new byte[][] { VALUES[4], VALUES[5] }, 0, 1);
// Flush and redo
TEST_UTIL.flush();
// Verify we can get each one properly
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[5], VALUES[5]);
// Verify we don't accidentally get others
getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[3]);
getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[6]);
scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[3]);
scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[6]);
// Ensure maxVersions in query is respected
get = new Get(ROW);
get.addColumn(FAMILY, QUALIFIER);
get.readVersions(2);
result = ht.get(get);
assertNResult(result, ROW, FAMILY, QUALIFIER, new long[] { STAMPS[4], STAMPS[5] },
new byte[][] { VALUES[4], VALUES[5] }, 0, 1);
scan = new Scan().withStartRow(ROW);
scan.addColumn(FAMILY, QUALIFIER);
scan.readVersions(2);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILY, QUALIFIER, new long[] { STAMPS[4], STAMPS[5] },
new byte[][] { VALUES[4], VALUES[5] }, 0, 1);
// Add some memstore and retest
// Insert 4 more versions of same column and a dupe
put = new Put(ROW);
put.addColumn(FAMILY, QUALIFIER, STAMPS[3], VALUES[3]);
put.addColumn(FAMILY, QUALIFIER, STAMPS[6], VALUES[6]);
put.addColumn(FAMILY, QUALIFIER, STAMPS[7], VALUES[7]);
put.addColumn(FAMILY, QUALIFIER, STAMPS[8], VALUES[8]);
ht.put(put);
// Ensure maxVersions in query is respected
get = new Get(ROW);
get.addColumn(FAMILY, QUALIFIER);
get.readAllVersions();
result = ht.get(get);
assertNResult(result, ROW, FAMILY, QUALIFIER,
new long[] { STAMPS[1], STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7],
STAMPS[8] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3], VALUES[4], VALUES[5], VALUES[6], VALUES[7],
VALUES[8] }, 0, 7);
scan = new Scan().withStartRow(ROW);
scan.addColumn(FAMILY, QUALIFIER);
scan.readAllVersions();
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILY, QUALIFIER,
new long[] { STAMPS[1], STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7],
STAMPS[8] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3], VALUES[4], VALUES[5], VALUES[6], VALUES[7],
VALUES[8] }, 0, 7);
get = new Get(ROW);
get.readAllVersions();
result = ht.get(get);
assertNResult(result, ROW, FAMILY, QUALIFIER,
new long[] { STAMPS[1], STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7],
STAMPS[8] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3], VALUES[4], VALUES[5], VALUES[6], VALUES[7],
VALUES[8] }, 0, 7);
scan = new Scan().withStartRow(ROW);
scan.readAllVersions();
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILY, QUALIFIER,
new long[] { STAMPS[1], STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7],
STAMPS[8] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3], VALUES[4], VALUES[5], VALUES[6], VALUES[7],
VALUES[8] }, 0, 7);
// Verify we can get each one properly
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
getVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[7], VALUES[7]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[1], VALUES[1]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[2], VALUES[2]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[4], VALUES[4]);
scanVersionAndVerify(ht, ROW, FAMILY, QUALIFIER, STAMPS[7], VALUES[7]);
// Verify we don't accidentally get others
getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
getVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[9]);
scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[0]);
scanVersionAndVerifyMissing(ht, ROW, FAMILY, QUALIFIER, STAMPS[9]);
// Ensure maxVersions of table is respected
TEST_UTIL.flush();
// Insert 4 more versions of same column and a dupe
put = new Put(ROW);
put.addColumn(FAMILY, QUALIFIER, STAMPS[9], VALUES[9]);
put.addColumn(FAMILY, QUALIFIER, STAMPS[11], VALUES[11]);
put.addColumn(FAMILY, QUALIFIER, STAMPS[13], VALUES[13]);
put.addColumn(FAMILY, QUALIFIER, STAMPS[15], VALUES[15]);
ht.put(put);
get = new Get(ROW);
get.addColumn(FAMILY, QUALIFIER);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertNResult(result, ROW, FAMILY, QUALIFIER,
new long[] { STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7], STAMPS[8], STAMPS[9],
STAMPS[11], STAMPS[13], STAMPS[15] },
new byte[][] { VALUES[3], VALUES[4], VALUES[5], VALUES[6], VALUES[7], VALUES[8], VALUES[9],
VALUES[11], VALUES[13], VALUES[15] }, 0, 9);
scan = new Scan().withStartRow(ROW);
scan.addColumn(FAMILY, QUALIFIER);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILY, QUALIFIER,
new long[] { STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[7], STAMPS[8], STAMPS[9],
STAMPS[11], STAMPS[13], STAMPS[15] },
new byte[][] { VALUES[3], VALUES[4], VALUES[5], VALUES[6], VALUES[7], VALUES[8], VALUES[9],
VALUES[11], VALUES[13], VALUES[15] }, 0, 9);
// Delete a version in the memstore and a version in a storefile
Delete delete = new Delete(ROW);
delete.addColumn(FAMILY, QUALIFIER, STAMPS[11]);
delete.addColumn(FAMILY, QUALIFIER, STAMPS[7]);
ht.delete(delete);
// Test that it's gone
get = new Get(ROW);
get.addColumn(FAMILY, QUALIFIER);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertNResult(result, ROW, FAMILY, QUALIFIER,
new long[] { STAMPS[1], STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[8],
STAMPS[9], STAMPS[13], STAMPS[15] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3], VALUES[4], VALUES[5], VALUES[6], VALUES[8],
VALUES[9], VALUES[13], VALUES[15] }, 0, 9);
scan = new Scan().withStartRow(ROW);
scan.addColumn(FAMILY, QUALIFIER);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILY, QUALIFIER,
new long[] { STAMPS[1], STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6], STAMPS[8],
STAMPS[9], STAMPS[13], STAMPS[15] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3], VALUES[4], VALUES[5], VALUES[6], VALUES[8],
VALUES[9], VALUES[13], VALUES[15] }, 0, 9);
}
}
@Test @SuppressWarnings("checkstyle:MethodLength") public void testVersionLimits()
throws Exception {
final TableName tableName = name.getTableName();
byte[][] FAMILIES = makeNAscii(FAMILY, 3);
int[] LIMITS = { 1, 3, 5 };
long[] STAMPS = makeStamps(10);
byte[][] VALUES = makeNAscii(VALUE, 10);
try (Table ht = TEST_UTIL.createTable(tableName, FAMILIES, LIMITS)) {
// Insert limit + 1 on each family
Put put = new Put(ROW);
put.addColumn(FAMILIES[0], QUALIFIER, STAMPS[0], VALUES[0]);
put.addColumn(FAMILIES[0], QUALIFIER, STAMPS[1], VALUES[1]);
put.addColumn(FAMILIES[1], QUALIFIER, STAMPS[0], VALUES[0]);
put.addColumn(FAMILIES[1], QUALIFIER, STAMPS[1], VALUES[1]);
put.addColumn(FAMILIES[1], QUALIFIER, STAMPS[2], VALUES[2]);
put.addColumn(FAMILIES[1], QUALIFIER, STAMPS[3], VALUES[3]);
put.addColumn(FAMILIES[2], QUALIFIER, STAMPS[0], VALUES[0]);
put.addColumn(FAMILIES[2], QUALIFIER, STAMPS[1], VALUES[1]);
put.addColumn(FAMILIES[2], QUALIFIER, STAMPS[2], VALUES[2]);
put.addColumn(FAMILIES[2], QUALIFIER, STAMPS[3], VALUES[3]);
put.addColumn(FAMILIES[2], QUALIFIER, STAMPS[4], VALUES[4]);
put.addColumn(FAMILIES[2], QUALIFIER, STAMPS[5], VALUES[5]);
put.addColumn(FAMILIES[2], QUALIFIER, STAMPS[6], VALUES[6]);
ht.put(put);
// Verify we only get the right number out of each
// Family0
Get get = new Get(ROW);
get.addColumn(FAMILIES[0], QUALIFIER);
get.readVersions(Integer.MAX_VALUE);
Result result = ht.get(get);
assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[] { STAMPS[1] },
new byte[][] { VALUES[1] }, 0, 0);
get = new Get(ROW);
get.addFamily(FAMILIES[0]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[] { STAMPS[1] },
new byte[][] { VALUES[1] }, 0, 0);
Scan scan = new Scan().withStartRow(ROW);
scan.addColumn(FAMILIES[0], QUALIFIER);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[] { STAMPS[1] },
new byte[][] { VALUES[1] }, 0, 0);
scan = new Scan().withStartRow(ROW);
scan.addFamily(FAMILIES[0]);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[] { STAMPS[1] },
new byte[][] { VALUES[1] }, 0, 0);
// Family1
get = new Get(ROW);
get.addColumn(FAMILIES[1], QUALIFIER);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertNResult(result, ROW, FAMILIES[1], QUALIFIER,
new long[] { STAMPS[1], STAMPS[2], STAMPS[3] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3] }, 0, 2);
get = new Get(ROW);
get.addFamily(FAMILIES[1]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertNResult(result, ROW, FAMILIES[1], QUALIFIER,
new long[] { STAMPS[1], STAMPS[2], STAMPS[3] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3] }, 0, 2);
scan = new Scan().withStartRow(ROW);
scan.addColumn(FAMILIES[1], QUALIFIER);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILIES[1], QUALIFIER,
new long[] { STAMPS[1], STAMPS[2], STAMPS[3] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3] }, 0, 2);
scan = new Scan().withStartRow(ROW);
scan.addFamily(FAMILIES[1]);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILIES[1], QUALIFIER,
new long[] { STAMPS[1], STAMPS[2], STAMPS[3] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3] }, 0, 2);
// Family2
get = new Get(ROW);
get.addColumn(FAMILIES[2], QUALIFIER);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertNResult(result, ROW, FAMILIES[2], QUALIFIER,
new long[] { STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6] },
new byte[][] { VALUES[2], VALUES[3], VALUES[4], VALUES[5], VALUES[6] }, 0, 4);
get = new Get(ROW);
get.addFamily(FAMILIES[2]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertNResult(result, ROW, FAMILIES[2], QUALIFIER,
new long[] { STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6] },
new byte[][] { VALUES[2], VALUES[3], VALUES[4], VALUES[5], VALUES[6] }, 0, 4);
scan = new Scan().withStartRow(ROW);
scan.addColumn(FAMILIES[2], QUALIFIER);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILIES[2], QUALIFIER,
new long[] { STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6] },
new byte[][] { VALUES[2], VALUES[3], VALUES[4], VALUES[5], VALUES[6] }, 0, 4);
scan = new Scan().withStartRow(ROW);
scan.addFamily(FAMILIES[2]);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILIES[2], QUALIFIER,
new long[] { STAMPS[2], STAMPS[3], STAMPS[4], STAMPS[5], STAMPS[6] },
new byte[][] { VALUES[2], VALUES[3], VALUES[4], VALUES[5], VALUES[6] }, 0, 4);
// Try all families
get = new Get(ROW);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertEquals("Expected 9 keys but received " + result.size(), 9, result.size());
get = new Get(ROW);
get.addFamily(FAMILIES[0]);
get.addFamily(FAMILIES[1]);
get.addFamily(FAMILIES[2]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertEquals("Expected 9 keys but received " + result.size(), 9, result.size());
get = new Get(ROW);
get.addColumn(FAMILIES[0], QUALIFIER);
get.addColumn(FAMILIES[1], QUALIFIER);
get.addColumn(FAMILIES[2], QUALIFIER);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertEquals("Expected 9 keys but received " + result.size(), 9, result.size());
scan = new Scan().withStartRow(ROW);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertEquals("Expected 9 keys but received " + result.size(), 9, result.size());
scan = new Scan().withStartRow(ROW);
scan.readVersions(Integer.MAX_VALUE);
scan.addFamily(FAMILIES[0]);
scan.addFamily(FAMILIES[1]);
scan.addFamily(FAMILIES[2]);
result = getSingleScanResult(ht, scan);
assertEquals("Expected 9 keys but received " + result.size(), 9, result.size());
scan = new Scan().withStartRow(ROW);
scan.readVersions(Integer.MAX_VALUE);
scan.addColumn(FAMILIES[0], QUALIFIER);
scan.addColumn(FAMILIES[1], QUALIFIER);
scan.addColumn(FAMILIES[2], QUALIFIER);
result = getSingleScanResult(ht, scan);
assertEquals("Expected 9 keys but received " + result.size(), 9, result.size());
}
}
@Test public void testDeleteFamilyVersion() throws Exception {
try (Admin admin = TEST_UTIL.getAdmin()) {
final TableName tableName = name.getTableName();
byte[][] QUALIFIERS = makeNAscii(QUALIFIER, 1);
byte[][] VALUES = makeN(VALUE, 5);
long[] ts = { 1000, 2000, 3000, 4000, 5000 };
try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 5)) {
Put put = new Put(ROW);
for (int q = 0; q < 1; q++) {
for (int t = 0; t < 5; t++) {
put.addColumn(FAMILY, QUALIFIERS[q], ts[t], VALUES[t]);
}
}
ht.put(put);
admin.flush(tableName);
Delete delete = new Delete(ROW);
delete.addFamilyVersion(FAMILY, ts[1]); // delete version '2000'
delete.addFamilyVersion(FAMILY, ts[3]); // delete version '4000'
ht.delete(delete);
admin.flush(tableName);
for (int i = 0; i < 1; i++) {
Get get = new Get(ROW);
get.addColumn(FAMILY, QUALIFIERS[i]);
get.readVersions(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);
}
}
}
}
@Test public void testDeleteFamilyVersionWithOtherDeletes() throws Exception {
final TableName tableName = name.getTableName();
byte[][] QUALIFIERS = makeNAscii(QUALIFIER, 5);
byte[][] VALUES = makeN(VALUE, 5);
long[] ts = { 1000, 2000, 3000, 4000, 5000 };
try (Admin admin = TEST_UTIL.getAdmin(); Table ht = TEST_UTIL.createTable(tableName, FAMILY,
5)) {
Put put;
Result result;
Get get;
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.addColumn(FAMILY, QUALIFIERS[q], ts[t], VALUES[t]);
}
}
ht.put(put);
admin.flush(tableName);
// 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.addColumn(FAMILY, QUALIFIERS[q], ts[t], VALUES[t]);
}
}
ht.put(put);
admin.flush(tableName);
// 3. delete on ROW
delete = new Delete(ROW);
// delete version <= 2000 of all columns
// note: addFamily must be the first since it will mask
// the subsequent other type deletes!
delete.addFamily(FAMILY, ts[1]);
// delete version '4000' of all columns
delete.addFamilyVersion(FAMILY, ts[3]);
// delete version <= 3000 of column 0
delete.addColumns(FAMILY, QUALIFIERS[0], ts[2]);
// delete version <= 5000 of column 2
delete.addColumns(FAMILY, QUALIFIERS[2], ts[4]);
// delete version 5000 of column 4
delete.addColumn(FAMILY, QUALIFIERS[4], ts[4]);
ht.delete(delete);
admin.flush(tableName);
// 4. delete on ROWS[0]
delete = new Delete(ROW2);
delete.addFamilyVersion(FAMILY, ts[1]); // delete version '2000'
delete.addFamilyVersion(FAMILY, ts[3]); // delete version '4000'
ht.delete(delete);
admin.flush(tableName);
// 5. check ROW
get = new Get(ROW);
get.addColumn(FAMILY, QUALIFIERS[0]);
get.readVersions(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.readVersions(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.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertEquals(0, result.size());
get = new Get(ROW);
get.addColumn(FAMILY, QUALIFIERS[3]);
get.readVersions(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.readVersions(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.readVersions(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);
}
}
}
@Test public void testDeleteWithFailed() throws Exception {
final TableName tableName = name.getTableName();
byte[][] FAMILIES = makeNAscii(FAMILY, 3);
byte[][] VALUES = makeN(VALUE, 5);
long[] ts = { 1000, 2000, 3000, 4000, 5000 };
try (Table ht = TEST_UTIL.createTable(tableName, FAMILIES, 3)) {
Put put = new Put(ROW);
put.addColumn(FAMILIES[0], QUALIFIER, ts[0], VALUES[0]);
ht.put(put);
// delete wrong family
Delete delete = new Delete(ROW);
delete.addFamily(FAMILIES[1], ts[0]);
ht.delete(delete);
Get get = new Get(ROW);
get.addFamily(FAMILIES[0]);
get.readAllVersions();
Result result = ht.get(get);
assertTrue(Bytes.equals(result.getValue(FAMILIES[0], QUALIFIER), VALUES[0]));
}
}
@Test
@SuppressWarnings("checkstyle:MethodLength")
public void testDeletes() throws Exception {
final TableName tableName = name.getTableName();
byte[][] ROWS = makeNAscii(ROW, 6);
byte[][] FAMILIES = makeNAscii(FAMILY, 3);
byte[][] VALUES = makeN(VALUE, 5);
long[] ts = { 1000, 2000, 3000, 4000, 5000 };
try (Table ht = TEST_UTIL.createTable(tableName, FAMILIES, 3)) {
Put put = new Put(ROW);
put.addColumn(FAMILIES[0], QUALIFIER, ts[0], VALUES[0]);
put.addColumn(FAMILIES[0], QUALIFIER, ts[1], VALUES[1]);
ht.put(put);
Delete delete = new Delete(ROW);
delete.addFamily(FAMILIES[0], ts[0]);
ht.delete(delete);
Get get = new Get(ROW);
get.addFamily(FAMILIES[0]);
get.readVersions(Integer.MAX_VALUE);
Result result = ht.get(get);
assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[] { ts[1] },
new byte[][] { VALUES[1] }, 0, 0);
Scan scan = new Scan().withStartRow(ROW);
scan.addFamily(FAMILIES[0]);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[] { ts[1] },
new byte[][] { VALUES[1] }, 0, 0);
// Test delete latest version
put = new Put(ROW);
put.addColumn(FAMILIES[0], QUALIFIER, ts[4], VALUES[4]);
put.addColumn(FAMILIES[0], QUALIFIER, ts[2], VALUES[2]);
put.addColumn(FAMILIES[0], QUALIFIER, ts[3], VALUES[3]);
put.addColumn(FAMILIES[0], null, ts[4], VALUES[4]);
put.addColumn(FAMILIES[0], null, ts[2], VALUES[2]);
put.addColumn(FAMILIES[0], null, ts[3], VALUES[3]);
ht.put(put);
delete = new Delete(ROW);
delete.addColumn(FAMILIES[0], QUALIFIER); // ts[4]
ht.delete(delete);
get = new Get(ROW);
get.addColumn(FAMILIES[0], QUALIFIER);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[] { ts[1], ts[2], ts[3] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3] }, 0, 2);
scan = new Scan().withStartRow(ROW);
scan.addColumn(FAMILIES[0], QUALIFIER);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[] { ts[1], ts[2], ts[3] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3] }, 0, 2);
// Test for HBASE-1847
delete = new Delete(ROW);
delete.addColumn(FAMILIES[0], null);
ht.delete(delete);
// Cleanup null qualifier
delete = new Delete(ROW);
delete.addColumns(FAMILIES[0], null);
ht.delete(delete);
// Expected client behavior might be that you can re-put deleted values
// But alas, this is not to be. We can't put them back in either case.
put = new Put(ROW);
put.addColumn(FAMILIES[0], QUALIFIER, ts[0], VALUES[0]); // 1000
put.addColumn(FAMILIES[0], QUALIFIER, ts[4], VALUES[4]); // 5000
ht.put(put);
// It used to be due to the internal implementation of Get, that
// the Get() call would return ts[4] UNLIKE the Scan below. With
// the switch to using Scan for Get this is no longer the case.
get = new Get(ROW);
get.addFamily(FAMILIES[0]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[] { ts[1], ts[2], ts[3] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3] }, 0, 2);
// The Scanner returns the previous values, the expected-naive-unexpected behavior
scan = new Scan().withStartRow(ROW);
scan.addFamily(FAMILIES[0]);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[] { ts[1], ts[2], ts[3] },
new byte[][] { VALUES[1], VALUES[2], VALUES[3] }, 0, 2);
// Test deleting an entire family from one row but not the other various ways
put = new Put(ROWS[0]);
put.addColumn(FAMILIES[1], QUALIFIER, ts[0], VALUES[0]);
put.addColumn(FAMILIES[1], QUALIFIER, ts[1], VALUES[1]);
put.addColumn(FAMILIES[2], QUALIFIER, ts[2], VALUES[2]);
put.addColumn(FAMILIES[2], QUALIFIER, ts[3], VALUES[3]);
ht.put(put);
put = new Put(ROWS[1]);
put.addColumn(FAMILIES[1], QUALIFIER, ts[0], VALUES[0]);
put.addColumn(FAMILIES[1], QUALIFIER, ts[1], VALUES[1]);
put.addColumn(FAMILIES[2], QUALIFIER, ts[2], VALUES[2]);
put.addColumn(FAMILIES[2], QUALIFIER, ts[3], VALUES[3]);
ht.put(put);
put = new Put(ROWS[2]);
put.addColumn(FAMILIES[1], QUALIFIER, ts[0], VALUES[0]);
put.addColumn(FAMILIES[1], QUALIFIER, ts[1], VALUES[1]);
put.addColumn(FAMILIES[2], QUALIFIER, ts[2], VALUES[2]);
put.addColumn(FAMILIES[2], QUALIFIER, ts[3], VALUES[3]);
ht.put(put);
// Assert that above went in.
get = new Get(ROWS[2]);
get.addFamily(FAMILIES[1]);
get.addFamily(FAMILIES[2]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertEquals("Expected 4 key but received " + result.size() + ": " + result, 4,
result.size());
delete = new Delete(ROWS[0]);
delete.addFamily(FAMILIES[2]);
ht.delete(delete);
delete = new Delete(ROWS[1]);
delete.addColumns(FAMILIES[1], QUALIFIER);
ht.delete(delete);
delete = new Delete(ROWS[2]);
delete.addColumn(FAMILIES[1], QUALIFIER);
delete.addColumn(FAMILIES[1], QUALIFIER);
delete.addColumn(FAMILIES[2], QUALIFIER);
ht.delete(delete);
get = new Get(ROWS[0]);
get.addFamily(FAMILIES[1]);
get.addFamily(FAMILIES[2]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertEquals("Expected 2 keys but received " + result.size(), 2, result.size());
assertNResult(result, ROWS[0], FAMILIES[1], QUALIFIER, new long[] { ts[0], ts[1] },
new byte[][] { VALUES[0], VALUES[1] }, 0, 1);
scan = new Scan().withStartRow(ROWS[0]);
scan.addFamily(FAMILIES[1]);
scan.addFamily(FAMILIES[2]);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertEquals("Expected 2 keys but received " + result.size(), 2, result.size());
assertNResult(result, ROWS[0], FAMILIES[1], QUALIFIER, new long[] { ts[0], ts[1] },
new byte[][] { VALUES[0], VALUES[1] }, 0, 1);
get = new Get(ROWS[1]);
get.addFamily(FAMILIES[1]);
get.addFamily(FAMILIES[2]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertEquals("Expected 2 keys but received " + result.size(), 2, result.size());
scan = new Scan().withStartRow(ROWS[1]);
scan.addFamily(FAMILIES[1]);
scan.addFamily(FAMILIES[2]);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertEquals("Expected 2 keys but received " + result.size(), 2, result.size());
get = new Get(ROWS[2]);
get.addFamily(FAMILIES[1]);
get.addFamily(FAMILIES[2]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertEquals(1, result.size());
assertNResult(result, ROWS[2], FAMILIES[2], QUALIFIER, new long[] { ts[2] },
new byte[][] { VALUES[2] }, 0, 0);
scan = new Scan().withStartRow(ROWS[2]);
scan.addFamily(FAMILIES[1]);
scan.addFamily(FAMILIES[2]);
scan.readVersions(Integer.MAX_VALUE);
result = getSingleScanResult(ht, scan);
assertEquals(1, result.size());
assertNResult(result, ROWS[2], FAMILIES[2], QUALIFIER, new long[] { ts[2] },
new byte[][] { VALUES[2] }, 0, 0);
// Test if we delete the family first in one row (HBASE-1541)
delete = new Delete(ROWS[3]);
delete.addFamily(FAMILIES[1]);
ht.delete(delete);
put = new Put(ROWS[3]);
put.addColumn(FAMILIES[2], QUALIFIER, VALUES[0]);
ht.put(put);
put = new Put(ROWS[4]);
put.addColumn(FAMILIES[1], QUALIFIER, VALUES[1]);
put.addColumn(FAMILIES[2], QUALIFIER, VALUES[2]);
ht.put(put);
get = new Get(ROWS[3]);
get.addFamily(FAMILIES[1]);
get.addFamily(FAMILIES[2]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertEquals("Expected 1 key but received " + result.size(), 1, result.size());
get = new Get(ROWS[4]);
get.addFamily(FAMILIES[1]);
get.addFamily(FAMILIES[2]);
get.readVersions(Integer.MAX_VALUE);
result = ht.get(get);
assertEquals("Expected 2 keys but received " + result.size(), 2, result.size());
scan = new Scan().withStartRow(ROWS[3]);
scan.addFamily(FAMILIES[1]);
scan.addFamily(FAMILIES[2]);
scan.readVersions(Integer.MAX_VALUE);
ResultScanner scanner = ht.getScanner(scan);
result = scanner.next();
assertEquals("Expected 1 key but received " + result.size(), 1, result.size());
assertTrue(Bytes.equals(CellUtil.cloneRow(result.rawCells()[0]), ROWS[3]));
assertTrue(Bytes.equals(CellUtil.cloneValue(result.rawCells()[0]), VALUES[0]));
result = scanner.next();
assertEquals("Expected 2 keys but received " + result.size(), 2, result.size());
assertTrue(Bytes.equals(CellUtil.cloneRow(result.rawCells()[0]), ROWS[4]));
assertTrue(Bytes.equals(CellUtil.cloneRow(result.rawCells()[1]), ROWS[4]));
assertTrue(Bytes.equals(CellUtil.cloneValue(result.rawCells()[0]), VALUES[1]));
assertTrue(Bytes.equals(CellUtil.cloneValue(result.rawCells()[1]), VALUES[2]));
scanner.close();
// Add test of bulk deleting.
for (int i = 0; i < 10; i++) {
byte[] bytes = Bytes.toBytes(i);
put = new Put(bytes);
put.setDurability(Durability.SKIP_WAL);
put.addColumn(FAMILIES[0], QUALIFIER, bytes);
ht.put(put);
}
for (int i = 0; i < 10; i++) {
byte[] bytes = Bytes.toBytes(i);
get = new Get(bytes);
get.addFamily(FAMILIES[0]);
result = ht.get(get);
assertEquals(1, result.size());
}
ArrayList<Delete> deletes = new ArrayList<>();
for (int i = 0; i < 10; i++) {
byte[] bytes = Bytes.toBytes(i);
delete = new Delete(bytes);
delete.addFamily(FAMILIES[0]);
deletes.add(delete);
}
ht.delete(deletes);
for (int i = 0; i < 10; i++) {
byte[] bytes = Bytes.toBytes(i);
get = new Get(bytes);
get.addFamily(FAMILIES[0]);
result = ht.get(get);
assertTrue(result.isEmpty());
}
}
}
}