Search in sources :

Example 1 with VersionedEntry

use of org.hibernate.cache.infinispan.util.VersionedEntry in project hibernate-orm by hibernate.

the class VersionedTest method testCollectionUpdate.

@Test
public void testCollectionUpdate() throws Exception {
    // the first insert puts VersionedEntry(null, null, timestamp), so we have to wait a while to cache the entry
    TIME_SERVICE.advance(1);
    withTxSession(s -> {
        Item item = s.load(Item.class, itemId);
        OtherItem otherItem = new OtherItem();
        otherItem.setName("Other 1");
        s.persist(otherItem);
        item.addOtherItem(otherItem);
    });
    withTxSession(s -> {
        Item item = s.load(Item.class, itemId);
        Set<OtherItem> otherItems = item.getOtherItems();
        assertFalse(otherItems.isEmpty());
        otherItems.remove(otherItems.iterator().next());
    });
    AdvancedCache collectionCache = ((BaseTransactionalDataRegion) sessionFactory().getSecondLevelCacheRegion(Item.class.getName() + ".otherItems")).getCache();
    CountDownLatch putFromLoadLatch = new CountDownLatch(1);
    AtomicBoolean committing = new AtomicBoolean(false);
    CollectionUpdateTestInterceptor collectionUpdateTestInterceptor = new CollectionUpdateTestInterceptor(putFromLoadLatch);
    AnotherCollectionUpdateTestInterceptor anotherInterceptor = new AnotherCollectionUpdateTestInterceptor(putFromLoadLatch, committing);
    collectionCache.addInterceptor(collectionUpdateTestInterceptor, collectionCache.getInterceptorChain().size() - 1);
    collectionCache.addInterceptor(anotherInterceptor, 0);
    TIME_SERVICE.advance(1);
    Future<Boolean> addFuture = executor.submit(() -> withTxSessionApply(s -> {
        collectionUpdateTestInterceptor.updateLatch.await();
        Item item = s.load(Item.class, itemId);
        OtherItem otherItem = new OtherItem();
        otherItem.setName("Other 2");
        s.persist(otherItem);
        item.addOtherItem(otherItem);
        committing.set(true);
        return true;
    }));
    Future<Boolean> readFuture = executor.submit(() -> withTxSessionApply(s -> {
        Item item = s.load(Item.class, itemId);
        assertTrue(item.getOtherItems().isEmpty());
        return true;
    }));
    addFuture.get();
    readFuture.get();
    collectionCache.removeInterceptor(CollectionUpdateTestInterceptor.class);
    collectionCache.removeInterceptor(AnotherCollectionUpdateTestInterceptor.class);
    withTxSession(s -> assertFalse(s.load(Item.class, itemId).getOtherItems().isEmpty()));
}
Also used : BaseTransactionalDataRegion(org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion) Arrays(java.util.Arrays) VersionedEntry(org.hibernate.cache.infinispan.util.VersionedEntry) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Session(org.hibernate.Session) Caches(org.hibernate.cache.infinispan.util.Caches) AtomicReference(java.util.concurrent.atomic.AtomicReference) Future(java.util.concurrent.Future) PessimisticLockException(org.hibernate.PessimisticLockException) InvocationContext(org.infinispan.context.InvocationContext) AdvancedCache(org.infinispan.AdvancedCache) Map(java.util.Map) BiConsumer(java.util.function.BiConsumer) Item(org.hibernate.test.cache.infinispan.functional.entities.Item) OtherItem(org.hibernate.test.cache.infinispan.functional.entities.OtherItem) Synchronization(javax.transaction.Synchronization) StaleStateException(org.hibernate.StaleStateException) CyclicBarrier(java.util.concurrent.CyclicBarrier) ByRef(org.infinispan.commons.util.ByRef) Set(java.util.Set) Assert.assertTrue(org.junit.Assert.assertTrue) Test(org.junit.Test) Assert.assertNotEquals(org.junit.Assert.assertNotEquals) TimeUnit(java.util.concurrent.TimeUnit) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) BaseCustomInterceptor(org.infinispan.interceptors.base.BaseCustomInterceptor) Assert.assertNull(org.junit.Assert.assertNull) Flag(org.infinispan.context.Flag) Assert.assertFalse(org.junit.Assert.assertFalse) PutKeyValueCommand(org.infinispan.commands.write.PutKeyValueCommand) Collections(java.util.Collections) Assert.assertEquals(org.junit.Assert.assertEquals) SharedSessionContractImplementor(org.hibernate.engine.spi.SharedSessionContractImplementor) Item(org.hibernate.test.cache.infinispan.functional.entities.Item) OtherItem(org.hibernate.test.cache.infinispan.functional.entities.OtherItem) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) OtherItem(org.hibernate.test.cache.infinispan.functional.entities.OtherItem) BaseTransactionalDataRegion(org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion) AdvancedCache(org.infinispan.AdvancedCache) CountDownLatch(java.util.concurrent.CountDownLatch) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Test(org.junit.Test)

