Search in sources :

Example 1 with ParallelExecutorTask

use of com.scalar.db.transaction.consensuscommit.ParallelExecutor.ParallelExecutorTask in project scalardb by scalar-labs.

the class Snapshot method toSerializableWithExtraRead.

@VisibleForTesting
void toSerializableWithExtraRead(DistributedStorage storage) throws ExecutionException, CommitConflictException {
    if (!isExtraReadEnabled()) {
        return;
    }
    List<ParallelExecutorTask> tasks = new ArrayList<>();
    // Read set by scan is re-validated to check if there is no anti-dependency
    for (Map.Entry<Scan, List<Key>> entry : scanSet.entrySet()) {
        tasks.add(() -> {
            Map<Key, TransactionResult> currentReadMap = new HashMap<>();
            Set<Key> validatedReadSet = new HashSet<>();
            Scanner scanner = null;
            try {
                Scan scan = entry.getKey();
                // only get tx_id and tx_version columns because we use only them to compare
                scan.clearProjections();
                scan.withProjection(Attribute.ID).withProjection(Attribute.VERSION);
                ScalarDbUtils.addProjectionsForKeys(scan, getTableMetadata(scan));
                scanner = storage.scan(scan);
                for (Result result : scanner) {
                    TransactionResult transactionResult = new TransactionResult(result);
                    // Ignore records that this transaction has prepared (and that are in the write set)
                    if (transactionResult.getId().equals(id)) {
                        continue;
                    }
                    currentReadMap.put(new Key(scan, result), transactionResult);
                }
            } finally {
                if (scanner != null) {
                    try {
                        scanner.close();
                    } catch (IOException e) {
                        LOGGER.warn("failed to close the scanner", e);
                    }
                }
            }
            for (Key key : entry.getValue()) {
                if (writeSet.containsKey(key) || deleteSet.containsKey(key)) {
                    continue;
                }
                // Check if read records are not changed
                TransactionResult latestResult = currentReadMap.get(key);
                if (isChanged(Optional.of(latestResult), readSet.get(key))) {
                    throwExceptionDueToAntiDependency();
                }
                validatedReadSet.add(key);
            }
            // Check if the size of a read set by scan is not changed
            if (currentReadMap.size() != validatedReadSet.size()) {
                throwExceptionDueToAntiDependency();
            }
        });
    }
    // Calculate read set validated by scan
    Set<Key> validatedReadSetByScan = new HashSet<>();
    for (List<Key> values : scanSet.values()) {
        validatedReadSetByScan.addAll(values);
    }
    // Read set by get is re-validated to check if there is no anti-dependency
    for (Map.Entry<Key, Optional<TransactionResult>> entry : readSet.entrySet()) {
        Key key = entry.getKey();
        if (writeSet.containsKey(key) || deleteSet.containsKey(key) || validatedReadSetByScan.contains(key)) {
            continue;
        }
        tasks.add(() -> {
            // only get tx_id and tx_version columns because we use only them to compare
            Get get = new Get(key.getPartitionKey(), key.getClusteringKey().orElse(null)).withProjection(Attribute.ID).withProjection(Attribute.VERSION).withConsistency(Consistency.LINEARIZABLE).forNamespace(key.getNamespace()).forTable(key.getTable());
            Optional<TransactionResult> latestResult = storage.get(get).map(TransactionResult::new);
            // Check if a read record is not changed
            if (isChanged(latestResult, entry.getValue())) {
                throwExceptionDueToAntiDependency();
            }
        });
    }
    parallelExecutor.validate(tasks);
}
Also used : Scanner(com.scalar.db.api.Scanner) Optional(java.util.Optional) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) IOException(java.io.IOException) ParallelExecutorTask(com.scalar.db.transaction.consensuscommit.ParallelExecutor.ParallelExecutorTask) Result(com.scalar.db.api.Result) Get(com.scalar.db.api.Get) Scan(com.scalar.db.api.Scan) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) HashSet(java.util.HashSet) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Aggregations

VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 Get (com.scalar.db.api.Get)1 Result (com.scalar.db.api.Result)1 Scan (com.scalar.db.api.Scan)1 Scanner (com.scalar.db.api.Scanner)1 ParallelExecutorTask (com.scalar.db.transaction.consensuscommit.ParallelExecutor.ParallelExecutorTask)1 IOException (java.io.IOException)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 List (java.util.List)1 Map (java.util.Map)1 Optional (java.util.Optional)1