[Neo] Estrange exception when running multithreaded

Mattias Persson mattias at neotechnology.com
Fri Feb 26 09:52:54 CET 2010


2010/2/26 Raul Raja Martinez <raulraja at gmail.com>:
> Hi Mattias,
>
> Thanks for the docs.
> I'm trying to solve this issue now and here is the problem I'm facing...
>
> Where it says in the wiki:
> "Rewrite your code, making sure that such scenarios won't happen.
> Run your deadlock-prone code in a try-catch(DeadlockDetectedException)
> block and just rerun the entire transaction if such an exception is
> caught."
>
> My transactions start and end in an interceptor that provides advice
> to method invokations.
> The invokations happen inside a thread pool concurrently.
>
> This is what the interceptor looks like. I have no way to recover from
> the deadlock. Are you implying in that advice that
> I should synchronize in the operation that is causing the write lock?
> Is there anyway to configure Neo to wait on deadlock for a release up
> to certain time?
> If I reissue a method call that is transactional other state not
> related to the neo transactions such as indexes, etc... may modify
> other state objects, I'd rather have the transaction wait for release
> and continue as other transactions are completing.
To make the executing thread wait would result in a deadlock, that's
why the exception is thrown so that isn't really an option.

Regarding state: if you're referring to components in neo4j, they all
handle state correctly if a transaction is rolled back (in this case
where a DeadlockDetectedException is thrown)... even the IndexService
and such components so that won't be a problem.
>
> Here is the code for the interceptor. The advised methods are
> Runnables that get executed async by a threadpool.
>
> /**
>  * A method interceptor that provides transaction advice around a
> method invocation opening and closing a transaction accordingly
>  */
> public class Neo4JTransactionAdviceInterceptor implements MethodInterceptor {
>
>    private final static Logger log =
> Logger.getLogger(Neo4JTransactionAdviceInterceptor.class);
>
>    private GraphDatabaseService neoService;
>
>    public void setNeoService(GraphDatabaseService neoService) {
>        this.neoService = neoService;
>    }
>
>    /**
>     * provides transaction advice around a method invocation opening
> and closing a transaction accordingly
>     *
>     * @param invocation the method invocation joinpoint
>     * @return the result of the call to {@link
>     *         org.aopalliance.intercept.Joinpoint#proceed()}, might
> be intercepted by the
>     *         interceptor.
>     * @throws Throwable if the interceptors or the
>     *                   target-object throws an exception.
>     */
>    public Object invoke(MethodInvocation invocation) throws Throwable {
>        Transaction tx = neoService.beginTx();
>        Object result = null;
>                try {
>                        result = invocation.proceed();
>                        tx.success();
>                } catch (DeadlockDetectedException e) {
>            tx.failure();
>            log.debug("deadlock detected for invocation " + invocation
> + " result: " + result + " transaction: " + tx);
>        } catch (Throwable t) {
>                        tx.failure();
>            throw t;
>                } finally {
>                        tx.finish();
>                }
>        return result;
>    }
> }
>
>

How about making your code look something like (I removed unecessary
tx.failure() calls, see
http://wiki.neo4j.org/content/Transactions#Controlling_success):

public Object invoke(MethodInvocation invocation) throws Throwable {
    Object result = null;
    for ( int i = 0; i < 10; i++ ) {
        Transaction tx = neoService.beginTx();
        try {
            result = invocation.proceed();
            tx.success();
            return result;
        } catch (DeadlockDetectedException e) {
            log.debug("deadlock detected for invocation " + invocation
                + " result: " + result + " transaction: " + tx);
        } finally {
            tx.finish();
        }
    }
    return result;
}

Where 10 is the number of retries to do before giving up. It may not
look very elegant, but there's really no "silver bullet" for the the
deadlock problem.

-- 
Mattias Persson, [mattias at neotechnology.com]
Neo Technology, www.neotechnology.com


More information about the User mailing list