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 2013/11/20 18:02:25 UTC
svn commit: r1543877 - in /sling/trunk/bundles/extensions/discovery/impl/src:
main/java/org/apache/sling/discovery/impl/common/resource/
test/java/org/apache/sling/discovery/impl/cluster/
test/java/org/apache/sling/discovery/impl/setup/
Author: stefanegli
Date: Wed Nov 20 17:02:24 2013
New Revision: 1543877
URL: http://svn.apache.org/r1543877
Log:
SLING-3253 : fixed leader election: actually using calculated leaderId resulting from leader election, instead of doing the leader election again based on only the slingId
Modified:
sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/resource/EstablishedClusterView.java
sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.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/common/resource/EstablishedClusterView.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/resource/EstablishedClusterView.java?rev=1543877&r1=1543876&r2=1543877&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/resource/EstablishedClusterView.java (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/resource/EstablishedClusterView.java Wed Nov 20 17:02:24 2013
@@ -25,6 +25,7 @@ import java.util.LinkedList;
import java.util.List;
import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.discovery.InstanceDescription;
import org.apache.sling.discovery.impl.Config;
import org.apache.sling.discovery.impl.common.DefaultClusterViewImpl;
@@ -51,6 +52,7 @@ public class EstablishedClusterView exte
final String localId) {
super(view.getViewId());
+ String leaderId = view.getResource().adaptTo(ValueMap.class).get("leaderId", String.class);
final Iterator<Resource> it1 = view.getResource().getChild("members")
.getChildren().iterator();
final List<Resource> instanceRess = new LinkedList<Resource>();
@@ -73,8 +75,11 @@ public class EstablishedClusterView exte
}
});
- final Resource leader = instanceRess.get(0);
- final String leaderId = leader.getName();
+ if (leaderId==null || leaderId.length()==0) {
+ // fallback to pre-SLING-3253: choose leader based on slingId alone.
+ final Resource leader = instanceRess.get(0);
+ leaderId = leader.getName();
+ }
InstanceDescription leaderInstance = null;
for (Iterator<Resource> it2 = instanceRess.iterator(); it2.hasNext();) {
Modified: sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.java?rev=1543877&r1=1543876&r2=1543877&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.java (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.java Wed Nov 20 17:02:24 2013
@@ -19,6 +19,8 @@
package org.apache.sling.discovery.impl.cluster;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -73,6 +75,57 @@ public class ClusterTest {
instance2 = null;
instance3 = null;
}
+
+ /** test leader behaviour with ascending slingIds, SLING-3253 **/
+ @Test
+ public void testLeaderAsc() throws Throwable {
+ doTestLeader("000", "111");
+ }
+
+ /** test leader behaviour with descending slingIds, SLING-3253 **/
+ @Test
+ public void testLeaderDesc() throws Throwable {
+ doTestLeader("111", "000");
+ }
+
+ private void doTestLeader(String slingId1, String slingId2) throws Throwable {
+ // stop 1 and 2 and create them with a lower heartbeat timeout
+ instance2.stopHeartbeats();
+ instance1.stopHeartbeats();
+ instance2.stop();
+ instance1.stop();
+ instance1 = Instance.newStandaloneInstance("/var/discovery/impl/", "firstInstance", true, 1, 1, slingId1);
+ // sleep so that the two dont have the same startup time, and thus leaderElectionId is lower for instance1
+ Thread.sleep(200);
+ instance2 = Instance.newClusterInstance("/var/discovery/impl/", "secondInstance", instance1,
+ false, 1, 1, slingId2);
+ assertNotNull(instance1);
+ assertNotNull(instance2);
+
+ // the two instances are still isolated - so in a cluster of size 1
+ assertEquals(1, instance1.getClusterViewService().getClusterView().getInstances().size());
+ assertEquals(1, instance2.getClusterViewService().getClusterView().getInstances().size());
+ assertTrue(instance1.getLocalInstanceDescription().isLeader());
+ assertTrue(instance2.getLocalInstanceDescription().isLeader());
+
+ // let the sync/voting happen
+ instance1.runHeartbeatOnce();
+ instance2.runHeartbeatOnce();
+ Thread.sleep(500);
+ instance1.runHeartbeatOnce();
+ instance2.runHeartbeatOnce();
+ Thread.sleep(500);
+ instance1.runHeartbeatOnce();
+ instance2.runHeartbeatOnce();
+
+ // now they must be in the same cluster, so in a cluster of size 1
+ assertEquals(2, instance1.getClusterViewService().getClusterView().getInstances().size());
+ assertEquals(2, instance2.getClusterViewService().getClusterView().getInstances().size());
+
+ // the first instance should be the leader - since it was started first
+ assertTrue(instance1.getLocalInstanceDescription().isLeader());
+ assertFalse(instance2.getLocalInstanceDescription().isLeader());
+ }
@Test
public void testStableClusterId() throws Throwable {
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=1543877&r1=1543876&r2=1543877&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 Wed Nov 20 17:02:24 2013
@@ -18,9 +18,12 @@
*/
package org.apache.sling.discovery.impl.setup;
+import static org.junit.Assert.fail;
+
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
@@ -47,6 +50,7 @@ import org.apache.sling.commons.schedule
import org.apache.sling.commons.scheduler.impl.QuartzScheduler;
import org.apache.sling.commons.threads.ThreadPoolManager;
import org.apache.sling.commons.threads.impl.DefaultThreadPoolManager;
+import org.apache.sling.discovery.InstanceDescription;
import org.apache.sling.discovery.PropertyProvider;
import org.apache.sling.discovery.TopologyEventListener;
import org.apache.sling.discovery.impl.Config;
@@ -65,7 +69,7 @@ public class Instance {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
- public final String slingId = UUID.randomUUID().toString();
+ public final String slingId;
ClusterViewServiceImpl clusterViewService;
@@ -150,13 +154,14 @@ public class Instance {
private Instance(String debugName,
ResourceResolverFactory resourceResolverFactory, boolean resetRepo)
throws Exception {
- this("/var/discovery/impl/", debugName, resourceResolverFactory, resetRepo, 20, 1);
+ this("/var/discovery/impl/", debugName, resourceResolverFactory, resetRepo, 20, 1, UUID.randomUUID().toString());
}
private Instance(String discoveryResourcePath, String debugName,
ResourceResolverFactory resourceResolverFactory, boolean resetRepo,
- final int heartbeatTimeout, final int minEventDelay)
+ final int heartbeatTimeout, final int minEventDelay, String slingId)
throws Exception {
+ this.slingId = slingId;
this.debugName = debugName;
osgiMock = new OSGiMock();
@@ -263,10 +268,17 @@ public class Instance {
}
public static Instance newStandaloneInstance(String discoveryResourcePath, String debugName,
+ boolean resetRepo, int heartbeatTimeout, int minEventDelay, String slingId) throws Exception {
+ ResourceResolverFactory resourceResolverFactory = MockFactory
+ .mockResourceResolverFactory();
+ return new Instance(discoveryResourcePath, debugName, resourceResolverFactory, resetRepo, heartbeatTimeout, minEventDelay, slingId);
+ }
+
+ public static Instance newStandaloneInstance(String discoveryResourcePath, String debugName,
boolean resetRepo, int heartbeatTimeout, int minEventDelay) throws Exception {
ResourceResolverFactory resourceResolverFactory = MockFactory
.mockResourceResolverFactory();
- return new Instance(discoveryResourcePath, debugName, resourceResolverFactory, resetRepo, heartbeatTimeout, minEventDelay);
+ return new Instance(discoveryResourcePath, debugName, resourceResolverFactory, resetRepo, heartbeatTimeout, minEventDelay, UUID.randomUUID().toString());
}
public static Instance newStandaloneInstance(String debugName,
@@ -277,8 +289,13 @@ public class Instance {
}
public static Instance newClusterInstance(String discoveryResourcePath, String debugName, Instance other,
+ boolean resetRepo, int heartbeatTimeout, int minEventDelay, String slingId) throws Exception {
+ return new Instance(discoveryResourcePath, debugName, other.resourceResolverFactory, resetRepo, heartbeatTimeout, minEventDelay, slingId);
+ }
+
+ public static Instance newClusterInstance(String discoveryResourcePath, String debugName, Instance other,
boolean resetRepo, int heartbeatTimeout, int minEventDelay) throws Exception {
- return new Instance(discoveryResourcePath, debugName, other.resourceResolverFactory, resetRepo, heartbeatTimeout, minEventDelay);
+ return new Instance(discoveryResourcePath, debugName, other.resourceResolverFactory, resetRepo, heartbeatTimeout, minEventDelay, UUID.randomUUID().toString());
}
public static Instance newClusterInstance(String debugName, Instance other,
@@ -304,6 +321,19 @@ public class Instance {
public ClusterViewService getClusterViewService() {
return clusterViewService;
}
+
+ public InstanceDescription getLocalInstanceDescription() {
+ final Iterator<InstanceDescription> it = getClusterViewService().getClusterView().getInstances().iterator();
+ while(it.hasNext()) {
+ final InstanceDescription id = it.next();
+ if (slingId.equals(id.getSlingId())) {
+ return id;
+ }
+ }
+ fail("no local instanceDescription found");
+ // never called:
+ return null;
+ }
public void runHeartbeatOnce() {
logger.info("Instance ["+slingId+"] issues a heartbeat now "+new Date());
@@ -318,7 +348,14 @@ public class Instance {
logger.info("startHeartbeats: stopped.");
}
logger.info("startHeartbeats: activating...");
- OSGiMock.activate(heartbeatHandler);
+ try{
+ OSGiMock.activate(heartbeatHandler);
+ } catch(Error er) {
+ er.printStackTrace(System.out);
+ throw er;
+ } catch(RuntimeException re) {
+ re.printStackTrace(System.out);
+ }
logger.info("startHeartbeats: initializing...");
heartbeatRunner = new HeartbeatRunner(intervalInSeconds);
Thread th = new Thread(heartbeatRunner, "Test-Heartbeat-Runner");