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

org.hibernate.cache.infinispan.access.LockingInterceptor Maven / Gradle / Ivy

There is a newer version: 5.6.15.Final
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate.cache.infinispan.access;

import org.infinispan.commands.write.DataWriteCommand;
import org.infinispan.context.Flag;
import org.infinispan.context.InvocationContext;
import org.infinispan.interceptors.locking.NonTransactionalLockingInterceptor;
import org.infinispan.util.concurrent.TimeoutException;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

/**
 * With regular {@link org.infinispan.interceptors.locking.NonTransactionalLockingInterceptor},
 * async replication does not work in combination with synchronous replication: sync replication
 * relies on locking to order writes on backup while async replication relies on FIFO-ordering
 * from primary to backup. If these two combine, there's a possibility that on backup two modifications
 * modifications will proceed concurrently.
 * Similar issue threatens consistency when the command has {@link org.infinispan.context.Flag#CACHE_MODE_LOCAL}
 * - these commands don't acquire locks either.
 *
 * Therefore, this interceptor locks the entry all the time. {@link UnorderedDistributionInterceptor} does not forward
 * the message from non-origin to any other node, and the distribution interceptor won't block on RPC but will return
 * {@link CompletableFuture} and we'll wait for it here.
 */
public class LockingInterceptor extends NonTransactionalLockingInterceptor {
	private static final Log log = LogFactory.getLog(LockingInterceptor.class);
	private static final boolean trace = log.isTraceEnabled();

	@Override
	protected Object visitDataWriteCommand(InvocationContext ctx, DataWriteCommand command) throws Throwable {
		Object returnValue = null;
		try {
			// Clear any metadata; we'll set them as appropriate in TombstoneCallInterceptor
			command.setMetadata(null);

			lockAndRecord(ctx, command.getKey(), getLockTimeoutMillis(command));

			returnValue = invokeNextInterceptor(ctx, command);
			return returnValue;
		}
		catch (TimeoutException e) {
			if (!ctx.isOriginLocal() && command.hasFlag(Flag.ZERO_LOCK_ACQUISITION_TIMEOUT)) {
				// FAIL_SILENTLY flag is not replicated to remote nodes and zero acquisition timeouts cause
				// very noisy logs.
				if (trace) {
					log.tracef("Silently ignoring exception", e);
				}
				return null;
			}
			else {
				throw e;
			}
		}
		finally {
			lockManager.unlockAll(ctx);
			if (returnValue instanceof CompletableFuture) {
				try {
					((CompletableFuture) returnValue).join();
				}
				catch (CompletionException e) {
					throw e.getCause();
				}
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy