Search in sources :

Example 6 with LockWaitEvent

use of org.neo4j.kernel.impl.locking.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);
    try {
        // Grab the global lock map we will be using
        ConcurrentMap<Long, ForsetiLockManager.Lock> lockMap = lockMaps[resourceType.typeId()];
        // And grab our local lock maps
        PrimitiveLongIntMap heldShareLocks = sharedLockCounts[resourceType.typeId()];
        PrimitiveLongIntMap heldExclusiveLocks = exclusiveLockCounts[resourceType.typeId()];
        for (long resourceId : resourceIds) {
            // First, check if we already hold this as a shared lock
            int heldCount = heldShareLocks.get(resourceId);
            if (heldCount != -1) {
                // 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 waitStartMillis = clock.millis();
            LockWaitEvent waitEvent = null;
            try {
                // Retry loop
                while (true) {
                    assertValid(waitStartMillis, 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(false, resourceType, resourceId);
                    }
                    applyWaitStrategy(resourceType, tries++);
                    // And take note of who we are waiting for. This is used for deadlock detection.
                    markAsWaitingFor(existingLock, resourceType, resourceId);
                }
            } finally {
                if (waitEvent != null) {
                    waitEvent.close();
                }
            }
            // Got the lock, no longer waiting for anyone.
            clearWaitList();
            // Make a local note about the fact that we now hold this lock
            heldShareLocks.put(resourceId, 1);
        }
    } finally {
        stateHolder.decrementActiveClients();
    }
}
Also used : PrimitiveLongIntMap(org.neo4j.collection.primitive.PrimitiveLongIntMap) LockWaitEvent(org.neo4j.kernel.impl.locking.LockWaitEvent) ActiveLock(org.neo4j.kernel.impl.locking.ActiveLock)

Example 7 with LockWaitEvent

use of org.neo4j.kernel.impl.locking.LockWaitEvent in project neo4j by neo4j.

the class RWLock method acquireReadLock.

/**
     * Tries to acquire read lock for a given transaction. If
     * <CODE>this.writeCount</CODE> is greater than the currents tx's write
     * count the transaction has to wait and the {@link RagManager#checkWaitOn}
     * method is invoked for deadlock detection.
     * <p/>
     * If the lock can be acquired the lock count is updated on <CODE>this</CODE>
     * and the transaction lock element (tle).
     * Waiting for a lock can also be terminated. In that case waiting thread will be interrupted and corresponding
     * {@link org.neo4j.kernel.impl.locking.community.RWLock.TxLockElement} will be marked as terminated.
     * In that case lock will not be acquired and false will be return as result of acquisition
     *
     * @return true is lock was acquired, false otherwise
     * @throws DeadlockDetectedException if a deadlock is detected
     */
synchronized boolean acquireReadLock(LockTracer tracer, Object tx) throws DeadlockDetectedException {
    TxLockElement tle = getOrCreateLockElement(tx);
    LockRequest lockRequest = null;
    LockWaitEvent waitEvent = null;
    // used to track do we need to add lock request to a waiting queue or we still have it there
    boolean addLockRequest = true;
    try {
        tle.incrementRequests();
        Thread currentThread = currentThread();
        long lockAcquisitionTimeBoundary = clock.millis() + lockAcquisitionTimeoutMillis;
        while (!tle.isTerminated() && (totalWriteCount > tle.writeCount)) {
            assertNotExpired(lockAcquisitionTimeBoundary);
            ragManager.checkWaitOn(this, tx);
            if (addLockRequest) {
                lockRequest = new LockRequest(tle, READ, currentThread);
                waitingThreadList.addFirst(lockRequest);
            }
            if (waitEvent == null) {
                waitEvent = tracer.waitForLock(false, resource.type(), resource.resourceId());
            }
            addLockRequest = waitUninterruptedly(lockAcquisitionTimeBoundary);
            ragManager.stopWaitOn(this, tx);
        }
        if (!tle.isTerminated()) {
            registerReadLockAcquired(tx, tle);
            return true;
        } else {
            // if it was register before it will be cleaned up during standard lock release call
            if (tle.requests == 1 && tle.isFree()) {
                txLockElementMap.remove(tx);
            }
            return false;
        }
    } finally {
        if (waitEvent != null) {
            waitEvent.close();
        }
        cleanupWaitingListRequests(lockRequest, tle, addLockRequest);
        // for cases when spurious wake up was the reason why we waked up, but also there
        // was an interruption as described at 17.2 just clearing interruption flag
        interrupted();
        // if deadlocked, remove marking so lock is removed when empty
        tle.decrementRequests();
        unmark();
    }
}
Also used : LockWaitEvent(org.neo4j.kernel.impl.locking.LockWaitEvent) Thread.currentThread(java.lang.Thread.currentThread)

