use of org.neo4j.lock.Lock in project neo4j by neo4j.
the class FullScanStoreViewTest method shouldLockNodesWhileReadingThem.
@Test
void shouldLockNodesWhileReadingThem() {
// given
StoreScan storeScan = storeView.visitNodes(new int[] { labelId }, id -> id == propertyKeyId, new TestPropertyScanConsumer(), null, false, true, NULL, INSTANCE);
// when
storeScan.run(NO_EXTERNAL_UPDATES);
// then
assertThat(lockMocks.size()).as("allocated locks: " + lockMocks.keySet()).isGreaterThanOrEqualTo(2);
Lock lock0 = lockMocks.get(0L);
Lock lock1 = lockMocks.get(1L);
assertNotNull(lock0, "Lock[node=0] never acquired");
assertNotNull(lock1, "Lock[node=1] never acquired");
InOrder order = inOrder(locks, lock0, lock1);
order.verify(locks).acquireNodeLock(0, SHARED);
order.verify(lock0).release();
order.verify(locks).acquireNodeLock(1, SHARED);
order.verify(lock1).release();
}
use of org.neo4j.lock.Lock in project neo4j by neo4j.
the class FullScanStoreViewTest method shouldLockRelationshipsWhileReadingThem.
@Test
void shouldLockRelationshipsWhileReadingThem() throws Exception {
// given
StoreScan storeScan = storeView.visitRelationships(new int[] { relTypeId }, id -> id == relPropertyKeyId, new TestPropertyScanConsumer(), null, true, true, NULL, INSTANCE);
// when
storeScan.run(NO_EXTERNAL_UPDATES);
// then
assertThat(lockMocks.size()).as("allocated locks: " + lockMocks.keySet()).isGreaterThanOrEqualTo(2);
Lock lock0 = lockMocks.get(0L);
Lock lock1 = lockMocks.get(1L);
assertNotNull(lock0, "Lock[relationship=0] never acquired");
assertNotNull(lock1, "Lock[relationship=1] never acquired");
InOrder order = inOrder(locks, lock0, lock1);
order.verify(locks).acquireRelationshipLock(0, SHARED);
order.verify(lock0).release();
order.verify(locks).acquireRelationshipLock(1, SHARED);
order.verify(lock1).release();
}
use of org.neo4j.lock.Lock in project neo4j by neo4j.
the class UniqueConstraintCompatibility method applyChangesToPopulatingUpdater.
/**
* NOTE the tests using this will currently succeed for the wrong reasons,
* because the data-changing transaction does not actually release the
* schema read lock early enough for the PopulatingUpdater to come into
* play.
*/
private Future<?> applyChangesToPopulatingUpdater(long blockDataChangeTransactionOnLockOnId, long blockPopulatorOnLockOnId, final Action... actions) throws InterruptedException, ExecutionException {
// We want to issue an update to an index populator for a constraint.
// However, creating a constraint takes a schema write lock, while
// creating nodes and setting their properties takes a schema read
// lock. We need to sneak past these locks.
final CountDownLatch createNodeReadyLatch = new CountDownLatch(1);
final CountDownLatch createNodeCommitLatch = new CountDownLatch(1);
Future<?> updatingTransaction = executor.submit(() -> {
try (Transaction tx = db.beginTx()) {
for (Action action : actions) {
action.accept(tx);
}
tx.commit();
createNodeReadyLatch.countDown();
awaitUninterruptibly(createNodeCommitLatch);
}
});
createNodeReadyLatch.await();
// The above transaction now contain the changes we want to expose to
// the IndexUpdater as updates. This will happen when we commit the
// transaction. The transaction now also holds the schema read lock,
// so we can't begin creating our constraint just yet.
// We first have to unlock the schema, and then block just before we
// send off our updates. We can do that by making another thread take a
// read lock on the node we just created, and then initiate our commit.
Lock lockBlockingDataChangeTransaction = getLockService().acquireNodeLock(blockDataChangeTransactionOnLockOnId, LockType.EXCLUSIVE);
// Before we begin creating the constraint, we take a write lock on an
// "earlier" node, to hold up the populator for the constraint index.
Lock lockBlockingIndexPopulator = getLockService().acquireNodeLock(blockPopulatorOnLockOnId, LockType.EXCLUSIVE);
// This thread tries to create a constraint. It should block, waiting for it's
// population job to finish, and it's population job should in turn be blocked
// on the lockBlockingIndexPopulator above:
final CountDownLatch createConstraintTransactionStarted = new CountDownLatch(1);
Future<?> createConstraintTransaction = executor.submit(() -> createUniqueConstraint(createConstraintTransactionStarted));
createConstraintTransactionStarted.await();
// Now we can initiate the data-changing commit. It should then
// release the schema read lock, and block on the
// lockBlockingDataChangeTransaction.
createNodeCommitLatch.countDown();
// Now we can issue updates to the populator in the still ongoing population job.
// We do that by releasing the lock that is currently preventing our
// data-changing transaction from committing.
lockBlockingDataChangeTransaction.release();
// And we observe that our updating transaction has completed as well:
updatingTransaction.get();
// Now we can release the lock blocking the populator, allowing it to finish:
lockBlockingIndexPopulator.release();
// And return the future for examination:
return createConstraintTransaction;
}
use of org.neo4j.lock.Lock in project neo4j by neo4j.
the class GenerateIndexUpdatesStep method process.
@Override
protected void process(long[] entityIds, BatchSender sender, CursorContext cursorContext) throws Exception {
GeneratedIndexUpdates updates = new GeneratedIndexUpdates(gatherPropertyUpdates, gatherTokenUpdates);
try (CURSOR nodeCursor = entityCursorBehaviour.allocateEntityScanCursor(cursorContext);
StoragePropertyCursor propertyCursor = reader.allocatePropertyCursor(cursorContext, memoryTracker)) {
for (long entityId : entityIds) {
try (Lock ignored = lockFunction.apply(entityId)) {
nodeCursor.single(entityId);
if (nodeCursor.next()) {
generateUpdates(updates, nodeCursor, propertyCursor);
if (updates.propertiesByteSize > maxBatchSizeBytes) {
batchDone(updates, sender);
updates = new GeneratedIndexUpdates(gatherPropertyUpdates, gatherTokenUpdates);
}
}
}
}
}
batchDone(updates, sender);
}
use of org.neo4j.lock.Lock in project neo4j by neo4j.
the class LockGroupTest method shouldReleaseAllLocksWhenExitingTheLockGroupRegion.
@Test
void shouldReleaseAllLocksWhenExitingTheLockGroupRegion() {
// given
Lock lock1 = mock(Lock.class);
Lock lock2 = mock(Lock.class);
Lock lock3 = mock(Lock.class);
// when
try (LockGroup locks = new LockGroup()) {
locks.add(lock1);
locks.add(lock2);
locks.add(lock3);
}
// then
verify(lock1).release();
verify(lock2).release();
verify(lock3).release();
}
Aggregations