Hi Evgeniy,
I've fixed the issue.
PFA a patch.
On Tue, Apr 4, 2017 at 12:23 AM, Andrey Mashenkov <
[email protected]> wrote:
> Hi Evgeniy,
>
> Looks like a bug. I've created a ticket [1].
> Seems, this reporoduced only when service deployment with dynamic
> approach. When Ignite starts with service configured - all looks fine for
> me.
>
> [1] https://issues.apache.org/jira/browse/IGNITE-4907
>
> On Mon, Apr 3, 2017 at 4:26 PM, Evgeniy Ignatiev <
> [email protected]> wrote:
>
>> Hello.
>>
>> Recently we discovered that if a service is configured in
>> IgniteConfiguration with e.g. maxPerNodeCount equal to 1 and totalCount
>> equal to 3, we start-up 2 Ignite nodes - then cancel the service after some
>> time and redeploy it with the same config as ignite.services().deploy(...)
>> - we observe more than instance of service starting per node.
>>
>> Here is a minimal code that demonstrates this issue:
>> https://github.com/YevIgn/ignite-services-bug - After the call to
>> ignite.services().deploy(...) - the output to console is "Started 3
>> services" while "Started 2 services" is expected as there are only two
>> nodes. This is with the Ignite 1.9.0.
>>
>> Could you please look into it?
>>
>>
>>
>
>
> --
> Best regards,
> Andrey V. Mashenkov
>
--
Best regards,
Andrey V. Mashenkov
Index: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceProcessorMultiNodeSelfTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceProcessorMultiNodeSelfTest.java (date 1491479030000)
+++ modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceProcessorMultiNodeSelfTest.java (date 1491990083000)
@@ -264,4 +264,65 @@
stopGrid("client");
}
}
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testDeployLimits() throws Exception {
+ String name = "serviceWithLimitsUpdateTopology";
+
+ Ignite g = randomGrid();
+
+ final int totalInstances = nodeCount() + 1;
+
+ CountDownLatch latch = new CountDownLatch(nodeCount());
+
+ DummyService.exeLatch(name, latch);
+
+ ServiceConfiguration srvcCfg = new ServiceConfiguration();
+
+ srvcCfg.setName(name);
+ srvcCfg.setMaxPerNodeCount(1);
+ srvcCfg.setTotalCount(totalInstances);
+ srvcCfg.setService(new DummyService());
+
+ IgniteServices svcs = g.services().withAsync();
+
+ svcs.deploy(srvcCfg);
+
+ IgniteFuture<?> fut = svcs.future();
+
+ info("Deployed service: " + name);
+
+ fut.get();
+
+ info("Finished waiting for service future: " + name);
+
+ latch.await();
+
+ TestCase.assertEquals(name, nodeCount(), DummyService.started(name));
+ TestCase.assertEquals(name, 0, DummyService.cancelled(name));
+
+ checkCount(name, g.services().serviceDescriptors(), nodeCount());
+
+ int extraNodes = 2;
+
+ latch = new CountDownLatch(1);
+
+ DummyService.exeLatch(name, latch);
+
+ startExtraNodes(2);
+
+ try {
+ latch.await();
+
+ TestCase.assertEquals(name, totalInstances, DummyService.started(name));
+ TestCase.assertEquals(name, 0, DummyService.cancelled(name));
+
+ checkCount(name, g.services().serviceDescriptors(), totalInstances);
+ }
+ finally {
+ stopExtraNodes(extraNodes);
+ }
+ }
}
\ No newline at end of file
Index: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceProcessorMultiNodeConfigSelfTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceProcessorMultiNodeConfigSelfTest.java (date 1488459441000)
+++ modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceProcessorMultiNodeConfigSelfTest.java (revision )
@@ -17,8 +17,11 @@
package org.apache.ignite.internal.processors.service;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.ignite.Ignite;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
import org.apache.ignite.internal.util.lang.GridAbsPredicateX;
import org.apache.ignite.services.ServiceConfiguration;
import org.apache.ignite.testframework.GridTestUtils;
@@ -33,6 +36,9 @@
/** Node singleton name. */
private static final String NODE_SINGLE = "serviceConfigEachNode";
+ /** Node singleton name. */
+ private static final String NODE_SINGLE_WITH_LIMIT = "serviceConfigWithLimit";
+
/** Affinity service name. */
private static final String AFFINITY = "serviceConfigAffinity";
@@ -46,7 +52,7 @@
/** {@inheritDoc} */
@Override protected ServiceConfiguration[] services() {
- ServiceConfiguration[] arr = new ServiceConfiguration[3];
+ List<ServiceConfiguration> cfgs = new ArrayList<>();
ServiceConfiguration cfg = new ServiceConfiguration();
@@ -55,7 +61,7 @@
cfg.setTotalCount(1);
cfg.setService(new DummyService());
- arr[0] = cfg;
+ cfgs.add(cfg);
cfg = new ServiceConfiguration();
@@ -63,7 +69,7 @@
cfg.setMaxPerNodeCount(1);
cfg.setService(new DummyService());
- arr[1] = cfg;
+ cfgs.add(cfg);
cfg = new ServiceConfiguration();
@@ -74,9 +80,18 @@
cfg.setTotalCount(1);
cfg.setService(new AffinityService(AFFINITY_KEY));
- arr[2] = cfg;
+ cfgs.add(cfg);
- return arr;
+ cfg = new ServiceConfiguration();
+
+ cfg.setName(NODE_SINGLE_WITH_LIMIT);
+ cfg.setMaxPerNodeCount(1);
+ cfg.setTotalCount(nodeCount() + 1);
+ cfg.setService(new DummyService());
+
+ cfgs.add(cfg);
+
+ return cfgs.toArray(new ServiceConfiguration[cfgs.size()]);
}
/** {@inheritDoc} */
@@ -91,6 +106,8 @@
DummyService.cancelled(CLUSTER_SINGLE) == 0 &&
DummyService.started(NODE_SINGLE) == nodeCount() &&
DummyService.cancelled(NODE_SINGLE) == 0 &&
+ DummyService.started(NODE_SINGLE_WITH_LIMIT) >= nodeCount() &&
+ DummyService.cancelled(NODE_SINGLE_WITH_LIMIT) == 0 &&
actualCount(AFFINITY, randomGrid().services().serviceDescriptors()) == 1;
}
},
@@ -143,6 +160,59 @@
finally {
stopExtraNodes(nodeCnt);
}
+
+ checkCount(AFFINITY, g.services().serviceDescriptors(), 1);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testDeployLimits() throws Exception {
+ final Ignite g = randomGrid();
+
+ final String name = NODE_SINGLE_WITH_LIMIT;
+
+ waitForDeployment(name, nodeCount());
+
+ checkCount(name, g.services().serviceDescriptors(), nodeCount());
+
+ int extraNodes = 2;
+
+ CountDownLatch latch = new CountDownLatch(1);
+
+ DummyService.exeLatch(name, latch);
+
+ startExtraNodes(extraNodes);
+
+ try {
+ latch.await();
+
+ checkCount(name, g.services().serviceDescriptors(), nodeCount() + 1);
+ }
+ finally {
+ stopExtraNodes(extraNodes);
+ }
+
+ assertEquals(name, 1, DummyService.cancelled(name));
+
+ waitForDeployment(name, nodeCount());
+
+ checkCount(name, g.services().serviceDescriptors(), nodeCount());
+ }
+
+ /**
+ * @param srvcName Service name
+ * @param expectedDeps Expected number of service deployments
+ *
+ */
+ private boolean waitForDeployment(final String srvcName, final int expectedDeps) throws IgniteInterruptedCheckedException {
+ final Ignite g = randomGrid();
+
+ return GridTestUtils.waitForCondition(new GridAbsPredicateX() {
+ @Override public boolean applyx() {
+ return actualCount(srvcName, g.services().serviceDescriptors()) == expectedDeps;
+ }
+ }, 1500);
}
/**
@@ -195,5 +265,9 @@
finally {
stopExtraNodes(newNodes);
}
+
+ waitForDeployment(name, nodeCount());
+
+ checkCount(name, g.services().serviceDescriptors(), nodeCount());
}
}
\ No newline at end of file
Index: modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java (date 1491479030000)
+++ modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java (date 1491990083000)
@@ -972,7 +972,7 @@
int perNodeCnt = totalCnt != 0 ? totalCnt / size : maxPerNodeCnt;
int remainder = totalCnt != 0 ? totalCnt % size : 0;
- if (perNodeCnt > maxPerNodeCnt && maxPerNodeCnt != 0) {
+ if (perNodeCnt >= maxPerNodeCnt && maxPerNodeCnt != 0) {
perNodeCnt = maxPerNodeCnt;
remainder = 0;
}