Example 8 with LockWaitEvent

use of org.neo4j.kernel.impl.locking.LockWaitEvent in project neo4j by neo4j.

the class ExecutingQueryTest method shouldReportWaitTime.

@Test
public void shouldReportWaitTime() throws Exception {
    // given
    query.planningCompleted(new PlannerInfo("the-planner", "the-runtime", emptyList()));
    // then
    assertEquals("running", query.snapshot().status());
    // when
    clock.forward(10, TimeUnit.SECONDS);
    try (LockWaitEvent event = lock("NODE", 17)) {
        clock.forward(5, TimeUnit.SECONDS);
        // then
        QuerySnapshot snapshot = query.snapshot();
        assertEquals("waiting", snapshot.status());
        assertThat(snapshot.resourceInformation(), CoreMatchers.<Map<String, Object>>allOf(hasEntry("waitTimeMillis", 5_000L), hasEntry("resourceType", "NODE"), hasEntry(equalTo("resourceIds"), longArray(17))));
        assertEquals(5_000, snapshot.waitTimeMillis());
    }
    {
        QuerySnapshot snapshot = query.snapshot();
        assertEquals("running", snapshot.status());
        assertEquals(5_000, snapshot.waitTimeMillis());
    }
    // when
    clock.forward(2, TimeUnit.SECONDS);
    try (LockWaitEvent event = lock("RELATIONSHIP", 612)) {
        clock.forward(1, TimeUnit.SECONDS);
        // then
        QuerySnapshot snapshot = query.snapshot();
        assertEquals("waiting", snapshot.status());
        assertThat(snapshot.resourceInformation(), CoreMatchers.<Map<String, Object>>allOf(hasEntry("waitTimeMillis", 1_000L), hasEntry("resourceType", "RELATIONSHIP"), hasEntry(equalTo("resourceIds"), longArray(612))));
        assertEquals(6_000, snapshot.waitTimeMillis());
    }
    {
        QuerySnapshot snapshot = query.snapshot();
        assertEquals("running", snapshot.status());
        assertEquals(6_000, snapshot.waitTimeMillis());
    }
}
Also used : LockWaitEvent(org.neo4j.kernel.impl.locking.LockWaitEvent) Test(org.junit.Test)

Example 9 with LockWaitEvent

use of org.neo4j.kernel.impl.locking.LockWaitEvent in project neo4j by neo4j.

the class ExecutingQueryTest method shouldTransitionBetweenStates.

@Test
public void shouldTransitionBetweenStates() throws Exception {
    // initial
    assertEquals("planning", query.snapshot().status());
    // when
    query.planningCompleted(new PlannerInfo("the-planner", "the-runtime", emptyList()));
    // then
    assertEquals("running", query.snapshot().status());
    // when
    try (LockWaitEvent event = lock("NODE", 17)) {
        // then
        assertEquals("waiting", query.snapshot().status());
    }
    // then
    assertEquals("running", query.snapshot().status());
    // when
    query.waitsForQuery(subQuery);
    // then
    assertEquals("waiting", query.snapshot().status());
    // when
    query.waitsForQuery(null);
    // then
    assertEquals("running", query.snapshot().status());
}
Also used : LockWaitEvent(org.neo4j.kernel.impl.locking.LockWaitEvent) Test(org.junit.Test)

Aggregations

LockWaitEvent (org.neo4j.kernel.impl.locking.LockWaitEvent)9 Thread.currentThread (java.lang.Thread.currentThread)2 Test (org.junit.Test)2 PrimitiveLongIntMap (org.neo4j.collection.primitive.PrimitiveLongIntMap)2 ActiveLock (org.neo4j.kernel.impl.locking.ActiveLock)2 DeadlockDetectedException (org.neo4j.kernel.DeadlockDetectedException)1 LockClientStoppedException (org.neo4j.kernel.impl.locking.LockClientStoppedException)1