You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by st...@apache.org on 2015/09/22 16:30:01 UTC
svn commit: r1704640 - in /sling/trunk/bundles/extensions/discovery/impl/src:
main/java/org/apache/sling/discovery/impl/cluster/voting/
test/java/org/apache/sling/discovery/impl/common/heartbeat/
test/java/org/apache/sling/discovery/impl/setup/
Author: stefanegli
Date: Tue Sep 22 14:29:59 2015
New Revision: 1704640
URL: http://svn.apache.org/viewvc?rev=1704640&view=rev
Log:
SLING-5027 : avoid vote-loop introduced with SLING-3434 (through the votedAt property) - by not voting again if already voted
Modified:
sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingView.java
sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatTest.java
sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/Instance.java
Modified: sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingView.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingView.java?rev=1704640&r1=1704639&r2=1704640&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingView.java (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingView.java Tue Sep 22 14:29:59 2015
@@ -25,6 +25,10 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFormatException;
+
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
@@ -298,8 +302,21 @@ public class VotingView extends View {
if (vote == null) {
memberMap.remove("vote");
} else {
- memberMap.put("vote", vote);
- memberMap.put("votedAt", Calendar.getInstance());
+ boolean shouldVote = true;
+ try {
+ if (memberMap.containsKey("vote") && ((Property)memberMap.get("vote")).getBoolean()==vote) {
+ logger.debug("vote: already voted, with same vote ("+vote+"), not voting again");
+ shouldVote = false;
+ }
+ } catch (ValueFormatException e) {
+ logger.warn("vote: got a ValueFormatException: "+e, e);
+ } catch (RepositoryException e) {
+ logger.warn("vote: got a RepositoryException: "+e, e);
+ }
+ if (shouldVote) {
+ memberMap.put("vote", vote);
+ memberMap.put("votedAt", Calendar.getInstance());
+ }
}
try {
getResource().getResourceResolver().commit();
Modified: sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatTest.java?rev=1704640&r1=1704639&r2=1704640&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatTest.java (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatTest.java Tue Sep 22 14:29:59 2015
@@ -23,21 +23,32 @@ import static org.junit.Assert.assertFal
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.Serializable;
+import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.UUID;
+import javax.jcr.Property;
+
+import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.commons.scheduler.Scheduler;
import org.apache.sling.discovery.TopologyEvent;
import org.apache.sling.discovery.TopologyEventListener;
import org.apache.sling.discovery.TopologyView;
import org.apache.sling.discovery.impl.DiscoveryServiceImpl;
+import org.apache.sling.discovery.impl.cluster.voting.VotingHelper;
+import org.apache.sling.discovery.impl.cluster.voting.VotingView;
import org.apache.sling.discovery.impl.setup.Instance;
import org.junit.After;
import org.junit.Test;
@@ -427,4 +438,83 @@ public class HeartbeatTest {
}
});
}
+
+ /**
+ * SLING-5027 : test to reproduce the voting loop
+ * (and verify that it's fixed)
+ */
+ @Test
+ public void testVotingLoop() throws Throwable {
+ Instance slowMachine1 = Instance.newStandaloneInstance("/var/discovery/impl/", "slow1", true, 600 /*600sec timeout*/,
+ 999 /* 999sec interval: to disable it*/, 0, UUID.randomUUID().toString());
+ instances.add(slowMachine1);
+ SimpleTopologyEventListener slowListener1 = new SimpleTopologyEventListener("slow1");
+ slowMachine1.bindTopologyEventListener(slowListener1);
+ Instance slowMachine2 = Instance.newClusterInstance("/var/discovery/impl/", "slow2", slowMachine1, false, 600, 999, 0);
+ instances.add(slowMachine2);
+ SimpleTopologyEventListener slowListener2 = new SimpleTopologyEventListener("slow2");
+ slowMachine2.bindTopologyEventListener(slowListener2);
+ Instance fastMachine = Instance.newClusterInstance("/var/discovery/impl/", "fast", slowMachine1, false, 600, 999, 0);
+ instances.add(fastMachine);
+ SimpleTopologyEventListener fastListener = new SimpleTopologyEventListener("fast");
+ fastMachine.bindTopologyEventListener(fastListener);
+ HeartbeatHandler hhSlow1 = slowMachine1.getHeartbeatHandler();
+ HeartbeatHandler hhSlow2 = slowMachine2.getHeartbeatHandler();
+ HeartbeatHandler hhFast = fastMachine.getHeartbeatHandler();
+
+ Thread.sleep(1000);
+ assertFalse(fastMachine.getDiscoveryService().getTopology().isCurrent());
+ assertFalse(slowMachine1.getDiscoveryService().getTopology().isCurrent());
+ assertFalse(slowMachine2.getDiscoveryService().getTopology().isCurrent());
+ assertNull(fastListener.getLastEvent());
+ assertNull(slowListener1.getLastEvent());
+ assertNull(slowListener2.getLastEvent());
+
+ // prevent the slow machine from voting
+ slowMachine1.stopVoting();
+
+ // now let all issue a heartbeat
+ hhSlow1.issueHeartbeat();
+ hhSlow2.issueHeartbeat();
+ hhFast.issueHeartbeat();
+
+ // now let the fast one start a new voting, to which
+ // only the fast one will vote, the slow one doesn't.
+ // that will cause a voting loop
+ hhFast.checkView();
+
+ Calendar previousVotedAt = null;
+ for(int i=0; i<5; i++) {
+ Thread.sleep(1000);
+ // now check the ongoing votings
+ ResourceResolverFactory factory = fastMachine.getResourceResolverFactory();
+ ResourceResolver resourceResolver = factory
+ .getAdministrativeResourceResolver(null);
+ try{
+ List<VotingView> ongoingVotings =
+ VotingHelper.listOpenNonWinningVotings(resourceResolver, fastMachine.getConfig());
+ assertNotNull(ongoingVotings);
+ assertEquals(1, ongoingVotings.size());
+ VotingView ongoingVote = ongoingVotings.get(0);
+ assertFalse(ongoingVote.isWinning());
+ assertFalse(ongoingVote.hasVotedOrIsInitiator(slowMachine1.getSlingId()));
+ assertTrue(ongoingVote.hasVotedOrIsInitiator(slowMachine2.getSlingId()));
+ final Resource memberResource = ongoingVote.getResource().getChild("members").getChild(slowMachine2.getSlingId());
+ final ModifiableValueMap memberMap = memberResource.adaptTo(ModifiableValueMap.class);
+ Property vote = (Property) memberMap.get("vote");
+ assertEquals(Boolean.TRUE, vote.getBoolean());
+ Property votedAt = (Property) memberMap.get("votedAt");
+ if (previousVotedAt==null) {
+ previousVotedAt = votedAt.getDate();
+ } else {
+ assertEquals(previousVotedAt, votedAt.getDate());
+ }
+ } catch(Exception e) {
+ resourceResolver.close();
+ fail("Exception: "+e);
+ }
+ }
+
+ }
+
}
Modified: sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/Instance.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/Instance.java?rev=1704640&r1=1704639&r2=1704640&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/Instance.java (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/Instance.java Tue Sep 22 14:29:59 2015
@@ -594,6 +594,10 @@ public class Instance {
public void dumpRepo() throws Exception {
dumpRepo(resourceResolverFactory);
}
+
+ public ResourceResolverFactory getResourceResolverFactory() {
+ return resourceResolverFactory;
+ }
public static void dumpRepo(ResourceResolverFactory resourceResolverFactory) throws Exception {
Session session = resourceResolverFactory
@@ -688,4 +692,11 @@ public class Instance {
public void installVotingOnHeartbeatHandler() throws NoSuchFieldException {
PrivateAccessor.setField(heartbeatHandler, "votingHandler", votingHandler);
}
+
+ public void stopVoting() {
+ if (observationListener!=null) {
+ observationListener.stop();
+ observationListener = null;
+ }
+ }
}