Search in sources :

Example 36 with Value

use of com.palantir.atlasdb.keyvalue.api.Value in project atlasdb by palantir.

the class SnapshotTransaction method getRanges.

@Override
public Iterable<BatchingVisitable<RowResult<byte[]>>> getRanges(final TableReference tableRef, Iterable<RangeRequest> rangeRequests) {
    checkGetPreconditions(tableRef);
    if (perfLogger.isDebugEnabled()) {
        perfLogger.debug("Passed {} ranges to getRanges({}, {})", Iterables.size(rangeRequests), tableRef, rangeRequests);
    }
    if (!Iterables.isEmpty(rangeRequests)) {
        hasReads = true;
    }
    return FluentIterable.from(Iterables.partition(rangeRequests, BATCH_SIZE_GET_FIRST_PAGE)).transformAndConcat(input -> {
        Timer.Context timer = getTimer("processedRangeMillis").time();
        Map<RangeRequest, TokenBackedBasicResultsPage<RowResult<Value>, byte[]>> firstPages = keyValueService.getFirstBatchForRanges(tableRef, input, getStartTimestamp());
        validateExternalAndCommitLocksIfNecessary(tableRef, getStartTimestamp());
        SortedMap<Cell, byte[]> postFiltered = postFilterPages(tableRef, firstPages.values());
        List<BatchingVisitable<RowResult<byte[]>>> ret = Lists.newArrayListWithCapacity(input.size());
        for (RangeRequest rangeRequest : input) {
            TokenBackedBasicResultsPage<RowResult<Value>, byte[]> prePostFilter = firstPages.get(rangeRequest);
            byte[] nextStartRowName = getNextStartRowName(rangeRequest, prePostFilter);
            List<Entry<Cell, byte[]>> mergeIterators = getPostFilteredWithLocalWrites(tableRef, postFiltered, rangeRequest, prePostFilter.getResults(), nextStartRowName);
            ret.add(new AbstractBatchingVisitable<RowResult<byte[]>>() {

                @Override
                protected <K extends Exception> void batchAcceptSizeHint(int batchSizeHint, ConsistentVisitor<RowResult<byte[]>, K> visitor) throws K {
                    checkGetPreconditions(tableRef);
                    final Iterator<RowResult<byte[]>> rowResults = Cells.createRowView(mergeIterators);
                    while (rowResults.hasNext()) {
                        if (!visitor.visit(ImmutableList.of(rowResults.next()))) {
                            return;
                        }
                    }
                    if ((nextStartRowName.length == 0) || !prePostFilter.moreResultsAvailable()) {
                        return;
                    }
                    RangeRequest newRange = rangeRequest.getBuilder().startRowInclusive(nextStartRowName).build();
                    getRange(tableRef, newRange).batchAccept(batchSizeHint, visitor);
                }
            });
        }
        long processedRangeMillis = TimeUnit.NANOSECONDS.toMillis(timer.stop());
        log.trace("Processed {} range requests for {} in {}ms", SafeArg.of("numRequests", input.size()), LoggingArgs.tableRef(tableRef), SafeArg.of("millis", processedRangeMillis));
        return ret;
    });
}
Also used : TokenBackedBasicResultsPage(com.palantir.util.paging.TokenBackedBasicResultsPage) AbstractBatchingVisitable(com.palantir.common.base.AbstractBatchingVisitable) BatchingVisitable(com.palantir.common.base.BatchingVisitable) RowResult(com.palantir.atlasdb.keyvalue.api.RowResult) Entry(java.util.Map.Entry) Timer(com.codahale.metrics.Timer) RangeRequest(com.palantir.atlasdb.keyvalue.api.RangeRequest) Value(com.palantir.atlasdb.keyvalue.api.Value) PeekingIterator(com.google.common.collect.PeekingIterator) AbstractIterator(com.google.common.collect.AbstractIterator) LocalRowColumnRangeIterator(com.palantir.atlasdb.keyvalue.impl.LocalRowColumnRangeIterator) ClosableIterator(com.palantir.common.base.ClosableIterator) RowColumnRangeIterator(com.palantir.atlasdb.keyvalue.api.RowColumnRangeIterator) ForwardingClosableIterator(com.palantir.common.base.ForwardingClosableIterator) Iterator(java.util.Iterator) Cell(com.palantir.atlasdb.keyvalue.api.Cell)

