You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2015/11/11 19:14:07 UTC
[1/3] phoenix git commit: PHOENIX-2396 Set root cause exception when
parsing server exception
Repository: phoenix
Updated Branches:
refs/heads/4.x-HBase-0.98 dfdcba45a -> 14580f78c
PHOENIX-2396 Set root cause exception when parsing server exception
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/a722b0eb
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/a722b0eb
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/a722b0eb
Branch: refs/heads/4.x-HBase-0.98
Commit: a722b0eb957d599f2be164bc39ef58a5133bc19e
Parents: dfdcba4
Author: James Taylor <ja...@apache.org>
Authored: Tue Nov 10 16:27:12 2015 -0800
Committer: James Taylor <jt...@salesforce.com>
Committed: Wed Nov 11 09:58:37 2015 -0800
----------------------------------------------------------------------
.../apache/phoenix/exception/SQLExceptionCode.java | 5 ++---
.../java/org/apache/phoenix/util/ServerUtil.java | 15 +++++----------
2 files changed, 7 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/a722b0eb/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
index 53a13be..cc0d0ed 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
@@ -418,11 +418,10 @@ public enum SQLExceptionCode {
}
}
- public static SQLExceptionCode fromErrorCode(int errorCode) throws SQLException {
+ public static SQLExceptionCode fromErrorCode(int errorCode) {
SQLExceptionCode code = errorCodeMap.get(errorCode);
if (code == null) {
- throw new SQLExceptionInfo.Builder(SQLExceptionCode.UNKNOWN_ERROR_CODE)
- .setMessage(Integer.toString(errorCode)).build().buildException();
+ return SQLExceptionCode.UNKNOWN_ERROR_CODE;
}
return code;
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/a722b0eb/phoenix-core/src/main/java/org/apache/phoenix/util/ServerUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/ServerUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/ServerUtil.java
index 0998e72..a51dc84 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/ServerUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/ServerUtil.java
@@ -116,21 +116,16 @@ public class ServerUtil {
}
private static SQLException parseRemoteException(Throwable t) {
- String message = t.getLocalizedMessage();
- if (message != null) {
+ String message = t.getLocalizedMessage();
+ if (message != null) {
// If the message matches the standard pattern, recover the SQLException and throw it.
Matcher matcher = PATTERN.matcher(t.getLocalizedMessage());
if (matcher.find()) {
int statusCode = Integer.parseInt(matcher.group(1));
- SQLExceptionCode code;
- try {
- code = SQLExceptionCode.fromErrorCode(statusCode);
- } catch (SQLException e) {
- return e;
- }
- return new SQLExceptionInfo.Builder(code).setMessage(matcher.group()).build().buildException();
+ SQLExceptionCode code = SQLExceptionCode.fromErrorCode(statusCode);
+ return new SQLExceptionInfo.Builder(code).setMessage(matcher.group()).setRootCause(t).build().buildException();
}
- }
+ }
return null;
}
[3/3] phoenix git commit: PHOENIX-2399 Server is sometimes unable to
find Phoenix driver
Posted by ja...@apache.org.
PHOENIX-2399 Server is sometimes unable to find Phoenix driver
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/14580f78
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/14580f78
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/14580f78
Branch: refs/heads/4.x-HBase-0.98
Commit: 14580f78cf58327b794477356d0bc33200a08778
Parents: b9a3c53
Author: James Taylor <ja...@apache.org>
Authored: Tue Nov 10 18:15:08 2015 -0800
Committer: James Taylor <jt...@salesforce.com>
Committed: Wed Nov 11 10:08:34 2015 -0800
----------------------------------------------------------------------
.../example/EndToEndCoveredIndexingIT.java | 1634 +++++++++---------
.../EndtoEndIndexingWithCompressionIT.java | 31 +-
.../phoenix/mapreduce/CsvBulkLoadToolIT.java | 5 +
.../apache/phoenix/mapreduce/IndexToolIT.java | 5 +
.../org/apache/phoenix/query/QueryServices.java | 1 +
.../phoenix/query/QueryServicesOptions.java | 6 +
.../java/org/apache/phoenix/util/QueryUtil.java | 13 +-
.../phoenix/query/QueryServicesTestImpl.java | 6 +-
8 files changed, 872 insertions(+), 829 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndToEndCoveredIndexingIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndToEndCoveredIndexingIT.java b/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndToEndCoveredIndexingIT.java
index 1cf6b5c..01812f3 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndToEndCoveredIndexingIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndToEndCoveredIndexingIT.java
@@ -18,6 +18,7 @@
package org.apache.phoenix.hbase.index.covered.example;
+import static org.apache.phoenix.query.BaseTest.initAndRegisterDriver;
import static org.apache.phoenix.query.BaseTest.setUpConfigForMiniCluster;
import java.io.IOException;
@@ -47,6 +48,11 @@ import org.apache.phoenix.end2end.NeedsOwnMiniClusterTest;
import org.apache.phoenix.hbase.index.IndexTestingUtils;
import org.apache.phoenix.hbase.index.Indexer;
import org.apache.phoenix.hbase.index.TableName;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
+import org.apache.phoenix.util.PhoenixRuntime;
+import org.apache.phoenix.util.ReadOnlyProps;
+import org.apache.phoenix.util.TestUtil;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -61,824 +67,838 @@ import org.junit.experimental.categories.Category;
*/
@Category(NeedsOwnMiniClusterTest.class)
public class EndToEndCoveredIndexingIT {
- private static final Log LOG = LogFactory.getLog(EndToEndCoveredIndexingIT.class);
- protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
- private static final String FAM_STRING = "FAMILY";
- private static final byte[] FAM = Bytes.toBytes(FAM_STRING);
- private static final String FAM2_STRING = "FAMILY2";
- private static final byte[] FAM2 = Bytes.toBytes(FAM2_STRING);
- private static final byte[] EMPTY_BYTES = new byte[0];
- private static final byte[] indexed_qualifer = Bytes.toBytes("indexed_qual");
- private static final byte[] regular_qualifer = Bytes.toBytes("reg_qual");
- private static final byte[] row1 = Bytes.toBytes("row1");
- private static final byte[] value1 = Bytes.toBytes("val1");
- private static final byte[] value2 = Bytes.toBytes("val2");
- private static final byte[] value3 = Bytes.toBytes("val3");
- // match a single family:qualifier pair
- private static final CoveredColumn col1 = new CoveredColumn(FAM_STRING, indexed_qualifer);
- // matches the family2:* columns
- private static final CoveredColumn col2 = new CoveredColumn(FAM2_STRING, null);
- private static final CoveredColumn col3 = new CoveredColumn(FAM2_STRING, indexed_qualifer);
-
- @Rule
- public TableName TestTable = new TableName();
-
- private ColumnGroup fam1;
- private ColumnGroup fam2;
-
- // setup a couple of index columns
- private void setupColumns() {
- fam1 = new ColumnGroup(getIndexTableName());
- fam2 = new ColumnGroup(getIndexTableName() + "2");
- // values are [col1][col2_1]...[col2_n]
- fam1.add(col1);
- fam1.add(col2);
- // value is [col2]
- fam2.add(col3);
- }
-
- private String getIndexTableName() {
- return Bytes.toString(TestTable.getTableName()) + "_index";
- }
-
- @BeforeClass
- public static void setupCluster() throws Exception {
- Configuration conf = UTIL.getConfiguration();
- setUpConfigForMiniCluster(conf);
- IndexTestingUtils.setupConfig(conf);
- // disable version checking, so we can test against whatever version of HBase happens to be
- // installed (right now, its generally going to be SNAPSHOT versions).
- conf.setBoolean(Indexer.CHECK_VERSION_CONF_KEY, false);
- UTIL.startMiniCluster();
- }
-
- @AfterClass
- public static void teardownCluster() throws Exception {
- UTIL.shutdownMiniCluster();
- }
-
- @Before
- public void setup() throws Exception {
- setupColumns();
- }
-
- /**
- * Test that a bunch of puts with a single timestamp across all the puts builds and inserts index
- * entries as expected
- * @throws Exception on failure
- */
- @Test
- public void testSimpleTimestampedUpdates() throws Exception {
- HTable primary = createSetupTables(fam1);
-
- // do a put to the primary table
- Put p = new Put(row1);
- long ts = 10;
- p.add(FAM, indexed_qualifer, ts, value1);
- p.add(FAM, regular_qualifer, ts, value2);
- primary.put(p);
- primary.flushCommits();
-
- // read the index for the expected values
- HTable index1 = new HTable(UTIL.getConfiguration(), getIndexTableName());
-
- // build the expected kvs
- List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
- List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
-
- // verify that the index matches
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
- // cleanup
- closeAndCleanupTables(primary, index1);
- }
-
- /**
- * Test that the multiple timestamps in a single put build the correct index updates.
- * @throws Exception on failure
- */
- @Test
- public void testMultipleTimestampsInSinglePut() throws Exception {
- HTable primary = createSetupTables(fam1);
-
- // do a put to the primary table
- Put p = new Put(row1);
- long ts1 = 10;
- long ts2 = 11;
- p.add(FAM, indexed_qualifer, ts1, value1);
- p.add(FAM, regular_qualifer, ts1, value2);
- // our group indexes all columns in the this family, so any qualifier here is ok
- p.add(FAM2, regular_qualifer, ts2, value3);
- primary.put(p);
- primary.flushCommits();
-
- // read the index for the expected values
- HTable index1 = new HTable(UTIL.getConfiguration(), getIndexTableName());
-
- // build the expected kvs
- List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
- // check the first entry at ts1
- List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
-
- // check the second entry at ts2
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
-
- // cleanup
- closeAndCleanupTables(primary, index1);
- }
-
- /**
- * Test that we make updates to multiple {@link ColumnGroup}s across a single put/delete
- * @throws Exception on failure
- */
- @Test
- public void testMultipleConcurrentGroupsUpdated() throws Exception {
- HTable primary = createSetupTables(fam1, fam2);
-
- // do a put to the primary table
- Put p = new Put(row1);
- long ts = 10;
- p.add(FAM, indexed_qualifer, ts, value1);
- p.add(FAM, regular_qualifer, ts, value2);
- p.add(FAM2, indexed_qualifer, ts, value3);
- primary.put(p);
- primary.flushCommits();
-
- // read the index for the expected values
- HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
- HTable index2 = new HTable(UTIL.getConfiguration(), fam2.getTable());
-
- // build the expected kvs
- List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
- List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
- // and check the second index as well
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col3));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index2, expected, ts, value3);
-
- // cleanup
- closeAndCleanupTables(primary, index1, index2);
- }
-
- /**
- * HBase has a 'fun' property wherein you can completely clobber an existing row if you make a
- * {@link Put} at the exact same dimension (row, cf, cq, ts) as an existing row. The old row
- * disappears and the new value (since the rest of the row is the same) completely subsumes it.
- * This test ensures that we remove the old entry and put a new entry in its place.
- * @throws Exception on failure
- */
- @Test
- public void testOverwritingPutsCorrectlyGetIndexed() throws Exception {
- HTable primary = createSetupTables(fam1);
-
- // do a put to the primary table
- Put p = new Put(row1);
- long ts = 10;
- p.add(FAM, indexed_qualifer, ts, value1);
- p.add(FAM, regular_qualifer, ts, value2);
- primary.put(p);
- primary.flushCommits();
-
- // read the index for the expected values
- HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-
- // build the expected kvs
- List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
- // check the first entry at ts
- List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
- // now overwrite the put in the primary table with a new value
- p = new Put(row1);
- p.add(FAM, indexed_qualifer, ts, value3);
- primary.put(p);
- primary.flushCommits();
-
- pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
- // check the first entry at ts
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value3);
- // and verify that a scan at the first entry returns nothing (ignore the updated row)
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts,
- value1, value2);
-
- // cleanup
- closeAndCleanupTables(primary, index1);
- }
-
- @Test
- public void testSimpleDeletes() throws Exception {
- HTable primary = createSetupTables(fam1);
-
- // do a simple Put
- long ts = 10;
- Put p = new Put(row1);
- p.add(FAM, indexed_qualifer, ts, value1);
- p.add(FAM, regular_qualifer, ts, value2);
- primary.put(p);
- primary.flushCommits();
-
- Delete d = new Delete(row1);
- primary.delete(d);
-
- HTable index = new HTable(UTIL.getConfiguration(), fam1.getTable());
- List<KeyValue> expected = Collections.<KeyValue> emptyList();
- // scan over all time should cause the delete to be covered
- IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, 0, Long.MAX_VALUE, value1,
- HConstants.EMPTY_END_ROW);
-
- // scan at the older timestamp should still show the older value
- List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts, value1);
-
- // cleanup
- closeAndCleanupTables(index, primary);
- }
-
- /**
- * If we don't have any updates to make to the index, we don't take a lock on the WAL. However, we
- * need to make sure that we don't try to unlock the WAL on write time when we don't write
- * anything, since that will cause an java.lang.IllegalMonitorStateException
- * @throws Exception on failure
- */
- @Test
- public void testDeletesWithoutPreviousState() throws Exception {
- HTable primary = createSetupTables(fam1);
-
- // do a delete on the primary table (no data, so no index updates...hopefully).
- long ts = 10;
- Delete d = new Delete(row1);
- primary.delete(d);
-
- HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
- List<KeyValue> expected = Collections.<KeyValue> emptyList();
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
- // a delete of a specific family/column should also not show any index updates
- d = new Delete(row1);
- d.deleteColumn(FAM, indexed_qualifer);
- primary.delete(d);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
- // also just a family marker should have the same effect
- d = new Delete(row1);
- d.deleteFamily(FAM);
- primary.delete(d);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
- // also just a family marker should have the same effect
- d = new Delete(row1);
- d.deleteColumns(FAM, indexed_qualifer);
- primary.delete(d);
- primary.flushCommits();
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
- // cleanup
- closeAndCleanupTables(primary, index1);
- }
-
- /**
- * Similar to the {@link #testMultipleTimestampsInSinglePut()}, this check the same with deletes
- * @throws Exception on failure
- */
- @Test
- public void testMultipleTimestampsInSingleDelete() throws Exception {
- HTable primary = createSetupTables(fam1);
-
- // do a put to the primary table
- Put p = new Put(row1);
- long ts1 = 10, ts2 = 11, ts3 = 12;
- p.add(FAM, indexed_qualifer, ts1, value1);
- // our group indexes all columns in the this family, so any qualifier here is ok
- p.add(FAM2, regular_qualifer, ts2, value3);
- primary.put(p);
- primary.flushCommits();
-
- // check to make sure everything we expect is there
- HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-
- // ts1, we just have v1
- List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
- List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
-
- // at ts2, don't have the above anymore
- pairs.clear();
- expected = Collections.emptyList();
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, ts2 + 1, value1, value1);
- // but we do have the new entry at ts2
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
-
- // now build up a delete with a couple different timestamps
- Delete d = new Delete(row1);
- // these deletes have to match the exact ts since we are doing an exact match (deleteColumn).
- d.deleteColumn(FAM, indexed_qualifer, ts1);
- // since this doesn't match exactly, we actually shouldn't see a change in table state
- d.deleteColumn(FAM2, regular_qualifer, ts3);
- primary.delete(d);
-
- // at ts1, we should have the put covered exactly by the delete and into the entire future
- expected = Collections.emptyList();
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, Long.MAX_VALUE, value1,
- value1);
-
- // at ts2, we should just see value3
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
-
- // the later delete is a point delete, so we shouldn't see any change at ts3
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, ts3, value1,
- HConstants.EMPTY_END_ROW);
-
- // cleanup
- closeAndCleanupTables(primary, index1);
- }
-
- /**
- * Covering deletes (via {@link Delete#deleteColumns}) cover everything back in time from the
- * given time. If its modifying the latest state, we don't need to do anything but add deletes. If
- * its modifying back in time state, we need to just fix up the surrounding elements as anything
- * else ahead of it will be fixed up by later updates.
- * <p>
- * similar to {@link #testMultipleTimestampsInSingleDelete()}, but with covering deletes.
- * @throws Exception on failure
- */
- @Test
- public void testDeleteColumnsInThePast() throws Exception {
- HTable primary = createSetupTables(fam1);
-
- // do a put to the primary table
- Put p = new Put(row1);
- long ts1 = 10, ts2 = 11, ts3 = 12;
- p.add(FAM, indexed_qualifer, ts1, value1);
- p.add(FAM2, regular_qualifer, ts2, value3);
- primary.put(p);
- primary.flushCommits();
-
- // now build up a delete with a couple different timestamps
- Delete d = new Delete(row1);
- // these deletes don't need to match the exact ts because they cover everything earlier
- d.deleteColumns(FAM, indexed_qualifer, ts2);
- d.deleteColumns(FAM2, regular_qualifer, ts3);
- primary.delete(d);
-
- // read the index for the expected values
- HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-
- // build the expected kvs
- List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
- // check the first entry at ts1
- List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
-
- // delete at ts2 changes what the put would insert
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
-
- // final delete clears out everything
- expected = Collections.emptyList();
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value1);
-
- // cleanup
- closeAndCleanupTables(primary, index1);
- }
-
- /**
- * If the client is using custom timestamps is possible that the updates come out-of-order (i.e.
- * update to ts 10 comes after the update to ts 12). In the case, we need to be sure that the
- * index is correctly updated when the out of order put arrives.
- * @throws Exception
- */
- @Test
- public void testOutOfOrderUpdates() throws Exception {
- HTable primary = createSetupTables(fam1);
-
- // do a put to the primary table
- Put p = new Put(row1);
- long ts = 12;
- p.add(FAM, indexed_qualifer, ts, value1);
- primary.put(p);
- primary.flushCommits();
-
- // read the index for the expected values
- HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-
- // build the expected kvs
- List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
- // check the first entry at ts
- List<KeyValue> expectedTs1 = CoveredColumnIndexCodec
- .getIndexKeyValueForTesting(row1, ts, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs1, ts, value1);
-
- // now make a put back in time
- long ts2 = ts - 2;
- p = new Put(row1);
- p.add(FAM, indexed_qualifer, ts2, value2);
- primary.put(p);
- primary.flushCommits();
-
- pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value2, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
- // check to make sure the back in time entry exists
- List<KeyValue> expectedTs2 = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2,
- pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs2, ts2, value2);
- // then it should be gone at the newer ts (because it deletes itself)
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts2,
- ts + 1, value2, HConstants.EMPTY_END_ROW);
-
- // but that the original index entry is still visible at ts, just fine
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs1, ts, value1);
-
- // cleanup
- closeAndCleanupTables(primary, index1);
- }
-
- /**
- * Its possible (i.e. from a fast, frequently writing client) that they put more than the
- * 'visible' number of versions in a row before a client make a put 'back in time' on that row. If
- * we don't scan the current table properly, we won't see an index update for that 'back in time'
- * update since the usual lookup will only see the regular number of versions. This ability to see
- * back in time depends on running HBase 0.94.9
- * @throws Exception on failure
- */
- @Test
- public void testExceedVersionsOutOfOrderPut() throws Exception {
- // setup the index
- HTable primary = createSetupTables(fam2);
-
- // do a put to the primary table
- Put p = new Put(row1);
- long ts1 = 1, ts2 = 2, ts3 = 3, ts4 = 4, ts5 = 5;
- byte[] value4 = Bytes.toBytes("val4");
- byte[] value5 = Bytes.toBytes("val5");
- p.add(FAM2, indexed_qualifer, ts1, value1);
- primary.put(p);
- primary.flushCommits();
-
- p = new Put(row1);
- p.add(FAM2, indexed_qualifer, ts3, value3);
- primary.put(p);
- primary.flushCommits();
-
- p = new Put(row1);
- p.add(FAM2, indexed_qualifer, ts4, value4);
- primary.put(p);
- primary.flushCommits();
-
- p = new Put(row1);
- p.add(FAM2, indexed_qualifer, ts5, value5);
- primary.put(p);
- primary.flushCommits();
-
- // read the index for the expected values
- HTable index = new HTable(UTIL.getConfiguration(), fam2.getTable());
-
- // do a raw scan of everything in the table
- if (LOG.isDebugEnabled()) {
- // the whole table, all the keys
- Scan s = new Scan();
- s.setRaw(true);
- ResultScanner scanner = index.getScanner(s);
- for (Result r : scanner) {
- LOG.debug("Found row:" + r);
- }
- scanner.close();
+ private static final Log LOG = LogFactory.getLog(EndToEndCoveredIndexingIT.class);
+ protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
+ private static final String FAM_STRING = "FAMILY";
+ private static final byte[] FAM = Bytes.toBytes(FAM_STRING);
+ private static final String FAM2_STRING = "FAMILY2";
+ private static final byte[] FAM2 = Bytes.toBytes(FAM2_STRING);
+ private static final byte[] EMPTY_BYTES = new byte[0];
+ private static final byte[] indexed_qualifer = Bytes.toBytes("indexed_qual");
+ private static final byte[] regular_qualifer = Bytes.toBytes("reg_qual");
+ private static final byte[] row1 = Bytes.toBytes("row1");
+ private static final byte[] value1 = Bytes.toBytes("val1");
+ private static final byte[] value2 = Bytes.toBytes("val2");
+ private static final byte[] value3 = Bytes.toBytes("val3");
+ // match a single family:qualifier pair
+ private static final CoveredColumn col1 = new CoveredColumn(FAM_STRING, indexed_qualifer);
+ // matches the family2:* columns
+ private static final CoveredColumn col2 = new CoveredColumn(FAM2_STRING, null);
+ private static final CoveredColumn col3 = new CoveredColumn(FAM2_STRING, indexed_qualifer);
+
+ @Rule
+ public TableName TestTable = new TableName();
+
+ private ColumnGroup fam1;
+ private ColumnGroup fam2;
+
+ // setup a couple of index columns
+ private void setupColumns() {
+ fam1 = new ColumnGroup(getIndexTableName());
+ fam2 = new ColumnGroup(getIndexTableName() + "2");
+ // values are [col1][col2_1]...[col2_n]
+ fam1.add(col1);
+ fam1.add(col2);
+ // value is [col2]
+ fam2.add(col3);
}
- /*
- * now we have definitely exceeded the number of versions visible to a usual client of the
- * primary table, so we should try doing a put 'back in time' an make sure that has the correct
- * index values and cleanup
+ private String getIndexTableName() {
+ return Bytes.toString(TestTable.getTableName()) + "_index";
+ }
+
+ protected static void setupConfig() throws Exception {
+ Configuration conf = UTIL.getConfiguration();
+ setUpConfigForMiniCluster(conf);
+ IndexTestingUtils.setupConfig(conf);
+ // disable version checking, so we can test against whatever version of HBase happens to be
+ // installed (right now, its generally going to be SNAPSHOT versions).
+ conf.setBoolean(Indexer.CHECK_VERSION_CONF_KEY, false);
+ }
+
+ protected static void initDriver() throws Exception {
+ Configuration conf = UTIL.getConfiguration();
+ String zkQuorum = TestUtil.LOCALHOST + PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR + UTIL.getZkCluster().getClientPort();
+ String url = PhoenixRuntime.JDBC_PROTOCOL +
+ PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR + zkQuorum +
+ PhoenixRuntime.JDBC_PROTOCOL_TERMINATOR +
+ conf.get(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS);
+ initAndRegisterDriver(url, ReadOnlyProps.EMPTY_PROPS);
+ }
+
+ @BeforeClass
+ public static void setupCluster() throws Exception {
+ setupConfig();
+ UTIL.startMiniCluster();
+ initDriver();
+ }
+
+ @AfterClass
+ public static void teardownCluster() throws Exception {
+ UTIL.shutdownMiniCluster();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ setupColumns();
+ }
+
+ /**
+ * Test that a bunch of puts with a single timestamp across all the puts builds and inserts index
+ * entries as expected
+ * @throws Exception on failure
+ */
+ @Test
+ public void testSimpleTimestampedUpdates() throws Exception {
+ HTable primary = createSetupTables(fam1);
+
+ // do a put to the primary table
+ Put p = new Put(row1);
+ long ts = 10;
+ p.add(FAM, indexed_qualifer, ts, value1);
+ p.add(FAM, regular_qualifer, ts, value2);
+ primary.put(p);
+ primary.flushCommits();
+
+ // read the index for the expected values
+ HTable index1 = new HTable(UTIL.getConfiguration(), getIndexTableName());
+
+ // build the expected kvs
+ List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+ List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+
+ // verify that the index matches
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+ // cleanup
+ closeAndCleanupTables(primary, index1);
+ }
+
+ /**
+ * Test that the multiple timestamps in a single put build the correct index updates.
+ * @throws Exception on failure
+ */
+ @Test
+ public void testMultipleTimestampsInSinglePut() throws Exception {
+ HTable primary = createSetupTables(fam1);
+
+ // do a put to the primary table
+ Put p = new Put(row1);
+ long ts1 = 10;
+ long ts2 = 11;
+ p.add(FAM, indexed_qualifer, ts1, value1);
+ p.add(FAM, regular_qualifer, ts1, value2);
+ // our group indexes all columns in the this family, so any qualifier here is ok
+ p.add(FAM2, regular_qualifer, ts2, value3);
+ primary.put(p);
+ primary.flushCommits();
+
+ // read the index for the expected values
+ HTable index1 = new HTable(UTIL.getConfiguration(), getIndexTableName());
+
+ // build the expected kvs
+ List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+ // check the first entry at ts1
+ List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
+
+ // check the second entry at ts2
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
+
+ // cleanup
+ closeAndCleanupTables(primary, index1);
+ }
+
+ /**
+ * Test that we make updates to multiple {@link ColumnGroup}s across a single put/delete
+ * @throws Exception on failure
+ */
+ @Test
+ public void testMultipleConcurrentGroupsUpdated() throws Exception {
+ HTable primary = createSetupTables(fam1, fam2);
+
+ // do a put to the primary table
+ Put p = new Put(row1);
+ long ts = 10;
+ p.add(FAM, indexed_qualifer, ts, value1);
+ p.add(FAM, regular_qualifer, ts, value2);
+ p.add(FAM2, indexed_qualifer, ts, value3);
+ primary.put(p);
+ primary.flushCommits();
+
+ // read the index for the expected values
+ HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+ HTable index2 = new HTable(UTIL.getConfiguration(), fam2.getTable());
+
+ // build the expected kvs
+ List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
+ List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+ // and check the second index as well
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col3));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index2, expected, ts, value3);
+
+ // cleanup
+ closeAndCleanupTables(primary, index1, index2);
+ }
+
+ /**
+ * HBase has a 'fun' property wherein you can completely clobber an existing row if you make a
+ * {@link Put} at the exact same dimension (row, cf, cq, ts) as an existing row. The old row
+ * disappears and the new value (since the rest of the row is the same) completely subsumes it.
+ * This test ensures that we remove the old entry and put a new entry in its place.
+ * @throws Exception on failure
+ */
+ @Test
+ public void testOverwritingPutsCorrectlyGetIndexed() throws Exception {
+ HTable primary = createSetupTables(fam1);
+
+ // do a put to the primary table
+ Put p = new Put(row1);
+ long ts = 10;
+ p.add(FAM, indexed_qualifer, ts, value1);
+ p.add(FAM, regular_qualifer, ts, value2);
+ primary.put(p);
+ primary.flushCommits();
+
+ // read the index for the expected values
+ HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+
+ // build the expected kvs
+ List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+ // check the first entry at ts
+ List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+ // now overwrite the put in the primary table with a new value
+ p = new Put(row1);
+ p.add(FAM, indexed_qualifer, ts, value3);
+ primary.put(p);
+ primary.flushCommits();
+
+ pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+ // check the first entry at ts
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value3);
+ // and verify that a scan at the first entry returns nothing (ignore the updated row)
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts,
+ value1, value2);
+
+ // cleanup
+ closeAndCleanupTables(primary, index1);
+ }
+
+ @Test
+ public void testSimpleDeletes() throws Exception {
+ HTable primary = createSetupTables(fam1);
+
+ // do a simple Put
+ long ts = 10;
+ Put p = new Put(row1);
+ p.add(FAM, indexed_qualifer, ts, value1);
+ p.add(FAM, regular_qualifer, ts, value2);
+ primary.put(p);
+ primary.flushCommits();
+
+ Delete d = new Delete(row1);
+ primary.delete(d);
+
+ HTable index = new HTable(UTIL.getConfiguration(), fam1.getTable());
+ List<KeyValue> expected = Collections.<KeyValue> emptyList();
+ // scan over all time should cause the delete to be covered
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, 0, Long.MAX_VALUE, value1,
+ HConstants.EMPTY_END_ROW);
+
+ // scan at the older timestamp should still show the older value
+ List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts, value1);
+
+ // cleanup
+ closeAndCleanupTables(index, primary);
+ }
+
+ /**
+ * If we don't have any updates to make to the index, we don't take a lock on the WAL. However, we
+ * need to make sure that we don't try to unlock the WAL on write time when we don't write
+ * anything, since that will cause an java.lang.IllegalMonitorStateException
+ * @throws Exception on failure
*/
- p = new Put(row1);
- p.add(FAM2, indexed_qualifer, ts2, value2);
- primary.put(p);
- primary.flushCommits();
-
- // // read the index for the expected values
- // HTable index = new HTable(UTIL.getConfiguration(), fam2.getTable());
- //
- // do a raw scan of everything in the table
- if (LOG.isDebugEnabled()) {
- // the whole table, all the keys
- Scan s = new Scan();
- s.setRaw(true);
- ResultScanner scanner = index.getScanner(s);
- for (Result r : scanner) {
- LOG.debug("Found row:" + r);
- }
- scanner.close();
+ @Test
+ public void testDeletesWithoutPreviousState() throws Exception {
+ HTable primary = createSetupTables(fam1);
+
+ // do a delete on the primary table (no data, so no index updates...hopefully).
+ long ts = 10;
+ Delete d = new Delete(row1);
+ primary.delete(d);
+
+ HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+ List<KeyValue> expected = Collections.<KeyValue> emptyList();
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+ // a delete of a specific family/column should also not show any index updates
+ d = new Delete(row1);
+ d.deleteColumn(FAM, indexed_qualifer);
+ primary.delete(d);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+ // also just a family marker should have the same effect
+ d = new Delete(row1);
+ d.deleteFamily(FAM);
+ primary.delete(d);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+ // also just a family marker should have the same effect
+ d = new Delete(row1);
+ d.deleteColumns(FAM, indexed_qualifer);
+ primary.delete(d);
+ primary.flushCommits();
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+ // cleanup
+ closeAndCleanupTables(primary, index1);
}
- // build the expected kvs
- List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col3));
-
- // check the value1 should be present at the earliest timestamp
- List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts1, value1, value2);
-
- // and value1 should be removed at ts2 (even though it came later)
- IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts1,
- ts2 + 1, value1, value2); // timestamp + 1 since its exclusive end timestamp
-
- // late added column should be there just fine at its timestamp
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value2, col3));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts2, value2);
-
- // and check that the late entry also removes its self at the next timestamp up
- IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts3,
- value2, value3);
-
- // then we should have the rest of the inserts at their appropriate timestamps. Everything else
- // should be exactly the same, except we shouldn't see ts0 anymore at ts2
-
- // check the third entry
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col3));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts3, value3);
-
- // check the fourth entry
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value4, col3));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts4, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts4, value4);
-
- // check the first entry at ts4
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value2, col3));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts2, value2);
- // verify that we remove the entry, even though its too far 'back in time'
- IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts3,
- value4);
-
- // cleanup
- closeAndCleanupTables(primary, index);
- }
-
- /**
- * Similar to {@link #testExceedVersionsOutOfOrderPut()}, but mingles deletes and puts.
- * @throws Exception on failure
- */
- @Test
- public void testExceedVersionsOutOfOrderUpdates() throws Exception {
- HTable primary = createSetupTables(fam1);
-
- // setup the data to store
- long ts1 = 1, ts2 = 2, ts3 = 3, ts4 = 4, ts5 = 5, ts6 = 6;
- byte[] value4 = Bytes.toBytes("val4"), value5 = Bytes.toBytes("val5"), value6 =
- Bytes.toBytes("val6");
- // values for the other column to index
- byte[] v1_1 = ArrayUtils.addAll(value1, Bytes.toBytes("_otherCol")), v3_1 =
- ArrayUtils.addAll(value3, Bytes.toBytes("_otherCol")), v5_1 =
- ArrayUtils.addAll(value5, Bytes.toBytes("_otherCol")), v6_1 =
- ArrayUtils.addAll(value6, Bytes.toBytes("_otherCol"));
-
- // make some puts to the primary table
- Put p = new Put(row1);
- p.add(FAM, indexed_qualifer, ts1, value1);
- p.add(FAM2, indexed_qualifer, ts1, v1_1);
- primary.put(p);
- primary.flushCommits();
-
- p = new Put(row1);
- p.add(FAM, indexed_qualifer, ts3, value3);
- p.add(FAM2, indexed_qualifer, ts3, v3_1);
- primary.put(p);
- primary.flushCommits();
-
- p = new Put(row1);
- p.add(FAM, indexed_qualifer, ts5, value5);
- p.add(FAM2, indexed_qualifer, ts5, v5_1);
- primary.put(p);
- primary.flushCommits();
-
- p = new Put(row1);
- p.add(FAM, indexed_qualifer, ts6, value6);
- p.add(FAM2, indexed_qualifer, ts6, v6_1);
- primary.put(p);
- primary.flushCommits();
-
- /*
- * now we have definitely exceeded the number of versions visible to a usual client of the
- * primary table, so we should try doing a put 'back in time' an make sure that has the correct
- * index values and cleanup
+ /**
+ * Similar to the {@link #testMultipleTimestampsInSinglePut()}, this check the same with deletes
+ * @throws Exception on failure
*/
- p = new Put(row1);
- p.add(FAM, indexed_qualifer, ts2, value2);
- primary.put(p);
- primary.flushCommits();
-
- // read the index for the expected values
- HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-
- // do a raw scan of everything in the table
- if (LOG.isDebugEnabled()) {
- Scan s = new Scan();
- s.setRaw(true);
- ResultScanner scanner = index1.getScanner(s);
- for (Result r : scanner) {
- LOG.debug("Found row:" + r);
- }
- scanner.close();
+ @Test
+ public void testMultipleTimestampsInSingleDelete() throws Exception {
+ HTable primary = createSetupTables(fam1);
+
+ // do a put to the primary table
+ Put p = new Put(row1);
+ long ts1 = 10, ts2 = 11, ts3 = 12;
+ p.add(FAM, indexed_qualifer, ts1, value1);
+ // our group indexes all columns in the this family, so any qualifier here is ok
+ p.add(FAM2, regular_qualifer, ts2, value3);
+ primary.put(p);
+ primary.flushCommits();
+
+ // check to make sure everything we expect is there
+ HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+
+ // ts1, we just have v1
+ List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+ List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
+
+ // at ts2, don't have the above anymore
+ pairs.clear();
+ expected = Collections.emptyList();
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, ts2 + 1, value1, value1);
+ // but we do have the new entry at ts2
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
+
+ // now build up a delete with a couple different timestamps
+ Delete d = new Delete(row1);
+ // these deletes have to match the exact ts since we are doing an exact match (deleteColumn).
+ d.deleteColumn(FAM, indexed_qualifer, ts1);
+ // since this doesn't match exactly, we actually shouldn't see a change in table state
+ d.deleteColumn(FAM2, regular_qualifer, ts3);
+ primary.delete(d);
+
+ // at ts1, we should have the put covered exactly by the delete and into the entire future
+ expected = Collections.emptyList();
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, Long.MAX_VALUE, value1,
+ value1);
+
+ // at ts2, we should just see value3
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
+
+ // the later delete is a point delete, so we shouldn't see any change at ts3
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, ts3, value1,
+ HConstants.EMPTY_END_ROW);
+
+ // cleanup
+ closeAndCleanupTables(primary, index1);
}
- // build the expected kvs
- List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
- pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
-
- // check the value1 should be present at the earliest timestamp
- List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1, value2);
-
- // and value1 should be removed at ts2 (even though it came later)
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts1,
- ts2 + 1, value1, value2); // timestamp + 1 since its exclusive end timestamp
-
- // late added column should be there just fine at its timestamp
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value2, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value2);
-
- // and check that the late entry also removes its self at the next timestamp up
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts3,
- value2, value3);
-
- // -----------------------------------------------
- // Check Delete intermingled
- // -----------------------------------------------
-
- // verify that the old row is there
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(v3_1, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
- // scan from the start key forward (should only include [value3][v3_3])
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, expected.get(0).getKey(),
- value4);
-
- // then do a delete of just one of the indexed columns. This should insert a delete for all just
- // the single value, then a put & a later corresponding in the past for the new value
- Delete d = new Delete(row1);
- d.deleteColumn(FAM2, indexed_qualifer, ts3);
- primary.delete(d);
-
- // we shouldn't find that entry, but we should find [value3][v1_1] since that is next entry back
- // in time from the current
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
- // it should be re-written at 3
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value3, value4);
-
- // but we shouldn't find it at ts5 since it should be covered again
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts5,
- value3, value4);
-
- // now remove all the older columns in FAM2 at 4
- d = new Delete(row1);
- d.deleteColumns(FAM2, indexed_qualifer, ts4);
- primary.delete(d);
-
- // we shouldn't find that entry, but we should find [value3][null] since deleteColumns removes
- // all the entries for that column
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts4, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts4, value3, value4);
-
- // same as above, but now do it at 3 (on earlier)
- d = new Delete(row1);
- d.deleteColumns(FAM2, indexed_qualifer, ts3);
- primary.delete(d);
-
- // we shouldn't find that entry, but we should find [value3][null] since deleteColumns removes
- // all the entries for that column
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value3, value4);
-
- // -----------------------------------------------
- // then we should have the rest of the inserts at their appropriate timestamps. Everything else
- // should be exactly the same, except we shouldn't see ts0 anymore at ts2
- // -----------------------------------------------
-
- // check the entry at 5
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value5, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(v5_1, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts5, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts5, value5);
-
- // check the entry at 6
- pairs.clear();
- pairs.add(new Pair<byte[], CoveredColumn>(value6, col1));
- pairs.add(new Pair<byte[], CoveredColumn>(v6_1, col2));
- expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts6, pairs);
- IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts6, value5);
-
- // cleanup
- closeAndCleanupTables(primary, index1);
- }
-
- /**
- * Create the primary table (to which you should write), setup properly for indexing the given
- * {@link ColumnGroup}s. Also creates the necessary index tables to match the passes groups.
- * @param groups {@link ColumnGroup}s to index, creating one index table per column group.
- * @return reference to the primary table
- * @throws IOException if there is an issue communicating with HBase
- */
- @SuppressWarnings("deprecation")
-private HTable createSetupTables(ColumnGroup... groups) throws IOException {
- HBaseAdmin admin = UTIL.getHBaseAdmin();
- // setup the index
- CoveredColumnIndexSpecifierBuilder builder = new CoveredColumnIndexSpecifierBuilder();
- for (ColumnGroup group : groups) {
- builder.addIndexGroup(group);
- // create the index tables
- CoveredColumnIndexer.createIndexTable(admin, group.getTable());
+ /**
+ * Covering deletes (via {@link Delete#deleteColumns}) cover everything back in time from the
+ * given time. If its modifying the latest state, we don't need to do anything but add deletes. If
+ * its modifying back in time state, we need to just fix up the surrounding elements as anything
+ * else ahead of it will be fixed up by later updates.
+ * <p>
+ * similar to {@link #testMultipleTimestampsInSingleDelete()}, but with covering deletes.
+ * @throws Exception on failure
+ */
+ @Test
+ public void testDeleteColumnsInThePast() throws Exception {
+ HTable primary = createSetupTables(fam1);
+
+ // do a put to the primary table
+ Put p = new Put(row1);
+ long ts1 = 10, ts2 = 11, ts3 = 12;
+ p.add(FAM, indexed_qualifer, ts1, value1);
+ p.add(FAM2, regular_qualifer, ts2, value3);
+ primary.put(p);
+ primary.flushCommits();
+
+ // now build up a delete with a couple different timestamps
+ Delete d = new Delete(row1);
+ // these deletes don't need to match the exact ts because they cover everything earlier
+ d.deleteColumns(FAM, indexed_qualifer, ts2);
+ d.deleteColumns(FAM2, regular_qualifer, ts3);
+ primary.delete(d);
+
+ // read the index for the expected values
+ HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+
+ // build the expected kvs
+ List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+ // check the first entry at ts1
+ List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
+
+ // delete at ts2 changes what the put would insert
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
+
+ // final delete clears out everything
+ expected = Collections.emptyList();
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value1);
+
+ // cleanup
+ closeAndCleanupTables(primary, index1);
}
- // setup the primary table
- String indexedTableName = Bytes.toString(TestTable.getTableName());
- @SuppressWarnings("deprecation")
- HTableDescriptor pTable = new HTableDescriptor(indexedTableName);
- pTable.addFamily(new HColumnDescriptor(FAM));
- pTable.addFamily(new HColumnDescriptor(FAM2));
- builder.build(pTable);
-
- // create the primary table
- admin.createTable(pTable);
- HTable primary = new HTable(UTIL.getConfiguration(), indexedTableName);
- primary.setAutoFlush(false);
- return primary;
- }
-
- private void closeAndCleanupTables(HTable... tables) throws IOException {
- if (tables == null) {
- return;
+ /**
+ * If the client is using custom timestamps is possible that the updates come out-of-order (i.e.
+ * update to ts 10 comes after the update to ts 12). In the case, we need to be sure that the
+ * index is correctly updated when the out of order put arrives.
+ * @throws Exception
+ */
+ @Test
+ public void testOutOfOrderUpdates() throws Exception {
+ HTable primary = createSetupTables(fam1);
+
+ // do a put to the primary table
+ Put p = new Put(row1);
+ long ts = 12;
+ p.add(FAM, indexed_qualifer, ts, value1);
+ primary.put(p);
+ primary.flushCommits();
+
+ // read the index for the expected values
+ HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+
+ // build the expected kvs
+ List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+ // check the first entry at ts
+ List<KeyValue> expectedTs1 = CoveredColumnIndexCodec
+ .getIndexKeyValueForTesting(row1, ts, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs1, ts, value1);
+
+ // now make a put back in time
+ long ts2 = ts - 2;
+ p = new Put(row1);
+ p.add(FAM, indexed_qualifer, ts2, value2);
+ primary.put(p);
+ primary.flushCommits();
+
+ pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value2, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+ // check to make sure the back in time entry exists
+ List<KeyValue> expectedTs2 = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2,
+ pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs2, ts2, value2);
+ // then it should be gone at the newer ts (because it deletes itself)
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts2,
+ ts + 1, value2, HConstants.EMPTY_END_ROW);
+
+ // but that the original index entry is still visible at ts, just fine
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs1, ts, value1);
+
+ // cleanup
+ closeAndCleanupTables(primary, index1);
}
- for (HTable table : tables) {
- table.close();
- UTIL.deleteTable(table.getTableName());
+ /**
+ * Its possible (i.e. from a fast, frequently writing client) that they put more than the
+ * 'visible' number of versions in a row before a client make a put 'back in time' on that row. If
+ * we don't scan the current table properly, we won't see an index update for that 'back in time'
+ * update since the usual lookup will only see the regular number of versions. This ability to see
+ * back in time depends on running HBase 0.94.9
+ * @throws Exception on failure
+ */
+ @Test
+ public void testExceedVersionsOutOfOrderPut() throws Exception {
+ // setup the index
+ HTable primary = createSetupTables(fam2);
+
+ // do a put to the primary table
+ Put p = new Put(row1);
+ long ts1 = 1, ts2 = 2, ts3 = 3, ts4 = 4, ts5 = 5;
+ byte[] value4 = Bytes.toBytes("val4");
+ byte[] value5 = Bytes.toBytes("val5");
+ p.add(FAM2, indexed_qualifer, ts1, value1);
+ primary.put(p);
+ primary.flushCommits();
+
+ p = new Put(row1);
+ p.add(FAM2, indexed_qualifer, ts3, value3);
+ primary.put(p);
+ primary.flushCommits();
+
+ p = new Put(row1);
+ p.add(FAM2, indexed_qualifer, ts4, value4);
+ primary.put(p);
+ primary.flushCommits();
+
+ p = new Put(row1);
+ p.add(FAM2, indexed_qualifer, ts5, value5);
+ primary.put(p);
+ primary.flushCommits();
+
+ // read the index for the expected values
+ HTable index = new HTable(UTIL.getConfiguration(), fam2.getTable());
+
+ // do a raw scan of everything in the table
+ if (LOG.isDebugEnabled()) {
+ // the whole table, all the keys
+ Scan s = new Scan();
+ s.setRaw(true);
+ ResultScanner scanner = index.getScanner(s);
+ for (Result r : scanner) {
+ LOG.debug("Found row:" + r);
+ }
+ scanner.close();
+ }
+
+ /*
+ * now we have definitely exceeded the number of versions visible to a usual client of the
+ * primary table, so we should try doing a put 'back in time' an make sure that has the correct
+ * index values and cleanup
+ */
+ p = new Put(row1);
+ p.add(FAM2, indexed_qualifer, ts2, value2);
+ primary.put(p);
+ primary.flushCommits();
+
+ // // read the index for the expected values
+ // HTable index = new HTable(UTIL.getConfiguration(), fam2.getTable());
+ //
+ // do a raw scan of everything in the table
+ if (LOG.isDebugEnabled()) {
+ // the whole table, all the keys
+ Scan s = new Scan();
+ s.setRaw(true);
+ ResultScanner scanner = index.getScanner(s);
+ for (Result r : scanner) {
+ LOG.debug("Found row:" + r);
+ }
+ scanner.close();
+ }
+
+ // build the expected kvs
+ List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col3));
+
+ // check the value1 should be present at the earliest timestamp
+ List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts1, value1, value2);
+
+ // and value1 should be removed at ts2 (even though it came later)
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts1,
+ ts2 + 1, value1, value2); // timestamp + 1 since its exclusive end timestamp
+
+ // late added column should be there just fine at its timestamp
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value2, col3));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts2, value2);
+
+ // and check that the late entry also removes its self at the next timestamp up
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts3,
+ value2, value3);
+
+ // then we should have the rest of the inserts at their appropriate timestamps. Everything else
+ // should be exactly the same, except we shouldn't see ts0 anymore at ts2
+
+ // check the third entry
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col3));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts3, value3);
+
+ // check the fourth entry
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value4, col3));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts4, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts4, value4);
+
+ // check the first entry at ts4
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value2, col3));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts2, value2);
+ // verify that we remove the entry, even though its too far 'back in time'
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts3,
+ value4);
+
+ // cleanup
+ closeAndCleanupTables(primary, index);
+ }
+
+ /**
+ * Similar to {@link #testExceedVersionsOutOfOrderPut()}, but mingles deletes and puts.
+ * @throws Exception on failure
+ */
+ @Test
+ public void testExceedVersionsOutOfOrderUpdates() throws Exception {
+ HTable primary = createSetupTables(fam1);
+
+ // setup the data to store
+ long ts1 = 1, ts2 = 2, ts3 = 3, ts4 = 4, ts5 = 5, ts6 = 6;
+ byte[] value4 = Bytes.toBytes("val4"), value5 = Bytes.toBytes("val5"), value6 =
+ Bytes.toBytes("val6");
+ // values for the other column to index
+ byte[] v1_1 = ArrayUtils.addAll(value1, Bytes.toBytes("_otherCol")), v3_1 =
+ ArrayUtils.addAll(value3, Bytes.toBytes("_otherCol")), v5_1 =
+ ArrayUtils.addAll(value5, Bytes.toBytes("_otherCol")), v6_1 =
+ ArrayUtils.addAll(value6, Bytes.toBytes("_otherCol"));
+
+ // make some puts to the primary table
+ Put p = new Put(row1);
+ p.add(FAM, indexed_qualifer, ts1, value1);
+ p.add(FAM2, indexed_qualifer, ts1, v1_1);
+ primary.put(p);
+ primary.flushCommits();
+
+ p = new Put(row1);
+ p.add(FAM, indexed_qualifer, ts3, value3);
+ p.add(FAM2, indexed_qualifer, ts3, v3_1);
+ primary.put(p);
+ primary.flushCommits();
+
+ p = new Put(row1);
+ p.add(FAM, indexed_qualifer, ts5, value5);
+ p.add(FAM2, indexed_qualifer, ts5, v5_1);
+ primary.put(p);
+ primary.flushCommits();
+
+ p = new Put(row1);
+ p.add(FAM, indexed_qualifer, ts6, value6);
+ p.add(FAM2, indexed_qualifer, ts6, v6_1);
+ primary.put(p);
+ primary.flushCommits();
+
+ /*
+ * now we have definitely exceeded the number of versions visible to a usual client of the
+ * primary table, so we should try doing a put 'back in time' an make sure that has the correct
+ * index values and cleanup
+ */
+ p = new Put(row1);
+ p.add(FAM, indexed_qualifer, ts2, value2);
+ primary.put(p);
+ primary.flushCommits();
+
+ // read the index for the expected values
+ HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+
+ // do a raw scan of everything in the table
+ if (LOG.isDebugEnabled()) {
+ Scan s = new Scan();
+ s.setRaw(true);
+ ResultScanner scanner = index1.getScanner(s);
+ for (Result r : scanner) {
+ LOG.debug("Found row:" + r);
+ }
+ scanner.close();
+ }
+
+ // build the expected kvs
+ List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+ pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
+
+ // check the value1 should be present at the earliest timestamp
+ List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1, value2);
+
+ // and value1 should be removed at ts2 (even though it came later)
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts1,
+ ts2 + 1, value1, value2); // timestamp + 1 since its exclusive end timestamp
+
+ // late added column should be there just fine at its timestamp
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value2, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value2);
+
+ // and check that the late entry also removes its self at the next timestamp up
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts3,
+ value2, value3);
+
+ // -----------------------------------------------
+ // Check Delete intermingled
+ // -----------------------------------------------
+
+ // verify that the old row is there
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(v3_1, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
+ // scan from the start key forward (should only include [value3][v3_3])
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, expected.get(0).getKey(),
+ value4);
+
+ // then do a delete of just one of the indexed columns. This should insert a delete for all just
+ // the single value, then a put & a later corresponding in the past for the new value
+ Delete d = new Delete(row1);
+ d.deleteColumn(FAM2, indexed_qualifer, ts3);
+ primary.delete(d);
+
+ // we shouldn't find that entry, but we should find [value3][v1_1] since that is next entry back
+ // in time from the current
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
+ // it should be re-written at 3
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value3, value4);
+
+ // but we shouldn't find it at ts5 since it should be covered again
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts5,
+ value3, value4);
+
+ // now remove all the older columns in FAM2 at 4
+ d = new Delete(row1);
+ d.deleteColumns(FAM2, indexed_qualifer, ts4);
+ primary.delete(d);
+
+ // we shouldn't find that entry, but we should find [value3][null] since deleteColumns removes
+ // all the entries for that column
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts4, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts4, value3, value4);
+
+ // same as above, but now do it at 3 (on earlier)
+ d = new Delete(row1);
+ d.deleteColumns(FAM2, indexed_qualifer, ts3);
+ primary.delete(d);
+
+ // we shouldn't find that entry, but we should find [value3][null] since deleteColumns removes
+ // all the entries for that column
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value3, value4);
+
+ // -----------------------------------------------
+ // then we should have the rest of the inserts at their appropriate timestamps. Everything else
+ // should be exactly the same, except we shouldn't see ts0 anymore at ts2
+ // -----------------------------------------------
+
+ // check the entry at 5
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value5, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(v5_1, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts5, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts5, value5);
+
+ // check the entry at 6
+ pairs.clear();
+ pairs.add(new Pair<byte[], CoveredColumn>(value6, col1));
+ pairs.add(new Pair<byte[], CoveredColumn>(v6_1, col2));
+ expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts6, pairs);
+ IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts6, value5);
+
+ // cleanup
+ closeAndCleanupTables(primary, index1);
+ }
+
+ /**
+ * Create the primary table (to which you should write), setup properly for indexing the given
+ * {@link ColumnGroup}s. Also creates the necessary index tables to match the passes groups.
+ * @param groups {@link ColumnGroup}s to index, creating one index table per column group.
+ * @return reference to the primary table
+ * @throws IOException if there is an issue communicating with HBase
+ */
+ private HTable createSetupTables(ColumnGroup... groups) throws IOException {
+ HBaseAdmin admin = UTIL.getHBaseAdmin();
+ // setup the index
+ CoveredColumnIndexSpecifierBuilder builder = new CoveredColumnIndexSpecifierBuilder();
+ for (ColumnGroup group : groups) {
+ builder.addIndexGroup(group);
+ // create the index tables
+ CoveredColumnIndexer.createIndexTable(admin, group.getTable());
+ }
+
+ // setup the primary table
+ String indexedTableName = Bytes.toString(TestTable.getTableName());
+ @SuppressWarnings("deprecation")
+ HTableDescriptor pTable = new HTableDescriptor(indexedTableName);
+ pTable.addFamily(new HColumnDescriptor(FAM));
+ pTable.addFamily(new HColumnDescriptor(FAM2));
+ builder.build(pTable);
+
+ // create the primary table
+ admin.createTable(pTable);
+ HTable primary = new HTable(UTIL.getConfiguration(), indexedTableName);
+ primary.setAutoFlush(false);
+ return primary;
+ }
+
+ private void closeAndCleanupTables(HTable... tables) throws IOException {
+ if (tables == null) {
+ return;
+ }
+
+ for (HTable table : tables) {
+ table.close();
+ UTIL.deleteTable(table.getTableName());
+ }
}
- }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndtoEndIndexingWithCompressionIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndtoEndIndexingWithCompressionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndtoEndIndexingWithCompressionIT.java
index 016c59e..b0aeea3 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndtoEndIndexingWithCompressionIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndtoEndIndexingWithCompressionIT.java
@@ -17,14 +17,10 @@
*/
package org.apache.phoenix.hbase.index.covered.example;
-import static org.apache.phoenix.query.BaseTest.setUpConfigForMiniCluster;
-
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec;
import org.apache.hadoop.hbase.regionserver.wal.WALCellCodec;
-import org.apache.phoenix.hbase.index.IndexTestingUtils;
-import org.apache.phoenix.hbase.index.Indexer;
import org.junit.BeforeClass;
/**
@@ -34,19 +30,16 @@ import org.junit.BeforeClass;
public class EndtoEndIndexingWithCompressionIT extends EndToEndCoveredIndexingIT {
- @BeforeClass
- public static void setupCluster() throws Exception {
- //add our codec and enable WAL compression
- Configuration conf = UTIL.getConfiguration();
- setUpConfigForMiniCluster(conf);
- IndexTestingUtils.setupConfig(conf);
- // disable version checking, so we can test against whatever version of HBase happens to be
- // installed (right now, its generally going to be SNAPSHOT versions).
- conf.setBoolean(Indexer.CHECK_VERSION_CONF_KEY, false);
- conf.set(WALCellCodec.WAL_CELL_CODEC_CLASS_KEY,
- IndexedWALEditCodec.class.getName());
- conf.setBoolean(HConstants.ENABLE_WAL_COMPRESSION, true);
- //start the mini-cluster
- UTIL.startMiniCluster();
- }
+ @BeforeClass
+ public static void setupCluster() throws Exception {
+ setupConfig();
+ //add our codec and enable WAL compression
+ Configuration conf = UTIL.getConfiguration();
+ conf.set(WALCellCodec.WAL_CELL_CODEC_CLASS_KEY,
+ IndexedWALEditCodec.class.getName());
+ conf.setBoolean(HConstants.ENABLE_WAL_COMPRESSION, true);
+ //start the mini-cluster
+ UTIL.startMiniCluster();
+ initDriver();
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java b/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java
index e2ebad4..0e74d7b 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java
@@ -38,6 +38,8 @@ import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.phoenix.end2end.NeedsOwnMiniClusterTest;
import org.apache.phoenix.jdbc.PhoenixDriver;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
import org.apache.phoenix.util.DateUtil;
import org.apache.phoenix.util.PhoenixRuntime;
import org.junit.AfterClass;
@@ -58,6 +60,9 @@ public class CsvBulkLoadToolIT {
hbaseTestUtil = new HBaseTestingUtility();
Configuration conf = hbaseTestUtil.getConfiguration();
setUpConfigForMiniCluster(conf);
+ // Since we're using the real PhoenixDriver in this test, remove the
+ // extra JDBC argument that causes the test driver to be used.
+ conf.set(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS);
hbaseTestUtil.startMiniCluster();
hbaseTestUtil.startMiniMapReduceCluster();
http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/IndexToolIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/IndexToolIT.java b/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/IndexToolIT.java
index 30cae36..c88a5f4 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/IndexToolIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/IndexToolIT.java
@@ -37,6 +37,8 @@ import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.phoenix.end2end.NeedsOwnMiniClusterTest;
import org.apache.phoenix.jdbc.PhoenixDriver;
import org.apache.phoenix.mapreduce.index.IndexTool;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
import org.apache.phoenix.util.MetaDataUtil;
import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.PropertiesUtil;
@@ -63,6 +65,9 @@ public class IndexToolIT {
hbaseTestUtil = new HBaseTestingUtility();
Configuration conf = hbaseTestUtil.getConfiguration();
conf.setBoolean("hbase.defaults.for.version.skip", true);
+ // Since we're using the real PhoenixDriver in this test, remove the
+ // extra JDBC argument that causes the test driver to be used.
+ conf.set(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS);
setUpConfigForMiniCluster(conf);
hbaseTestUtil.startMiniCluster();
hbaseTestUtil.startMiniMapReduceCluster();
http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
index 835f639..70d8f5e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
@@ -168,6 +168,7 @@ public interface QueryServices extends SQLCloseable {
public static final String COLLECT_REQUEST_LEVEL_METRICS = "phoenix.query.request.metrics.enabled";
public static final String ALLOW_VIEWS_ADD_NEW_CF_BASE_TABLE = "phoenix.schema.view.newcf";
public static final String RETURN_SEQUENCE_VALUES_ATTRIB = "phoenix.sequence.returnValues";
+ public static final String EXTRA_JDBC_ARGUMENTS_ATTRIB = "phoenix.jdbc.extra.arguments";
/**
http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
index 9f69c05..3a4a51f 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
@@ -27,6 +27,7 @@ import static org.apache.phoenix.query.QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB
import static org.apache.phoenix.query.QueryServices.DELAY_FOR_SCHEMA_UPDATE_CHECK;
import static org.apache.phoenix.query.QueryServices.DROP_METADATA_ATTRIB;
import static org.apache.phoenix.query.QueryServices.EXPLAIN_CHUNK_COUNT_ATTRIB;
+import static org.apache.phoenix.query.QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB;
import static org.apache.phoenix.query.QueryServices.FORCE_ROW_KEY_ORDER_ATTRIB;
import static org.apache.phoenix.query.QueryServices.GLOBAL_METRICS_ENABLED;
import static org.apache.phoenix.query.QueryServices.GROUPBY_MAX_CACHE_SIZE_ATTRIB;
@@ -198,6 +199,7 @@ public class QueryServicesOptions {
public static final boolean DEFAULT_ALLOW_VIEWS_ADD_NEW_CF_BASE_TABLE = true;
public static final boolean DEFAULT_RETURN_SEQUENCE_VALUES = false;
+ public static final String DEFAULT_EXTRA_JDBC_ARGUMENTS = "";
private final Configuration config;
@@ -543,4 +545,8 @@ public class QueryServicesOptions {
return this;
}
+ public QueryServicesOptions setExtraJDBCArguments(String extraArgs) {
+ config.set(EXTRA_JDBC_ARGUMENTS_ATTRIB, extraArgs);
+ return this;
+ }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
index 6506184..364bef5 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
@@ -45,6 +45,7 @@ import org.apache.phoenix.parse.HintNode;
import org.apache.phoenix.parse.HintNode.Hint;
import org.apache.phoenix.parse.WildcardParseNode;
import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
@@ -305,6 +306,9 @@ public final class QueryUtil {
throws ClassNotFoundException, SQLException {
// TODO: props is ignored!
// make sure we load the phoenix driver
+ // TODO: remove this - it doesn't belong here
+ // The driver should be loaded outside of this call as we might
+ // be using the test driver.
Class.forName(PhoenixDriver.class.getName());
// read the hbase properties from the configuration
@@ -341,8 +345,13 @@ public final class QueryUtil {
server = Joiner.on(',').join(servers);
String znodeParent = conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT,
HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT);
-
- return getUrl(server, port, znodeParent);
+ String url = getUrl(server, port, znodeParent);
+ // Mainly for testing to tack on the test=true part to ensure driver is found on server
+ String extraArgs = conf.get(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS);
+ if (extraArgs.length() > 0) {
+ url += extraArgs + PhoenixRuntime.JDBC_PROTOCOL_TERMINATOR;
+ }
+ return url;
}
public static String getViewStatement(String schemaName, String tableName, String where) {
http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java b/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java
index 9fee78f..5289ab9 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java
@@ -21,6 +21,7 @@ import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_SPOOL_DIRECT
import static org.apache.phoenix.query.QueryServicesOptions.withDefaults;
import org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec;
+import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.ReadOnlyProps;
@@ -53,6 +54,8 @@ public final class QueryServicesTestImpl extends BaseQueryServicesImpl {
public static final long DEFAULT_MAX_CLIENT_METADATA_CACHE_SIZE = 1024L*1024L*2L; // 2 Mb
public static final int DEFAULT_MIN_STATS_UPDATE_FREQ_MS = 0;
public static final boolean DEFAULT_EXPLAIN_CHUNK_COUNT = false; // TODO: update explain plans in test and set to true
+ public static final String DEFAULT_EXTRA_JDBC_ARGUMENTS = PhoenixRuntime.PHOENIX_TEST_DRIVER_URL_PARAM;
+
/**
* Set number of salt buckets lower for sequence table during testing, as a high
@@ -89,7 +92,8 @@ public final class QueryServicesTestImpl extends BaseQueryServicesImpl {
.setDropMetaData(DEFAULT_DROP_METADATA)
.setMaxClientMetaDataCacheSize(DEFAULT_MAX_CLIENT_METADATA_CACHE_SIZE)
.setMaxServerMetaDataCacheSize(DEFAULT_MAX_SERVER_METADATA_CACHE_SIZE)
- .setForceRowKeyOrder(DEFAULT_FORCE_ROWKEY_ORDER);
+ .setForceRowKeyOrder(DEFAULT_FORCE_ROWKEY_ORDER)
+ .setExtraJDBCArguments(DEFAULT_EXTRA_JDBC_ARGUMENTS);
}
public QueryServicesTestImpl(ReadOnlyProps defaultProps, ReadOnlyProps overrideProps) {
[2/3] phoenix git commit: PHOENIX-2397 Execution default-test of goal
org.apache.maven.plugins:maven-surefire-plugin:2.18:test failed.
NullPointerException
Posted by ja...@apache.org.
PHOENIX-2397 Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.18:test failed. NullPointerException
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/b9a3c532
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/b9a3c532
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/b9a3c532
Branch: refs/heads/4.x-HBase-0.98
Commit: b9a3c53204d6ca34758bea362025dfcc94e2931c
Parents: a722b0e
Author: James Taylor <ja...@apache.org>
Authored: Tue Nov 10 16:55:01 2015 -0800
Committer: James Taylor <jt...@salesforce.com>
Committed: Wed Nov 11 09:58:59 2015 -0800
----------------------------------------------------------------------
pom.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/b9a3c532/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index e492bee..da16d4e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -120,8 +120,8 @@
<!-- Plugin versions -->
<maven-eclipse-plugin.version>2.9</maven-eclipse-plugin.version>
<maven-build-helper-plugin.version>1.9.1</maven-build-helper-plugin.version>
- <maven-surefire-plugin.version>2.18</maven-surefire-plugin.version>
- <maven-failsafe-plugin.version>2.18</maven-failsafe-plugin.version>
+ <maven-surefire-plugin.version>2.19</maven-surefire-plugin.version>
+ <maven-failsafe-plugin.version>2.19</maven-failsafe-plugin.version>
<maven-dependency-plugin.version>2.1</maven-dependency-plugin.version>
<maven.assembly.version>2.5.2</maven.assembly.version>