Welcome to the community!
Here's useful link:
https://cwiki.apache.org/confluence/display/IGNITE/How+to+Contribute

On Mon, Mar 27, 2023 at 9:48 PM Prigoreanu, Alexandru <
prigoreanu.alexan...@anteash.com> wrote:

> Thank you!
>
> On Mon, Mar 27, 2023 at 11:33 AM Kseniya Romanova <ksroman...@apache.org>
> wrote:
>
>> Hi Alex! You can check if the preferred ASF Jira name is free and make a
>> request at https://selfserve.apache.org/jira-account.html
>> One of PMC members will approve right after this.
>>
>> Cheers,
>> Kseniya
>>
>> On Fri, Mar 24, 2023 at 10:24 PM Prigoreanu, Alexandru <
>> prigoreanu.alexan...@anteash.com> wrote:
>>
>>> hello everyone! please could you create a profile for me on jira so i can
>>> submit this issue there? thank you!
>>>
>>> On Wed, Mar 1, 2023 at 5:07 AM Prigoreanu, Alexandru <
>>> prigoreanu.alexan...@anteash.com> wrote:
>>>
>>> > Hello everyone! thank you for your time.
>>> >
>>> > - we have an entity PlaceImpl annotated @Cache(usage =
>>> > CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
>>> > - we use Ignite's L2 Hibernate cache implementation through the
>>> > application property
>>> >
>>> spring.jpa.properties.hibernate.cache.region.factory_class=org.apache.ignite.cache.hibernate.HibernateRegionFactory
>>> > - we use ignite 2.14.0, ignite-hibernate-ext 5.3.0, hibernate 5.4.33
>>> > - we have a complex transaction that creates a new PlaceImpl, saves it
>>> in
>>> > the database, and updates it.
>>> > - when the PlaceImpl is returned from the level 2 cache it does not
>>> > contain the latest data for some fields. let's say we expect that
>>> > PlaceImpl.description is not null while PlaceImpl.description is null.
>>> >
>>> > after a bit of debugging we got the following data:
>>> > - during the transaction the changes to PlaceImpl are flushed twice or
>>> > more: one in the middle of the transaction and the second one before
>>> the
>>> > transaction is committed.
>>> > - given the CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, this
>>> results in
>>> > 2 EntityUpdateAction for our PlaceImpl that was created (we don't talk
>>> > about inserts here) added to the collection of processes in
>>> > AfterTransactionCompletionProcessQueue.processes
>>> > - after the transaction is completed, on the processes of the
>>> > aforementioned list hibernate invokes doAfterTransactionCompletion
>>> >
>>> > public void afterTransactionCompletion(boolean success) {
>>> >   while ( !processes.isEmpty() ) {
>>> >     try {
>>> >       processes.poll().doAfterTransactionCompletion( success, session
>>> );
>>> >     }
>>> >
>>> > - the first EntityUpdateAction contains an incomplete PlaceImpl that
>>> does
>>> > not yet have all the fields set
>>> > - the second EntityUpdateAction contains the complete PlaceImpl with
>>> all
>>> > the fields set
>>> >
>>> > - the first EntityUpdateAction.doAfterTransactionCompletion gets to
>>> > execute HibernateNonStrictAccessStrategy.afterUpdate: here ctx is not
>>> null
>>> > and the if ctx != null branch is executed and the incomplete PlaceImpl
>>> is
>>> > put in the level 2 cache
>>> >
>>> >  @Override public boolean afterUpdate(Object key, Object val) {
>>> >      WriteContext ctx = writeCtx.get();
>>> >
>>> >
>>> >      if (log.isDebugEnabled())
>>> >          log.debug("Put after update [cache=" + cache.name() + ",
>>> key=" +
>>> > key + ", val=" + val + ']');
>>> >
>>> >
>>> >      if (ctx != null) {
>>> >          ctx.updated(key, val);
>>> >
>>> >
>>> >          unlock(key);
>>> >
>>> >
>>> >          return true;
>>> >      }
>>> >
>>> >
>>> >      return false;
>>> >  }
>>> >
>>> > which invokes also unlock(key);
>>> >
>>> >  @Override public void unlock(Object key) {
>>> >      try {
>>> >          WriteContext ctx = writeCtx.get();
>>> >
>>> >
>>> >          if (ctx != null && ctx.unlocked(key)) {
>>> >              writeCtx.remove();
>>> >
>>> >
>>> >              ctx.updateCache(cache);
>>> >          }
>>> >      }
>>> >
>>> >      catch (IgniteCheckedException e) {
>>> >          throw convertException(e);
>>> >      }
>>> >  }
>>> >
>>> > that removes writeCtx from the current thread with writeCtx.remove();
>>> >
>>> > - the second EntityUpdateAction.doAfterTransactionCompletion gets to
>>> > execute HibernateNonStrictAccessStrategy.afterUpdate: here ctx is null
>>> and
>>> > the if ctx != null branch is not executed, so the level 2 cache is
>>> never
>>> > updated with the latest changes in the PlaceImpl entity.
>>> >
>>> > we were able to have a minimal dummy text example of the transaction
>>> that
>>> > creates a PlaceImpl
>>> >
>>> >  @Test
>>> >  public void testPlaceImplCacheWorksWithFlush() throws Exception {
>>> >      long[] placeId = new long [] {0L};
>>> >      doInTransaction(() -> {
>>> >          PlaceImpl place = new PlaceImpl();
>>> >          entityManager.persist(place);
>>> >          placeId[0] = place.getId();
>>> >          entityManager.flush();
>>> >          place.setName("NAME"); //set some place properties
>>> >          entityManager.flush();
>>> >          place.setDescription("description"); //set some other place
>>> > properties
>>> >          assertThat(place.getDescription(),
>>> Matchers.is("description"));
>>> >      });
>>> >      //load place from the cache
>>> >      Place place = placeImplRepository.findOne(placeId[0]);
>>> >      assertThat(place.getName(), Matchers.is("NAME"));
>>> >      //the following assertion fails
>>> >      assertThat(place.getDescription(), Matchers.is("description"));
>>> >  }
>>> >
>>> > we are aware the given example should not manually invoke flushes but
>>> in
>>> > our real transaction the flush is not manual, our code provokes
>>> > inadvertently autoFlushIfRequired that happens to flush also updates
>>> to our
>>> > new PlaceImpl entity
>>> >
>>> > what are your thoughts on the matter?
>>> > could this be a bug?
>>> > should we not use Ignite's hibernate level 2 cache implementation
>>> > HibernateRegionFactory when transactions update entities with multiple
>>> > flushes?
>>> > if you have any pointers on a solution we could also try to provide
>>> you a
>>> > pull request with the implementation.
>>> >
>>> > thank you for your time!
>>> >
>>> > Alex
>>> >
>>>
>>

Reply via email to