Issue 1:
For example, I have this data on my Neo4J (I'm using v2.2.5):

merge (a1:Actor {id: "1"})
merge (m1:Movie {id: "M1"})
merge (m2:Movie {id: "M2"})
merge (m3:Movie {id: "M3"})
merge (a1)-[:ACTED_IN]->(m1)
merge (a1)-[:ACTED_IN]->(m2)
merge (a1)-[:ACTED_IN]->(m3);

Then I have two concurrent process that run these query:

Process-1:

MATCH (n:Actor {uuid: '1'})
CREATE (n)-[:ACTED_IN]->(m:Movie)
RETURN m;

Process-2:

MATCH (n:Actor {uuid: '1'})
OPTIONAL MATCH (n)-[r]-()
DELETE n, r;

Process-1 will create a new relationship and a new Movie node for the Actor and process-2 will delete the Actor and its relationships.

When the both process are run in same time, the delete (process-2) sometimes failed with this error:

org.neo4j.kernel.api.exceptions.TransactionFailureException: Node record Node[11,used=false,rel=4,prop=-1,labels=Inline(0x0:[]),light] still has relationships

or

Node[1208] is deleted and cannot be used to create a relationship

The delete failed because the delete query try to delete 3 ACTED_IN relationships from the Actor node, while when the DELETE command was just being executed, the process-1 query had successfully created a new ACTED_IN relationship (see analysis part below).

I managed to reproduce the error with this bash script (you need to have curl program):

#!/bin/bash

curl -XPOST http://localhost:7474/db/data/transaction/commit -H "Content-Type: application/json" -d '{"statements" : [ {"statement" : "MATCH (n:Actor {id: \"1\"}) OPTIONAL MATCH (n)-[r]-() DELETE n, r"} ]}' &
curl -XPOST http://localhost:7474/db/data/transaction/commit -H "Content-Type: application/json" -d '{"statements" : [ {"statement" : "MATCH (n:Actor {id: \"1\"}) CREATE (n)-[:ACTED_IN]->(m:Movie) RETURN m"} ]}' &

wait

Note: You might need to re-run the script again and clear up the database and reinsert the nodes again if the error doesn't show up as the process are executed concurrently, the issue doesn't always show up.

I wonder if when a cypher is executed, is there node or relationship locking being applied?

If looking from the problem above, I have a feeling there are no locking at all. From my analysis:

MATCH (n:Actor {uuid: '1'}) // n = Actor node
OPTIONAL MATCH (n)-[r]-() // r = 3 ACTED_IN relationships

// However, before reaching the DELETE command below,
// the Process-1's query has been executed inbetween,
// so currently the Actor node actually has 4 ACTED_IN relationships

DELETE n, r; // Since the Actor has 4 relationships
// but the variable r still refer to 3 relationships only,
// so this made the delete failed

I would expect when a cypher query is executed or run, neo4j will lock the processed node & relationship from being modified by other cypher process, so the other query process should wait until it finished.

Is there an explanation and solution for this?

Is there a way to lock the node or relationship from being modified by another process?

Issue 2:
NOTE: This description has been updated, the original description is at the bottom

While Neo4j primitives are read committed, Cypher composes these primitives together in ways that can lead to errors - notably cypher may read an entity that is subsequently deleted, and will then fail to perform some operation on it.

While this could be construed as a cypher issue, it is really an issue of isolation levels - we need to implement repeatable read isolation in the kernel to allow cypher to expose a single cypher statement as a read committed operation.

If you suspect an isolation issue

If you believe you are hitting a problem related to transaction isolation levels, please post a comment on this ticket with:

Any setup required

All cypher statements involved

What you expected the result to be

What the result actually is

Your Neo4j version, Java version and operating system

Workarounds

Lock the read set

Many (but not all) of the cases where this is an issue have a format like:

<match some stuff>
<perform some mutation>

For this category of statements, we suffer the same problem as SQL solves with SELECT ... FOR UPDATE. Cypher does not yet support a construct like that, but it can be emulated using the following pattern:

<match some stuff>
<set a property, for instance __lock__>
WITH <stuff>
<perform some mutation>

For example:

MATCH (n:Person)
SET n.__lock__ = 1
WITH n
SET n.description = "Some description"

Retry transaction

Particularly for small read operations and small writes, given the transactional nature of Neo4j, you can rollback and retry any transaction where a statement fails due to this issue. A common pattern for this is to model your query as a unit of work that can be retried.

Original message

@peterneubauer: 'See https://groups.google.com/group/neo4j/browse_thread/thread/9355edd2059d70e2/a51d06c894107327?lnk=gst&q=Concurrent+reading+and+deleting+on+relationships+leads+to+NotFoundException.+How+to+ignore%3F#a51d06c894107327 for background.

Example code is at http://code.google.com/p/graph-query-benchmarks/source/browse/trunk/graph-query-benchmarks/src/test/nz/ac/massey/cs/graphbenchmarks/spikes/neo4j/NeoIssues.java'