Example 37 with Value

use of com.palantir.atlasdb.keyvalue.api.Value in project atlasdb by palantir.

the class SnapshotTransaction method throwIfValueChangedConflict.

/**
 * This will throw if we have a value changed conflict.  This means that either we changed the
 * value and anyone did a write after our start timestamp, or we just touched the value (put the
 * same value as before) and a changed value was written after our start time.
 */
private void throwIfValueChangedConflict(TableReference table, Map<Cell, byte[]> writes, Set<CellConflict> spanningWrites, Set<CellConflict> dominatingWrites, LockToken commitLocksToken) {
    Map<Cell, CellConflict> cellToConflict = Maps.newHashMap();
    Map<Cell, Long> cellToTs = Maps.newHashMap();
    for (CellConflict c : Sets.union(spanningWrites, dominatingWrites)) {
        cellToConflict.put(c.getCell(), c);
        cellToTs.put(c.getCell(), c.getTheirStart() + 1);
    }
    Map<Cell, byte[]> oldValues = getIgnoringLocalWrites(table, cellToTs.keySet());
    Map<Cell, Value> conflictingValues = keyValueService.get(table, cellToTs);
    Set<Cell> conflictingCells = Sets.newHashSet();
    for (Entry<Cell, Long> cellEntry : cellToTs.entrySet()) {
        Cell cell = cellEntry.getKey();
        if (!writes.containsKey(cell)) {
            Validate.isTrue(false, "Missing write for cell: %s for table %s", cellToConflict.get(cell), table);
        }
        if (!conflictingValues.containsKey(cell)) {
            // This error case could happen if our locks expired.
            throwIfPreCommitRequirementsNotMet(commitLocksToken, getStartTimestamp());
            Validate.isTrue(false, "Missing conflicting value for cell: %s for table %s", cellToConflict.get(cell), table);
        }
        if (conflictingValues.get(cell).getTimestamp() != (cellEntry.getValue() - 1)) {
            // This error case could happen if our locks expired.
            throwIfPreCommitRequirementsNotMet(commitLocksToken, getStartTimestamp());
            Validate.isTrue(false, "Wrong timestamp for cell in table %s Expected: %s Actual: %s", table, cellToConflict.get(cell), conflictingValues.get(cell));
        }
        @Nullable byte[] oldVal = oldValues.get(cell);
        byte[] writeVal = writes.get(cell);
        byte[] conflictingVal = conflictingValues.get(cell).getContents();
        if (!Transactions.cellValuesEqual(oldVal, writeVal) || !Arrays.equals(writeVal, conflictingVal)) {
            conflictingCells.add(cell);
        } else if (log.isInfoEnabled()) {
            log.info("Another transaction committed to the same cell before us but their value was the same." + " Cell: {} Table: {}", UnsafeArg.of("cell", cell), LoggingArgs.tableRef(table));
        }
    }
    if (conflictingCells.isEmpty()) {
        return;
    }
    Predicate<CellConflict> conflicting = Predicates.compose(Predicates.in(conflictingCells), CellConflict.getCellFunction());
    getTransactionConflictsMeter().mark();
    throw TransactionConflictException.create(table, getStartTimestamp(), Sets.filter(spanningWrites, conflicting), Sets.filter(dominatingWrites, conflicting), System.currentTimeMillis() - timeCreated);
}
Also used : CellConflict(com.palantir.atlasdb.transaction.api.TransactionConflictException.CellConflict) AtomicLong(java.util.concurrent.atomic.AtomicLong) Value(com.palantir.atlasdb.keyvalue.api.Value) Cell(com.palantir.atlasdb.keyvalue.api.Cell) Nullable(javax.annotation.Nullable)

Example 38 with Value

use of com.palantir.atlasdb.keyvalue.api.Value in project atlasdb by palantir.

