Hello. Are nested transaction supported? >From what I'm testing here, it looks like unless I specify .failure() on the nested transaction, before it reaches .finish() the transaction is considered to be successful (even if I didn't call .success() on it). Though if I do call .failure() then the root transaction will be rolled back with exception: Exception in thread "main" org.neo4j.graphdb.TransactionFailureException: Unable to commit transaction at org.neo4j.kernel.TopLevelTransaction.finish(TopLevelTransaction.java:98) at org.neo4j.examples.CalculateShortestPath.main(CalculateShortestPath.java:116) Caused by: javax.transaction.RollbackException: Failed to commit, transaction rolledback at org.neo4j.kernel.impl.transaction.TxManager.rollbackCommit(TxManager.java:811) at org.neo4j.kernel.impl.transaction.TxManager.commit(TxManager.java:645) at org.neo4j.kernel.impl.transaction.TransactionImpl.commit(TransactionImpl.java:109) at org.neo4j.kernel.TopLevelTransaction.finish(TopLevelTransaction.java:85) ... 1 more
In the root transaction however, if I don't explicitly call .success() it is considered failure and rolled back on finish. This seem to be the main difference between root transaction and the nested transaction; was this intended? here's a sample program to test: (points 1. and 2. are important to me) 1. run it as it is, to see that nested transaction doesn't default to failure when none of .failure() or .success() are specified before reaching .finish(); is this a feature? (I just remembered that possibly someone told me about this yesterday? I cannot find the message) 2. uncomment // nestyTx.failure(); to see what happens when specifically stating that the nested transaction failed ==> the root one will rollback with exception, which might be fine, I guess... though maybe I would expect that the root transaction not be affected by a rolled back child transaction, I mean, I might retry the child transaction and succeed the second time, but the root will fail because some child transaction failed before... to get the idea of this, use this code block (you'll know where to put it, replacing the old part): Transaction nestyTx = graphDb.beginTx(); try { Relationship rel = one.createRelationshipTo( graphDb.createNode(), moo ); if ( i % 2 == 0 ) { nestyTx.success();// no need to uncomment this, for nested this is the default, not intended? } else { nestyTx.failure();// XXX: uncomment this to cause rootTx to fail } } finally { nestyTx.finish(); } 3. comment out the rootTx (all of begin/success/finish at once) to see the speed that nestyTx has when it isn't a nested transaction ==> way slower than when it's nested - though I guess this might make sense, since nothing is really committed unless the root transaction commits. /** * Licensed to Neo Technology under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Neo Technology licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.neo4j.examples; import java.io.*; import java.text.*; import org.neo4j.graphdb.*; import org.neo4j.graphdb.index.*; import org.neo4j.kernel.*; public class CalculateShortestPath { private static final int SHOWINFO_IF_COUNTING_REL_TOOK_MORE_THAN_ns = 2 * 300; private static final int SHOWINFO_IF_REL_TOOK_MORE_THAN_ns = 30000; private static final int SHOWEVERY_xTH_REL = 10000; private static final int HOWMANY_RELATIONSHIPS = 9000; private static final String DB_PATH = "neo4j-shortest-path"; private static final String NAME_KEY = "name"; private static RelationshipType KNOWS = DynamicRelationshipType .withName( "KNOWS" ); private static GraphDatabaseService graphDb; private static Index<Node> indexService; private static DecimalFormat commaDelimitedFormatter = new DecimalFormat( "###,###" ); public static String number( double val ) { return commaDelimitedFormatter.format( val ); } public static void main( final String[] args ) { // deleteFileOrDirectory( new File( DB_PATH ) );// XXX: graphDb = new EmbeddedGraphDatabase( DB_PATH ); indexService = graphDb.index().forNodes( "nodes" ); registerShutdownHook(); Transaction rootTx; rootTx = graphDb.beginTx(); Node one = getOrCreateNode( "one" ); DynamicRelationshipType moo = DynamicRelationshipType.withName( "moo" ); try { for ( int i = 1; i <= HOWMANY_RELATIONSHIPS; i++ ) { long start = System.nanoTime(); Transaction nestyTx = graphDb.beginTx(); try { Relationship rel = one.createRelationshipTo( graphDb.createNode(), moo ); // nestyTx.success();//no need to uncomment this, for nested this is the default // nestyTx.failure();//XXX: uncomment this to cause rootTx to fail } finally { nestyTx.finish(); } // rel.setProperty( "relname", i ); long end = System.nanoTime(); if ( ( i % SHOWEVERY_xTH_REL == 0 ) || ( end - start > SHOWINFO_IF_REL_TOOK_MORE_THAN_ns ) ) { System.out.println( number( i ) + " timeDelta=" + number( end - start ) ); } } System.out.println( "counting..." ); long start = System.nanoTime(); Iterable<Relationship> rel = one.getRelationships( Direction.OUTGOING, moo ); long count = 0; long tstart = 0; for ( Relationship relationship : rel ) { // long tend = System.nanoTime(); count++; // if ( ( tend - tstart > SHOWINFO_IF_COUNTING_REL_TOOK_MORE_THAN_ns ) ) { // System.out.println( number( count ) + " timeDelta=" + number( tend - tstart ) ); // } // tstart = System.nanoTime(); } long end = System.nanoTime(); System.out.println( "Node `" + one.getProperty( NAME_KEY ) + "` has " + number( count ) + " out rels, time=" + number( end - start ) ); // /* // * (Neo) --> (Trinity) // * \ ^ // * v / // * (Morpheus) --> (Cypher) // * \ | // * v v // * (Agent Smith) // */ // createChain( "Neo", "Trinity" ); // createChain( "Neo", "Morpheus", "Trinity" ); // createChain( "Morpheus", "Cypher", "Agent Smith" ); // createChain( "Morpheus", "Agent Smith" ); rootTx.success(); } finally { long start = System.nanoTime(); rootTx.finish(); long end = System.nanoTime(); System.out.println( "tx.finish() time=" + number( end - start ) ); } rootTx = graphDb.beginTx(); try { System.out.println( "counting outside of transaction..." ); long start = System.nanoTime(); Iterable<Relationship> rel = one.getRelationships( Direction.OUTGOING, moo ); long count = 0; for ( Relationship relationship : rel ) { count++; } long end = System.nanoTime(); System.out.println( "Node `" + one.getProperty( NAME_KEY ) + "` has " + number( count ) + " out rels, time=" + number( end - start ) ); // So let's find the shortest path between Neo and Agent Smith // Node neo = getOrCreateNode( "Neo" ); // Node agentSmith = getOrCreateNode( "Agent Smith" ); // // START SNIPPET: shortestPathUsage // PathFinder<Path> finder = GraphAlgoFactory.shortestPath( Traversal.expanderForTypes( KNOWS, Direction.BOTH ), 4 // ); // Path foundPath = finder.findSinglePath( neo, agentSmith ); // System.out.println( "Path from Neo to Agent Smith: " + Traversal.simplePathToString( foundPath, NAME_KEY ) ); // END SNIPPET: shortestPathUsage rootTx.success(); } finally { rootTx.finish(); } // graphDb.shutdown(); } private static void createChain( String... names ) { for ( int i = 0; i < names.length - 1; i++ ) { Node firstNode = getOrCreateNode( names[i] ); Node secondNode = getOrCreateNode( names[i + 1] ); firstNode.createRelationshipTo( secondNode, KNOWS ); } } private static Node getOrCreateNode( String name ) { Node node = indexService.get( NAME_KEY, name ).getSingle(); if ( node == null ) { System.out.println( "creating new node with name=" + name ); node = graphDb.createNode(); node.setProperty( NAME_KEY, name ); indexService.add( node, NAME_KEY, name ); } return node; } private static void registerShutdownHook() { // Registers a shutdown hook for the Neo4j instance so that it // shuts down nicely when the VM exits (even if you "Ctrl-C" the // running example before it's completed) Runtime.getRuntime().addShutdownHook( new Thread() { @SuppressWarnings( "synthetic-access" ) @Override public void run() { System.out.println( "Shutting down database ..." ); graphDb.shutdown(); } } ); } private static void deleteFileOrDirectory( File file ) { if ( file.exists() ) { if ( file.isDirectory() ) { for ( File child : file.listFiles() ) { deleteFileOrDirectory( child ); } } file.delete(); } } } _______________________________________________ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user