Hi,

I got this solved by following your suggestion and most important
decreasing the corePoolSize in the Thread pool.
Obviously the bigger the number of threads that are trying to run in
parallel the more likely to deadlocks.
What's most intriguing is that this same code without changes ran fine
before we updated to 1.0.

Anyway here is the updated interceptor...

/**
 * 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 {
        boolean deadlockDetected = false;
        int reattempts = 10;
        Object result = null;
        for (int i = 0; i < reattempts; i++) { //try up to ten times
            if (deadlockDetected) {
                Thread.sleep(100);
            }
            Transaction tx = neoService.beginTx();
            try {
                if (deadlockDetected) { //is this the right way to
handle invoking the method?
                    result = invocation.proceed();
                } else {
                    result = invocation.proceed();
                }
                tx.success();
                if (deadlockDetected) {
                    log.debug("successfully recovered from deadlock");
                }
                return result;
            } catch (DeadlockDetectedException e) {
                deadlockDetected = true;
                log.debug("deadlock detected for invocation " +
invocation + " attempt: " + i);
                tx.failure();
                if (i >= reattempts) {
                    log.error("permanent failure after attempt " + i);
                }
            } finally {
                tx.finish();
            }
        }
        return result;
    }
}

2010/2/26 Raul Raja Martinez <[email protected]>:
> That makes sense, I'll give it a try, thanks!
>
> 2010/2/26 Mattias Persson <[email protected]>:
>> 2010/2/26 Raul Raja Martinez <[email protected]>:
>>> 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, [[email protected]]
>> Neo Technology, www.neotechnology.com
>> _______________________________________________
>> Neo mailing list
>> [email protected]
>> https://lists.neo4j.org/mailman/listinfo/user
>>
>
>
>
> --
> Raul Raja
>



-- 
Raul Raja
_______________________________________________
Neo mailing list
[email protected]
https://lists.neo4j.org/mailman/listinfo/user

Reply via email to