All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.client.hotrod.impl.transaction.TransactionalRemoteCacheImpl Maven / Gradle / Ivy

There is a newer version: 15.1.0.Dev04
Show newest version
package org.infinispan.client.hotrod.impl.transaction;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Function;

import jakarta.transaction.SystemException;
import jakarta.transaction.Transaction;
import jakarta.transaction.TransactionManager;

import org.infinispan.client.hotrod.MetadataValue;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.client.hotrod.impl.RemoteCacheImpl;
import org.infinispan.client.hotrod.impl.Util;
import org.infinispan.client.hotrod.impl.transaction.entry.TransactionEntry;
import org.infinispan.client.hotrod.logging.Log;
import org.infinispan.client.hotrod.logging.LogFactory;
import org.infinispan.commons.time.TimeService;

/**
 * A {@link RemoteCache} implementation that handles {@link Transaction}.
 * 

* All streaming operation (example {@link TransactionalRemoteCacheImpl#retrieveEntries(String, int)}) and {@link * TransactionalRemoteCacheImpl#size()} aren't transactional in a way they don't interact with the transaction's data * (keys, values). *

* {@link TransactionalRemoteCacheImpl#containsValue(Object)} is a special case where a key with the specific value is * marked as read for the transaction. * * @author Pedro Ruivo * @since 9.3 */ public class TransactionalRemoteCacheImpl extends RemoteCacheImpl { private static final Log log = LogFactory.getLog(TransactionalRemoteCacheImpl.class, Log.class); private final boolean forceReturnValue; private final boolean recoveryEnabled; private final TransactionManager transactionManager; private final TransactionTable transactionTable; // TODO: the remote get is force to be sync and is blocking! // https://issues.redhat.com/browse/ISPN-11633 private final Function> remoteGet = this::getWithMetadataNotTracked; private final Function keyMarshaller = this::keyToBytes; private final Function valueMarshaller = this::valueToBytes; public TransactionalRemoteCacheImpl(RemoteCacheManager rcm, String name, boolean forceReturnValue, boolean recoveryEnabled, TransactionManager transactionManager, TransactionTable transactionTable, TimeService timeService) { super(rcm, name, timeService); this.forceReturnValue = forceReturnValue; this.recoveryEnabled = recoveryEnabled; this.transactionManager = transactionManager; this.transactionTable = transactionTable; } @Override public CompletableFuture removeWithVersionAsync(K key, long version) { TransactionContext txContext = getTransactionContext(); return txContext == null ? super.removeWithVersionAsync(key, version) : txContext.compute(key, entry -> removeEntryIfSameVersion(entry, version), remoteGet); } @Override public CompletableFuture replaceWithVersionAsync(K key, V newValue, long version, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) { TransactionContext txContext = getTransactionContext(); return txContext == null ? super.replaceWithVersionAsync(key, newValue, version, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit) : txContext.compute(key, entry -> replaceEntryIfSameVersion(entry, newValue, version, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit), remoteGet); } @Override public CompletableFuture> getWithMetadataAsync(K key) { TransactionContext txContext = getTransactionContext(); return txContext == null ? super.getWithMetadataAsync(key) : txContext.compute(key, TransactionEntry::toMetadataValue, remoteGet); } private MetadataValue getWithMetadataNotTracked(K key) { return Util.await(super.getWithMetadataAsync(key)); } @Override public CompletableFuture putAllAsync(Map map, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) { TransactionContext txContext = getTransactionContext(); if (txContext == null) { return super.putAllAsync(map, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit); } else { //this is local only map.forEach((key, value) -> txContext.compute(key, entry -> getAndSetEntry(entry, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit))); return CompletableFuture.completedFuture(null); } } @Override public CompletableFuture putAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) { TransactionContext txContext = getTransactionContext(); if (txContext == null) { return super.putAsync(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit); } if (forceReturnValue) { return txContext.compute(key, entry -> getAndSetEntry(entry, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit), remoteGet); } else { return txContext.compute(key, entry -> getAndSetEntry(entry, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit)); } } @Override public CompletableFuture putIfAbsentAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) { TransactionContext txContext = getTransactionContext(); return txContext == null ? super.putIfAbsentAsync(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit) : txContext.compute(key, entry -> putEntryIfAbsent(entry, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit), remoteGet); } @Override public CompletableFuture replaceAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) { TransactionContext txContext = getTransactionContext(); return txContext == null ? super.replaceAsync(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit) : txContext.compute(key, entry -> replaceEntry(entry, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit), remoteGet); } @Override public CompletableFuture replaceAsync(K key, V oldValue, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) { TransactionContext txContext = getTransactionContext(); return txContext == null ? super.replaceAsync(key, oldValue, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit) : txContext.compute(key, entry -> replaceEntryIfEquals(entry, oldValue, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit), remoteGet); } @Override public CompletableFuture containsKeyAsync(K key) { TransactionContext txContext = getTransactionContext(); return txContext == null ? super.containsKeyAsync(key) : txContext.containsKey(key, remoteGet); } @Override public boolean containsValue(Object value) { TransactionContext txContext = getTransactionContext(); return txContext == null ? super.containsValue(value) : txContext.containsValue(value, super::entrySet, remoteGet); } @Override public CompletableFuture getAsync(Object key) { TransactionContext txContext = getTransactionContext(); //noinspection unchecked return txContext == null ? super.getAsync(key) : txContext.compute((K) key, TransactionEntry::getValue, remoteGet); } @Override public CompletableFuture removeAsync(Object key) { TransactionContext txContext = getTransactionContext(); if (txContext == null) { return super.removeAsync(key); } if (forceReturnValue) { //noinspection unchecked return txContext.compute((K) key, this::removeEntry, remoteGet); } else { //noinspection unchecked return txContext.compute((K) key, this::removeEntry); } } @Override public CompletableFuture removeAsync(Object key, Object value) { TransactionContext txContext = getTransactionContext(); //noinspection unchecked return txContext == null ? super.removeAsync(key, value) : txContext.compute((K) key, entry -> removeEntryIfEquals(entry, value), remoteGet); } @Override public CompletableFuture computeIfAbsentAsync(K key, Function mappingFunction, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) { throw new UnsupportedOperationException(); } @Override public CompletableFuture computeIfPresentAsync(K key, BiFunction remappingFunction, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) { throw new UnsupportedOperationException(); } @Override public TransactionManager getTransactionManager() { return transactionManager; } @Override public boolean isTransactional() { return true; } boolean isRecoveryEnabled() { return recoveryEnabled; } Function keyMarshaller() { return keyMarshaller; } Function valueMarshaller() { return valueMarshaller; } private boolean removeEntryIfSameVersion(TransactionEntry entry, long version) { if (entry.exists() && entry.getVersion() == version) { entry.remove(); return true; } else { return false; } } private boolean replaceEntryIfSameVersion(TransactionEntry entry, V newValue, long version, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) { if (entry.exists() && entry.getVersion() == version) { entry.set(newValue, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit); return true; } else { return false; } } private V putEntryIfAbsent(TransactionEntry entry, V value, long lifespan, TimeUnit lifespanTimeUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) { V currentValue = entry.getValue(); if (currentValue == null) { entry.set(value, lifespan, lifespanTimeUnit, maxIdleTime, maxIdleTimeUnit); } return currentValue; } private V replaceEntry(TransactionEntry entry, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) { V currentValue = entry.getValue(); if (currentValue != null) { entry.set(value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit); } return currentValue; } private boolean replaceEntryIfEquals(TransactionEntry entry, V oldValue, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) { V currentValue = entry.getValue(); if (currentValue != null && Objects.deepEquals(currentValue, oldValue)) { entry.set(value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit); return true; } else { return false; } } private V removeEntry(TransactionEntry entry) { V oldValue = entry.getValue(); entry.remove(); return oldValue; } private boolean removeEntryIfEquals(TransactionEntry entry, Object value) { V oldValue = entry.getValue(); if (oldValue != null && Objects.deepEquals(oldValue, value)) { entry.remove(); return true; } return false; } private V getAndSetEntry(TransactionEntry entry, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) { V oldValue = entry.getValue(); entry.set(value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit); return oldValue; } private TransactionContext getTransactionContext() { assertRemoteCacheManagerIsStarted(); Transaction tx = getRunningTransaction(); if (tx != null) { return transactionTable.enlist(this, tx); } return null; } private Transaction getRunningTransaction() { try { return transactionManager.getTransaction(); } catch (SystemException e) { log.debug("Exception in getRunningTransaction().", e); return null; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy