use of org.apache.phoenix.hbase.index.util.ImmutableBytesPtr in project phoenix by apache.
the class DropColumnIT method verifyColValue.
private void verifyColValue(String indexTableName, String dataTableName, Connection conn, PTable dataTable, PColumn dataColumn, byte[] dataCq, PTable globalIndexTable, PColumn glovalIndexCol, byte[] globalIndexCq, PTable localIndexTable, PColumn localIndexCol, byte[] localIndexCq) throws SQLException, IOException, ArrayComparisonFailure {
// key value for v2 should exist in the data table
Scan scan = new Scan();
scan.setRaw(true);
byte[] key = Bytes.toBytes("a");
scan.setStartRow(key);
scan.setStopRow(key);
HTable table = (HTable) conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(dataTableName.getBytes());
ResultScanner results = table.getScanner(scan);
Result result = results.next();
assertNotNull(result);
byte[] colValue;
if (!mutable && columnEncoded) {
KeyValueColumnExpression colExpression = new SingleCellColumnExpression(dataColumn, "V2", dataTable.getEncodingScheme());
ImmutableBytesPtr ptr = new ImmutableBytesPtr();
colExpression.evaluate(new ResultTuple(result), ptr);
colValue = ptr.copyBytesIfNecessary();
} else {
colValue = result.getValue(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, dataCq);
}
assertArrayEquals("wrong column value for v2", Bytes.toBytes("1"), colValue);
assertNull(results.next());
// key value for v2 should exist in the global index table
scan = new Scan();
scan.setRaw(true);
table = (HTable) conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(indexTableName.getBytes());
results = table.getScanner(scan);
result = results.next();
assertNotNull(result);
if (!mutable && columnEncoded) {
KeyValueColumnExpression colExpression = new SingleCellColumnExpression(glovalIndexCol, "0:V2", globalIndexTable.getEncodingScheme());
ImmutableBytesPtr ptr = new ImmutableBytesPtr();
colExpression.evaluate(new ResultTuple(result), ptr);
colValue = ptr.copyBytesIfNecessary();
} else {
colValue = result.getValue(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, globalIndexCq);
}
assertArrayEquals("wrong column value for v2", Bytes.toBytes("1"), colValue);
assertNull(results.next());
// key value for v2 should exist in the local index table
scan = new Scan();
scan.setRaw(true);
scan.addFamily(QueryConstants.DEFAULT_LOCAL_INDEX_COLUMN_FAMILY_BYTES);
table = (HTable) conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(dataTableName.getBytes());
results = table.getScanner(scan);
result = results.next();
assertNotNull(result);
if (!mutable && columnEncoded) {
KeyValueColumnExpression colExpression = new SingleCellColumnExpression(localIndexCol, "0:V2", localIndexTable.getEncodingScheme());
ImmutableBytesPtr ptr = new ImmutableBytesPtr();
colExpression.evaluate(new ResultTuple(result), ptr);
colValue = ptr.copyBytesIfNecessary();
} else {
colValue = result.getValue(QueryConstants.DEFAULT_LOCAL_INDEX_COLUMN_FAMILY_BYTES, localIndexCq);
}
assertArrayEquals("wrong column value for v2", Bytes.toBytes("1"), colValue);
assertNull(results.next());
}
use of org.apache.phoenix.hbase.index.util.ImmutableBytesPtr in project phoenix by apache.
the class DropColumnIT method testDroppingIndexedColDropsIndex.
@Test
public void testDroppingIndexedColDropsIndex() throws Exception {
String indexTableName = generateUniqueName();
String dataTableFullName = SchemaUtil.getTableName(SCHEMA_NAME, generateUniqueName());
String localIndexTableName1 = "LOCAL_" + indexTableName + "_1";
String localIndexTableName2 = "LOCAL_" + indexTableName + "_2";
try (Connection conn = getConnection()) {
conn.setAutoCommit(false);
conn.createStatement().execute("CREATE TABLE " + dataTableFullName + " (k VARCHAR NOT NULL PRIMARY KEY, v1 VARCHAR, v2 VARCHAR) " + tableDDLOptions);
// create one regular and two local indexes
conn.createStatement().execute("CREATE INDEX " + indexTableName + " ON " + dataTableFullName + " (v2) INCLUDE (v1)");
conn.createStatement().execute("CREATE LOCAL INDEX " + localIndexTableName1 + " ON " + dataTableFullName + " (v2) INCLUDE (v1)");
conn.createStatement().execute("CREATE LOCAL INDEX " + localIndexTableName2 + " ON " + dataTableFullName + " (k) INCLUDE (v1)");
// upsert a single row
PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + dataTableFullName + " VALUES(?,?,?)");
stmt.setString(1, "a");
stmt.setString(2, "x");
stmt.setString(3, "1");
stmt.execute();
conn.commit();
// verify the indexes were created
PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
PTable dataTable = pconn.getTable(new PTableKey(null, dataTableFullName));
assertEquals("Unexpected number of indexes ", 3, dataTable.getIndexes().size());
PTable indexTable = dataTable.getIndexes().get(0);
byte[] indexTablePhysicalName = indexTable.getPhysicalName().getBytes();
PName localIndexTablePhysicalName = dataTable.getIndexes().get(1).getPhysicalName();
// drop v2 which causes the regular index and first local index to be dropped
conn.createStatement().execute("ALTER TABLE " + dataTableFullName + " DROP COLUMN v2 ");
// verify the both of the indexes' metadata were dropped
conn.createStatement().execute("SELECT * FROM " + dataTableFullName);
try {
conn.createStatement().execute("SELECT * FROM " + indexTableName);
fail("Index should have been dropped");
} catch (TableNotFoundException e) {
}
pconn = conn.unwrap(PhoenixConnection.class);
dataTable = pconn.getTable(new PTableKey(null, dataTableFullName));
try {
pconn.getTable(new PTableKey(null, indexTableName));
fail("index should have been dropped");
} catch (TableNotFoundException e) {
}
try {
pconn.getTable(new PTableKey(null, localIndexTableName1));
fail("index should have been dropped");
} catch (TableNotFoundException e) {
}
assertEquals("Unexpected number of indexes ", 1, dataTable.getIndexes().size());
// verify that the regular index physical table was dropped
try {
conn.unwrap(PhoenixConnection.class).getQueryServices().getTableDescriptor(indexTablePhysicalName);
fail("Index table should have been dropped");
} catch (TableNotFoundException e) {
}
// verify that the local index physical table was *not* dropped
conn.unwrap(PhoenixConnection.class).getQueryServices().getTableDescriptor(localIndexTablePhysicalName.getBytes());
PTable localIndex2 = conn.unwrap(PhoenixConnection.class).getTable(new PTableKey(null, localIndexTableName2));
// there should be a single row belonging to localIndexTableName2
Scan scan = new Scan();
scan.addFamily(QueryConstants.DEFAULT_LOCAL_INDEX_COLUMN_FAMILY_BYTES);
HTable table = (HTable) conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(localIndexTablePhysicalName.getBytes());
ResultScanner results = table.getScanner(scan);
Result result = results.next();
assertNotNull(result);
String indexColumnName = IndexUtil.getIndexColumnName(QueryConstants.DEFAULT_COLUMN_FAMILY, "V1");
PColumn localIndexCol = localIndex2.getColumnForColumnName(indexColumnName);
byte[] colValue;
if (!mutable && columnEncoded) {
KeyValueColumnExpression colExpression = new SingleCellColumnExpression(localIndexCol, indexColumnName, localIndex2.getEncodingScheme());
ImmutableBytesPtr ptr = new ImmutableBytesPtr();
colExpression.evaluate(new ResultTuple(result), ptr);
colValue = ptr.copyBytesIfNecessary();
} else {
colValue = result.getValue(QueryConstants.DEFAULT_LOCAL_INDEX_COLUMN_FAMILY_BYTES, localIndexCol.getColumnQualifierBytes());
}
assertNotNull("localIndexTableName2 row is missing", colValue);
assertNull(results.next());
}
}
use of org.apache.phoenix.hbase.index.util.ImmutableBytesPtr in project phoenix by apache.
the class StoreNullsIT method ensureNullsStoredCorrectly.
private void ensureNullsStoredCorrectly(Connection conn) throws Exception {
ResultSet rs1 = conn.createStatement().executeQuery("SELECT NAME FROM " + dataTableName);
rs1.next();
assertEquals("v1", rs1.getString(1));
rs1.next();
assertNull(rs1.getString(1));
rs1.next();
HTable htable = new HTable(getUtility().getConfiguration(), dataTableName);
Scan s = new Scan();
s.setRaw(true);
ResultScanner scanner = htable.getScanner(s);
// first row has a value for name
Result rs = scanner.next();
PTable table = conn.unwrap(PhoenixConnection.class).getTable(new PTableKey(null, dataTableName));
PColumn nameColumn = table.getColumnForColumnName("NAME");
byte[] qualifier = table.getImmutableStorageScheme() == ImmutableStorageScheme.SINGLE_CELL_ARRAY_WITH_OFFSETS ? QueryConstants.SINGLE_KEYVALUE_COLUMN_QUALIFIER_BYTES : nameColumn.getColumnQualifierBytes();
assertTrue(rs.containsColumn(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, qualifier));
// 2 because it also includes the empty key value column
assertTrue(rs.size() == 2);
KeyValueColumnExpression colExpression = table.getImmutableStorageScheme() == ImmutableStorageScheme.SINGLE_CELL_ARRAY_WITH_OFFSETS ? new SingleCellColumnExpression(nameColumn, "NAME", table.getEncodingScheme()) : new KeyValueColumnExpression(nameColumn);
ImmutableBytesPtr ptr = new ImmutableBytesPtr();
colExpression.evaluate(new ResultTuple(rs), ptr);
assertEquals(new ImmutableBytesPtr(PVarchar.INSTANCE.toBytes("v1")), ptr);
rs = scanner.next();
if (// we don't issue a put with empty value for immutable tables with cols stored per key value
!mutable && !columnEncoded || (mutable && !storeNulls)) {
// for this case we use a delete to represent the null
assertFalse(rs.containsColumn(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, qualifier));
assertEquals(1, rs.size());
} else {
assertTrue(rs.containsColumn(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, qualifier));
assertEquals(2, rs.size());
}
// assert null stored correctly
ptr = new ImmutableBytesPtr();
if (colExpression.evaluate(new ResultTuple(rs), ptr)) {
assertEquals(new ImmutableBytesPtr(ByteUtil.EMPTY_BYTE_ARRAY), ptr);
}
assertNull(scanner.next());
scanner.close();
htable.close();
}
use of org.apache.phoenix.hbase.index.util.ImmutableBytesPtr in project phoenix by apache.
the class MutationState method send.
@SuppressWarnings("deprecation")
private void send(Iterator<TableRef> tableRefIterator) throws SQLException {
int i = 0;
long[] serverTimeStamps = null;
boolean sendAll = false;
if (tableRefIterator == null) {
serverTimeStamps = validateAll();
tableRefIterator = mutations.keySet().iterator();
sendAll = true;
}
Map<ImmutableBytesPtr, RowMutationState> valuesMap;
List<TableRef> txTableRefs = Lists.newArrayListWithExpectedSize(mutations.size());
Map<TableInfo, List<Mutation>> physicalTableMutationMap = Maps.newLinkedHashMap();
// add tracing for this operation
try (TraceScope trace = Tracing.startNewSpan(connection, "Committing mutations to tables")) {
Span span = trace.getSpan();
ImmutableBytesWritable indexMetaDataPtr = new ImmutableBytesWritable();
boolean isTransactional;
while (tableRefIterator.hasNext()) {
// at this point we are going through mutations for each table
final TableRef tableRef = tableRefIterator.next();
valuesMap = mutations.get(tableRef);
if (valuesMap == null || valuesMap.isEmpty()) {
continue;
}
// Validate as we go if transactional since we can undo if a problem occurs (which is unlikely)
long serverTimestamp = serverTimeStamps == null ? validate(tableRef, valuesMap) : serverTimeStamps[i++];
final PTable table = tableRef.getTable();
Iterator<Pair<PName, List<Mutation>>> mutationsIterator = addRowMutations(tableRef, valuesMap, serverTimestamp, false, sendAll);
// build map from physical table to mutation list
boolean isDataTable = true;
while (mutationsIterator.hasNext()) {
Pair<PName, List<Mutation>> pair = mutationsIterator.next();
PName hTableName = pair.getFirst();
List<Mutation> mutationList = pair.getSecond();
TableInfo tableInfo = new TableInfo(isDataTable, hTableName, tableRef);
List<Mutation> oldMutationList = physicalTableMutationMap.put(tableInfo, mutationList);
if (oldMutationList != null)
mutationList.addAll(0, oldMutationList);
isDataTable = false;
}
// committed in the event of a failure.
if (table.isTransactional()) {
addUncommittedStatementIndexes(valuesMap.values());
if (txMutations.isEmpty()) {
txMutations = Maps.newHashMapWithExpectedSize(mutations.size());
}
// Keep all mutations we've encountered until a commit or rollback.
// This is not ideal, but there's not good way to get the values back
// in the event that we need to replay the commit.
// Copy TableRef so we have the original PTable and know when the
// indexes have changed.
joinMutationState(new TableRef(tableRef), valuesMap, txMutations);
}
}
long serverTimestamp = HConstants.LATEST_TIMESTAMP;
Iterator<Entry<TableInfo, List<Mutation>>> mutationsIterator = physicalTableMutationMap.entrySet().iterator();
while (mutationsIterator.hasNext()) {
Entry<TableInfo, List<Mutation>> pair = mutationsIterator.next();
TableInfo tableInfo = pair.getKey();
byte[] htableName = tableInfo.getHTableName().getBytes();
List<Mutation> mutationList = pair.getValue();
//create a span per target table
//TODO maybe we can be smarter about the table name to string here?
Span child = Tracing.child(span, "Writing mutation batch for table: " + Bytes.toString(htableName));
int retryCount = 0;
boolean shouldRetry = false;
do {
TableRef origTableRef = tableInfo.getOrigTableRef();
PTable table = origTableRef.getTable();
table.getIndexMaintainers(indexMetaDataPtr, connection);
final ServerCache cache = tableInfo.isDataTable() ? setMetaDataOnMutations(origTableRef, mutationList, indexMetaDataPtr) : null;
// If we haven't retried yet, retry for this case only, as it's possible that
// a split will occur after we send the index metadata cache to all known
// region servers.
shouldRetry = cache != null;
SQLException sqlE = null;
HTableInterface hTable = connection.getQueryServices().getTable(htableName);
try {
if (table.isTransactional()) {
// Track tables to which we've sent uncommitted data
txTableRefs.add(origTableRef);
addDMLFence(table);
uncommittedPhysicalNames.add(table.getPhysicalName().getString());
// rollback
if (!table.getIndexes().isEmpty()) {
hTable = new MetaDataAwareHTable(hTable, origTableRef);
}
TransactionAwareHTable txnAware = TransactionUtil.getTransactionAwareHTable(hTable, table.isImmutableRows());
// during a commit), as we don't need conflict detection for these.
if (tableInfo.isDataTable()) {
// Even for immutable, we need to do this so that an abort has the state
// necessary to generate the rows to delete.
addTransactionParticipant(txnAware);
} else {
txnAware.startTx(getTransaction());
}
hTable = txnAware;
}
long numMutations = mutationList.size();
GLOBAL_MUTATION_BATCH_SIZE.update(numMutations);
long startTime = System.currentTimeMillis();
child.addTimelineAnnotation("Attempt " + retryCount);
List<List<Mutation>> mutationBatchList = getMutationBatchList(batchSize, batchSizeBytes, mutationList);
for (List<Mutation> mutationBatch : mutationBatchList) {
hTable.batch(mutationBatch);
batchCount++;
}
if (logger.isDebugEnabled())
logger.debug("Sent batch of " + numMutations + " for " + Bytes.toString(htableName));
child.stop();
child.stop();
shouldRetry = false;
long mutationCommitTime = System.currentTimeMillis() - startTime;
GLOBAL_MUTATION_COMMIT_TIME.update(mutationCommitTime);
long mutationSizeBytes = calculateMutationSize(mutationList);
MutationMetric mutationsMetric = new MutationMetric(numMutations, mutationSizeBytes, mutationCommitTime);
mutationMetricQueue.addMetricsForTable(Bytes.toString(htableName), mutationsMetric);
if (tableInfo.isDataTable()) {
numRows -= numMutations;
}
// Remove batches as we process them
mutations.remove(origTableRef);
} catch (Exception e) {
serverTimestamp = ServerUtil.parseServerTimestamp(e);
SQLException inferredE = ServerUtil.parseServerExceptionOrNull(e);
if (inferredE != null) {
if (shouldRetry && retryCount == 0 && inferredE.getErrorCode() == SQLExceptionCode.INDEX_METADATA_NOT_FOUND.getErrorCode()) {
// Swallow this exception once, as it's possible that we split after sending the index metadata
// and one of the region servers doesn't have it. This will cause it to have it the next go around.
// If it fails again, we don't retry.
String msg = "Swallowing exception and retrying after clearing meta cache on connection. " + inferredE;
logger.warn(LogUtil.addCustomAnnotations(msg, connection));
connection.getQueryServices().clearTableRegionCache(htableName);
// add a new child span as this one failed
child.addTimelineAnnotation(msg);
child.stop();
child = Tracing.child(span, "Failed batch, attempting retry");
continue;
}
e = inferredE;
}
// Throw to client an exception that indicates the statements that
// were not committed successfully.
sqlE = new CommitException(e, getUncommittedStatementIndexes(), serverTimestamp);
} finally {
try {
if (cache != null)
cache.close();
} finally {
try {
hTable.close();
} catch (IOException e) {
if (sqlE != null) {
sqlE.setNextException(ServerUtil.parseServerException(e));
} else {
sqlE = ServerUtil.parseServerException(e);
}
}
if (sqlE != null) {
throw sqlE;
}
}
}
} while (shouldRetry && retryCount++ < 1);
}
}
}
use of org.apache.phoenix.hbase.index.util.ImmutableBytesPtr in project phoenix by apache.
the class MutationState method addRowMutations.
private Iterator<Pair<PName, List<Mutation>>> addRowMutations(final TableRef tableRef, final Map<ImmutableBytesPtr, RowMutationState> values, final long timestamp, boolean includeAllIndexes, final boolean sendAll) {
final PTable table = tableRef.getTable();
final // Only maintain tables with immutable rows through this client-side mechanism
Iterator<PTable> indexes = // TODO: remove check for isWALDisabled once PHOENIX-3137 is fixed.
includeAllIndexes || table.isWALDisabled() ? IndexMaintainer.nonDisabledIndexIterator(table.getIndexes().iterator()) : table.isImmutableRows() ? IndexMaintainer.enabledGlobalIndexIterator(table.getIndexes().iterator()) : Iterators.<PTable>emptyIterator();
final List<Mutation> mutationList = Lists.newArrayListWithExpectedSize(values.size());
final List<Mutation> mutationsPertainingToIndex = indexes.hasNext() ? Lists.<Mutation>newArrayListWithExpectedSize(values.size()) : null;
generateMutations(tableRef, timestamp, values, mutationList, mutationsPertainingToIndex);
return new Iterator<Pair<PName, List<Mutation>>>() {
boolean isFirst = true;
@Override
public boolean hasNext() {
return isFirst || indexes.hasNext();
}
@Override
public Pair<PName, List<Mutation>> next() {
if (isFirst) {
isFirst = false;
return new Pair<PName, List<Mutation>>(table.getPhysicalName(), mutationList);
}
PTable index = indexes.next();
List<Mutation> indexMutations;
try {
indexMutations = IndexUtil.generateIndexData(table, index, values, mutationsPertainingToIndex, connection.getKeyValueBuilder(), connection);
// we may also have to include delete mutations for immutable tables if we are not processing all the tables in the mutations map
if (!sendAll) {
TableRef key = new TableRef(index);
Map<ImmutableBytesPtr, RowMutationState> rowToColumnMap = mutations.remove(key);
if (rowToColumnMap != null) {
final List<Mutation> deleteMutations = Lists.newArrayList();
generateMutations(tableRef, timestamp, rowToColumnMap, deleteMutations, null);
indexMutations.addAll(deleteMutations);
}
}
} catch (SQLException e) {
throw new IllegalDataException(e);
}
return new Pair<PName, List<Mutation>>(index.getPhysicalName(), indexMutations);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
Aggregations