You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by bb...@apache.org on 2016/09/08 14:48:52 UTC
nifi git commit: NIFI-1966: Recreated issue that is outlined in JIRA
(the reason for re-opening the ticket) that results in
'java.util.NoSuchElementException: No value present' in unit test - Resolved
issue where two flows that are both empty but have di
Repository: nifi
Updated Branches:
refs/heads/master d36b76cc6 -> bc7c42efa
NIFI-1966: Recreated issue that is outlined in JIRA (the reason for re-opening the ticket) that results in 'java.util.NoSuchElementException: No value present' in unit test - Resolved issue where two flows that are both empty but have different fingerprints (due to root group id being different) causes vote election to fail
This closes #995.
Signed-off-by: Bryan Bende <bb...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/bc7c42ef
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/bc7c42ef
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/bc7c42ef
Branch: refs/heads/master
Commit: bc7c42efa53b363741a974a7fcf25e04f9208086
Parents: d36b76c
Author: Mark Payne <ma...@hotmail.com>
Authored: Wed Sep 7 21:07:01 2016 -0400
Committer: Bryan Bende <bb...@apache.org>
Committed: Thu Sep 8 10:48:24 2016 -0400
----------------------------------------------------------------------
.../flow/PopularVoteFlowElection.java | 22 +++++++++--
.../flow/TestPopularVoteFlowElection.java | 40 ++++++++++++++++++++
.../resources/conf/different-empty-flow.xml | 27 +++++++++++++
3 files changed, 85 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/nifi/blob/bc7c42ef/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/flow/PopularVoteFlowElection.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/flow/PopularVoteFlowElection.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/flow/PopularVoteFlowElection.java
index bc730d8..b9df55e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/flow/PopularVoteFlowElection.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/flow/PopularVoteFlowElection.java
@@ -23,10 +23,12 @@ import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
import org.apache.nifi.cluster.protocol.DataFlow;
import org.apache.nifi.cluster.protocol.NodeIdentifier;
@@ -156,12 +158,24 @@ public class PopularVoteFlowElection implements FlowElection {
return null;
}
+ final List<FlowCandidate> nonEmptyCandidates = candidateByFingerprint.values().stream()
+ .filter(candidate -> !candidate.isFlowEmpty())
+ .collect(Collectors.toList());
+
+ if (nonEmptyCandidates.isEmpty()) {
+ // All flow candidates are empty flows. Just use one of them.
+ final FlowCandidate electedCandidate = candidateByFingerprint.values().iterator().next();
+ this.electedDataFlow = electedCandidate.getDataFlow();
+ return electedCandidate;
+ }
+
final FlowCandidate elected;
- if (candidateByFingerprint.size() == 1) {
- elected = candidateByFingerprint.values().iterator().next();
+ if (nonEmptyCandidates.size() == 1) {
+ // Only one flow is non-empty. Use that one.
+ elected = nonEmptyCandidates.iterator().next();
} else {
- elected = candidateByFingerprint.values().stream()
- .filter(candidate -> !candidate.isFlowEmpty()) // We have more than 1 fingerprint. Do not consider empty flows.
+ // Choose the non-empty flow that got the most votes.
+ elected = nonEmptyCandidates.stream()
.max((candidate1, candidate2) -> Integer.compare(candidate1.getVotes(), candidate2.getVotes()))
.get();
}
http://git-wip-us.apache.org/repos/asf/nifi/blob/bc7c42ef/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/flow/TestPopularVoteFlowElection.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/flow/TestPopularVoteFlowElection.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/flow/TestPopularVoteFlowElection.java
index c01371db..b7f9e82 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/flow/TestPopularVoteFlowElection.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/flow/TestPopularVoteFlowElection.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.nio.file.Files;
@@ -34,6 +35,8 @@ import org.apache.nifi.cluster.protocol.StandardDataFlow;
import org.apache.nifi.fingerprint.FingerprintFactory;
import org.junit.Test;
import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
public class TestPopularVoteFlowElection {
@@ -62,6 +65,43 @@ public class TestPopularVoteFlowElection {
assertEquals(new String(flow), new String(electedDataFlow.getFlow()));
}
+ @Test
+ public void testDifferentEmptyFlows() throws IOException {
+ final FingerprintFactory fingerprintFactory = Mockito.mock(FingerprintFactory.class);
+ Mockito.when(fingerprintFactory.createFingerprint(Mockito.any(byte[].class))).thenAnswer(new Answer<String>() {
+ @Override
+ public String answer(final InvocationOnMock invocation) throws Throwable {
+ final byte[] flow = invocation.getArgumentAt(0, byte[].class);
+ final String xml = new String(flow);
+
+ // Return the ID of the root group as the fingerprint.
+ final String fingerprint = xml.replaceAll("(?s:(.*<id>)(.*?)(</id>.*))", "$2");
+ return fingerprint;
+ }
+ });
+
+ final PopularVoteFlowElection election = new PopularVoteFlowElection(1, TimeUnit.MINUTES, 3, fingerprintFactory);
+ final byte[] flow1 = Files.readAllBytes(Paths.get("src/test/resources/conf/empty-flow.xml"));
+ final byte[] flow2 = Files.readAllBytes(Paths.get("src/test/resources/conf/different-empty-flow.xml"));
+
+ assertFalse(election.isElectionComplete());
+ assertNull(election.getElectedDataFlow());
+ assertNull(election.castVote(createDataFlow(flow1), createNodeId(1)));
+
+ assertFalse(election.isElectionComplete());
+ assertNull(election.getElectedDataFlow());
+ assertNull(election.castVote(createDataFlow(flow1), createNodeId(2)));
+
+ assertFalse(election.isElectionComplete());
+ assertNull(election.getElectedDataFlow());
+
+ final DataFlow electedDataFlow = election.castVote(createDataFlow(flow2), createNodeId(3));
+ assertNotNull(electedDataFlow);
+
+ final String electedFlowXml = new String(electedDataFlow.getFlow());
+ assertTrue(new String(flow1).equals(electedFlowXml) || new String(flow2).equals(electedFlowXml));
+ }
+
@Test
public void testEmptyFlowIgnoredIfNonEmptyFlowExists() throws IOException {
http://git-wip-us.apache.org/repos/asf/nifi/blob/bc7c42ef/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/different-empty-flow.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/different-empty-flow.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/different-empty-flow.xml
new file mode 100644
index 0000000..8c9641a
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/different-empty-flow.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+ 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.
+-->
+<flowController encoding-version="1.0">
+ <maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
+ <maxEventDrivenThreadCount>5</maxEventDrivenThreadCount>
+ <rootGroup>
+ <id>11111111-1111-1111-1111-111111111111</id>
+ <name>Empty NiFi Flow</name>
+ <position x="0.0" y="0.0"/>
+ <comment/>
+ </rootGroup>
+ <controllerServices/>
+ <reportingTasks/>
+</flowController>
\ No newline at end of file