package org.infinispan.server.hotrod;
import java.io.IOException;
import java.security.PrivilegedActionException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.infinispan.AdvancedCache;
import org.infinispan.IllegalLifecycleStateException;
import org.infinispan.commons.CacheException;
import org.infinispan.commons.logging.LogFactory;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.container.versioning.NumericVersion;
import org.infinispan.context.Flag;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.remoting.transport.jgroups.SuspectException;
import org.infinispan.server.core.transport.ExtendedByteBufJava;
import org.infinispan.server.core.transport.NettyTransport;
import org.infinispan.server.hotrod.logging.Log;
import org.infinispan.server.hotrod.transport.ExtendedByteBuf;
import org.infinispan.stats.ClusterCacheStats;
import org.infinispan.stats.Stats;
import org.infinispan.util.KeyValuePair;
import org.infinispan.util.concurrent.TimeoutException;
import org.jgroups.SuspectedException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.util.CharsetUtil;
/**
* HotRod protocol decoder specific for specification version 2.0.
*
* @author Galder ZamarreƱo
* @since 7.0
*/
class Decoder2x implements VersionedDecoder {
private static final Log log = LogFactory.getLog(Decoder2x.class, Log.class);
private static final long EXPIRATION_NONE = -1;
private static final long EXPIRATION_DEFAULT = -2;
private static final CacheDecodeContext.ExpirationParam DEFAULT_EXPIRATION =
new CacheDecodeContext.ExpirationParam(-1, TimeUnitValue.SECONDS);
@Override
public boolean readHeader(ByteBuf buffer, byte version, long messageId, HotRodHeader header) throws Exception {
if (header.op == null) {
int readableBytes = buffer.readableBytes();
// We require at least 2 bytes at minimum
if (readableBytes < 2) {
buffer.resetReaderIndex();
return false;
}
byte streamOp = buffer.readByte();
int length = ExtendedByteBufJava.readMaybeVInt(buffer);
// Didn't have enough bytes for VInt or the length is too long for remaining
if (length == Integer.MIN_VALUE || length > buffer.readableBytes()) {
buffer.resetReaderIndex();
return false;
} else if (length == 0) {
header.cacheName = "";
} else {
byte[] bytes = new byte[length];
buffer.readBytes(bytes);
header.cacheName = new String(bytes, CharsetUtil.UTF_8);
}
header.op = HotRodOperation.fromRequestOpCode(streamOp);
if (header.op == null) {
throw new HotRodUnknownOperationException("Unknown operation: " + streamOp, version, messageId);
}
buffer.markReaderIndex();
}
int flag = ExtendedByteBufJava.readMaybeVInt(buffer);
if (flag == Integer.MIN_VALUE) {
return false;
}
if (buffer.readableBytes() < 2) {
buffer.resetReaderIndex();
return false;
}
byte clientIntelligence = buffer.readByte();
int topologyId = ExtendedByteBufJava.readMaybeVInt(buffer);
if (topologyId == Integer.MIN_VALUE) {
return false;
}
header.flag = flag;
header.clientIntel = clientIntelligence;
header.topologyId = topologyId;
buffer.markReaderIndex();
return true;
}
@Override
public CacheDecodeContext.RequestParameters readParameters(HotRodHeader header, ByteBuf buffer) {
switch (header.op) {
case REMOVE_IF_UNMODIFIED:
return readParameters(buffer, header, false, false, true);
case REPLACE_IF_UNMODIFIED:
return readParameters(buffer, header, true, true, true);
case GET_ALL:
return readParameters(buffer, header, false, true, false);
case PUT_STREAM:
return readParameters(buffer, header, true, false, true);
default:
return readParameters(buffer, header, true, true, false);
}
}
private static CacheDecodeContext.RequestParameters readParameters(ByteBuf buffer, HotRodHeader header, boolean readExpiration,
boolean readSize, boolean readVersion) {
CacheDecodeContext.ExpirationParam param1;
CacheDecodeContext.ExpirationParam param2;
long version;
int size;
if (readExpiration) {
boolean pre22Version = Constants.isVersionPre22(header.version);
byte firstUnit;
byte secondUnit;
if (pre22Version) {
firstUnit = secondUnit = TimeUnitValue.SECONDS.getCode();
} else {
if (buffer.readableBytes() == 0) {
return null;
}
byte units = buffer.readByte();
firstUnit = (byte) ((units & 0xf0) >> 4);
secondUnit = (byte) (units & 0x0f);
}
param1 = readExpirationParam(pre22Version, hasFlag(header, ProtocolFlag.DefaultLifespan), buffer, firstUnit);
if (param1 == null) {
return null;
}
param2 = readExpirationParam(pre22Version, hasFlag(header, ProtocolFlag.DefaultMaxIdle), buffer, secondUnit);
if (param2 == null) {
return null;
}
} else {
param1 = param2 = DEFAULT_EXPIRATION;
}
if (readVersion) {
version = ExtendedByteBufJava.readUnsignedMaybeLong(buffer);
if (version == Long.MIN_VALUE) {
return null;
}
} else {
version = -1;
}
if (readSize) {
size = ExtendedByteBufJava.readMaybeVInt(buffer);
if (size == Integer.MIN_VALUE) {
return null;
}
} else {
size = -1;
}
buffer.markReaderIndex();
return new CacheDecodeContext.RequestParameters(size, param1, param2, version);
}
private static CacheDecodeContext.ExpirationParam readExpirationParam(boolean pre22Version, boolean useDefault, ByteBuf buffer,
byte timeUnit) {
if (pre22Version) {
int duration = ExtendedByteBufJava.readMaybeVInt(buffer);
if (duration == Integer.MIN_VALUE) {
return null;
} else if (duration <= 0) {
duration = useDefault ? (int) EXPIRATION_DEFAULT : (int) EXPIRATION_NONE;
}
return new CacheDecodeContext.ExpirationParam(duration, TimeUnitValue.decode(timeUnit));
} else {
switch (timeUnit) {
// Default time unit
case 0x07:
return new CacheDecodeContext.ExpirationParam(EXPIRATION_DEFAULT, TimeUnitValue.decode(timeUnit));
// Infinite time unit
case 0x08:
return new CacheDecodeContext.ExpirationParam(EXPIRATION_NONE, TimeUnitValue.decode(timeUnit));
default:
long timeDuration = ExtendedByteBufJava.readMaybeVLong(buffer);
if (timeDuration == Long.MIN_VALUE) {
return null;
}
return new CacheDecodeContext.ExpirationParam(timeDuration, TimeUnitValue.decode(timeUnit));
}
}
}
private static boolean hasFlag(HotRodHeader h, ProtocolFlag f) {
return (h.flag & f.getValue()) == f.getValue();
}
@Override
public Response createSuccessResponse(HotRodHeader header, byte[] prev) {
return createResponse(header, OperationStatus.Success, prev);
}
@Override
public Response createNotExecutedResponse(HotRodHeader header, byte[] prev) {
return createResponse(header, OperationStatus.OperationNotExecuted, prev);
}
@Override
public Response createNotExistResponse(HotRodHeader header) {
return createResponse(header, OperationStatus.KeyDoesNotExist, null);
}
private Response createResponse(HotRodHeader h, OperationStatus st, byte[] prev) {
if (hasFlag(h, ProtocolFlag.ForceReturnPreviousValue)) {
switch (st) {
case Success:
switch (h.op) {
case PUT:
case REPLACE:
case REMOVE_IF_UNMODIFIED:
case REMOVE:
case REPLACE_IF_UNMODIFIED:
return new ResponseWithPrevious(h.version, h.messageId, h.cacheName,
h.clientIntel, h.op, OperationStatus.SuccessWithPrevious, h.topologyId, Optional.ofNullable(prev));
}
break;
case OperationNotExecuted:
switch (h.op) {
case PUT_IF_ABSENT:
case REPLACE_IF_UNMODIFIED:
case REMOVE_IF_UNMODIFIED:
return new ResponseWithPrevious(h.version, h.messageId, h.cacheName,
h.clientIntel, h.op, OperationStatus.NotExecutedWithPrevious, h.topologyId, Optional.ofNullable(prev));
}
break;
}
}
return new EmptyResponse(h.version, h.messageId, h.cacheName, h.clientIntel, h.op, st, h.topologyId);
}
@Override
public Response createGetResponse(HotRodHeader h, CacheEntry<byte[], byte[]> entry) {
HotRodOperation op = h.op;
if (entry != null) {
switch (op) {
case GET:
return new GetResponse(h.version, h.messageId, h.cacheName, h.clientIntel, HotRodOperation.GET,
OperationStatus.Success, h.topologyId, entry.getValue());
case GET_WITH_VERSION:
long version;
NumericVersion numericVersion = (NumericVersion) entry.getMetadata().version();
if (numericVersion != null) {
version = numericVersion.getVersion();
} else {
version = 0;
}
return new GetWithVersionResponse(h.version, h.messageId, h.cacheName, h.clientIntel,
HotRodOperation.GET_WITH_VERSION, OperationStatus.Success, h.topologyId, entry.getValue(),
version);
}
} else {
switch (op) {
case GET:
return new GetResponse(h.version, h.messageId, h.cacheName, h.clientIntel,
HotRodOperation.GET, OperationStatus.KeyDoesNotExist, h.topologyId, null);
case GET_WITH_VERSION:
return new GetWithVersionResponse(h.version, h.messageId, h.cacheName,
h.clientIntel, HotRodOperation.GET_WITH_VERSION, OperationStatus.KeyDoesNotExist,
h.topologyId, null, 0);
}
}
throw new IllegalStateException("Unreachable code");
}
@Override
public void customReadHeader(HotRodHeader header, ByteBuf buffer, CacheDecodeContext hrCtx, List<Object> out) {
switch (header.op) {
case AUTH:
ExtendedByteBuf.readMaybeString(buffer).flatMap(mech ->
ExtendedByteBuf.readMaybeRangedBytes(buffer).map(clientResponse -> {
hrCtx.operationDecodeContext = new KeyValuePair<>(mech, clientResponse);
buffer.markReaderIndex();
out.add(hrCtx);
return null;
}));
break;
case EXEC:
ExecRequestContext execCtx = (ExecRequestContext) hrCtx.operationDecodeContext;
// first time read
if (execCtx == null) {
Optional<ExecRequestContext> optional = ExtendedByteBuf.readMaybeString(buffer).flatMap(name ->
ExtendedByteBuf.readMaybeVInt(buffer).map(paramCount -> {
ExecRequestContext ctx = new ExecRequestContext(name, paramCount, new HashMap<>(paramCount));
hrCtx.operationDecodeContext = ctx;
// Mark that we read these
buffer.markReaderIndex();
return ctx;
}));
if (optional.isPresent()) {
execCtx = optional.get();
} else {
return;
}
}
if (execCtx.getParamSize() == 0) {
out.add(hrCtx);
} else {
Map<String, byte[]> map = execCtx.getParams();
boolean readAll = true;
while (map.size() < execCtx.getParamSize()) {
if (!ExtendedByteBuf.readMaybeString(buffer).flatMap(key ->
ExtendedByteBuf.readMaybeRangedBytes(buffer).map(value -> {
map.put(key, value);
buffer.markReaderIndex();
return value;
})).isPresent()) {
readAll = false;
break;
}
}
if (readAll) {
out.add(hrCtx);
}
}
break;
default:
// This operation doesn't need additional reads - has everything to process
out.add(hrCtx);
}
}
@Override
public void customReadKey(HotRodHeader header, ByteBuf buffer, CacheDecodeContext hrCtx, List<Object> out) {
switch (header.op) {
case BULK_GET:
case BULK_GET_KEYS:
ExtendedByteBuf.readMaybeVInt(buffer).ifPresent(number -> {
hrCtx.operationDecodeContext = number;
buffer.markReaderIndex();
out.add(hrCtx);
});
break;
case QUERY:
ExtendedByteBuf.readMaybeRangedBytes(buffer).ifPresent(query -> {
hrCtx.operationDecodeContext = query;
buffer.markReaderIndex();
out.add(hrCtx);
});
break;
case GET_STREAM:
ExtendedByteBuf.readMaybeVInt(buffer).ifPresent(offset -> {
hrCtx.operationDecodeContext = offset;
buffer.markReaderIndex();
out.add(hrCtx);
});
break;
case ADD_CLIENT_LISTENER:
ClientListenerRequestContext requestCtx;
if (hrCtx.operationDecodeContext == null) {
Optional<ClientListenerRequestContext> optional = ExtendedByteBuf.readMaybeRangedBytes(buffer).flatMap(listenerId ->
ExtendedByteBuf.readMaybeByte(buffer).map(includeState -> {
ClientListenerRequestContext ctx = new ClientListenerRequestContext(listenerId, includeState == 1);
hrCtx.operationDecodeContext = ctx;
// Mark that we read these
buffer.markReaderIndex();
return ctx;
}));
if (optional.isPresent()) {
requestCtx = optional.get();
} else {
return;
}
} else {
requestCtx = (ClientListenerRequestContext) hrCtx.operationDecodeContext;
}
if (requestCtx.getFilterFactoryInfo() == null) {
if (!readMaybeNamedFactory(buffer).map(f -> {
requestCtx.setFilterFactoryInfo(f);
buffer.markReaderIndex();
return requestCtx;
}).isPresent()) {
return;
}
}
if (requestCtx.getConverterFactoryInfo() == null) {
if (!readMaybeNamedFactory(buffer).map(converter -> {
boolean useRawData;
if (Constants.isVersion2x(header.version)) {
Optional<Byte> rawOptional = ExtendedByteBuf.readMaybeByte(buffer);
if (rawOptional.isPresent()) {
useRawData = rawOptional.get() == 1;
} else {
return null;
}
} else {
useRawData = false;
}
requestCtx.setConverterFactoryInfo(converter);
requestCtx.setUseRawData(useRawData);
buffer.markReaderIndex();
return requestCtx;
}).isPresent()) {
return;
}
}
if (Constants.isVersionPost25(header.version)) {
int listenerInterests = ExtendedByteBufJava.readMaybeVInt(buffer);
if (listenerInterests == Integer.MIN_VALUE)
return;
requestCtx.setListenerInterests(listenerInterests);
buffer.markReaderIndex();
}
out.add(hrCtx);
break;
case REMOVE_CLIENT_LISTENER:
ExtendedByteBuf.readMaybeRangedBytes(buffer).ifPresent(listenerId -> {
hrCtx.operationDecodeContext = listenerId;
buffer.markReaderIndex();
out.add(hrCtx);
});
break;
case ITERATION_START:
ExtendedByteBuf.readMaybeOptRangedBytes(buffer).flatMap(segments ->
ExtendedByteBuf.readMaybeOptString(buffer).map(name -> {
Optional<KeyValuePair<String, List<byte[]>>> factory;
boolean isPre24 = Constants.isVersionPre24(header.version);
if (name.isPresent()) {
if (isPre24) {
factory = Optional.of(new KeyValuePair<>(name.get(), Collections.emptyList()));
} else {
Optional<List<byte[]>> optionalParams = readOptionalParams(buffer);
if (optionalParams.isPresent()) {
factory = Optional.of(new KeyValuePair<>(name.get(), optionalParams.get()));
} else {
return null;
}
}
} else {
factory = Optional.empty();
}
int batchSize;
Optional<Integer> optionalBatchSize = ExtendedByteBuf.readMaybeVInt(buffer);
if (optionalBatchSize.isPresent()) {
batchSize = optionalBatchSize.get();
} else {
return null;
}
boolean metadata;
if (isPre24) {
metadata = false;
} else {
Optional<Byte> optionalMetadata = ExtendedByteBuf.readMaybeByte(buffer);
if (optionalMetadata.isPresent()) {
metadata = optionalMetadata.get() != 0;
} else {
return null;
}
}
hrCtx.operationDecodeContext = new IterationStartRequest(segments, factory, batchSize, metadata);
buffer.markReaderIndex();
out.add(hrCtx);
return null;
}));
break;
case ITERATION_NEXT:
case ITERATION_END:
ExtendedByteBuf.readMaybeString(buffer).ifPresent(iterationId -> {
hrCtx.operationDecodeContext = iterationId;
buffer.markReaderIndex();
out.add(hrCtx);
});
break;
}
}
private Optional<Optional<KeyValuePair<String, List<byte[]>>>> readMaybeNamedFactory(ByteBuf buffer) {
return ExtendedByteBuf.readMaybeString(buffer).flatMap(name -> {
if (!name.isEmpty()) {
return readOptionalParams(buffer).map(param -> Optional.of(new KeyValuePair<>(name, param)));
} else return Optional.of(Optional.empty());
});
}
private Optional<List<byte[]>> readOptionalParams(ByteBuf buffer) {
Optional<Byte> numParams = ExtendedByteBuf.readMaybeByte(buffer);
return numParams.map(p -> {
if (p > 0) {
List<byte[]> params = new ArrayList<>();
boolean readAll = true;
while (params.size() < p) {
if (!ExtendedByteBuf.readMaybeRangedBytes(buffer).map(param -> {
params.add(param);
return param;
}).isPresent()) {
readAll = false;
break;
}
}
if (readAll) {
return Optional.of(params);
}
return null;
} else return Optional.<List<byte[]>>of(Collections.emptyList());
}).orElse(Optional.empty());
}
@Override
public void customReadValue(HotRodHeader header, ByteBuf buffer, CacheDecodeContext hrCtx, List<Object> out) {
switch (header.op) {
case PUT_ALL:
int maxLength = hrCtx.params.valueLength;
Map<byte[], byte[]> map;
if (hrCtx.operationDecodeContext == null) {
map = new HashMap<>(maxLength);
hrCtx.operationDecodeContext = map;
} else {
map = (Map<byte[], byte[]>) hrCtx.operationDecodeContext;
}
boolean readAll = true;
while (map.size() < maxLength) {
if (!ExtendedByteBuf.readMaybeRangedBytes(buffer).flatMap(key ->
ExtendedByteBuf.readMaybeRangedBytes(buffer).map(value -> {
map.put(key, value);
buffer.markReaderIndex();
return value;
})).isPresent()) {
readAll = false;
break;
}
}
if (readAll) {
out.add(hrCtx);
}
break;
case GET_ALL:
maxLength = hrCtx.params.valueLength;
Set<byte[]> set;
if (hrCtx.operationDecodeContext == null) {
set = new HashSet<>(maxLength);
hrCtx.operationDecodeContext = set;
} else {
set = (Set<byte[]>) hrCtx.operationDecodeContext;
}
readAll = true;
while (set.size() < maxLength) {
if (!ExtendedByteBuf.readMaybeRangedBytes(buffer).map(bytes -> {
set.add(bytes);
buffer.markReaderIndex();
return bytes;
}).isPresent()) {
readAll = false;
break;
}
}
if (readAll) {
out.add(hrCtx);
}
break;
case PUT_STREAM:
ByteBuf vBuffer;
if (hrCtx.operationDecodeContext == null) {
hrCtx.operationDecodeContext = vBuffer = ByteBufAllocator.DEFAULT.buffer();
} else {
vBuffer = (ByteBuf) hrCtx.operationDecodeContext;
}
if (vBuffer != null) {
ExtendedByteBuf.readMaybeRangedBytes(buffer).map(bytes -> {
if (bytes.length > 0) {
vBuffer.writeBytes(bytes);
} else {
out.add(hrCtx);
}
buffer.markReaderIndex();
return Optional.empty();
});
}
break;
}
}
@Override
public StatsResponse createStatsResponse(CacheDecodeContext ctx, NettyTransport t) {
Stats cacheStats = ctx.cache.getStats();
Map<String, String> stats = new HashMap<>();
stats.put("timeSinceStart", String.valueOf(cacheStats.getTimeSinceStart()));
stats.put("currentNumberOfEntries", String.valueOf(cacheStats.getCurrentNumberOfEntries()));
stats.put("totalNumberOfEntries", String.valueOf(cacheStats.getTotalNumberOfEntries()));
stats.put("stores", String.valueOf(cacheStats.getStores()));
stats.put("retrievals", String.valueOf(cacheStats.getRetrievals()));
stats.put("hits", String.valueOf(cacheStats.getHits()));
stats.put("misses", String.valueOf(cacheStats.getMisses()));
stats.put("removeHits", String.valueOf(cacheStats.getRemoveHits()));
stats.put("removeMisses", String.valueOf(cacheStats.getRemoveMisses()));
stats.put("totalBytesRead", t.getTotalBytesRead());
stats.put("totalBytesWritten", t.getTotalBytesWritten());
HotRodHeader h = ctx.header;
if (!Constants.isVersionPre24(h.version)) {
ComponentRegistry registry = ctx.getCacheRegistry(h.cacheName);
ClusterCacheStats clusterCacheStats = registry.getComponent(ClusterCacheStats.class);
if (clusterCacheStats != null) {
stats.put("globalCurrentNumberOfEntries", String.valueOf(clusterCacheStats.getCurrentNumberOfEntries()));
stats.put("globalStores", String.valueOf(clusterCacheStats.getStores()));
stats.put("globalRetrievals", String.valueOf(clusterCacheStats.getRetrievals()));
stats.put("globalHits", String.valueOf(clusterCacheStats.getHits()));
stats.put("globalMisses", String.valueOf(clusterCacheStats.getMisses()));
stats.put("globalRemoveHits", String.valueOf(clusterCacheStats.getRemoveHits()));
stats.put("globalRemoveMisses", String.valueOf(clusterCacheStats.getRemoveMisses()));
}
}
return new StatsResponse(h.version, h.messageId, h.cacheName, h.clientIntel, stats, h.topologyId);
}
@Override
public ErrorResponse createErrorResponse(HotRodHeader h, Throwable t) {
if (t instanceof SuspectException) {
return createNodeSuspectedErrorResponse(h, t);
} else if (t instanceof IllegalLifecycleStateException) {
return createIllegalLifecycleStateErrorResponse(h, t);
} else if (t instanceof IOException) {
return new ErrorResponse(h.version, h.messageId, h.cacheName, h.clientIntel, OperationStatus.ParseError,
h.topologyId, t.toString());
} else if (t instanceof TimeoutException) {
return new ErrorResponse(h.version, h.messageId, h.cacheName, h.clientIntel,
OperationStatus.OperationTimedOut, h.topologyId, t.toString());
} else if (t instanceof CacheException) {
// JGroups and remote exceptions (inside RemoteException) can come wrapped up
Throwable cause = t.getCause() == null ? t : t.getCause();
if (cause instanceof SuspectedException) {
return createNodeSuspectedErrorResponse(h, cause);
} else if (cause instanceof IllegalLifecycleStateException) {
return createIllegalLifecycleStateErrorResponse(h, cause);
} else if (cause instanceof InterruptedException) {
return createIllegalLifecycleStateErrorResponse(h, cause);
} else {
return createServerErrorResponse(h, cause);
}
} else if (t instanceof InterruptedException) {
return createIllegalLifecycleStateErrorResponse(h, t);
} else if (t instanceof PrivilegedActionException) {
return createErrorResponse(h, t.getCause());
} else {
return createServerErrorResponse(h, t);
}
}
private ErrorResponse createNodeSuspectedErrorResponse(HotRodHeader h, Throwable t) {
return new ErrorResponse(h.version, h.messageId, h.cacheName, h.clientIntel,
OperationStatus.NodeSuspected, h.topologyId, t.toString());
}
private ErrorResponse createIllegalLifecycleStateErrorResponse(HotRodHeader h, Throwable t) {
return new ErrorResponse(h.version, h.messageId, h.cacheName, h.clientIntel,
OperationStatus.IllegalLifecycleState, h.topologyId, t.toString());
}
private ErrorResponse createServerErrorResponse(HotRodHeader h, Throwable t) {
return new ErrorResponse(h.version, h.messageId, h.cacheName, h.clientIntel,
OperationStatus.ServerError, h.topologyId, createErrorMsg(t));
}
String createErrorMsg(Throwable t) {
Set<Throwable> causes = new LinkedHashSet<>();
Throwable initial = t;
while (initial != null && !causes.contains(initial)) {
causes.add(initial);
initial = initial.getCause();
}
return causes.stream().map(Object::toString).collect(Collectors.joining("\n"));
}
@Override
public AdvancedCache<byte[], byte[]> getOptimizedCache(HotRodHeader h, AdvancedCache<byte[], byte[]> c, Configuration cacheCfg) {
boolean isTransactional = cacheCfg.transaction().transactionMode().isTransactional();
boolean isClustered = cacheCfg.clustering().cacheMode().isClustered();
AdvancedCache<byte[], byte[]> optCache = c;
if (isClustered && !isTransactional && h.op.isConditional()) {
log.warnConditionalOperationNonTransactional(h.op.toString());
}
if (h.op.canSkipCacheLoading() && hasFlag(h, ProtocolFlag.SkipCacheLoader)) {
optCache = c.withFlags(Flag.SKIP_CACHE_LOAD);
}
if (h.op.canSkipIndexing() && hasFlag(h, ProtocolFlag.SkipIndexing)) {
optCache = c.withFlags(Flag.SKIP_INDEXING);
}
if (!hasFlag(h, ProtocolFlag.ForceReturnPreviousValue)) {
if (h.op.isNotConditionalAndCanReturnPrevious()) {
optCache = optCache.withFlags(Flag.IGNORE_RETURN_VALUES);
}
} else if (!isTransactional && h.op.canReturnPreviousValue()) {
log.warnForceReturnPreviousNonTransactional(h.op.toString());
}
return optCache;
}
}
class ExecRequestContext {
private final String name;
private final int paramSize;
private final Map<String, byte[]> params;
ExecRequestContext(String name, int paramSize, Map<String, byte[]> params) {
this.name = name;
this.paramSize = paramSize;
this.params = params;
}
public String getName() {
return name;
}
public int getParamSize() {
return paramSize;
}
public Map<String, byte[]> getParams() {
return params;
}
}
class ClientListenerRequestContext {
private final byte[] listenerId;
private final boolean includeCurrentState;
private Optional<KeyValuePair<String, List<byte[]>>> filterFactoryInfo;
private Optional<KeyValuePair<String, List<byte[]>>> converterFactoryInfo;
private boolean useRawData;
private int listenerInterests;
ClientListenerRequestContext(byte[] listenerId, boolean includeCurrentState) {
this.listenerId = listenerId;
this.includeCurrentState = includeCurrentState;
}
public byte[] getListenerId() {
return listenerId;
}
public boolean isIncludeCurrentState() {
return includeCurrentState;
}
public Optional<KeyValuePair<String, List<byte[]>>> getFilterFactoryInfo() {
return filterFactoryInfo;
}
public void setFilterFactoryInfo(Optional<KeyValuePair<String, List<byte[]>>> filterFactoryInfo) {
this.filterFactoryInfo = filterFactoryInfo;
}
public Optional<KeyValuePair<String, List<byte[]>>> getConverterFactoryInfo() {
return converterFactoryInfo;
}
public void setConverterFactoryInfo(Optional<KeyValuePair<String, List<byte[]>>> converterFactoryInfo) {
this.converterFactoryInfo = converterFactoryInfo;
}
public boolean isUseRawData() {
return useRawData;
}
public void setUseRawData(boolean useRawData) {
this.useRawData = useRawData;
}
public int getListenerInterests() {
return listenerInterests;
}
public void setListenerInterests(int listenerInterests) {
this.listenerInterests = listenerInterests;
}
}
class IterationStartRequest {
private final Optional<byte[]> optionBitSet;
private final Optional<KeyValuePair<String, List<byte[]>>> factory;
private final int batch;
private final boolean metadata;
IterationStartRequest(Optional<byte[]> optionBitSet, Optional<KeyValuePair<String, List<byte[]>>> factory,
int batch, boolean metadata) {
this.optionBitSet = optionBitSet;
this.factory = factory;
this.batch = batch;
this.metadata = metadata;
}
public Optional<byte[]> getOptionBitSet() {
return optionBitSet;
}
public Optional<KeyValuePair<String, List<byte[]>>> getFactory() {
return factory;
}
public int getBatch() {
return batch;
}
public boolean isMetadata() {
return metadata;
}
}