org.infinispan.hotrod.impl.operations.GetWithMetadataOperation Maven / Gradle / Ivy
package org.infinispan.hotrod.impl.operations;
import java.net.SocketAddress;
import java.time.Duration;
import java.util.Set;
import org.infinispan.api.common.CacheEntry;
import org.infinispan.api.common.CacheEntryExpiration;
import org.infinispan.api.common.CacheEntryVersion;
import org.infinispan.api.common.CacheOptions;
import org.infinispan.hotrod.impl.DataFormat;
import org.infinispan.hotrod.impl.cache.CacheEntryImpl;
import org.infinispan.hotrod.impl.cache.CacheEntryMetadataImpl;
import org.infinispan.hotrod.impl.cache.CacheEntryVersionImpl;
import org.infinispan.hotrod.impl.logging.Log;
import org.infinispan.hotrod.impl.logging.LogFactory;
import org.infinispan.hotrod.impl.protocol.HotRodConstants;
import org.infinispan.hotrod.impl.transport.netty.ByteBufUtil;
import org.infinispan.hotrod.impl.transport.netty.HeaderDecoder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
/**
* Corresponds to getWithMetadata operation as described by
* Hot Rod protocol specification.
*
* @since 14.0
*/
public class GetWithMetadataOperation extends AbstractKeyOperation> implements RetryAwareCompletionStage> {
private static final Log log = LogFactory.getLog(GetWithMetadataOperation.class);
private final SocketAddress preferredServer;
private volatile boolean retried;
public GetWithMetadataOperation(OperationContext operationContext, K key, byte[] keyBytes,
CacheOptions options,
DataFormat dataFormat,
SocketAddress preferredServer) {
super(operationContext, GET_WITH_METADATA, GET_WITH_METADATA_RESPONSE, key, keyBytes, options, dataFormat);
this.preferredServer = preferredServer;
}
public RetryAwareCompletionStage> internalExecute() {
// The super.execute returns this, so the cast is safe
//noinspection unchecked
return (RetryAwareCompletionStage>) super.execute();
}
@Override
protected void executeOperation(Channel channel) {
scheduleRead(channel);
sendArrayOperation(channel, keyBytes);
}
@Override
protected void fetchChannelAndInvoke(int retryCount, Set failedServers) {
if (retryCount == 0 && preferredServer != null) {
operationContext.getChannelFactory().fetchChannelAndInvoke(preferredServer, this);
} else {
retried = retryCount != 0;
super.fetchChannelAndInvoke(retryCount, failedServers);
}
}
@Override
public void acceptResponse(ByteBuf buf, short status, HeaderDecoder decoder) {
if (HotRodConstants.isNotExist(status) || !HotRodConstants.isSuccess(status)) {
statsDataRead(false);
complete(null);
return;
}
short flags = buf.readUnsignedByte();
long creation = -1;
int lifespan = -1;
long lastUsed = -1;
int maxIdle = -1;
if ((flags & INFINITE_LIFESPAN) != INFINITE_LIFESPAN) {
creation = buf.readLong();
lifespan = ByteBufUtil.readVInt(buf);
}
if ((flags & INFINITE_MAXIDLE) != INFINITE_MAXIDLE) {
lastUsed = buf.readLong();
maxIdle = ByteBufUtil.readVInt(buf);
}
CacheEntryExpiration expiration;
if (lifespan < 0) {
if (maxIdle < 0) {
expiration = CacheEntryExpiration.IMMORTAL;
} else {
expiration = CacheEntryExpiration.withMaxIdle(Duration.ofSeconds(maxIdle));
}
} else {
if (maxIdle < 0) {
expiration = CacheEntryExpiration.withLifespan(Duration.ofSeconds(lifespan));
} else {
expiration = CacheEntryExpiration.withLifespanAndMaxIdle(Duration.ofSeconds(lifespan), Duration.ofSeconds(maxIdle));
}
}
CacheEntryVersion version = new CacheEntryVersionImpl(buf.readLong());
if (log.isTraceEnabled()) {
log.tracef("Received version: %s", version);
}
V value = dataFormat().valueToObj(ByteBufUtil.readArray(buf), operationContext.getConfiguration().getClassAllowList());
statsDataRead(true);
complete(new CacheEntryImpl<>(operationKey(), value, new CacheEntryMetadataImpl(creation, lastUsed, expiration, version)));
}
@Override
public Boolean wasRetried() {
return isDone() ? retried : null;
}
}