the class SnapshotTransaction method getWithPostFilteringInternal.

/**
 * This will return all the keys that still need to be postFiltered.  It will output properly
 * postFiltered keys to the results output param.
 */
private <T> Map<Cell, Value> getWithPostFilteringInternal(TableReference tableRef, Map<Cell, Value> rawResults, @Output Map<Cell, T> results, Function<Value, T> transformer) {
    Set<Long> startTimestampsForValues = getStartTimestampsForValues(rawResults.values());
    Map<Long, Long> commitTimestamps = getCommitTimestamps(tableRef, startTimestampsForValues, true);
    Map<Cell, Long> keysToReload = Maps.newHashMapWithExpectedSize(0);
    Map<Cell, Long> keysToDelete = Maps.newHashMapWithExpectedSize(0);
    for (Map.Entry<Cell, Value> e : rawResults.entrySet()) {
        Cell key = e.getKey();
        Value value = e.getValue();
        if (value.getTimestamp() == Value.INVALID_VALUE_TIMESTAMP) {
            getMeter(AtlasDbMetricNames.CellFilterMetrics.INVALID_START_TS).mark();
            // we clean up old values, and this transaction started at a timestamp before the garbage collection.
            switch(getReadSentinelBehavior()) {
                case IGNORE:
                    break;
                case THROW_EXCEPTION:
                    throw new TransactionFailedRetriableException("Tried to read a value that has been deleted. " + " This can be caused by hard delete transactions using the type " + TransactionType.AGGRESSIVE_HARD_DELETE + ". It can also be caused by transactions taking too long, or" + " its locks expired. Retrying it should work.");
                default:
                    throw new IllegalStateException("Invalid read sentinel behavior " + getReadSentinelBehavior());
            }
        } else {
            Long theirCommitTimestamp = commitTimestamps.get(value.getTimestamp());
            if (theirCommitTimestamp == null || theirCommitTimestamp == TransactionConstants.FAILED_COMMIT_TS) {
                keysToReload.put(key, value.getTimestamp());
                if (shouldDeleteAndRollback()) {
                    // This is from a failed transaction so we can roll it back and then reload it.
                    keysToDelete.put(key, value.getTimestamp());
                    getMeter(AtlasDbMetricNames.CellFilterMetrics.INVALID_COMMIT_TS).mark();
                }
            } else if (theirCommitTimestamp > getStartTimestamp()) {
                // The value's commit timestamp is after our start timestamp.
                // This means the value is from a transaction which committed
                // after our transaction began. We need to try reading at an
                // earlier timestamp.
                keysToReload.put(key, value.getTimestamp());
                getMeter(AtlasDbMetricNames.CellFilterMetrics.COMMIT_TS_GREATER_THAN_TRANSACTION_TS).mark();
            } else {
                // The value has a commit timestamp less than our start timestamp, and is visible and valid.
                if (value.getContents().length != 0) {
                    results.put(key, transformer.apply(value));
                }
            }
        }
    }
    if (!keysToDelete.isEmpty()) {
        // if we can't roll back the failed transactions, we should just try again
        if (!rollbackFailedTransactions(tableRef, keysToDelete, commitTimestamps, defaultTransactionService)) {
            return rawResults;
        }
    }
    if (!keysToReload.isEmpty()) {
        Map<Cell, Value> nextRawResults = keyValueService.get(tableRef, keysToReload);
        validateExternalAndCommitLocksIfNecessary(tableRef, getStartTimestamp());
        return nextRawResults;
    } else {
        return ImmutableMap.of();
    }
}
Also used : TransactionFailedRetriableException(com.palantir.atlasdb.transaction.api.TransactionFailedRetriableException) AtomicLong(java.util.concurrent.atomic.AtomicLong) Value(com.palantir.atlasdb.keyvalue.api.Value) Cell(com.palantir.atlasdb.keyvalue.api.Cell) Map(java.util.Map) ConcurrentNavigableMap(java.util.concurrent.ConcurrentNavigableMap) LinkedHashMap(java.util.LinkedHashMap) ImmutableSortedMap(com.google.common.collect.ImmutableSortedMap) ImmutableMap(com.google.common.collect.ImmutableMap) SortedMap(java.util.SortedMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) ConcurrentSkipListMap(java.util.concurrent.ConcurrentSkipListMap)

