blob: 12b5e371a4ff2deaab5a10fd127f6809bba7b026 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.internal.processors.cache.distributed.dht;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.IgniteDiagnosticAware;
import org.apache.ignite.internal.IgniteDiagnosticPrepareContext;
import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.NodeStoppingException;
import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
import org.apache.ignite.internal.cluster.ClusterTopologyServerNotFoundException;
import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
import org.apache.ignite.internal.processors.cache.CacheObject;
import org.apache.ignite.internal.processors.cache.EntryGetResult;
import org.apache.ignite.internal.processors.cache.GridCacheContext;
import org.apache.ignite.internal.processors.cache.GridCacheEntryEx;
import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo;
import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException;
import org.apache.ignite.internal.processors.cache.GridCacheFuture;
import org.apache.ignite.internal.processors.cache.GridCacheFutureAdapter;
import org.apache.ignite.internal.processors.cache.GridCacheMessage;
import org.apache.ignite.internal.processors.cache.GridCacheUtils.BackupPostProcessingClosure;
import org.apache.ignite.internal.processors.cache.IgniteCacheExpiryPolicy;
import org.apache.ignite.internal.processors.cache.KeyCacheObject;
import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture;
import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtInvalidPartitionException;
import org.apache.ignite.internal.processors.cache.distributed.near.CacheVersionedValue;
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearGetResponse;
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearSingleGetRequest;
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearSingleGetResponse;
import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.util.lang.GridPlainRunnable;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteInClosure;
import org.apache.ignite.lang.IgniteUuid;
import org.apache.ignite.plugin.extensions.communication.Message;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_NEAR_GET_MAX_REMAPS;
import static org.apache.ignite.IgniteSystemProperties.getInteger;
import static org.apache.ignite.internal.processors.cache.distributed.dht.CacheDistributedGetFutureAdapter.DFLT_MAX_REMAP_CNT;
import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.OWNING;
/**
*
*/
public class GridPartitionedSingleGetFuture extends GridCacheFutureAdapter<Object>
implements CacheGetFuture, IgniteDiagnosticAware {
/** Maximum number of attempts to remap key to the same primary node. */
protected static final int MAX_REMAP_CNT = getInteger(IGNITE_NEAR_GET_MAX_REMAPS, DFLT_MAX_REMAP_CNT);
/** Remap count updater. */
protected static final AtomicIntegerFieldUpdater<GridPartitionedSingleGetFuture> REMAP_CNT_UPD =
AtomicIntegerFieldUpdater.newUpdater(GridPartitionedSingleGetFuture.class, "remapCnt");
/** Logger reference. */
private static final AtomicReference<IgniteLogger> logRef = new AtomicReference<>();
/** Logger. */
private static IgniteLogger log;
/** Topology version. */
private AffinityTopologyVersion topVer;
/** Context. */
private final GridCacheContext cctx;
/** Key. */
private final KeyCacheObject key;
/** Read through flag. */
private final boolean readThrough;
/** Force primary flag. */
private final boolean forcePrimary;
/** Future ID. */
private final IgniteUuid futId;
/** Trackable flag. */
private boolean trackable;
/** Task name. */
private final String taskName;
/** Whether to deserialize binary objects. */
private final boolean deserializeBinary;
/** Skip values flag. */
private final boolean skipVals;
/** Expiry policy. */
private final IgniteCacheExpiryPolicy expiryPlc;
/** Flag indicating that get should be done on a locked topology version. */
private final boolean canRemap;
/** */
private final boolean needVer;
/** */
private final boolean keepCacheObjects;
/** */
private final boolean recovery;
/** */
@GridToStringInclude
private ClusterNode node;
/** Deployment class loader id which will be used for deserialization of entries on a distributed task. */
@GridToStringExclude
protected final IgniteUuid deploymentLdrId;
/** Post processing closure. */
private volatile BackupPostProcessingClosure postProcessingClos;
/** Transaction label. */
private final String txLbl;
/** Invalid mappened nodes. */
private Set<ClusterNode> invalidNodes = Collections.emptySet();
/** Remap count. */
protected volatile int remapCnt;
/**
* @param cctx Context.
* @param key Key.
* @param topVer Topology version.
* @param readThrough Read through flag.
* @param forcePrimary If {@code true} then will force network trip to primary node even if called on backup node.
* @param taskName Task name.
* @param deserializeBinary Deserialize binary flag.
* @param expiryPlc Expiry policy.
* @param skipVals Skip values flag.
* @param needVer If {@code true} returns values as tuples containing value and version.
* @param keepCacheObjects Keep cache objects flag.
* @param txLbl Transaction label.
*/
public GridPartitionedSingleGetFuture(
GridCacheContext cctx,
KeyCacheObject key,
AffinityTopologyVersion topVer,
boolean readThrough,
boolean forcePrimary,
String taskName,
boolean deserializeBinary,
@Nullable IgniteCacheExpiryPolicy expiryPlc,
boolean skipVals,
boolean needVer,
boolean keepCacheObjects,
boolean recovery,
String txLbl
) {
assert key != null;
AffinityTopologyVersion lockedTopVer = cctx.shared().lockedTopologyVersion(null);
if (lockedTopVer != null) {
topVer = lockedTopVer;
canRemap = false;
}
else
canRemap = true;
this.cctx = cctx;
this.key = key;
this.readThrough = readThrough;
this.forcePrimary = forcePrimary;
this.taskName = taskName;
this.deserializeBinary = deserializeBinary;
this.expiryPlc = expiryPlc;
this.skipVals = skipVals;
this.needVer = needVer;
this.keepCacheObjects = keepCacheObjects;
this.recovery = recovery;
this.topVer = topVer;
deploymentLdrId = U.contextDeploymentClassLoaderId(cctx.kernalContext());
this.txLbl = txLbl;
futId = IgniteUuid.randomUuid();
if (log == null)
log = U.logger(cctx.kernalContext(), logRef, GridPartitionedSingleGetFuture.class);
}
/**
* Initialize future.
*/
public void init() {
AffinityTopologyVersion mappingTopVer;
if (topVer.topologyVersion() > 0)
mappingTopVer = topVer;
else {
mappingTopVer = canRemap ?
cctx.affinity().affinityTopologyVersion() :
cctx.shared().exchange().readyAffinityVersion();
}
map(mappingTopVer);
}
/**
* @param topVer Topology version.
*/
@SuppressWarnings("unchecked")
private void map(AffinityTopologyVersion topVer) {
GridDhtPartitionsExchangeFuture fut = cctx.shared().exchange().lastTopologyFuture();
// Finished DHT future is required for topology validation.
if (!fut.isDone()) {
if (fut.initialVersion().after(topVer) || (fut.exchangeActions() != null && fut.exchangeActions().hasStop()))
fut = cctx.shared().exchange().lastFinishedFuture();
else {
fut.listen(new IgniteInClosure<IgniteInternalFuture<AffinityTopologyVersion>>() {
@Override public void apply(IgniteInternalFuture<AffinityTopologyVersion> fut) {
if (fut.error() != null)
onDone(fut.error());
else {
cctx.closures().runLocalSafe(new GridPlainRunnable() {
@Override public void run() {
map(topVer);
}
}, true);
}
}
});
return;
}
}
if (!validate(fut))
return;
ClusterNode node = mapKeyToNode(topVer);
if (node == null) {
assert isDone() : this;
return;
}
if (isDone())
return;
// Read value if node is localNode.
if (node.isLocal()) {
GridDhtFuture<GridCacheEntryInfo> fut0 = cctx.dht()
.getDhtSingleAsync(
node.id(),
-1,
key,
false,
readThrough,
topVer,
taskName == null ? 0 : taskName.hashCode(),
expiryPlc,
skipVals,
recovery,
txLbl
);
Collection<Integer> invalidParts = fut0.invalidPartitions();
if (!F.isEmpty(invalidParts)) {
addNodeAsInvalid(node);
AffinityTopologyVersion updTopVer = cctx.shared().exchange().readyAffinityVersion();
// Remap recursively.
map(updTopVer);
}
else {
fut0.listen(() -> {
try {
GridCacheEntryInfo info = fut0.get();
setResult(info);
}
catch (Exception e) {
U.error(log, "Failed to get values from dht cache [fut=" + fut0 + "]", e);
onDone(e);
}
});
}
}
else {
synchronized (this) {
assert this.node == null;
this.topVer = topVer;
this.node = node;
}
registrateFutureInMvccManager(this);
boolean needVer = this.needVer;
BackupPostProcessingClosure postClos = CU.createBackupPostProcessingClosure(topVer, log,
cctx, key, expiryPlc, readThrough && cctx.readThroughConfigured(), skipVals);
if (postClos != null) {
// Need version to correctly store value.
needVer = true;
postProcessingClos = postClos;
}
GridCacheMessage req = new GridNearSingleGetRequest(
cctx.cacheId(),
futId.localId(),
key,
readThrough,
topVer,
taskName == null ? 0 : taskName.hashCode(),
expiryPlc != null ? expiryPlc.forCreate() : -1L,
expiryPlc != null ? expiryPlc.forAccess() : -1L,
skipVals,
/*add reader*/false,
needVer,
cctx.deploymentEnabled(),
recovery,
txLbl
);
try {
cctx.io().send(node, req, cctx.ioPolicy());
}
catch (IgniteCheckedException e) {
if (e instanceof ClusterTopologyCheckedException)
onNodeLeft(node.id());
else
onDone(e);
}
}
}
/**
* @param topVer Topology version.
* @return Primary node or {@code null} if future was completed.
*/
@Nullable private ClusterNode mapKeyToNode(AffinityTopologyVersion topVer) {
int part = cctx.affinity().partition(key);
List<ClusterNode> affNodes = cctx.affinity().nodesByPartition(part, topVer);
// Failed if none affinity node found by assignment.
if (affNodes.isEmpty()) {
onDone(serverNotFoundError(part, topVer));
return null;
}
// Try to read key locally if we can.
if (tryLocalGet(key, part, topVer, affNodes))
return null;
ClusterNode affNode = cctx.selectAffinityNodeBalanced(affNodes, getInvalidNodes(), part, canRemap,
forcePrimary);
// Failed if none balanced node found.
if (affNode == null) {
onDone(serverNotFoundError(part, topVer));
return null;
}
return affNode;
}
/**
*
* @param key Key.
* @param part Partition.
* @param topVer Topology version.
* @param affNodes Affynity nodes.
*/
private boolean tryLocalGet(
KeyCacheObject key,
int part,
AffinityTopologyVersion topVer,
List<ClusterNode> affNodes
) {
boolean fastLocGet = (!forcePrimary || affNodes.get(0).isLocal()) && cctx.reserveForFastLocalGet(part, topVer);
if (fastLocGet) {
try {
if (localGet(topVer, key, part))
return true;
}
finally {
cctx.releaseForFastLocalGet(part, topVer);
}
}
return false;
}
/**
* @param topVer Topology version.
* @param part Partition.
* @return {@code True} if future completed.
*/
private boolean localGet(AffinityTopologyVersion topVer, KeyCacheObject key, int part) {
assert cctx.affinityNode() : this;
GridDhtCacheAdapter colocated = cctx.dht();
boolean readNoEntry = cctx.readNoEntry(expiryPlc, false);
boolean evt = !skipVals;
while (true) {
cctx.shared().database().checkpointReadLock();
try {
CacheObject v = null;
GridCacheVersion ver = null;
boolean skipEntry = readNoEntry;
if (readNoEntry) {
KeyCacheObject key0 = (KeyCacheObject)cctx.cacheObjects().prepareForCache(key, cctx);
CacheDataRow row = cctx.offheap().read(cctx, key0);
if (row != null) {
long expireTime = row.expireTime();
if (expireTime == 0 || expireTime > U.currentTimeMillis()) {
v = row.value();
if (needVer)
ver = row.version();
if (evt) {
cctx.events().readEvent(key,
null,
txLbl,
row.value(),
taskName,
!deserializeBinary);
}
}
else
skipEntry = false;
}
}
if (!skipEntry) {
GridCacheEntryEx entry = colocated.entryEx(key);
// If our DHT cache do has value, then we peek it.
if (entry != null) {
boolean isNew = entry.isNewLocked();
if (needVer) {
EntryGetResult res = entry.innerGetVersioned(
null,
null,
/*update-metrics*/false,
/*event*/evt,
null,
taskName,
expiryPlc,
true,
null);
if (res != null) {
v = res.value();
ver = res.version();
}
}
else {
v = entry.innerGet(
null,
null,
/*read-through*/false,
/*update-metrics*/false,
/*event*/evt,
null,
taskName,
expiryPlc,
true);
}
entry.touch();
// Entry was not in memory or in swap, so we remove it from cache.
if (v == null) {
if (isNew && entry.markObsoleteIfEmpty(ver))
colocated.removeEntry(entry);
}
}
}
if (v != null) {
if (!skipVals && cctx.statisticsEnabled())
cctx.cache().metrics0().onRead(true);
if (!skipVals)
setResult(v, ver);
else
setSkipValueResult(true, ver);
return true;
}
boolean topStable = cctx.isReplicated() || topVer.equals(cctx.topology().lastTopologyChangeVersion());
// Entry not found, complete future with null result if topology did not change and there is no store.
if (!cctx.readThroughConfigured() && (topStable || partitionOwned(part))) {
if (!skipVals && cctx.statisticsEnabled())
colocated.metrics0().onRead(false);
if (skipVals)
setSkipValueResult(false, null);
else
setResult(null, null);
return true;
}
return false;
}
catch (GridCacheEntryRemovedException ignored) {
// No-op, will retry.
}
catch (GridDhtInvalidPartitionException ignored) {
return false;
}
catch (IgniteCheckedException e) {
onDone(e);
return true;
}
finally {
cctx.shared().database().checkpointReadUnlock();
}
}
}
/**
* @param fut Future.
*/
private void registrateFutureInMvccManager(GridCacheFuture<?> fut) {
if (!trackable) {
trackable = true;
cctx.mvcc().addFuture(fut, futId);
}
}
/**
* @param nodeId Node ID.
* @param res Result.
*/
public void onResult(UUID nodeId, GridNearSingleGetResponse res) {
// Brake here if response from unexpected node.
if (!processResponse(nodeId))
return;
// Brake here if exception was throws on remote node or
// parition on remote node is invalid.
if (!checkError(nodeId, res.invalidPartitions(), res.topologyVersion(), res.error()))
return;
Message res0 = res.result();
if (needVer) {
CacheVersionedValue verVal = (CacheVersionedValue)res0;
if (verVal != null) {
if (skipVals)
setSkipValueResult(true, verVal.version());
else
setResult(verVal.value(), verVal.version());
}
else {
if (skipVals)
setSkipValueResult(false, null);
else
setResult(null, null);
}
}
else {
if (skipVals)
setSkipValueResult(res.containsValue(), null);
else if (readThrough && res0 instanceof CacheVersionedValue) {
// Could be versioned value for store in backup.
CacheVersionedValue verVal = (CacheVersionedValue)res0;
setResult(verVal.value(), verVal.version());
}
else
setResult((CacheObject)res0, null);
}
}
/** {@inheritDoc} */
@Override public void onResult(UUID nodeId, GridNearGetResponse res) {
// Brake here if response from unexpected node.
if (!processResponse(nodeId))
return;
// Brake here if exception was throws on remote node or
// parition on remote node is invalid.
if (!checkError(nodeId, !F.isEmpty(res.invalidPartitions()), res.topologyVersion(), res.error()))
return;
Collection<GridCacheEntryInfo> infos = res.entries();
assert F.isEmpty(infos) || infos.size() == 1 : infos;
setResult(F.first(infos));
}
/**
* @param nodeId Node ID.
* @return {@code True} if should process received response.
*/
private boolean processResponse(UUID nodeId) {
synchronized (this) {
if (node != null && node.id().equals(nodeId)) {
node = null;
return true;
}
}
return false;
}
/**
* @param err Error.
* @param invalidParts Invalid partitions error flag.
* @param rmtTopVer Received topology version.
* @param nodeId Node ID.
* @return {@code True} if should process received response.
*/
private boolean checkError(
UUID nodeId,
boolean invalidParts,
AffinityTopologyVersion rmtTopVer,
@Nullable IgniteCheckedException err
) {
if (err != null) {
onDone(err);
return false;
}
if (invalidParts) {
addNodeAsInvalid(cctx.node(nodeId));
if (canRemap)
awaitVersionAndRemap(rmtTopVer);
else
map(topVer);
return false;
}
return true;
}
/**
* @param info Entry info.
*/
private void setResult(@Nullable GridCacheEntryInfo info) {
assert info == null || skipVals == (info.value() == null);
if (skipVals) {
if (info != null)
setSkipValueResult(true, info.version());
else
setSkipValueResult(false, null);
}
else {
if (info != null)
setResult(info.value(), info.version());
else
setResult(null, null);
}
}
/**
* @param res Result.
* @param ver Version.
*/
private void setSkipValueResult(boolean res, @Nullable GridCacheVersion ver) {
assert skipVals;
if (needVer) {
assert ver != null || !res;
onDone(new EntryGetResult(res, ver));
}
else
onDone(res);
}
/**
* @param val Value.
* @param ver Version.
*/
private void setResult(@Nullable CacheObject val, @Nullable GridCacheVersion ver) {
cctx.shared().database().checkpointReadLock();
try {
assert !skipVals;
if (val != null) {
if (postProcessingClos != null)
postProcessingClos.apply(val, ver);
if (!keepCacheObjects) {
Object res = cctx.unwrapBinaryIfNeeded(
val,
!deserializeBinary,
true,
U.deploymentClassLoader(cctx.kernalContext(), deploymentLdrId)
);
onDone(needVer ? new EntryGetResult(res, ver) : res);
}
else
onDone(needVer ? new EntryGetResult(val, ver) : val);
}
else
onDone(null);
}
catch (Exception e) {
onDone(e);
}
finally {
cctx.shared().database().checkpointReadUnlock();
}
}
/**
* @param part Partition.
* @return {@code True} if partition is in owned state.
*/
private boolean partitionOwned(int part) {
return cctx.topology().partitionState(cctx.localNodeId(), part) == OWNING;
}
/**
* @param node Invalid node.
*/
private synchronized void addNodeAsInvalid(ClusterNode node) {
if (invalidNodes == Collections.<ClusterNode>emptySet())
invalidNodes = new HashSet<>();
invalidNodes.add(node);
}
/**
* @return Set of invalid cluster nodes.
*/
protected synchronized Set<ClusterNode> getInvalidNodes() {
return invalidNodes;
}
/**
* @param topVer Topology version.
*/
private boolean checkRetryPermits(AffinityTopologyVersion topVer) {
if (topVer.equals(this.topVer))
return true;
if (REMAP_CNT_UPD.incrementAndGet(this) > MAX_REMAP_CNT) {
ClusterNode node0 = node;
onDone(new ClusterTopologyCheckedException("Failed to remap key to a new node after " +
MAX_REMAP_CNT + " attempts (key got remapped to the same node) [key=" + key + ", node=" +
(node0 != null ? U.toShortString(node0) : null) + ", invalidNodes=" + invalidNodes + ']'));
return false;
}
return true;
}
/**
* @param part Partition.
* @param topVer Topology version.
* @return Exception.
*/
private ClusterTopologyServerNotFoundException serverNotFoundError(int part, AffinityTopologyVersion topVer) {
return new ClusterTopologyServerNotFoundException("Failed to map keys for cache " +
"(all partition nodes left the grid) [topVer=" + topVer + ", part=" + part + ", cache=" + cctx.name() + ']');
}
/**
* @param topFut Ready topology future for validation.
* @return True if validate success, False is not.
*/
private boolean validate(GridDhtTopologyFuture topFut) {
assert topFut.isDone() : topFut;
if (!checkRetryPermits(topFut.topologyVersion()))
return false;
Throwable error = topFut.validateCache(cctx, recovery, true, key, null);
if (error != null) {
onDone(error);
return false;
}
else
return true;
}
/** {@inheritDoc} */
@Override public IgniteUuid futureId() {
return futId;
}
/** {@inheritDoc} */
@Override public boolean onNodeLeft(UUID nodeId) {
if (!processResponse(nodeId))
return false;
if (canRemap) {
long maxTopVer = Math.max(topVer.topologyVersion() + 1, cctx.discovery().topologyVersion());
awaitVersionAndRemap(new AffinityTopologyVersion(maxTopVer));
}
else
remap(topVer);
return true;
}
/**
* @param topVer Topology version.
*/
private void awaitVersionAndRemap(AffinityTopologyVersion topVer) {
IgniteInternalFuture<AffinityTopologyVersion> awaitTopVerFut = cctx.shared().exchange().affinityReadyFuture(topVer);
awaitTopVerFut.listen(() -> {
try {
remap(awaitTopVerFut.get());
}
catch (IgniteCheckedException e) {
onDone(e);
}
});
}
/**
* @param topVer Topology version.
*/
private void remap(final AffinityTopologyVersion topVer) {
cctx.closures().runLocalSafe(new GridPlainRunnable() {
@Override public void run() {
// If topology changed reset collection of invalid nodes.
synchronized (this) {
invalidNodes = Collections.emptySet();
}
map(topVer);
}
});
}
/** {@inheritDoc} */
@Override public boolean onDone(Object res, Throwable err) {
if (super.onDone(res, err)) {
// Don't forget to clean up.
if (trackable)
cctx.mvcc().removeFuture(futId);
if (!(err instanceof NodeStoppingException))
cctx.dht().sendTtlUpdateRequest(expiryPlc);
return true;
}
return false;
}
/** {@inheritDoc} */
@Override public boolean trackable() {
return trackable;
}
/** {@inheritDoc} */
@Override public void markNotTrackable() {
// No-op.
}
/** {@inheritDoc} */
@Override public void addDiagnosticRequest(IgniteDiagnosticPrepareContext ctx) {
if (!isDone()) {
UUID nodeId;
AffinityTopologyVersion topVer;
synchronized (this) {
nodeId = node != null ? node.id() : null;
topVer = this.topVer;
}
if (nodeId != null)
ctx.basicInfo(nodeId, "GridPartitionedSingleGetFuture waiting for " +
"response [node=" + nodeId +
", key=" + key +
", futId=" + futId +
", topVer=" + topVer + ']');
}
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(GridPartitionedSingleGetFuture.class, this, "super", super.toString());
}
}