[ 
https://issues.apache.org/jira/browse/IGNITE-25172?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Aleksey Plekhanov updated IGNITE-25172:
---------------------------------------
    Description: 
For transactional caches expired entries are not deleted if they are locked and 
there was attempt to expire.

Reproducer:
{code:java}
@Test
public void testEntriesLeakTx() throws Exception {
    IgniteEx srv = startGrid();

    IgniteCache<Object, Object> cache = srv.getOrCreateCache(new 
CacheConfiguration<>(DEFAULT_CACHE_NAME)
        .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL))
        .withExpiryPolicy(new CreatedExpiryPolicy(new 
Duration(TimeUnit.MILLISECONDS, 100)));  

    cache.put(0, 0);

    try (Transaction tx = 
srv.transactions().txStart(TransactionConcurrency.PESSIMISTIC, 
TransactionIsolation.REPEATABLE_READ)) {
        cache.get(0);

        doSleep(1_000);

        tx.commit();
    }

    assertEquals(0, cache.size());
}{code}
The same problem also occurs when CDC is trying to insert almost expired 
entries to a transactional cache (CDC uses putAllConflict method):
{code:java}
@Test
public void testEntriesLeakCdc() throws Exception {
    IgniteEx srv = startGrid();

    IgniteCache<Object, Object> cache = srv.getOrCreateCache(new 
CacheConfiguration<>(DEFAULT_CACHE_NAME)
        .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));

    IgniteInternalCache<Object, Object> cachex = srv.cachex(DEFAULT_CACHE_NAME);

    GridCacheVersion ver = new GridCacheVersion(1, 1, 1, 2);
    CacheObjectImpl val = new CacheObjectImpl(1, null);

    Map<KeyCacheObject, GridCacheDrInfo> map = new HashMap<>();

    for (int i = 0; i < 100_000; i++)
        map.put(
            new KeyCacheObjectImpl(i, null, -1),
            new GridCacheDrExpirationInfo(val, ver, 1, CU.toExpireTime(1)));

    cachex.putAllConflict(map);

    assertTrue(GridTestUtils.waitForCondition(() -> cache.size() == 0, 
10_000L));
} {code}
There is locks check in {{GridCacheMapEntry#onExpired}} method:
{code:java}
if (mvccExtras() != null)
    return false; {code}
Before actual entry remove. Due to this check entry stays in cache, while 
{{PendingTree}} entry already removed.

  was:
For transactional caches expired entries are not deleted if they are locked and 
there was attempt to expire.

Reproducer:
{code:java}
@Test
public void testEntriesLeakTx() throws Exception {
    IgniteEx srv = startGrid();

    IgniteCache<Object, Object> cache = srv.getOrCreateCache(new 
CacheConfiguration<>(DEFAULT_CACHE_NAME)
        .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL))
        .withExpiryPolicy(new CreatedExpiryPolicy(new 
Duration(TimeUnit.MILLISECONDS, 100)));

    Map<Integer, Integer> map = new TreeMap<>();

    for (int i = 0; i < 1_000; i++)
        map.put(i, i);

    cache.putAll(map);

    try (Transaction tx = 
srv.transactions().txStart(TransactionConcurrency.PESSIMISTIC, 
TransactionIsolation.REPEATABLE_READ)) {
        cache.getAll(map.keySet());

        doSleep(1_000);

        tx.commit();
    }

    assertEquals(0, cache.size());
} {code}
The same problem also occurs when CDC is trying to insert almost expired 
entries to a transactional cache (CDC uses putAllConflict method):
{code:java}
@Test
public void testEntriesLeakCdc() throws Exception {
    IgniteEx srv = startGrid();

    IgniteCache<Object, Object> cache = srv.getOrCreateCache(new 
CacheConfiguration<>(DEFAULT_CACHE_NAME)
        .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));

    IgniteInternalCache<Object, Object> cachex = srv.cachex(DEFAULT_CACHE_NAME);

    GridCacheVersion ver = new GridCacheVersion(1, 1, 1, 2);
    CacheObjectImpl val = new CacheObjectImpl(1, null);

    Map<KeyCacheObject, GridCacheDrInfo> map = new HashMap<>();

    for (int i = 0; i < 100_000; i++)
        map.put(
            new KeyCacheObjectImpl(i, null, -1),
            new GridCacheDrExpirationInfo(val, ver, 1, CU.toExpireTime(1)));

    cachex.putAllConflict(map);

    assertTrue(GridTestUtils.waitForCondition(() -> cache.size() == 0, 
10_000L));
} {code}
There is locks check in \{{GridCacheMapEntry#onExpired}} method:
{code:java}
if (mvccExtras() != null)
    return false; {code}
Before actual entry remove. Due to this check entry stays in cache, while 
{{PendingTree}} entry already removed.


> Expired locked tx cache entries are not deleted
> -----------------------------------------------
>
>                 Key: IGNITE-25172
>                 URL: https://issues.apache.org/jira/browse/IGNITE-25172
>             Project: Ignite
>          Issue Type: Bug
>            Reporter: Aleksey Plekhanov
>            Priority: Major
>              Labels: ise
>
> For transactional caches expired entries are not deleted if they are locked 
> and there was attempt to expire.
> Reproducer:
> {code:java}
> @Test
> public void testEntriesLeakTx() throws Exception {
>     IgniteEx srv = startGrid();
>     IgniteCache<Object, Object> cache = srv.getOrCreateCache(new 
> CacheConfiguration<>(DEFAULT_CACHE_NAME)
>         .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL))
>         .withExpiryPolicy(new CreatedExpiryPolicy(new 
> Duration(TimeUnit.MILLISECONDS, 100)));  
>     cache.put(0, 0);
>     try (Transaction tx = 
> srv.transactions().txStart(TransactionConcurrency.PESSIMISTIC, 
> TransactionIsolation.REPEATABLE_READ)) {
>         cache.get(0);
>         doSleep(1_000);
>         tx.commit();
>     }
>     assertEquals(0, cache.size());
> }{code}
> The same problem also occurs when CDC is trying to insert almost expired 
> entries to a transactional cache (CDC uses putAllConflict method):
> {code:java}
> @Test
> public void testEntriesLeakCdc() throws Exception {
>     IgniteEx srv = startGrid();
>     IgniteCache<Object, Object> cache = srv.getOrCreateCache(new 
> CacheConfiguration<>(DEFAULT_CACHE_NAME)
>         .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));
>     IgniteInternalCache<Object, Object> cachex = 
> srv.cachex(DEFAULT_CACHE_NAME);
>     GridCacheVersion ver = new GridCacheVersion(1, 1, 1, 2);
>     CacheObjectImpl val = new CacheObjectImpl(1, null);
>     Map<KeyCacheObject, GridCacheDrInfo> map = new HashMap<>();
>     for (int i = 0; i < 100_000; i++)
>         map.put(
>             new KeyCacheObjectImpl(i, null, -1),
>             new GridCacheDrExpirationInfo(val, ver, 1, CU.toExpireTime(1)));
>     cachex.putAllConflict(map);
>     assertTrue(GridTestUtils.waitForCondition(() -> cache.size() == 0, 
> 10_000L));
> } {code}
> There is locks check in {{GridCacheMapEntry#onExpired}} method:
> {code:java}
> if (mvccExtras() != null)
>     return false; {code}
> Before actual entry remove. Due to this check entry stays in cache, while 
> {{PendingTree}} entry already removed.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to