Search in sources :

Example 1 with LockWaitEvent

use of org.neo4j.lock.LockWaitEvent in project neo4j by neo4j.

the class ForsetiClient method tryUpgradeToExclusiveWithShareLockHeld.

/**
 * Attempt to upgrade a share lock that we hold to an exclusive lock.
 */
private boolean tryUpgradeToExclusiveWithShareLockHeld(LockTracer tracer, LockWaitEvent priorEvent, ResourceType resourceType, long resourceId, SharedLock sharedLock, int tries, long waitStartNano) throws AcquireLockTimeoutException {
    if (sharedLock.tryAcquireUpdateLock(this)) {
        LockWaitEvent waitEvent = null;
        try {
            // Now we just wait for all clients to release the the share lock
            while (sharedLock.numberOfHolders() > 1) {
                assertValid(waitStartNano, resourceType, resourceId);
                if (waitEvent == null && priorEvent == null) {
                    waitEvent = tracer.waitForLock(EXCLUSIVE, resourceType, userTransactionId, resourceId);
                }
                waitFor(sharedLock, resourceType, resourceId, tries++);
            }
            return true;
        } catch (Throwable e) {
            sharedLock.releaseUpdateLock();
            if (e instanceof DeadlockDetectedException || e instanceof LockClientStoppedException) {
                throw (RuntimeException) e;
            }
            throw new TransactionFailureException("Failed to upgrade shared lock to exclusive: " + sharedLock, e);
        } finally {
            if (waitEvent != null) {
                waitEvent.close();
            }
            clearWaitList();
            waitingForLock = null;
        }
    }
    return false;
}
Also used : TransactionFailureException(org.neo4j.graphdb.TransactionFailureException) LockClientStoppedException(org.neo4j.kernel.impl.locking.LockClientStoppedException) DeadlockDetectedException(org.neo4j.kernel.DeadlockDetectedException) LockWaitEvent(org.neo4j.lock.LockWaitEvent)

Example 2 with LockWaitEvent

use of org.neo4j.lock.LockWaitEvent in project neo4j by neo4j.

the class ForsetiClient method acquireExclusive.

@Override
public void acquireExclusive(LockTracer tracer, ResourceType resourceType, long... resourceIds) throws AcquireLockTimeoutException {
    hasLocks = true;
    stateHolder.incrementActiveClients(this);
    LockWaitEvent waitEvent = null;
    try {
        ConcurrentMap<Long, ForsetiLockManager.Lock> lockMap = lockMaps[resourceType.typeId()];
        HeapTrackingLongIntHashMap heldLocks = getExclusiveLockCount(resourceType);
        for (long resourceId : resourceIds) {
            int heldCount = heldLocks.getIfAbsent(resourceId, NO_CLIENT_ID);
            if (heldCount != NO_CLIENT_ID) {
                // We already have a lock on this, just increment our local reference counter.
                heldLocks.put(resourceId, Math.incrementExact(heldCount));
                continue;
            }
            // Grab the global lock
            ForsetiLockManager.Lock existingLock;
            int tries = 0;
            long waitStartNano = clock.nanos();
            boolean upgraded = false;
            while ((existingLock = lockMap.putIfAbsent(resourceId, myExclusiveLock)) != null) {
                assertValid(waitStartNano, resourceType, resourceId);
                // for it to convert to an exclusive lock.
                if (tries > 50 && existingLock instanceof SharedLock) {
                    // Then we should upgrade that lock
                    SharedLock sharedLock = (SharedLock) existingLock;
                    if (tryUpgradeSharedToExclusive(tracer, waitEvent, resourceType, lockMap, resourceId, sharedLock, waitStartNano)) {
                        upgraded = true;
                        break;
                    }
                }
                if (waitEvent == null) {
                    waitEvent = tracer.waitForLock(EXCLUSIVE, resourceType, userTransactionId, resourceId);
                }
                waitFor(existingLock, resourceType, resourceId, tries++);
            }
            heldLocks.put(resourceId, 1);
            if (!upgraded) {
                memoryTracker.allocateHeap(CONCURRENT_NODE_SIZE);
            }
        }
    } finally {
        if (waitEvent != null) {
            waitEvent.close();
        }
        clearWaitList();
        waitingForLock = null;
        stateHolder.decrementActiveClients();
    }
}
Also used : HeapTrackingLongIntHashMap(org.neo4j.collection.trackable.HeapTrackingLongIntHashMap) LockWaitEvent(org.neo4j.lock.LockWaitEvent) ActiveLock(org.neo4j.lock.ActiveLock)

