Search in sources :

Example 1 with PermanentLockingException

use of org.janusgraph.diskstorage.locking.PermanentLockingException in project janusgraph by JanusGraph.

the class JanusGraphTest method executeLockConflictingTransactionJobs.

/**
 * Executes a transaction job in two parallel transactions under the assumptions that the two transactions
 * should conflict and the one committed later should throw a locking exception due to mismatch of expected value.
 *
 * @param graph
 * @param job
 */
private void executeLockConflictingTransactionJobs(JanusGraph graph, TransactionJob job) {
    JanusGraphTransaction tx1 = graph.newTransaction();
    JanusGraphTransaction tx2 = graph.newTransaction();
    job.run(tx1);
    job.run(tx2);
    /*
         * Under pessimistic locking, tx1 should abort and tx2 should commit.
         * Under optimistic locking, tx1 may commit and tx2 may abort.
         */
    JanusGraphException janusGraphException;
    if (isLockingOptimistic()) {
        tx1.commit();
        janusGraphException = assertThrows(JanusGraphException.class, tx2::commit);
    } else {
        janusGraphException = assertThrows(JanusGraphException.class, tx1::commit);
        tx2.commit();
    }
    Throwable rootCause = janusGraphException.getCause().getCause();
    assertTrue(rootCause instanceof PermanentLockingException);
    assertTrue(rootCause.getMessage().contains("Expected value mismatch for"));
}
Also used : JanusGraphTransaction(org.janusgraph.core.JanusGraphTransaction) PermanentLockingException(org.janusgraph.diskstorage.locking.PermanentLockingException) JanusGraphException(org.janusgraph.core.JanusGraphException)

Example 2 with PermanentLockingException

use of org.janusgraph.diskstorage.locking.PermanentLockingException in project janusgraph by JanusGraph.

the class ExpectedValueCheckingStore method acquireLock.

/**
 * {@inheritDoc}
 * <p>
 * This implementation supports locking when {@code lockStore} is non-null.
 * <p>
 * Consider the following scenario. This method is called twice with
 * identical key, column, and txh arguments, but with different
 * expectedValue arguments in each call. In testing, it seems JanusGraph's
 * graphdb requires that implementations discard the second expectedValue
 * and, when checking expectedValues vs actual values just prior to mutate,
 * only the initial expectedValue argument should be considered.
 */
@Override
public void acquireLock(StaticBuffer key, StaticBuffer column, StaticBuffer expectedValue, StoreTransaction txh) throws BackendException {
    if (locker != null) {
        ExpectedValueCheckingTransaction tx = (ExpectedValueCheckingTransaction) txh;
        if (tx.isMutationStarted())
            throw new PermanentLockingException("Attempted to obtain a lock after mutations had been persisted");
        KeyColumn lockID = new KeyColumn(key, column);
        log.debug("Attempting to acquireLock on {} ev={}", lockID, expectedValue);
        locker.writeLock(lockID, tx.getConsistentTx());
        tx.storeExpectedValue(this, lockID, expectedValue);
    } else {
        store.acquireLock(key, column, expectedValue, unwrapTx(txh));
    }
}
Also used : PermanentLockingException(org.janusgraph.diskstorage.locking.PermanentLockingException) KeyColumn(org.janusgraph.diskstorage.util.KeyColumn)

Example 3 with PermanentLockingException

use of org.janusgraph.diskstorage.locking.PermanentLockingException in project janusgraph by JanusGraph.

the class ExpectedValueCheckingTransaction method checkSingleExpectedValueUnsafe.

private void checkSingleExpectedValueUnsafe(final KeyColumn kc, final StaticBuffer ev, final ExpectedValueCheckingStore store) throws BackendException {
    final StaticBuffer nextBuf = BufferUtil.nextBiggerBuffer(kc.getColumn());
    KeySliceQuery ksq = new KeySliceQuery(kc.getKey(), kc.getColumn(), nextBuf);
    // Call getSlice on the wrapped store using the quorum+ consistency tx
    Iterable<Entry> actualEntries = store.getBackingStore().getSlice(ksq, strongConsistentTx);
    if (null == actualEntries)
        actualEntries = Collections.emptyList();
    /*
         * Discard any columns which do not exactly match kc.getColumn().
         *
         * For example, it's possible that the slice returned columns which for
         * which kc.getColumn() is a prefix.
         */
    actualEntries = Iterables.filter(actualEntries, input -> {
        if (!input.getColumn().equals(kc.getColumn())) {
            log.debug("Dropping entry {} (only accepting column {})", input, kc.getColumn());
            return false;
        }
        log.debug("Accepting entry {}", input);
        return true;
    });
    // Extract values from remaining Entry instances
    final Iterable<StaticBuffer> actualValues = Iterables.transform(actualEntries, e -> {
        final StaticBuffer actualCol = e.getColumnAs(StaticBuffer.STATIC_FACTORY);
        assert null != actualCol;
        assert null != kc.getColumn();
        assert 0 >= kc.getColumn().compareTo(actualCol);
        assert 0 > actualCol.compareTo(nextBuf);
        return e.getValueAs(StaticBuffer.STATIC_FACTORY);
    });
    final Iterable<StaticBuffer> expectedValues;
    if (null == ev) {
        expectedValues = Collections.emptyList();
    } else {
        expectedValues = Collections.singletonList(ev);
    }
    if (!Iterables.elementsEqual(expectedValues, actualValues)) {
        throw new PermanentLockingException("Expected value mismatch for " + kc + ": expected=" + expectedValues + " vs actual=" + actualValues + " (store=" + store.getName() + ")");
    }
}
Also used : BackendException(org.janusgraph.diskstorage.BackendException) LocalLockMediator(org.janusgraph.diskstorage.locking.LocalLockMediator) Iterables(com.google.common.collect.Iterables) Logger(org.slf4j.Logger) Locker(org.janusgraph.diskstorage.locking.Locker) BackendOperation(org.janusgraph.diskstorage.util.BackendOperation) LoggerFactory(org.slf4j.LoggerFactory) HashMap(java.util.HashMap) Callable(java.util.concurrent.Callable) KeySliceQuery(org.janusgraph.diskstorage.keycolumnvalue.KeySliceQuery) PermanentLockingException(org.janusgraph.diskstorage.locking.PermanentLockingException) KeyColumnValueStore(org.janusgraph.diskstorage.keycolumnvalue.KeyColumnValueStore) List(java.util.List) BaseTransactionConfig(org.janusgraph.diskstorage.BaseTransactionConfig) Duration(java.time.Duration) Map(java.util.Map) Entry(org.janusgraph.diskstorage.Entry) StaticBuffer(org.janusgraph.diskstorage.StaticBuffer) BufferUtil(org.janusgraph.diskstorage.util.BufferUtil) KeyColumn(org.janusgraph.diskstorage.util.KeyColumn) Preconditions(com.google.common.base.Preconditions) StoreTransaction(org.janusgraph.diskstorage.keycolumnvalue.StoreTransaction) Collections(java.util.Collections) Entry(org.janusgraph.diskstorage.Entry) PermanentLockingException(org.janusgraph.diskstorage.locking.PermanentLockingException) StaticBuffer(org.janusgraph.diskstorage.StaticBuffer) KeySliceQuery(org.janusgraph.diskstorage.keycolumnvalue.KeySliceQuery)

