What changed about deleting nodes in 1.9.M02 and 1.8.1 (compared to 1.9.M01)?

103 views
Skip to first unread message

Mat Tyndall

unread,
Dec 21, 2012, 6:26:39 AM12/21/12
to ne...@googlegroups.com
I'm switching from 1.9.M01 and all of a sudden I'm getting [Error: Node[348] has been deleted in this tx] and Error: Node[348] not found when I try to do queries that involve deleting some nodes.

All my tests were passing before so something changed and it sure doesn't seem to be documented to me. Is this a bug?

-Mat

Mattias Persson

unread,
Dec 21, 2012, 9:46:34 AM12/21/12
to Neo4j Development

What is your tests/querids like? Also, is it through Cypher ir the Java API?

--
 
 

alfio...@gmail.com

unread,
Dec 21, 2012, 10:18:12 AM12/21/12
to ne...@googlegroups.com
I experience the same thing and I am using SDN 2.1.0, Neo4j 1.8, using AspectJ advanced mapping mode (compile time weaving) on JDK 7

       @Test
public void test_deleteApplicationByEntityId() {
Assert.assertEquals(appRepo.count(), 0);
final Application persistedApp = createApplication("TEST_NAME-test_deleteApplicationByEntityId",
       "TEST DISPLAY NAME - test_deleteApplicationByEntityId", "TEST APP DESCRIPTION - test_deleteApplicationByEntityId");

Assert.assertNotNull(appRepo.findByEntityId(persistedApp.getEntityId()));
Assert.assertTrue(service.deleteApplicationByEntityId(persistedApp.getEntityId()));
Assert.assertNull(appRepo.findByEntityId(persistedApp.getEntityId()));
}

The unit test is running in the context of a Transaction, and the line highlighted in red throws the following exception:

FAILED: test_deleteApplicationByEntityId
java.lang.IllegalStateException: Node[3] has been deleted in this tx
at org.neo4j.kernel.impl.core.LockReleaser$CowEntityElement.assertNotDeleted(LockReleaser.java:133)
at org.neo4j.kernel.impl.core.LockReleaser$CowEntityElement.getPropertyAddMap(LockReleaser.java:126)
at org.neo4j.kernel.impl.core.LockReleaser$CowNodeElement.getPropertyAddMap(LockReleaser.java:143)
at org.neo4j.kernel.impl.core.LockReleaser.getCowPropertyAddMap(LockReleaser.java:545)
at org.neo4j.kernel.impl.core.NodeManager.getCowPropertyAddMap(NodeManager.java:1089)
at org.neo4j.kernel.impl.core.Primitive.hasProperty(Primitive.java:291)
at org.neo4j.kernel.impl.core.NodeImpl.hasProperty(NodeImpl.java:52)
at org.neo4j.kernel.impl.core.NodeProxy.hasProperty(NodeProxy.java:160)
at org.springframework.data.neo4j.fieldaccess.PropertyFieldAccessorFactory$PropertyFieldAccessor.doGetValue(PropertyFieldAccessorFactory.java:85)
at org.springframework.data.neo4j.fieldaccess.PropertyFieldAccessorFactory$PropertyFieldAccessor.getValue(PropertyFieldAccessorFactory.java:80)
at org.springframework.data.neo4j.fieldaccess.DefaultEntityState.getValue(DefaultEntityState.java:97)
at org.springframework.data.neo4j.fieldaccess.DetachedEntityState.getValue(DetachedEntityState.java:101)
at org.springframework.data.neo4j.fieldaccess.DetachedEntityState.getValue(DetachedEntityState.java:106)
at com.azaptree.spring.data.impl.AbstractEntity.entityId_aroundBody61$advice(AbstractEntity.java:256)
at com.azaptree.spring.data.impl.AbstractEntity.getEntityId(AbstractEntity.java:159)
at test.com.azaptree.spring.application.service.manager.impl.ApplicationManagerServiceTest.test_deleteApplicationByEntityId(ApplicationManagerServiceTest.java:114)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
at org.testng.internal.MethodInvocationHelper$1.runTestMethod(MethodInvocationHelper.java:182)
at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.run(AbstractTestNGSpringContextTests.java:155)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.testng.internal.MethodInvocationHelper.invokeHookable(MethodInvocationHelper.java:194)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:707)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:128)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1203)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1128)
at org.testng.TestNG.run(TestNG.java:1036)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)

I would consider this a defect (not a feature)

alfio...@gmail.com

unread,
Dec 21, 2012, 1:28:21 PM12/21/12
to ne...@googlegroups.com
I had a similar question posted, and Michael Hunger responded - see https://groups.google.com/forum/?fromgroups=#!topic/neo4j/H6r_yrHqjCc

The answer is: this is the "expected" behaivor.

Mattias Persson

unread,
Dec 21, 2012, 2:01:56 PM12/21/12
to Neo4j Development
To have neo4j throw exception instead of returning null is expected behaviour, yes. I wonder what made this behaviour different in 1.9.M01 as compared to M02.

