silent-box
silent-box

Reputation: 1666

Neo4j: explicit pessimistic locking via Java API or Cypher

Is there a way to manually acquire write lock on a certain set of nodes via Neo4J Java API or Cypher?

There are examples in documentation, but only for embedded Neo4j version. Standard Java Transaction interface does not contain such methods: https://neo4j.com/docs/api/java-driver/current/org/neo4j/driver/v1/Transaction.html

Also I can't find a way to do it via Cypher.

Upvotes: 3

Views: 399

Answers (2)

Steffen Harbich
Steffen Harbich

Reputation: 2749

To extend the answer of @InverseFalcon, here is an example for the write lock by writing to a node:

@Test
public void testPessimisticLocking() throws InterruptedException {
    txn.execute(status -> {
        session.query("CREATE (n:Lock {uuid:'test'})", Map.of(), false);
        return null;
    });

    ExecutorService executor = Executors.newFixedThreadPool(2);
    Runnable task = () -> {
        LOG.debug("Starting task");

        txn.execute(status -> {
            long time = System.nanoTime();
            LOG.debug("Locking node with time={}", time);
            session.query("MATCH (n:Lock {uuid:'test'}) SET n.time = {0}", Map.of("0", time), false);

            LOG.debug("Query done, waiting some time...");
            try {
                Thread.sleep(5000);
            }
            catch (InterruptedException e) {
                LOG.warn("Interrupted", e);
            }
            LOG.debug("Waiting done");

            return null;
        });

        LOG.debug("Finished task");
    };

    for (int i = 0; i < 2; i++) {
        executor.execute(task);
    }

    executor.shutdown();
    executor.awaitTermination(20, TimeUnit.MINUTES);
}

The test creates a node of label "Lock". It starts two tasks in parallel that try to acquire the write lock on the node. Each task is waiting 5sec within the transaction once it has acquired the lock (simulates workload). Debug output is:

2019-10-26 09:47:09,502 [pool-3-thread-1] DEBUG - Starting task
2019-10-26 09:47:09,508 [pool-3-thread-1] DEBUG - Locking node with time=82297334790500
2019-10-26 09:47:09,513 [pool-3-thread-2] DEBUG - Starting task
2019-10-26 09:47:09,515 [pool-3-thread-2] DEBUG - Locking node with time=82297342219000
2019-10-26 09:47:09,605 [pool-3-thread-2] DEBUG - Query done, waiting some time...
2019-10-26 09:47:14,627 [pool-3-thread-2] DEBUG - Waiting done
2019-10-26 09:47:14,643 [pool-3-thread-1] DEBUG - Query done, waiting some time...
2019-10-26 09:47:14,645 [pool-3-thread-2] DEBUG - Finished task
2019-10-26 09:47:19,643 [pool-3-thread-1] DEBUG - Waiting done
2019-10-26 09:47:19,841 [pool-3-thread-1] DEBUG - Finished task

In the log you can see that one task is acquiring the lock just when the other task finished the transaction.

Upvotes: 1

InverseFalcon
InverseFalcon

Reputation: 30397

You can take a write lock by writing to a node, such as by setting or removing a property. I think this also works when removing non-existent properties.

If you have APOC Procedures installed, you can call the apoc.lock.nodes() procedure, passing it a list of the nodes to lock.

Upvotes: 3

Related Questions