/*
* INESC-ID, Instituto de Engenharia de Sistemas e Computadores Investigação e Desevolvimento em Lisboa
* Copyright 2013 INESC-ID 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 3.0 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.gmu;
import org.infinispan.commands.tx.PrepareCommand;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.container.entries.gmu.InternalGMUCacheEntry;
import org.infinispan.container.gmu.L1GMUContainer;
import org.infinispan.container.versioning.VersionGenerator;
import org.infinispan.container.versioning.gmu.GMUVersionGenerator;
import org.infinispan.context.InvocationContext;
import org.infinispan.context.impl.TxInvocationContext;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.interceptors.DistributionInterceptor;
import org.infinispan.remoting.responses.Response;
import org.infinispan.remoting.transport.Address;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
import java.util.Collection;
import java.util.Map;
import static org.infinispan.transaction.gmu.GMUHelper.joinAndSetTransactionVersion;
import static org.infinispan.transaction.gmu.GMUHelper.toGMUVersionGenerator;
/**
* @author Pedro Ruivo
* @author Sebastiano Peluso
* @author Hugo Pimentel
* @since 5.2
*/
public class GMUDistributionInterceptor extends DistributionInterceptor {
private static final Log log = LogFactory.getLog(GMUDistributionInterceptor.class);
protected GMUVersionGenerator versionGenerator;
private L1GMUContainer l1GMUContainer;
@Inject
public void setVersionGenerator(VersionGenerator versionGenerator, L1GMUContainer l1GMUContainer) {
this.versionGenerator = toGMUVersionGenerator(versionGenerator);
this.l1GMUContainer = l1GMUContainer;
}
@Override
protected void prepareOnAffectedNodes(TxInvocationContext ctx, PrepareCommand command,
Collection<Address> recipients, boolean sync) {
Map<Address, Response> responses = rpcManager.invokeRemotely(recipients, command, true, true, false);
log.debugf("prepare command for transaction %s is sent. responses are: %s",
command.getGlobalTransaction().prettyPrint(), responses.toString());
joinAndSetTransactionVersion(responses.values(), ctx, versionGenerator);
}
@Override
protected InternalCacheEntry retrieveFromRemoteSource(Object key, InvocationContext ctx, boolean acquireRemoteLock)
throws Exception {
if (ctx instanceof TxInvocationContext) {
if (log.isTraceEnabled()) {
log.tracef("Trying to retrieve a the key %s from L1 GMU Data Container", key);
}
TxInvocationContext txInvocationContext = (TxInvocationContext) ctx;
InternalGMUCacheEntry gmuCacheEntry = l1GMUContainer.getValidVersion(key,
txInvocationContext.getTransactionVersion(),
txInvocationContext.getAlreadyReadFrom());
if (gmuCacheEntry != null) {
if (log.isTraceEnabled()) {
log.tracef("Retrieve a L1 entry for key %s: %s", key, gmuCacheEntry);
}
txInvocationContext.addKeyReadInCommand(key, gmuCacheEntry);
txInvocationContext.addReadFrom(dm.getPrimaryLocation(key));
return gmuCacheEntry.getInternalCacheEntry();
}
}
if (log.isTraceEnabled()) {
log.tracef("Failed to retrieve a L1 entry for key %s", key);
}
return super.retrieveFromRemoteSource(key, ctx, acquireRemoteLock);
}
@Override
protected void storeInL1(Object key, InternalCacheEntry ice, InvocationContext ctx, boolean isWrite) throws Throwable {
if (log.isTraceEnabled()) {
log.tracef("Doing a put in L1 into the L1 GMU Data Container");
}
InternalGMUCacheEntry gmuCacheEntry = ctx.getKeysReadInCommand().get(key);
if (gmuCacheEntry == null) {
throw new NullPointerException("GMU cache entry cannot be null");
}
l1GMUContainer.insertOrUpdate(key, gmuCacheEntry);
CacheEntry ce = ctx.lookupEntry(key);
if (ce == null || ce.isNull() || ce.isLockPlaceholder() || ce.getValue() == null) {
if (ce != null && ce.isChanged()) {
ce.setValue(ice.getValue());
} else {
if (isWrite)
entryFactory.wrapEntryForPut(ctx, key, ice, false);
else
ctx.putLookedUpEntry(key, ice);
}
}
}
}