Example 3 with LockWaitEvent

use of org.neo4j.lock.LockWaitEvent in project neo4j by neo4j.

the class ForsetiClient method acquireShared.

@Override
public void acquireShared(LockTracer tracer, ResourceType resourceType, long... resourceIds) throws AcquireLockTimeoutException {
    hasLocks = true;
    stateHolder.incrementActiveClients(this);
    LockWaitEvent waitEvent = null;
    try {
        // Grab the global lock map we will be using
        ConcurrentMap<Long, ForsetiLockManager.Lock> lockMap = lockMaps[resourceType.typeId()];
        // And grab our local lock maps
        HeapTrackingLongIntHashMap heldShareLocks = getSharedLockCount(resourceType);
        HeapTrackingLongIntHashMap heldExclusiveLocks = getExclusiveLockCount(resourceType);
        for (long resourceId : resourceIds) {
            // First, check if we already hold this as a shared lock
            int heldCount = heldShareLocks.getIfAbsent(resourceId, NO_CLIENT_ID);
            if (heldCount != NO_CLIENT_ID) {
                // We already have a lock on this, just increment our local reference counter.
                heldShareLocks.put(resourceId, Math.incrementExact(heldCount));
                continue;
            }
            // Second, check if we hold it as an exclusive lock
            if (heldExclusiveLocks.containsKey(resourceId)) {
                // We already have an exclusive lock, so just leave that in place.
                // When the exclusive lock is released, it will be automatically downgraded to a shared lock,
                // since we bumped the share lock reference count.
                heldShareLocks.put(resourceId, 1);
                continue;
            }
            // We don't hold the lock, so we need to grab it via the global lock map
            int tries = 0;
            SharedLock mySharedLock = null;
            long waitStartNano = clock.nanos();
            // Retry loop
            while (true) {
                assertValid(waitStartNano, resourceType, resourceId);
                // Check if there is a lock for this entity in the map
                ForsetiLockManager.Lock existingLock = lockMap.get(resourceId);
                // No lock
                if (existingLock == null) {
                    // Try to create a new shared lock
                    if (mySharedLock == null) {
                        mySharedLock = new SharedLock(this);
                    }
                    if (lockMap.putIfAbsent(resourceId, mySharedLock) == null) {
                        // Success, we now hold the shared lock.
                        break;
                    } else {
                        continue;
                    }
                } else // Someone holds shared lock on this entity, try and get in on that action
                if (existingLock instanceof SharedLock) {
                    if (((SharedLock) existingLock).acquire(this)) {
                        // Success!
                        break;
                    }
                } else // Someone holds an exclusive lock on this entity
                if (existingLock instanceof ExclusiveLock) {
                // We need to wait, just let the loop run.
                } else {
                    throw new UnsupportedOperationException("Unknown lock type: " + existingLock);
                }
                if (waitEvent == null) {
                    waitEvent = tracer.waitForLock(SHARED, resourceType, userTransactionId, resourceId);
                }
                // And take note of who we are waiting for. This is used for deadlock detection.
                waitFor(existingLock, resourceType, resourceId, tries++);
            }
            // Make a local note about the fact that we now hold this lock
            heldShareLocks.put(resourceId, 1);
            memoryTracker.allocateHeap(CONCURRENT_NODE_SIZE);
        }
    } finally {
        if (waitEvent != null) {
            waitEvent.close();
        }
        clearWaitList();
        waitingForLock = null;
        stateHolder.decrementActiveClients();
    }
}
Also used : HeapTrackingLongIntHashMap(org.neo4j.collection.trackable.HeapTrackingLongIntHashMap) LockWaitEvent(org.neo4j.lock.LockWaitEvent) ActiveLock(org.neo4j.lock.ActiveLock)

Example 4 with LockWaitEvent

