Hi Dharam,
Geode does conflict check when committing the transaction to ensure that no
other updates have been performed on the entry since the value was read in
the transaction. In your above case, it would work as follows:
Tx1: read value as 0
Tx2: read value as 0
Tx1: update to $500.
Tx2: update to $100.
Tx1: commit, grabs d-lock (so no other transaction can successfully
commit), then validate if the value is still $0 in the region, then puts
the $500 entry into the region.
Tx2: commit, grabs d-lock (succeedes only if Tx1 has finished or not yet
started). Then checks if the value is still $0 in the region. It will fail
here since the value is now $500.

The validation check against the region mentioned above is implemented as a
reference check (== operation). So, you should enable copy-on-read so that
the changes you make to the entry are reflected as commit exceptions.
Please refer to "Region Operations Return References" section in docs
<http://geode.apache.org/docs/guide/17/developing/transactions/design_considerations.html>
.

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