Search in sources :

Example 1 with CellConflict

use of com.palantir.atlasdb.transaction.api.TransactionConflictException.CellConflict 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)

Aggregations

Cell (com.palantir.atlasdb.keyvalue.api.Cell)1 Value (com.palantir.atlasdb.keyvalue.api.Value)1 CellConflict (com.palantir.atlasdb.transaction.api.TransactionConflictException.CellConflict)1 AtomicLong (java.util.concurrent.atomic.AtomicLong)1 Nullable (javax.annotation.Nullable)1