use of org.neo4j.lock.LockWaitEvent in project neo4j by neo4j.

the class ExecutingQueryTest method shouldTransitionBetweenStates.

@Test
void shouldTransitionBetweenStates() {
    // initial
    assertEquals("parsing", query.snapshot().status());
    // when
    query.onObfuscatorReady(null);
    // then
    assertEquals("planning", query.snapshot().status());
    // when
    query.onCompilationCompleted(new CompilerInfo("the-planner", "the-runtime", emptyList()), READ_ONLY, null);
    // then
    assertEquals("planned", query.snapshot().status());
    // when
    query.onExecutionStarted(new FakeMemoryTracker());
    // then
    assertEquals("running", query.snapshot().status());
    // when
    try (LockWaitEvent ignored = lock("NODE", 17)) {
        // then
        assertEquals("waiting", query.snapshot().status());
    }
    // then
    assertEquals("running", query.snapshot().status());
}
Also used : FakeMemoryTracker(org.neo4j.test.FakeMemoryTracker) LockWaitEvent(org.neo4j.lock.LockWaitEvent) Test(org.junit.jupiter.api.Test)

Example 5 with LockWaitEvent

use of org.neo4j.lock.LockWaitEvent in project neo4j by neo4j.

the class ExecutingQueryTest method shouldReportWaitTime.

@Test
void shouldReportWaitTime() {
    // given
    query.onObfuscatorReady(null);
    query.onCompilationCompleted(new CompilerInfo("the-planner", "the-runtime", emptyList()), READ_ONLY, null);
    query.onExecutionStarted(new FakeMemoryTracker());
    // then
    assertEquals("running", query.snapshot().status());
    // when
    clock.forward(10, TimeUnit.SECONDS);
    try (LockWaitEvent ignored = lock("NODE", 17)) {
        clock.forward(5, TimeUnit.SECONDS);
        // then
        QuerySnapshot snapshot = query.snapshot();
        assertEquals("waiting", snapshot.status());
        assertThat(snapshot.resourceInformation()).containsEntry("waitTimeMillis", 5_000L).containsEntry("resourceType", "NODE").containsEntry("transactionId", 10L).containsEntry("resourceIds", new long[] { 17 });
        assertEquals(5_000_000, snapshot.waitTimeMicros());
    }
    {
        QuerySnapshot snapshot = query.snapshot();
        assertEquals("running", snapshot.status());
        assertEquals(5_000_000, snapshot.waitTimeMicros());
    }
    // when
    clock.forward(2, TimeUnit.SECONDS);
    try (LockWaitEvent ignored = lock("RELATIONSHIP", 612)) {
        clock.forward(1, TimeUnit.SECONDS);
        // then
        QuerySnapshot snapshot = query.snapshot();
        assertEquals("waiting", snapshot.status());
        assertThat(snapshot.resourceInformation()).containsEntry("waitTimeMillis", 1_000L).containsEntry("resourceType", "RELATIONSHIP").containsEntry("transactionId", 10L).containsEntry("resourceIds", new long[] { 612 });
        assertEquals(6_000_000, snapshot.waitTimeMicros());
    }
    {
        QuerySnapshot snapshot = query.snapshot();
        assertEquals("running", snapshot.status());
        assertEquals(6_000_000, snapshot.waitTimeMicros());
    }
}
Also used : FakeMemoryTracker(org.neo4j.test.FakeMemoryTracker) LockWaitEvent(org.neo4j.lock.LockWaitEvent) Test(org.junit.jupiter.api.Test)

Aggregations

LockWaitEvent (org.neo4j.lock.LockWaitEvent)5 Test (org.junit.jupiter.api.Test)2 HeapTrackingLongIntHashMap (org.neo4j.collection.trackable.HeapTrackingLongIntHashMap)2 ActiveLock (org.neo4j.lock.ActiveLock)2 FakeMemoryTracker (org.neo4j.test.FakeMemoryTracker)2 TransactionFailureException (org.neo4j.graphdb.TransactionFailureException)1 DeadlockDetectedException (org.neo4j.kernel.DeadlockDetectedException)1 LockClientStoppedException (org.neo4j.kernel.impl.locking.LockClientStoppedException)1