Hi Dharam,

Only <pool-3-thread-1> tid=0x4b got the lock and apply its changes to Geode.

[debug 2018/10/19 09:36:48.608 IST <pool-3-thread-1> tid=0x4b]
txApplyPut 
cbEvent=EntryEventImpl[op=UPDATE;region=/Customers;key=1234;oldValue=null;newValue=com.example.geode.model.Customer@3491dea3;callbackArg=null;originRemote=false;originMember=192.168.31.62(SampleServer:9006)<ec><v0>:1024;id=EventIDid=30bytes;threadID=3;sequenceID=1]]

<pool-3-thread-2> tid=0x4c did not get the lock and transaction failed
with CommitConflictException:

[debug 2018/10/19 09:36:48.609 IST <pool-3-thread-2> tid=0x4c]
<DLockRequestProcessor 13 waiting for 1 replies from
[192.168.31.62(SampleServer:9006)<ec><v0>:1024]> got
process(DLockRequestProcessor.DLockResponseMessage responding
TRY_LOCK_FAILED; serviceName=DTLS(version 0); objectName=[TXLockBatch:
txLockId=TXLockId: 192.168.31.62(SampleServer:9006)<ec><v0>:1024-3;
reqs=[regionPath=/Customers keys=[1234]]; participants=[]];
responseCode=4; keyIfFailed=The key  1234  in region  /Customers  was
being modified by another transaction locally.; leaseExpireTime=0;
processorId=13; lockId=13) from
192.168.31.62(SampleServer:9006)<ec><v0>:1024

We do not see the txApplyPut in the logs for thread-2 which means the
transaction does not write to cache.

The following code snip shows that transaction is failed with
CommitConflictException in TXLockServiceImpl.txLock()

logger.debug("[TXLockServiceImpl.txLock] acquire try-locks for {}", batch);


// TODO: get a readWriteLock to make the following block atomic...

Object[] keyIfFail = new Object[1];

gotLocks = this.dlock.acquireTryLocks(batch, TIMEOUT_MILLIS, LEASE_MILLIS,
keyIfFail);

