entry : msg.partitions().entrySet()) {
Integer grpId = entry.getKey();
@@ -1699,7 +1744,7 @@ else if (!grp.isLocal())
entry.getValue(),
null,
msg.partsToReload(cctx.localNodeId(), grpId),
- msg.partitionSizes(grpId),
+ partsSizes.getOrDefault(grpId, Collections.emptyMap()),
msg.topologyVersion());
}
}
@@ -2434,7 +2479,7 @@ public void exchangerBlockingSectionEnd() {
}
/** */
- private boolean currentThreadIsExchanger() {
+ public boolean currentThreadIsExchanger() {
return exchWorker != null && Thread.currentThread() == exchWorker.runner();
}
@@ -3342,4 +3387,124 @@ private AffinityReadyFuture(AffinityTopologyVersion topVer) {
return S.toString(AffinityReadyFuture.class, this, super.toString());
}
}
+
+ /**
+ * That wrapper class allows avoiding the propagation of the user's exceptions into the Exchange thread.
+ */
+ private class PartitionsExchangeAwareWrapper implements PartitionsExchangeAware {
+ /** */
+ private final PartitionsExchangeAware delegate;
+
+ /**
+ * Creates a new wrapper.
+ * @param delegate Delegate.
+ */
+ public PartitionsExchangeAwareWrapper(PartitionsExchangeAware delegate) {
+ this.delegate = delegate;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onInitBeforeTopologyLock(GridDhtPartitionsExchangeFuture fut) {
+ try {
+ delegate.onInitBeforeTopologyLock(fut);
+ }
+ catch (Exception e) {
+ U.warn(log, "Failed to execute exchange callback.", e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onInitAfterTopologyLock(GridDhtPartitionsExchangeFuture fut) {
+ try {
+ delegate.onInitAfterTopologyLock(fut);
+ }
+ catch (Exception e) {
+ U.warn(log, "Failed to execute exchange callback.", e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onDoneBeforeTopologyUnlock(GridDhtPartitionsExchangeFuture fut) {
+ try {
+ delegate.onDoneBeforeTopologyUnlock(fut);
+ }
+ catch (Exception e) {
+ U.warn(log, "Failed to execute exchange callback.", e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onDoneAfterTopologyUnlock(GridDhtPartitionsExchangeFuture fut) {
+ try {
+ delegate.onDoneAfterTopologyUnlock(fut);
+ }
+ catch (Exception e) {
+ U.warn(log, "Failed to execute exchange callback.", e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return delegate.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
+ @Override public boolean equals(Object obj) {
+ return delegate.equals(obj);
+ }
+ }
+
+ /**
+ * Class to limit action count for unique objects.
+ *
+ * NO guarantees of thread safety are provided.
+ */
+ private static class ActionLimiter {
+ /** */
+ private final int limit;
+
+ /**
+ * Internal storage of objects and counters for each of object.
+ */
+ private final Map actionsCnt = new HashMap<>();
+
+ /**
+ * Set of active objects.
+ */
+ private final Set activeObjects = new HashSet<>();
+
+ /**
+ * @param limit Limit.
+ */
+ private ActionLimiter(int limit) {
+ this.limit = limit;
+ }
+
+ /**
+ * Shows if action is allowed for the given object. Adds this object to internal set of active
+ * objects that are still in use.
+ *
+ * @param obj object.
+ */
+ boolean allowAction(T obj) {
+ activeObjects.add(obj);
+
+ int cnt = actionsCnt.computeIfAbsent(obj, o -> new AtomicInteger(0))
+ .incrementAndGet();
+
+ return (cnt <= limit);
+ }
+
+ /**
+ * Removes old objects from limiter's internal storage. All objects that are contained in internal
+ * storage but not in set of active objects, are assumed as 'old'. This method is to be called
+ * after processing of collection of objects to purge limiter's internal storage.
+ */
+ void trim() {
+ actionsCnt.keySet().removeIf(key -> !activeObjects.contains(key));
+
+ activeObjects.clear();
+ }
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTxFinishSync.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTxFinishSync.java
index 1f688f64cc9e2..514e78e898086 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTxFinishSync.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTxFinishSync.java
@@ -29,7 +29,6 @@
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.util.future.GridFinishedFuture;
import org.apache.ignite.internal.util.future.GridFutureAdapter;
-import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.lang.IgniteFuture;
import org.jetbrains.annotations.Nullable;
@@ -66,9 +65,16 @@ public void onFinishSend(UUID nodeId, long threadId) {
ThreadFinishSync threadSync = threadMap.get(threadId);
if (threadSync == null)
- threadSync = F.addIfAbsent(threadMap, threadId, new ThreadFinishSync(threadId));
+ threadMap.put(threadId, threadSync = new ThreadFinishSync(threadId));
- threadSync.onSend(nodeId);
+ synchronized (threadSync) {
+ //thread has to create new ThreadFinishSync
+ //if other thread executing onAckReceived method removed previous threadSync object
+ if (threadMap.get(threadId) == null)
+ threadMap.put(threadId, threadSync = new ThreadFinishSync(threadId));
+
+ threadSync.onSend(nodeId);
+ }
}
/**
@@ -104,8 +110,14 @@ public void onDisconnected(IgniteFuture> reconnectFut) {
public void onAckReceived(UUID nodeId, long threadId) {
ThreadFinishSync threadSync = threadMap.get(threadId);
- if (threadSync != null)
+ if (threadSync != null) {
threadSync.onReceive(nodeId);
+
+ synchronized (threadSync) {
+ if (threadSync.isEmpty())
+ threadMap.remove(threadId);
+ }
+ }
}
/**
@@ -114,8 +126,14 @@ public void onAckReceived(UUID nodeId, long threadId) {
* @param nodeId Left node ID.
*/
public void onNodeLeft(UUID nodeId) {
- for (ThreadFinishSync threadSync : threadMap.values())
+ for (ThreadFinishSync threadSync : threadMap.values()) {
threadSync.onNodeLeft(nodeId);
+
+ synchronized (threadSync) {
+ if (threadSync.isEmpty())
+ threadMap.remove(threadSync);
+ }
+ }
}
/**
@@ -193,7 +211,7 @@ public void onDisconnected(IgniteFuture> reconnectFut) {
* @param nodeId Node ID response received from.
*/
public void onReceive(UUID nodeId) {
- TxFinishSync sync = nodeMap.get(nodeId);
+ TxFinishSync sync = nodeMap.remove(nodeId);
if (sync != null)
sync.onReceive();
@@ -208,6 +226,13 @@ public void onNodeLeft(UUID nodeId) {
if (sync != null)
sync.onNodeLeft();
}
+
+ /**
+ *
+ */
+ private boolean isEmpty() {
+ return nodeMap.isEmpty();
+ }
}
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java
index 0db9b4e79a4df..ad83cbe967fb4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java
@@ -126,6 +126,10 @@ public abstract class GridDistributedTxRemoteAdapter extends IgniteTxAdapter
/** {@code True} if tx should skip adding itself to completed version map on finish. */
private boolean skipCompletedVers;
+ /** Transaction label. */
+ @GridToStringInclude
+ @Nullable private String txLbl;
+
/**
* Empty constructor required for {@link Externalizable}.
*/
@@ -147,6 +151,7 @@ public GridDistributedTxRemoteAdapter() {
* @param txSize Expected transaction size.
* @param subjId Subject ID.
* @param taskNameHash Task name hash code.
+ * @param txLbl Transaction label.
*/
public GridDistributedTxRemoteAdapter(
GridCacheSharedContext, ?> ctx,
@@ -161,7 +166,8 @@ public GridDistributedTxRemoteAdapter(
long timeout,
int txSize,
@Nullable UUID subjId,
- int taskNameHash
+ int taskNameHash,
+ String txLbl
) {
super(
ctx,
@@ -179,6 +185,7 @@ public GridDistributedTxRemoteAdapter(
taskNameHash);
this.invalidate = invalidate;
+ this.txLbl = txLbl;
commitVersion(commitVer);
@@ -996,6 +1003,11 @@ protected void addExplicit(IgniteTxEntry e) {
}
}
+ /** {@inheritDoc} */
+ @Override public String label() {
+ return txLbl;
+ }
+
/** {@inheritDoc} */
@Override public String toString() {
return GridToStringBuilder.toString(GridDistributedTxRemoteAdapter.class, this, "super", super.toString());
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
index c24d48f9029c6..a5303fc5dad37 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
@@ -788,6 +788,7 @@ else if (log.isDebugEnabled())
* @param taskName Task name.
* @param expiry Expiry policy.
* @param skipVals Skip values flag.
+ * @param txLbl Transaction label.
* @param mvccSnapshot MVCC snapshot.
* @return Get future.
*/
@@ -800,6 +801,7 @@ IgniteInternalFuture