use of org.apache.phoenix.hbase.index.scanner.ScannerBuilder.CoveredDeleteScanner in project phoenix by apache.
the class LocalTableState method getIndexedColumnsTableState.
/**
* Get a scanner on the columns that are needed by the index.
* <p>
* The returned scanner is already pre-seeked to the first {@link KeyValue} that matches the given
* columns with a timestamp earlier than the timestamp to which the table is currently set (the
* current state of the table for which we need to build an update).
* <p>
* If none of the passed columns matches any of the columns in the pending update (as determined
* by {@link ColumnReference#matchesFamily(byte[])} and
* {@link ColumnReference#matchesQualifier(byte[])}, then an empty scanner will be returned. This
* is because it doesn't make sense to build index updates when there is no change in the table
* state for any of the columns you are indexing.
* <p>
* <i>NOTE:</i> This method should <b>not</b> be used during
* {@link IndexCodec#getIndexDeletes(TableState, BatchState)} as the pending update will not yet have been
* applied - you are merely attempting to cleanup the current state and therefore do <i>not</i>
* need to track the indexed columns.
* <p>
* As a side-effect, we update a timestamp for the next-most-recent timestamp for the columns you
* request - you will never see a column with the timestamp we are tracking, but the next oldest
* timestamp for that column.
* @param indexedColumns the columns to that will be indexed
* @param ignoreNewerMutations ignore mutations newer than m when determining current state. Useful
* when replaying mutation state for partial index rebuild where writes succeeded to the data
* table, but not to the index table.
* @param indexMetaData TODO
* @return an iterator over the columns and the {@link IndexUpdate} that should be passed back to
* the builder. Even if no update is necessary for the requested columns, you still need
* to return the {@link IndexUpdate}, just don't set the update for the
* {@link IndexUpdate}.
* @throws IOException
*/
public Pair<CoveredDeleteScanner, IndexUpdate> getIndexedColumnsTableState(Collection<? extends ColumnReference> indexedColumns, boolean ignoreNewerMutations, boolean isStateForDeletes, IndexMetaData indexMetaData) throws IOException {
// check to see if we haven't initialized any columns yet
Collection<? extends ColumnReference> toCover = this.columnSet.findNonCoveredColumns(indexedColumns);
// add the covered columns to the set
for (ColumnReference ref : toCover) {
this.columnSet.addColumn(ref);
}
boolean requiresPriorRowState = indexMetaData.requiresPriorRowState(update);
if (!toCover.isEmpty()) {
// needing to lookup the prior row values.
if (requiresPriorRowState) {
// add the current state of the row. Uses listCells() to avoid a new array creation.
this.addUpdateCells(this.table.getCurrentRowState(update, toCover, ignoreNewerMutations).listCells(), false);
}
}
// filter out things with a newer timestamp and track the column references to which it applies
ColumnTracker tracker = new ColumnTracker(indexedColumns);
synchronized (this.trackedColumns) {
// we haven't seen this set of columns before, so we need to create a new tracker
if (!this.trackedColumns.contains(tracker)) {
this.trackedColumns.add(tracker);
}
}
CoveredDeleteScanner scanner = this.scannerBuilder.buildIndexedColumnScanner(indexedColumns, tracker, ts, // TODO: use mutable transactional secondary index implementation instead (PhoenixTransactionalIndexer)
isStateForDeletes && (requiresPriorRowState || insertingData(update)));
return new Pair<CoveredDeleteScanner, IndexUpdate>(scanner, new IndexUpdate(tracker));
}
use of org.apache.phoenix.hbase.index.scanner.ScannerBuilder.CoveredDeleteScanner in project phoenix by apache.
the class LocalTableStateTest method testNoScannerForImmutableRows.
@Test
public void testNoScannerForImmutableRows() throws Exception {
IndexMetaData indexMetaData = new IndexMetaData() {
@Override
public ReplayWrite getReplayWrite() {
return null;
}
@Override
public boolean requiresPriorRowState(Mutation m) {
return false;
}
};
Put m = new Put(row);
m.add(fam, qual, ts, val);
// setup mocks
Configuration conf = new Configuration(false);
RegionCoprocessorEnvironment env = Mockito.mock(RegionCoprocessorEnvironment.class);
Mockito.when(env.getConfiguration()).thenReturn(conf);
Region region = Mockito.mock(Region.class);
Mockito.when(env.getRegion()).thenReturn(region);
Mockito.when(region.getScanner(Mockito.any(Scan.class))).thenThrow(new ScannerCreatedException("Should not open scanner when data is immutable"));
LocalHBaseState state = new LocalTable(env);
LocalTableState table = new LocalTableState(state, m);
// add the kvs from the mutation
table.addPendingUpdates(KeyValueUtil.ensureKeyValues(m.get(fam, qual)));
// setup the lookup
ColumnReference col = new ColumnReference(fam, qual);
table.setCurrentTimestamp(ts);
// check that our value still shows up first on scan, even though this is a lazy load
Pair<CoveredDeleteScanner, IndexUpdate> p = table.getIndexedColumnsTableState(Arrays.asList(col), false, false, indexMetaData);
Scanner s = p.getFirst();
assertEquals("Didn't get the pending mutation's value first", m.get(fam, qual).get(0), s.next());
}
use of org.apache.phoenix.hbase.index.scanner.ScannerBuilder.CoveredDeleteScanner in project phoenix by apache.
the class LocalTableStateTest method testOnlyLoadsRequestedColumns.
@SuppressWarnings("unchecked")
@Test
public void testOnlyLoadsRequestedColumns() throws Exception {
// setup mocks
RegionCoprocessorEnvironment env = Mockito.mock(RegionCoprocessorEnvironment.class);
Region region = Mockito.mock(Region.class);
Mockito.when(env.getRegion()).thenReturn(region);
RegionScanner scanner = Mockito.mock(RegionScanner.class);
Mockito.when(region.getScanner(Mockito.any(Scan.class))).thenReturn(scanner);
final KeyValue storedKv = new KeyValue(row, fam, qual, ts, Type.Put, Bytes.toBytes("stored-value"));
storedKv.setSequenceId(2);
Mockito.when(scanner.next(Mockito.any(List.class))).thenAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
List<KeyValue> list = (List<KeyValue>) invocation.getArguments()[0];
list.add(storedKv);
return false;
}
});
LocalHBaseState state = new LocalTable(env);
Put pendingUpdate = new Put(row);
pendingUpdate.add(fam, qual, ts, val);
LocalTableState table = new LocalTableState(state, pendingUpdate);
// do the lookup for the given column
ColumnReference col = new ColumnReference(fam, qual);
table.setCurrentTimestamp(ts);
// check that the value is there
Pair<CoveredDeleteScanner, IndexUpdate> p = table.getIndexedColumnsTableState(Arrays.asList(col), false, false, indexMetaData);
Scanner s = p.getFirst();
// make sure it read the table the one time
assertEquals("Didn't get the stored keyvalue!", storedKv, s.next());
// on the second lookup it shouldn't access the underlying table again - the cached columns
// should know they are done
p = table.getIndexedColumnsTableState(Arrays.asList(col), false, false, indexMetaData);
s = p.getFirst();
assertEquals("Lost already loaded update!", storedKv, s.next());
Mockito.verify(env, Mockito.times(1)).getRegion();
Mockito.verify(region, Mockito.times(1)).getScanner(Mockito.any(Scan.class));
}
Aggregations