use of com.palantir.atlasdb.keyvalue.api.Value in project atlasdb by palantir.
the class CassandraKeyValueServiceImpl method getMetadataForTables.
/**
* Gets the metadata for all non-hidden tables.
* <p>
* Does not require all Cassandra nodes to be up and available, works as long as quorum is achieved.
*
* @return a mapping of table names to their respective metadata in form of a byte array. Consider
* {@link TableMetadata#BYTES_HYDRATOR} for hydrating.
*/
@Override
public Map<TableReference, byte[]> getMetadataForTables() {
Map<TableReference, byte[]> tableToMetadataContents = Maps.newHashMap();
// we don't even have a metadata table yet. Return empty map.
if (!getAllTableReferencesWithoutFiltering().contains(AtlasDbConstants.DEFAULT_METADATA_TABLE)) {
log.trace("getMetadata called with no _metadata table present");
return tableToMetadataContents;
}
try (ClosableIterator<RowResult<Value>> range = getRange(AtlasDbConstants.DEFAULT_METADATA_TABLE, RangeRequest.all(), Long.MAX_VALUE)) {
while (range.hasNext()) {
RowResult<Value> valueRow = range.next();
Iterable<Entry<Cell, Value>> cells = valueRow.getCells();
for (Entry<Cell, Value> entry : cells) {
Value value = entry.getValue();
TableReference tableRef = CassandraKeyValueServices.tableReferenceFromBytes(entry.getKey().getRowName());
byte[] contents;
if (value == null) {
contents = AtlasDbConstants.EMPTY_TABLE_METADATA;
} else {
contents = value.getContents();
}
if (!HiddenTables.isHidden(tableRef)) {
tableToMetadataContents.put(tableRef, contents);
}
}
}
}
return tableToMetadataContents;
}
use of com.palantir.atlasdb.keyvalue.api.Value in project atlasdb by palantir.
the class CassandraKeyValueServiceImpl method getRowsColumnRangeIteratorForSingleHost.
private Map<byte[], RowColumnRangeIterator> getRowsColumnRangeIteratorForSingleHost(InetSocketAddress host, TableReference tableRef, List<byte[]> rows, BatchColumnRangeSelection batchColumnRangeSelection, long startTs) {
try {
RowColumnRangeExtractor.RowColumnRangeResult firstPage = getRowsColumnRangeForSingleHost(host, tableRef, rows, batchColumnRangeSelection, startTs);
Map<byte[], LinkedHashMap<Cell, Value>> results = firstPage.getResults();
Map<byte[], Column> rowsToLastCompositeColumns = firstPage.getRowsToLastCompositeColumns();
Map<byte[], byte[]> incompleteRowsToNextColumns = Maps.newHashMap();
for (Entry<byte[], Column> e : rowsToLastCompositeColumns.entrySet()) {
byte[] row = e.getKey();
byte[] col = CassandraKeyValueServices.decomposeName(e.getValue()).getLhSide();
// If we read a version of the cell before our start timestamp, it will be the most recent version
// readable to us and we can continue to the next column. Otherwise we have to continue reading
// this column.
Map<Cell, Value> rowResult = results.get(row);
boolean completedCell = (rowResult != null) && rowResult.containsKey(Cell.create(row, col));
boolean endOfRange = isEndOfColumnRange(completedCell, col, firstPage.getRowsToRawColumnCount().get(row), batchColumnRangeSelection);
if (!endOfRange) {
byte[] nextCol = getNextColumnRangeColumn(completedCell, col);
incompleteRowsToNextColumns.put(row, nextCol);
}
}
Map<byte[], RowColumnRangeIterator> ret = Maps.newHashMapWithExpectedSize(rows.size());
for (byte[] row : rowsToLastCompositeColumns.keySet()) {
Iterator<Entry<Cell, Value>> resultIterator;
Map<Cell, Value> result = results.get(row);
if (result != null) {
resultIterator = result.entrySet().iterator();
} else {
resultIterator = Collections.emptyIterator();
}
byte[] nextCol = incompleteRowsToNextColumns.get(row);
if (nextCol == null) {
ret.put(row, new LocalRowColumnRangeIterator(resultIterator));
} else {
BatchColumnRangeSelection newColumnRange = BatchColumnRangeSelection.create(nextCol, batchColumnRangeSelection.getEndCol(), batchColumnRangeSelection.getBatchHint());
ret.put(row, new LocalRowColumnRangeIterator(Iterators.concat(resultIterator, getRowColumnRange(host, tableRef, row, newColumnRange, startTs))));
}
}
// We saw no Cassandra results at all for these rows, so the entire column range is empty for these rows.
for (byte[] row : firstPage.getEmptyRows()) {
ret.put(row, new LocalRowColumnRangeIterator(Collections.emptyIterator()));
}
return ret;
} catch (Exception e) {
throw QosAwareThrowables.unwrapAndThrowRateLimitExceededOrAtlasDbDependencyException(e);
}
}
use of com.palantir.atlasdb.keyvalue.api.Value in project atlasdb by palantir.
the class CassandraKeyValueServiceImpl method getRowsForSingleHost.
private Map<Cell, Value> getRowsForSingleHost(final InetSocketAddress host, final TableReference tableRef, final List<byte[]> rows, final long startTs) {
try {
int rowCount = 0;
final Map<Cell, Value> result = Maps.newHashMap();
int fetchBatchCount = config.fetchBatchCount();
for (final List<byte[]> batch : Lists.partition(rows, fetchBatchCount)) {
rowCount += batch.size();
result.putAll(clientPool.runWithRetryOnHost(host, new FunctionCheckedException<CassandraClient, Map<Cell, Value>, Exception>() {
@Override
public Map<Cell, Value> apply(CassandraClient client) throws Exception {
// We want to get all the columns in the row so set start and end to empty.
SlicePredicate pred = SlicePredicates.create(Range.ALL, Limit.NO_LIMIT);
List<ByteBuffer> rowNames = wrap(batch);
Map<ByteBuffer, List<ColumnOrSuperColumn>> results = wrappingQueryRunner.multiget("getRows", client, tableRef, rowNames, pred, readConsistency);
Map<Cell, Value> ret = Maps.newHashMapWithExpectedSize(batch.size());
new ValueExtractor(ret).extractResults(results, startTs, ColumnSelection.all());
return ret;
}
@Override
public String toString() {
return "multiget_slice(" + tableRef.getQualifiedName() + ", " + batch.size() + " rows" + ")";
}
}));
}
if (rowCount > fetchBatchCount) {
log.warn("Rebatched in getRows a call to {} that attempted to multiget {} rows; " + "this may indicate overly-large batching on a higher level.\n{}", LoggingArgs.tableRef(tableRef), SafeArg.of("rowCount", rowCount), SafeArg.of("stacktrace", CassandraKeyValueServices.getFilteredStackTrace("com.palantir")));
}
return ImmutableMap.copyOf(result);
} catch (Exception e) {
throw QosAwareThrowables.unwrapAndThrowRateLimitExceededOrAtlasDbDependencyException(e);
}
}
use of com.palantir.atlasdb.keyvalue.api.Value in project atlasdb by palantir.
the class OneNodeDownGetTest method canGetRange.
@Test
public void canGetRange() {
final RangeRequest range = RangeRequest.builder().endRowExclusive(OneNodeDownTestSuite.SECOND_ROW).build();
ClosableIterator<RowResult<Value>> it = OneNodeDownTestSuite.kvs.getRange(OneNodeDownTestSuite.TEST_TABLE, range, Long.MAX_VALUE);
ImmutableMap<byte[], Value> expectedColumns = ImmutableMap.of(OneNodeDownTestSuite.FIRST_COLUMN, OneNodeDownTestSuite.DEFAULT_VALUE, OneNodeDownTestSuite.SECOND_COLUMN, OneNodeDownTestSuite.DEFAULT_VALUE);
RowResult<Value> expectedRowResult = RowResult.create(OneNodeDownTestSuite.FIRST_ROW, ImmutableSortedMap.copyOf(expectedColumns, UnsignedBytes.lexicographicalComparator()));
assertThat(it).containsExactly(expectedRowResult);
}
use of com.palantir.atlasdb.keyvalue.api.Value in project atlasdb by palantir.
the class SnapshotTransaction method partitionByRow.
/**
* Partitions a {@link RowColumnRangeIterator} into contiguous blocks that share the same row name.
* {@link KeyValueService#getRowsColumnRange(TableReference, Iterable, ColumnRangeSelection, int, long)} guarantees
* that all columns for a single row are adjacent, so this method will return an {@link Iterator} with exactly one
* entry per non-empty row.
*/
private Iterator<Map.Entry<byte[], RowColumnRangeIterator>> partitionByRow(RowColumnRangeIterator rawResults) {
PeekingIterator<Map.Entry<Cell, Value>> peekableRawResults = Iterators.peekingIterator(rawResults);
return new AbstractIterator<Map.Entry<byte[], RowColumnRangeIterator>>() {
byte[] prevRowName;
@Override
protected Map.Entry<byte[], RowColumnRangeIterator> computeNext() {
finishConsumingPreviousRow(peekableRawResults);
if (!peekableRawResults.hasNext()) {
return endOfData();
}
byte[] nextRowName = peekableRawResults.peek().getKey().getRowName();
Iterator<Map.Entry<Cell, Value>> columnsIterator = new AbstractIterator<Map.Entry<Cell, Value>>() {
@Override
protected Map.Entry<Cell, Value> computeNext() {
if (!peekableRawResults.hasNext() || !Arrays.equals(peekableRawResults.peek().getKey().getRowName(), nextRowName)) {
return endOfData();
}
return peekableRawResults.next();
}
};
prevRowName = nextRowName;
return Maps.immutableEntry(nextRowName, new LocalRowColumnRangeIterator(columnsIterator));
}
private void finishConsumingPreviousRow(PeekingIterator<Map.Entry<Cell, Value>> iter) {
int numConsumed = 0;
while (iter.hasNext() && Arrays.equals(iter.peek().getKey().getRowName(), prevRowName)) {
iter.next();
numConsumed++;
}
if (numConsumed > 0) {
log.warn("Not all columns for row {} were read. {} columns were discarded.", UnsafeArg.of("row", Arrays.toString(prevRowName)), SafeArg.of("numColumnsDiscarded", numConsumed));
}
}
};
}
Aggregations