Example 2 with VersionedEntry

use of org.hibernate.cache.infinispan.util.VersionedEntry in project hibernate-orm by hibernate.

the class NonStrictAccessDelegate method putFromLoad.

@Override
public boolean putFromLoad(SharedSessionContractImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) throws CacheException {
    long lastRegionInvalidation = region.getLastRegionInvalidation();
    if (txTimestamp < lastRegionInvalidation) {
        log.tracef("putFromLoad not executed since tx started at %d, before last region invalidation finished = %d", txTimestamp, lastRegionInvalidation);
        return false;
    }
    assert version != null;
    if (minimalPutOverride) {
        Object prev = cache.get(key);
        if (prev != null) {
            Object oldVersion = getVersion(prev);
            if (oldVersion != null) {
                if (versionComparator.compare(version, oldVersion) <= 0) {
                    if (trace) {
                        log.tracef("putFromLoad not executed since version(%s) <= oldVersion(%s)", version, oldVersion);
                    }
                    return false;
                }
            } else if (prev instanceof VersionedEntry && txTimestamp <= ((VersionedEntry) prev).getTimestamp()) {
                if (trace) {
                    log.tracef("putFromLoad not executed since tx started at %d and entry was invalidated at %d", txTimestamp, ((VersionedEntry) prev).getTimestamp());
                }
                return false;
            }
        }
    }
    // we can't use putForExternalRead since the PFER flag means that entry is not wrapped into context
    // when it is present in the container. TombstoneCallInterceptor will deal with this.
    // Even if value is instanceof CacheEntry, we have to wrap it in VersionedEntry and add transaction timestamp.
    // Otherwise, old eviction record wouldn't be overwritten.
    putFromLoadCache.put(key, new VersionedEntry(value, version, txTimestamp));
    return true;
}
Also used : VersionedEntry(org.hibernate.cache.infinispan.util.VersionedEntry)

Example 3 with VersionedEntry

use of org.hibernate.cache.infinispan.util.VersionedEntry in project hibernate-orm by hibernate.

the class VersionedCallInterceptor method visitPutKeyValueCommand.

