Permalink
Browse files

Introduce a common base class for replication and distribution interc…

…eptors for code reuse

Move some methods from DistributionManager to BaseDistributionInterceptor.
  • Loading branch information...
anistor authored and Mircea Markus committed Mar 6, 2013
1 parent cc1ac8e commit f0aaac1fbc91fb362bc8be6fec012321a0f1bde4
@@ -22,10 +22,6 @@
*/
package org.infinispan.distribution;
-import org.infinispan.commands.FlagAffectedCommand;
-import org.infinispan.container.entries.CacheEntry;
-import org.infinispan.container.entries.InternalCacheEntry;
-import org.infinispan.context.InvocationContext;
import org.infinispan.distribution.ch.ConsistentHash;
import org.infinispan.factories.scopes.Scope;
import org.infinispan.factories.scopes.Scopes;
@@ -95,24 +91,6 @@
*/
Set<Address> locateAll(Collection<Object> keys); //todo [anistor] this has to take an additional parameter that specifies if the lookup is for read or write
- /**
- * Transforms a cache entry so it is marked for L1 rather than the primary cache data structure. This should be done
- * if it is deemed that the entry is targeted for L1 storage rather than storage in the primary data container.
- *
- * @param entry entry to transform
- */
- void transformForL1(CacheEntry entry);
-
- /**
- * Retrieves a cache entry from a remote source. Would typically involve an RPC call using a {@link org.infinispan.commands.remote.ClusteredGetCommand}
- * and some form of quorum of responses if the responses returned are inconsistent - often the case if there is a
- * rehash in progress, involving nodes that the key maps to.
- *
- * @param key key to look up
- * @return an internal cache entry, or null if it cannot be located
- */
- InternalCacheEntry retrieveFromRemoteSource(Object key, InvocationContext ctx, boolean acquireRemoteLock, FlagAffectedCommand command) throws Exception;
-
/**
* Retrieves the consistent hash instance currently in use, an instance of the configured ConsistentHash
* class (which defaults to {@link org.infinispan.distribution.ch.DefaultConsistentHash}.
@@ -22,31 +22,16 @@
*/
package org.infinispan.distribution;
-import org.infinispan.commands.CommandsFactory;
-import org.infinispan.commands.FlagAffectedCommand;
-import org.infinispan.commands.remote.ClusteredGetCommand;
-import org.infinispan.configuration.cache.Configuration;
-import org.infinispan.container.entries.CacheEntry;
-import org.infinispan.container.entries.InternalCacheEntry;
-import org.infinispan.container.entries.InternalCacheValue;
-import org.infinispan.context.InvocationContext;
-import org.infinispan.context.impl.TxInvocationContext;
import org.infinispan.distribution.ch.ConsistentHash;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.factories.annotations.Start;
import org.infinispan.jmx.annotations.MBean;
import org.infinispan.jmx.annotations.ManagedOperation;
import org.infinispan.jmx.annotations.Parameter;
import org.infinispan.statetransfer.StateTransferManager;
-import org.infinispan.remoting.responses.ClusteredGetResponseValidityFilter;
-import org.infinispan.remoting.responses.Response;
-import org.infinispan.remoting.responses.SuccessfulResponse;
-import org.infinispan.remoting.rpc.ResponseFilter;
-import org.infinispan.remoting.rpc.ResponseMode;
import org.infinispan.remoting.rpc.RpcManager;
import org.infinispan.remoting.transport.Address;
import org.infinispan.topology.CacheTopology;
-import org.infinispan.transaction.xa.GlobalTransaction;
import org.infinispan.util.Immutables;
import org.infinispan.util.InfinispanCollections;
import org.infinispan.util.logging.Log;
@@ -70,9 +55,7 @@
private static final boolean trace = log.isTraceEnabled();
// Injected components
- private Configuration configuration;
private RpcManager rpcManager;
- private CommandsFactory cf;
private StateTransferManager stateTransferManager;
/**
@@ -82,11 +65,8 @@ public DistributionManagerImpl() {
}
@Inject
- public void init(Configuration configuration, RpcManager rpcManager, CommandsFactory cf,
- StateTransferManager stateTransferManager) {
- this.configuration = configuration;
+ public void init(RpcManager rpcManager, StateTransferManager stateTransferManager) {
this.rpcManager = rpcManager;
- this.cf = cf;
this.stateTransferManager = stateTransferManager;
}
@@ -147,39 +127,6 @@ public Address getPrimaryLocation(Object key) {
return getConsistentHash().locateAllOwners(keys);
}
- @Override
- public void transformForL1(CacheEntry entry) {
- if (entry.getLifespan() < 0 || entry.getLifespan() > configuration.clustering().l1().lifespan())
- entry.setLifespan(configuration.clustering().l1().lifespan());
- }
-
- @Override
- public InternalCacheEntry retrieveFromRemoteSource(Object key, InvocationContext ctx, boolean acquireRemoteLock, FlagAffectedCommand command) throws Exception {
- GlobalTransaction gtx = acquireRemoteLock ? ((TxInvocationContext)ctx).getGlobalTransaction() : null;
- ClusteredGetCommand get = cf.buildClusteredGetCommand(key, command.getFlags(), acquireRemoteLock, gtx);
-
- List<Address> targets = new ArrayList<Address>(getReadConsistentHash().locateOwners(key));
- // if any of the recipients has left the cluster since the command was issued, just don't wait for its response
- targets.retainAll(rpcManager.getTransport().getMembers());
- ResponseFilter filter = new ClusteredGetResponseValidityFilter(targets, getAddress());
- Map<Address, Response> responses = rpcManager.invokeRemotely(targets, get, ResponseMode.WAIT_FOR_VALID_RESPONSE,
- configuration.clustering().sync().replTimeout(), true, filter);
-
- if (!responses.isEmpty()) {
- for (Response r : responses.values()) {
- if (r instanceof SuccessfulResponse) {
- InternalCacheValue cacheValue = (InternalCacheValue) ((SuccessfulResponse) r).getResponseValue();
- return cacheValue.toInternalCacheEntry(key);
- }
- }
- }
-
- // TODO If everyone returned null, and the read CH has changed, retry the remote get.
- // Otherwise our get command might be processed by the old owners after they have invalidated their data
- // and we'd return a null even though the key exists on
- return null;
- }
-
@Override
public ConsistentHash getConsistentHash() {
return getWriteConsistentHash();
@@ -0,0 +1,120 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other
+ * contributors as indicated by the @author tags. All rights reserved.
+ * See the copyright.txt in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.interceptors;
+
+import org.infinispan.commands.CommandsFactory;
+import org.infinispan.commands.FlagAffectedCommand;
+import org.infinispan.commands.read.AbstractDataCommand;
+import org.infinispan.commands.write.WriteCommand;
+import org.infinispan.container.DataContainer;
+import org.infinispan.container.EntryFactory;
+import org.infinispan.container.entries.CacheEntry;
+import org.infinispan.container.entries.InternalCacheEntry;
+import org.infinispan.context.Flag;
+import org.infinispan.context.InvocationContext;
+import org.infinispan.distribution.ch.ConsistentHash;
+import org.infinispan.factories.annotations.Inject;
+import org.infinispan.factories.annotations.Start;
+import org.infinispan.interceptors.base.BaseRpcInterceptor;
+import org.infinispan.statetransfer.StateTransferManager;
+import org.infinispan.util.concurrent.locks.LockManager;
+
+/**
+ * Base class for replication and distribution interceptors.
+ *
+ * @author anistor@redhat.com
+ * @since 5.2
+ */
+public abstract class ClusteringInterceptor extends BaseRpcInterceptor {
+
+ protected CommandsFactory cf;
+ protected EntryFactory entryFactory;
+ protected LockManager lockManager;
+ protected DataContainer dataContainer;
+ protected StateTransferManager stateTransferManager;
+ protected boolean needReliableReturnValues;
+
+ @Inject
+ public void injectDependencies(CommandsFactory cf, EntryFactory entryFactory,
+ LockManager lockManager, DataContainer dataContainer,
+ StateTransferManager stateTransferManager) {
+ this.cf = cf;
+ this.entryFactory = entryFactory;
+ this.lockManager = lockManager;
+ this.dataContainer = dataContainer;
+ this.stateTransferManager = stateTransferManager;
+ }
+
+ @Start
+ public void configure() {
+ needReliableReturnValues = !cacheConfiguration.unsafe().unreliableReturnValues();
+ }
+
+ protected boolean isNeedReliableReturnValues(FlagAffectedCommand command) {
+ return !command.hasFlag(Flag.SKIP_REMOTE_LOOKUP)
+ && !command.hasFlag(Flag.IGNORE_RETURN_VALUES) && needReliableReturnValues;
+ }
+
+ protected boolean needsRemoteGet(InvocationContext ctx, AbstractDataCommand command) {
+ if (command.hasFlag(Flag.CACHE_MODE_LOCAL)
+ || command.hasFlag(Flag.SKIP_REMOTE_LOOKUP)
+ || command.hasFlag(Flag.IGNORE_RETURN_VALUES)) {
+ return false;
+ }
+ boolean shouldFetchFromRemote = false;
+ CacheEntry entry = ctx.lookupEntry(command.getKey());
+ if (entry == null || entry.isNull() || entry.isLockPlaceholder()) {
+ Object key = command.getKey();
+ ConsistentHash ch = stateTransferManager.getCacheTopology().getReadConsistentHash();
+ shouldFetchFromRemote = ctx.isOriginLocal() && !ch.isKeyLocalToNode(rpcManager.getAddress(), key) && !dataContainer.containsKey(key);
+ if (!shouldFetchFromRemote && getLog().isTraceEnabled()) {
+ getLog().tracef("Not doing a remote get for key %s since entry is mapped to current node (%s) or is in L1. Owners are %s", key, rpcManager.getAddress(), ch.locateOwners(key));
+ }
+ }
+ return shouldFetchFromRemote;
+ }
+
+ /**
+ * For conditional operations (replace, remove, put if absent) Used only for optimistic transactional caches, to solve the following situation:
+ * <pre>
+ * - node A (owner, tx originator) does a successful replace
+ * - the actual value changes
+ * - tx commits. The value is applied on A (the check was performed at operation time) but is not applied on
+ * B (check is performed at commit time).
+ * In such situations (optimistic caches) the remote conditional command should not re-check the old value.
+ * </pre>
+ */
+ protected boolean ignorePreviousValueOnBackup(WriteCommand command, InvocationContext ctx) {
+ return ctx.isOriginLocal() && command.isSuccessful();
+ }
+
+ /**
+ * Retrieves a cache entry from a remote source. Would typically involve an RPC call using a {@link org.infinispan.commands.remote.ClusteredGetCommand}
+ * and some form of quorum of responses if the responses returned are inconsistent - often the case if there is a
+ * rehash in progress, involving nodes that the key maps to.
+ *
+ * @param key key to look up
+ * @return an internal cache entry, or null if it cannot be located
+ */
+ protected abstract InternalCacheEntry retrieveFromRemoteSource(Object key, InvocationContext ctx, boolean acquireRemoteLock, FlagAffectedCommand command) throws Exception;
+}
Oops, something went wrong.

0 comments on commit f0aaac1

Please sign in to comment.