Example 39 with Value

use of com.palantir.atlasdb.keyvalue.api.Value in project atlasdb by palantir.

the class AbstractDbWriteTable method put.

@Override
public void put(Collection<Map.Entry<Cell, Value>> data) {
    List<Object[]> args = Lists.newArrayListWithCapacity(data.size());
    for (Entry<Cell, Value> entry : data) {
        Cell cell = entry.getKey();
        Value val = entry.getValue();
        args.add(new Object[] { cell.getRowName(), cell.getColumnName(), val.getTimestamp(), val.getContents() });
    }
    put(args);
}
Also used : Value(com.palantir.atlasdb.keyvalue.api.Value) Cell(com.palantir.atlasdb.keyvalue.api.Cell)

Example 40 with Value

use of com.palantir.atlasdb.keyvalue.api.Value in project atlasdb by palantir.

the class DbKvs method fillOverflowValues.

private void fillOverflowValues(ConnectionSupplier conns, TableReference tableRef, Map<Cell, OverflowValue> overflowValues, @Output Map<Cell, Value> values) {
    Iterator<Entry<Cell, OverflowValue>> overflowIterator = overflowValues.entrySet().iterator();
    while (overflowIterator.hasNext()) {
        Entry<Cell, OverflowValue> entry = overflowIterator.next();
        Value value = values.get(entry.getKey());
        if (value != null && value.getTimestamp() > entry.getValue().ts()) {
            overflowIterator.remove();
        }
    }
    Map<Long, byte[]> resolvedOverflowValues = overflowValueLoader.loadOverflowValues(conns, tableRef, Collections2.transform(overflowValues.values(), OverflowValue::id));
    for (Entry<Cell, OverflowValue> entry : overflowValues.entrySet()) {
        Cell cell = entry.getKey();
        OverflowValue ov = entry.getValue();
        byte[] val = resolvedOverflowValues.get(ov.id());
        Preconditions.checkNotNull(val, "Failed to load overflow data: cell=%s, overflowId=%s", cell, ov.id());
        values.put(cell, Value.create(val, ov.ts()));
    }
}
Also used : Entry(java.util.Map.Entry) Value(com.palantir.atlasdb.keyvalue.api.Value) Cell(com.palantir.atlasdb.keyvalue.api.Cell)

Aggregations

Value (com.palantir.atlasdb.keyvalue.api.Value)74 Cell (com.palantir.atlasdb.keyvalue.api.Cell)55 RangeRequest (com.palantir.atlasdb.keyvalue.api.RangeRequest)20 RowResult (com.palantir.atlasdb.keyvalue.api.RowResult)18 Test (org.junit.Test)18 Entry (java.util.Map.Entry)16 TokenBackedBasicResultsPage (com.palantir.util.paging.TokenBackedBasicResultsPage)15 Map (java.util.Map)15 SortedMap (java.util.SortedMap)13 ImmutableMap (com.google.common.collect.ImmutableMap)12 TableReference (com.palantir.atlasdb.keyvalue.api.TableReference)10 LinkedHashMap (java.util.LinkedHashMap)9 ImmutableList (com.google.common.collect.ImmutableList)7 KeyAlreadyExistsException (com.palantir.atlasdb.keyvalue.api.KeyAlreadyExistsException)7 InsufficientConsistencyException (com.palantir.atlasdb.keyvalue.api.InsufficientConsistencyException)6 RowColumnRangeIterator (com.palantir.atlasdb.keyvalue.api.RowColumnRangeIterator)6 List (java.util.List)6 ImmutableSortedMap (com.google.common.collect.ImmutableSortedMap)5 BatchColumnRangeSelection (com.palantir.atlasdb.keyvalue.api.BatchColumnRangeSelection)5 LocalRowColumnRangeIterator (com.palantir.atlasdb.keyvalue.impl.LocalRowColumnRangeIterator)5