@Override
public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
    MVCCEntry e = (MVCCEntry) ctx.lookupEntry(command.getKey());
    if (e == null) {
        return null;
    }
    Object oldValue = e.getValue();
    Object oldVersion = null;
    long oldTimestamp = Long.MIN_VALUE;
    if (oldValue instanceof VersionedEntry) {
        oldVersion = ((VersionedEntry) oldValue).getVersion();
        oldTimestamp = ((VersionedEntry) oldValue).getTimestamp();
        oldValue = ((VersionedEntry) oldValue).getValue();
    } else if (oldValue instanceof org.hibernate.cache.spi.entry.CacheEntry) {
        oldVersion = ((org.hibernate.cache.spi.entry.CacheEntry) oldValue).getVersion();
    }
    Object newValue = command.getValue();
    Object newVersion;
    long newTimestamp;
    Object actualNewValue = newValue;
    boolean isRemoval = false;
    if (newValue instanceof VersionedEntry) {
        VersionedEntry ve = (VersionedEntry) newValue;
        newVersion = ve.getVersion();
        newTimestamp = ve.getTimestamp();
        if (ve.getValue() == null) {
            isRemoval = true;
        } else if (ve.getValue() instanceof org.hibernate.cache.spi.entry.CacheEntry) {
            actualNewValue = ve.getValue();
        }
    } else {
        throw new IllegalArgumentException(String.valueOf(newValue));
    }
    if (newVersion == null) {
        // eviction or post-commit removal: we'll store it with given timestamp
        setValue(e, newValue, expiringMetadata);
        return null;
    }
    if (oldVersion == null) {
        assert oldValue == null || oldTimestamp != Long.MIN_VALUE;
        if (newTimestamp <= oldTimestamp) {
            // the invalid value
            assert oldValue == null;
        } else {
            setValue(e, actualNewValue, defaultMetadata);
        }
        return null;
    }
    int compareResult = versionComparator.compare(newVersion, oldVersion);
    if (isRemoval && compareResult >= 0) {
        setValue(e, actualNewValue, expiringMetadata);
    } else if (compareResult > 0) {
        setValue(e, actualNewValue, defaultMetadata);
    }
    return null;
}
Also used : VersionedEntry(org.hibernate.cache.infinispan.util.VersionedEntry) CacheEntry(org.infinispan.container.entries.CacheEntry) MVCCEntry(org.infinispan.container.entries.MVCCEntry)

Example 4 with VersionedEntry

use of org.hibernate.cache.infinispan.util.VersionedEntry in project hibernate-orm by hibernate.

the class BaseTransactionalDataRegion method removeEntries.

private void removeEntries(boolean inTransaction, KeyValueFilter filter) {
    // If the transaction is required, we simply need it -> will create our own
    boolean startedTx = false;
    if (!inTransaction && requiresTransaction) {
        try {
            tm.begin();
            startedTx = true;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    // We can never use cache.clear() since tombstones must be kept.
    try {
        AdvancedCache localCache = Caches.localCache(cache);
        CloseableIterator<CacheEntry> it = Caches.entrySet(localCache, Tombstone.EXCLUDE_TOMBSTONES).iterator();
        long now = nextTimestamp();
        try {
            while (it.hasNext()) {
                // Cannot use it.next(); it.remove() due to ISPN-5653
                CacheEntry entry = it.next();
                switch(strategy) {
                    case TOMBSTONES:
                        localCache.remove(entry.getKey(), entry.getValue());
                        break;
                    case VERSIONED_ENTRIES:
                        localCache.put(entry.getKey(), new VersionedEntry(null, null, now), tombstoneExpiration, TimeUnit.MILLISECONDS);
                        break;
                }
            }
        } finally {
            it.close();
        }
    } finally {
        if (startedTx) {
            try {
                tm.commit();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
Also used : VersionedEntry(org.hibernate.cache.infinispan.util.VersionedEntry) AdvancedCache(org.infinispan.AdvancedCache) CacheEntry(org.infinispan.container.entries.CacheEntry)

Aggregations

VersionedEntry (org.hibernate.cache.infinispan.util.VersionedEntry)4 AdvancedCache (org.infinispan.AdvancedCache)2 CacheEntry (org.infinispan.container.entries.CacheEntry)2 Arrays (java.util.Arrays)1 Collections (java.util.Collections)1 List (java.util.List)1 Map (java.util.Map)1 Set (java.util.Set)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 CyclicBarrier (java.util.concurrent.CyclicBarrier)1 Future (java.util.concurrent.Future)1 TimeUnit (java.util.concurrent.TimeUnit)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 BiConsumer (java.util.function.BiConsumer)1 Synchronization (javax.transaction.Synchronization)1 PessimisticLockException (org.hibernate.PessimisticLockException)1 Session (org.hibernate.Session)1 StaleStateException (org.hibernate.StaleStateException)1 BaseTransactionalDataRegion (org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion)1