From 61692cb41555da5d1efda8f19cb2973cc852deb2 Mon Sep 17 00:00:00 2001 From: Stefan Armbruster Date: Tue, 19 Sep 2017 13:35:06 +0200 Subject: [PATCH] implementing read locks (#601) * implementing read locks * fixing failing test --- src/main/java/apoc/lock/Lock.java | 24 +++++++++ src/test/java/apoc/lock/LockTest.java | 62 ++++++++++++++++++++++ src/test/java/apoc/schema/SchemasTest.java | 4 ++ 3 files changed, 90 insertions(+) create mode 100644 src/test/java/apoc/lock/LockTest.java diff --git a/src/main/java/apoc/lock/Lock.java b/src/main/java/apoc/lock/Lock.java index 974ccc0bbd..e88391720c 100644 --- a/src/main/java/apoc/lock/Lock.java +++ b/src/main/java/apoc/lock/Lock.java @@ -40,6 +40,19 @@ public void nodes(@Name("nodes") List nodes) { tx.success(); } } + + @Procedure(mode = Mode.READ, name = "apoc.lock.read.nodes") + @Description("apoc.lock.read.nodes([nodes]) acquires a read lock on the given nodes") + public void readLockOnNodes(@Name("nodes") List nodes) { + try (Transaction tx = db.beginTx()) { + for (Node node : nodes) { + tx.acquireReadLock(node); + } + tx.success(); + } + } + + @Procedure(mode = Mode.WRITE) @Description("apoc.lock.rels([relationships]) acquires a write lock on the given relationship") public void rels(@Name("rels") List rels) { @@ -50,4 +63,15 @@ public void rels(@Name("rels") List rels) { tx.success(); } } + + @Procedure(mode = Mode.READ, name = "apoc.lock.read.rels") + @Description("apoc.lock.read.rels([relationships]) acquires a read lock on the given relationship") + public void readLocksOnRels(@Name("rels") List rels) { + try (Transaction tx = db.beginTx()) { + for (Relationship rel : rels) { + tx.acquireReadLock(rel); + } + tx.success(); + } + } } diff --git a/src/test/java/apoc/lock/LockTest.java b/src/test/java/apoc/lock/LockTest.java new file mode 100644 index 0000000000..fb83cb7cef --- /dev/null +++ b/src/test/java/apoc/lock/LockTest.java @@ -0,0 +1,62 @@ +package apoc.lock; + +import apoc.util.TestUtil; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Transaction; +import org.neo4j.helpers.collection.Iterators; +import org.neo4j.test.TestGraphDatabaseFactory; + +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; + +public class LockTest { + + private static GraphDatabaseService db; + + @BeforeClass + public static void setUp() throws Exception { + db = new TestGraphDatabaseFactory().newImpermanentDatabase(); + TestUtil.registerProcedure(db, Lock.class); + } + + @AfterClass + public static void tearDown() { + db.shutdown(); + } + + @Test + public void shouldReadLockBlockAWrite() throws Exception { + + Node node; + try (Transaction tx = db.beginTx()) { + node = db.createNode(); + tx.success(); + } + + try (Transaction tx = db.beginTx()) { + final Object n = Iterators.single(db.execute("match (n) CALL apoc.lock.read.nodes([n]) return n").columnAs("n")); + assertEquals(n, node); + + final Thread thread = new Thread(() -> { + db.execute("match (n) delete n"); + + }); + thread.start(); + thread.join(TimeUnit.SECONDS.toMillis(1)); + + // the blocked thread didn't do any work, so we still have nodes + long count = Iterators.count(db.execute("match (n) return n").columnAs("n")); + assertEquals(1, count); + + tx.success(); + } + + + + } +} diff --git a/src/test/java/apoc/schema/SchemasTest.java b/src/test/java/apoc/schema/SchemasTest.java index 0684deffa2..8a4f80e8ec 100644 --- a/src/test/java/apoc/schema/SchemasTest.java +++ b/src/test/java/apoc/schema/SchemasTest.java @@ -295,6 +295,10 @@ public void testIndexNotExists() { public void testIndexOnMultipleProperties() { ignoreException(() -> { db.execute("CREATE INDEX ON :Foo(bar, foo)").close(); + try (Transaction tx = db.beginTx()) { + db.schema().awaitIndexesOnline(1, TimeUnit.SECONDS); + tx.success(); + } testResult(db, "CALL apoc.schema.nodes()", (result) -> { // Get the index info Map r = result.next();