if (gotLocks) { // ...otherwise race can occur between tryLocks and readLock

  acquireRecoveryReadLock();

} else if (keyIfFail[0] != null) {

-->  throw new CommitConflictException(

      String.format("Concurrent transaction commit detected %s",

          keyIfFail[0]));

} else {

  throw new CommitConflictException(

      String.format("Failed to request try locks from grantor: %s",

          this.dlock.getLockGrantorId()));


I will try to find out why your application does not get the
CommitConflictException thrown by Geode.

-Eric



On Sat, Oct 20, 2018 at 8:10 AM Dharam Thacker <[email protected]>
wrote:

> Hello Swapil & Team,
>
> Did you get chance to look into this? Ideally it's a plain case of *optimistic
> locking*. It works exactly fine with *JPA using @Version* property and 
> *optimistic
> locking*. [Same example by changing Customer model to be compatible with
> database table]
>
> As I mentioned that *both transactions are working exactly together*
> reading first cut copy of Customer and still passing. I believe in geode,
> we already have optimistic locking implemented in transactions.  Could you
> validate debug logs and/or POC project which I had send earlier?
>
> It's similar to below customer bank account analogy I have account with
> bank balance as 0 initially.
>
> Tx1: When I started, customer balance was 0, so let me add $500 and end
> result will be $500
>
> Tx2: When I started, customer balance was 0, so let me add $100 and end
> result will be $100 .
>
> Both transactions start at the same time, they read customer account
> object from cache, with balance as 0 initially which is nothing but a
> snapshot copy when transaction started.
> But at least 1 of the transaction should be proved wrong while committing.
> That's not case here and it's becoming $100.
>
> *Note*: 1 second of delay which I introduced to simulate this scenario in
> my poc project is just to simulate external service call which makes sense
> for real life project.
>
> Thanks,
> - Dharam Thacker
>
>
> On Fri, Oct 19, 2018 at 9:45 AM Dharam Thacker <[email protected]>
> wrote:
>
>> Thank you Swapnil! I understand your point. If I start threads as you
>> mentioned it does work.
>>
>> But if you see my attachment, both transactions *actually start together
>> with thread pool and reads same copy of customer from cache* as I have
>> added 1 second of delay in update service as soon as they read the copy of
>> customer from cache.
>>
>> I have attached *DEBUG level logs* *in file(Debug_Logs.txt)* as well
>> more information. I am sure something is not right here.
>>
>> After that I was expecting 1 transaction to win as other thread has
>> definitely older copy of customer data. Info logs shown below for quick
>> information.
>>
>> *INFO Logs for quick glance:*
>>
>> pool-3-thread-2 : Entered into update method
>> pool-3-thread-1 : Entered into update method
>> pool-3-thread-2 : CurrentCopy >> {
>>   "cid" : "1234",
>>   *"name" : "A1",*
>>   "address" : "India"
>> }
>> pool-3-thread-1 : CurrentCopy >> {
>>   "cid" : "1234",
>>   *"name" : "A1",*
>>   "address" : "India"
>> }
>> pool-3-thread-2 : Current customer name >> A1
>> pool-3-thread-1 : Current customer name >> A1
>> pool-3-thread-2 : Final Data >> {
>>   "cid" : "1234",
>>   "name" : "A3",
>>   "address" : "India"
>> }
>> pool-3-thread-1 : Final Data >> {
>>   "cid" : "1234",
>>   "name" : "A2",
>>   "address" : "India"
>> }
>> pool-3-thread-1 : Exiting from update method
>> pool-3-thread-2 : Exiting from update method
>> Main thread is going to wait for 5 seconds...
>> Main thread is going to shutdown pool...
>>
>>
>> Thanks,
>> Dharam
>>
>>
>>
>> On Fri, Oct 19, 2018, 03:25 Swapnil Bawaskar <[email protected]>
>> wrote:
>>
>>> Hi Dharam,
>>> If there are two requests that read and write the same entry, you can
>>> trust Geode to throw a CommitConflictException if the changes are going to
>>> overwrite one another. My above example will throw this exception.
>>> If that exception is not thrown, then your transactions actually
>>> happened one after the other, in which case the second transaction should
>>> be able to read the change made by the first transaction.
>>>
>>>
>>> On Thu, Oct 18, 2018 at 11:30 AM Dharam Thacker <
>>> [email protected]> wrote:
>>>
>>>> Thank you Swapnil!
>>>>
>>>> But how can we guarantee this?
>>>>
>>>> I have a spring boot geode client as web app. It has several emdpoints
>>>> to accept add/update/delete actions.
>>>>
>>>> If 2 users are trying to change same customer with undefined email as
>>>> initial state in 2 different rest requests in almost same time, of course
>>>> by reading original customer with no email and changing emails, how could
>>>> this be ensured?
>>>>
>>>> It may happen that user1's transaction succeded due to many possible
>>>> reasons, it's confirmed now that user2 has stale data and he will overwtite
>>>> changes.
>>>>
>>>> Could you suggest how we can handle it?
>>>>
>>>> Thanks,
>>>> Dharam
>>>>
>>>> On Thu, Oct 18, 2018, 23:46 Swapnil Bawaskar <[email protected]>
>>>> wrote:
>>>>
>>>>> If you just throw two transactions in a thread pool, you may or may
>>>>> not get an exception since one transaction may have completed before the
>>>>> other transaction begins. To deterministically make one transaction fail,
>>>>> you have to ensure that both threads have read the initial value and have
>>>>> made change to the original value before either transaction commits.
>>>>>
>>>>> region.put("K", "V");
>>>>>
>>>>> CountDownLatch latch1 = new CountDownLatch(1);
>>>>> CountDownLatch latch2 = new CountDownLatch(1);
>>>>> Thread th1 = new Thread(() -> {
>>>>> mgr.being();
>>>>> region.put("K", "V1");
>>>>> latch1.countDown();
>>>>> latch2.await();
>>>>> mgr.commit();
>>>>>
>>>>> });
>>>>> Thread th2 = new Thread(() -> {
>>>>> mgr.begin();
>>>>> region.put("K", "V2");
>>>>> latch1.await();
>>>>> latch2.countDown();
>>>>> mgr.commit();
>>>>> });
>>>>> th1.start();
>>>>> th2.start();
>>>>>
>>>>>
>>>>> On Thu, Oct 18, 2018 at 10:28 AM Dharam Thacker <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hello Team,
>>>>>>
>>>>>> I am trying to understand *transaction behavior* with apache geode.
>>>>>> I have created a simple demo as attached here in with this email.
>>>>>> It's a simple spring data geode application with apache geode 1.6.0
>>>>>>
>>>>>> Spring Startup Listener class >> SimpleApplicationListener .java
>>>>>> Service class >> CustomerService.java
>>>>>>
>>>>>> 2 thread are simultaneously trying to update customer=1234 by
>>>>>> changing name from [Thread-T1 - (From A1->To A2)] and [Thread-T2 - (From
>>>>>> A1->To A3)]
>>>>>> I assume that at least 1 thread has stale copy of data and should
>>>>>> throw commit conflict exception but I think I am missing something and 
>>>>>> it's
>>>>>> not behaving as expected.
>>>>>>
>>>>>> Could some one help me to understand what I am missing here?
>>>>>> [Attached tar.gz file]
>>>>>>
>>>>>> Thanks & Regards,
>>>>>> - Dharam Thacker
>>>>>>
>>>>>

Reply via email to