On Feb 11, 2011, at 12:20 PM, Sanne Grinovero wrote:
> 2011/2/11 Galder Zamarreño <galder(a)redhat.com>:
>> The other *Async() limit themselves to making the RPC call in a separate thread,
i.e. putAsync.
>>
>> So, by the time they have to go remote to replicate something, they've
already acquire the locks within the user thread and the transaction is in prepare state.
>>
>> The PrepareCommand should contains a GlobalTransaction which transforms into a
RemoteTransaction in the other node.
>>
>> I don't see the need to transfer actual javax.transaction.Transaction
information with these commands.
>
> So basically if I abort a transaction during which I performed some
> asyncPut() operations, they are not rolled back? I could live with
> that, as long as we clearly document this.
Of course it's rolled back. An async put within a transaction will only go remote
when you actually commit the transaction. So if u rollback, so remote puts are done.
And to clarify, an asyncPut will synchronously hit the cache store unless the cache store
is configured in async mode. If we want asyncPut() to be proper async, even for cache
store access, further work would be needed. I varguely remember someone talking about
this, could it have been Philippe Van Dyck? I can't find references to that right
now.
>
>>
>> Btw, I've just been talking to Mircea and we're considering passing
around the LocalTransaction between the caller and the getAsync thread rather than passing
javax.transaction.Transaction which we don't have control over.
>
> Jonathan mentioned a way to share transactions across threads using
> JBoss TransactionManager; the main problem with this is that while
> something similar might be supported by others: it's not standardized.
>
>>
>> On Feb 10, 2011, at 7:09 PM, Manik Surtani wrote:
>>
>>> How do other *Async() calls deal with jta, if at all?
>>>
>>> On 10 Feb 2011, at 11:10, Galder Zamarreño wrote:
>>>
>>>> That's a good optimisation Mircea, I've added it.
>>>>
>>>> There's another important problem to solve here which is, how do you
make getAsync() maintain the transaction semantics of the incoming thread? getAsync does
not acquire locks except in the case where the remote get leads to a L1 put in which case
a write lock is acquired on entry put on L1.
>>>>
>>>> The main problem here is how to make the transaction propagate from one
thread to the other? I tried to pass the current thread's transaction to the
getAsync() thread and create an invocation context using it. This doesn't work cos
LocalTxInvocationContext does not keep the current transaction, instead it keeps the
localTransaction which for 1st invocation is null.
>>>>
>>>> The Infinispan code relies on TransactionManager.getTransaction() which
most likely relies on a ThreadLocal being set to the current transaction. Once you switch
threads, this method returns null, and with the solution attempted solution I get:
>>>>
>>>> Caused by: java.lang.IllegalStateException: This should only be called in
an tx scope
>>>> at
org.infinispan.interceptors.TxInterceptor.enlist(TxInterceptor.java:193)
>>>> at
org.infinispan.interceptors.TxInterceptor.enlistReadAndInvokeNext(TxInterceptor.java:167)
>>>> at
org.infinispan.interceptors.TxInterceptor.visitGetKeyValueCommand(TxInterceptor.java:162)
>>>>
>>>> So, what I've done is get the InvocationContextContainer to take the
passed transaction and assign it to the local tx invocation context, and then use this
transaction rather than the one from tm.getTransaction() in the enlist method.
>>>>
>>>> I've created a pull request with this solution and you can find it
in:
https://github.com/infinispan/infinispan/pull/160
>>>>
>>>> Note that I've made a couple of TODOs in AbstractTxInvocationContext
in order to discuss potentially naming getTransaction/setTransaction differently and see
if we wanna merge somehow with getRunningTransaction() available in TxInvocationContext.
>>>>
>>>> Cheers,
>>>>
>>>> On Feb 9, 2011, at 6:42 PM, Mircea Markus wrote:
>>>>
>>>>> On 9 Feb 2011, at 17:35, Galder Zamarreño wrote:
>>>>>
>>>>>> Hmmmm, I've thought this further. The penalty of the thread
ctx switching is probably not that bad actually cos the point of getAsync() is the ability
to paralelise rather than how quickly getAsync() returns.
>>>>> Or a local get can be forced(flag) before giving control(if local
value doesn't exist) to the new thread.
>>>>>>
>>>>>> On Feb 9, 2011, at 4:38 PM, Galder Zamarreño wrote:
>>>>>>
>>>>>>> The problem that I see with that is getAsync() calls that
should resolve locally will get the penalty of the thread context switching.
>>>>>>>
>>>>>>> I think I have a workable solution without having to rely on
your suggestion which passes the test suite. I'll send a pull request and you
(Mircea+Manik) can have a look to it, and then we can decide :)
>>>>>>>
>>>>>>> On Feb 9, 2011, at 2:32 PM, Mircea Markus wrote:
>>>>>>>
>>>>>>>>
>>>>>>>> On 9 Feb 2011, at 12:34, Manik Surtani wrote:
>>>>>>>>
>>>>>>>>> What about putting the entire call on a separate
thread much earlier in the call stack? E.g., in the CacheDelegate? You get the added
benefit of any cache loading happening offline as well. Plus a much simpler impl. :)
>>>>>>>> +1.
>>>>>>>>>
>>>>>>>>> Sent from my iPhone
>>>>>>>>>
>>>>>>>>> On 9 Feb 2011, at 08:14, Galder Zamarreño
<galder(a)redhat.com> wrote:
>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> Re:
https://issues.jboss.org/browse/ISPN-293
>>>>>>>>>>
>>>>>>>>>> I have an issue with my implementation that
simply wraps the realRemoteGet in DistributionInterceptor around a Callable:
>>>>>>>>>>
>>>>>>>>>> Assume that cache is configured with
Distribution(numOwners=1, l1=enabled), no transactions, and we have a cluster of 2 nodes:
>>>>>>>>>>
>>>>>>>>>> - [main-thread] Put k0 in a cache that should own
it.
>>>>>>>>>> - [main-thread] Do a getAsync for k0 from a node
that does not own it:
>>>>>>>>>> - [async-thread] This leads to a remote get which
updates the L1 and updates the context created by the main-thread and putting the updated
entry in there (however, this thread does not release the locks)
>>>>>>>>>> - [main-thread] Next up, we put a new key, i.e.
k1, in the node that didn't own k0 (the node where we updated the L1 cache):
>>>>>>>>>> - Now this thread has used the same context that
the async thread used, so when it comes to releasing locks, it finds two entries in the
context, the one locked by the async-thread and one for the main-thread and it fails with
java.lang.IllegalMonitorStateException
>>>>>>>>>>
>>>>>>>>>> Now, what's happening here is the
async-thread is acquiring the lock but not releasing it because the release happens in the
DistLockInterceptor/LockingInterceptor, so a different interceptor to where the lock is
being acquired. So, in theory, the solution would be for DistLockInterceptor to wrap the
invokeNext() and afterCall() for when an async get so that all "remote get",
"l1 update", and "release locks", happen in a separate thread.
However, for this to work, it will need to figure out whether a remoteGet() will be
necessary in the first place, otherwise is useless. Whether the remoteGet should happen is
determined by this code in DistributionInterceptor:
>>>>>>>>>>
>>>>>>>>>> if (ctx.isOriginLocal() &&
!(isMappedToLocalNode = dm.isLocal(key)) && isNotInL1(key)) {
>>>>>>>>>>
>>>>>>>>>> Also, if DistLockInterceptor does this check, we
need to make sure DistributionInterceptor does not do it again, otherwise it's a
waste. I think this might work although it does require some further reengineering.
>>>>>>>>>>
>>>>>>>>>> I'm gonna try to implement this but wondering
whether anyone can see any potential flaws here, or if anyone has any better ideas :)
>>>>>>>>>>
>>>>>>>>>> Cheers,
>>>>>>>>>> --
>>>>>>>>>> Galder Zamarreño
>>>>>>>>>> Sr. Software Engineer
>>>>>>>>>> Infinispan, JBoss Cache
>
> _______________________________________________
> infinispan-dev mailing list
> infinispan-dev(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/infinispan-dev
--
Galder Zamarreño
Sr. Software Engineer
Infinispan, JBoss Cache
_______________________________________________
infinispan-dev mailing list
infinispan-dev(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/infinispan-dev
--
Galder Zamarreño
Sr. Software Engineer
Infinispan, JBoss Cache