Why would you consider this a bug?


2012/12/21 <alfio...@gmail.com>
--
 
 



--
Mattias Persson, [mat...@neotechnology.com]
Hacker, Neo Technology
www.neotechnology.com

Mat Tyndall

unread,
Dec 21, 2012, 4:39:22 PM12/21/12
to ne...@googlegroups.com
Neo4j is basically telling me that a deleted node used to exist but doesn't anymore.The problem is that I'm deleting nodes because I don't want to find them. 

START dimension = node:dimensions("dimension_id:77292")
MATCH dimension<-[r1?:DESCRIBES]-combo<-[r2?]-(), descriptor<-[r3?:COPY_OF]-combo-[r4?:USES]->()
WHERE r2 is null AND NOT(combo.descriptor_id? IN([1234, 12352]))
DELETE r1, combo, r3, r4
WITH dimension
MATCH dimension<-[?:DESCRIBES]-combo<-[r?]-(), combo-[?:USES]->template
RETURN dimension, combo, COUNT(DISTINCT r) as combo_inbound, template, COUNT(DISTINCT combo) as template_inbound

"Error: Node[119] not found" (that's the deleted combo node).

Wes Freeman

unread,
Dec 21, 2012, 4:42:49 PM12/21/12
to ne...@googlegroups.com
I assume it doesn't happen if you break up the query into two pieces (the delete and the second match).

+1 that this is kind of weird. Why is it matching anything if it should no longer exist?

Wes

--
 
 

Mattias Persson

unread,
Dec 21, 2012, 5:09:47 PM12/21/12
to Neo4j Development
Yes, absolutely in this Cypher scenario it looks like a bug. But I still think it's correct in your test scenario:

1) get N
2) delete N
3) get N --> throw exception



2012/12/21 Mat Tyndall <mat.t...@gmail.com>

Tero Paananen

unread,
Dec 21, 2012, 5:21:46 PM12/21/12
to ne...@googlegroups.com
> Yes, absolutely in this Cypher scenario it looks like a bug. But I still
> think it's correct in your test scenario:
>
> 1) get N
> 2) delete N
> 3) get N --> throw exception

The counter-argument is that most other (and all RDBMS) databases
would just give you an empty resultset.

-TPP

Mat Tyndall

unread,
Dec 21, 2012, 5:30:01 PM12/21/12
to ne...@googlegroups.com
It gets weirder. The last part of the query looks the same as my findDimension query so I changed it like this.

Q1

START dimension = node:dimensions("dimension_id:77292")
MATCH dimension<-[r1?:DESCRIBES]-combo<-[r2?]-(), descriptor<-[r3?:COPY_OF]-combo-[r4?:USES]->()
WHERE r2 is null AND NOT(combo.descriptor_id? IN([1234, 12352]))
DELETE r1, combo, r3, r4

Q2

START dimension = node:dimensions("dimension_id:77292")

MATCH dimension<-[?:DESCRIBES]-combo<-[r?]-(), combo-[?:USES]->template
RETURN dimension, combo, COUNT(DISTINCT r) as combo_inbound, template, COUNT(DISTINCT combo) as template_inbound


Guess what? It thew the same error IN Q1! and never made it to Q2. Splitting the function passed and failed the exact same tests with the same errors.

Mat Tyndall

unread,
Dec 21, 2012, 5:52:02 PM12/21/12
to ne...@googlegroups.com
Just ran some more tests.

Splitting the query seems to prevent errors when deleting 3/3 combos. 

WHERE r2 is null AND NOT(combo.descriptor_id? IN([]))
DELETE r1, combo, r3, r4

However, when deleting 1/3 combos, I still get [Error: Node[550] has been deleted in this tx].

WHERE r2 is null AND NOT(combo.descriptor_id? IN([536805,537805]))
DELETE r1, combo, r3, r4

Wes Freeman

unread,
Dec 21, 2012, 7:42:30 PM12/21/12
to ne...@googlegroups.com
You're not saying "3) get N", though, you're saying "3) find a matching node for this pattern" and I think it should just not find anything. 

Wes

--
 
 

Mat Tyndall

unread,
Dec 21, 2012, 8:46:03 PM12/21/12
to ne...@googlegroups.com
Wow, that was painful but I finally came up with a workaround that passes my tests.

Steps for updating combos attached to a dimension:

Q1. Add any new combos to the dimension, adding/deleting relationships ok, adding nodes ok.
      Find any combos that should be deleted, return their ids.
Q2. If Q1 returns any any combo_ids, delete those nodes and their relationships.
Q3. Lookup the dimension and all attached nodes and return the final result.

So the final result required me to break apart one query into 3 separate ones. 

Finally I can move on with my life. Thanks for all the help and suggestions, good luck tracking down the bug.

-Mat
Reply all
Reply to author
Forward
0 new messages