Example 4 with PermanentLockingException

use of org.janusgraph.diskstorage.locking.PermanentLockingException in project janusgraph by JanusGraph.

the class JanusGraphTest method executeParallelTransactions.

/**
 * Execute multiple transactions in different threads concurrently to test locking
 * @param job A transaction job which triggers locking
 * @param concurrency Number of threads, each of which runs a transaction
 * @return [number of successful transactions, number of transactions failed due to local lock contention]
 */
private int[] executeParallelTransactions(final TransactionJob job, int concurrency) {
    final CountDownLatch startLatch = new CountDownLatch(concurrency);
    final CountDownLatch finishLatch = new CountDownLatch(concurrency);
    final AtomicInteger txSuccess = new AtomicInteger(0);
    final AtomicInteger lockingExCount = new AtomicInteger(0);
    for (int i = 0; i < concurrency; i++) {
        new Thread() {

            @Override
            public void run() {
                JanusGraphTransaction tx = graph.newTransaction();
                try {
                    job.run(tx);
                    // we force all threads to wait until they are all ready to commit, so that we can test lock
                    // contention
                    awaitAllThreadsReady();
                    tx.commit();
                    txSuccess.incrementAndGet();
                } catch (Exception ex) {
                    ex.printStackTrace();
                    if (tx.isOpen())
                        tx.rollback();
                    if (ex.getCause() instanceof PermanentLockingException && ex.getCause().getMessage().contains("Local lock contention")) {
                        lockingExCount.incrementAndGet();
                    }
                } finally {
                    finishLatch.countDown();
                }
            }

            private void awaitAllThreadsReady() {
                startLatch.countDown();
                try {
                    startLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
    try {
        finishLatch.await(10000, TimeUnit.MILLISECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return new int[] { txSuccess.get(), lockingExCount.get() };
}
Also used : JanusGraphTransaction(org.janusgraph.core.JanusGraphTransaction) PermanentLockingException(org.janusgraph.diskstorage.locking.PermanentLockingException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) CountDownLatch(java.util.concurrent.CountDownLatch) ExecutionException(java.util.concurrent.ExecutionException) JanusGraphConfigurationException(org.janusgraph.core.JanusGraphConfigurationException) NotImplementedException(org.apache.commons.lang.NotImplementedException) PermanentLockingException(org.janusgraph.diskstorage.locking.PermanentLockingException) JanusGraphException(org.janusgraph.core.JanusGraphException) SchemaViolationException(org.janusgraph.core.SchemaViolationException) BackendException(org.janusgraph.diskstorage.BackendException)

Aggregations

PermanentLockingException (org.janusgraph.diskstorage.locking.PermanentLockingException)4 JanusGraphException (org.janusgraph.core.JanusGraphException)2 JanusGraphTransaction (org.janusgraph.core.JanusGraphTransaction)2 BackendException (org.janusgraph.diskstorage.BackendException)2 KeyColumn (org.janusgraph.diskstorage.util.KeyColumn)2 Preconditions (com.google.common.base.Preconditions)1 Iterables (com.google.common.collect.Iterables)1 Duration (java.time.Duration)1 Collections (java.util.Collections)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1 Callable (java.util.concurrent.Callable)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 ExecutionException (java.util.concurrent.ExecutionException)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 NotImplementedException (org.apache.commons.lang.NotImplementedException)1 JanusGraphConfigurationException (org.janusgraph.core.JanusGraphConfigurationException)1 SchemaViolationException (org.janusgraph.core.SchemaViolationException)1 BaseTransactionConfig (org.janusgraph.diskstorage.BaseTransactionConfig)1