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/10/31 11:04:37 UTC

svn commit: r1537422 - in /sling/trunk/bundles/extensions/discovery/impl/src: main/java/org/apache/sling/discovery/impl/cluster/voting/ main/java/org/apache/sling/discovery/impl/common/ test/java/org/apache/sling/discovery/impl/cluster/

Author: stefanegli
Date: Thu Oct 31 10:04:37 2013
New Revision: 1537422

URL: http://svn.apache.org/r1537422
Log:
SLING-3195 : Provide a property to uniquely identify a Cluster : achieved by making the existing ClusterView.getId stable: the id is stored as part of the votingView and propagates as part of view changes. The initial id is identical to the one chosen for the isolated-mode - hence for one-node cases the clusterView.getId is also stable in that case.

Modified:
    sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java
    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/main/java/org/apache/sling/discovery/impl/common/View.java
    sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.java

Modified: sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java?rev=1537422&r1=1537421&r2=1537422&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java Thu Oct 31 10:04:37 2013
@@ -366,6 +366,7 @@ public class VotingHandler implements Ev
         winningVoteMap.put("leaderId", leaderid);
         winningVoteMap.put("leaderElectionId", leaderElectionId);
         winningVoteMap.put("promotedAt", Calendar.getInstance());
+        winningVoteMap.put("promotedBy", slingId);
 
         // 3b: move the result under /established
         final String newEstablishedViewPath = establishedViewsResource.getPath()

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=1537422&r1=1537421&r2=1537422&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 Thu Oct 31 10:04:37 2013
@@ -32,6 +32,7 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.discovery.impl.Config;
 import org.apache.sling.discovery.impl.common.View;
+import org.apache.sling.discovery.impl.common.ViewHelper;
 import org.apache.sling.discovery.impl.common.resource.ResourceHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -64,6 +65,37 @@ public class VotingView extends View {
                         + newViewId);
         final ModifiableValueMap votingMap = votingResource.adaptTo(ModifiableValueMap.class);
         votingMap.put("votingStart", Calendar.getInstance());
+
+        String clusterId = null;
+        Calendar clusterIdDefinedAt = null;
+        String clusterIdDefinedBy = null;
+        final View currentlyEstablishedView = ViewHelper.getEstablishedView(resourceResolver, config);
+        if (currentlyEstablishedView != null) {
+        	final ValueMap establishedViewValueMap = currentlyEstablishedView.getResource().adaptTo(ValueMap.class);
+        	clusterId = establishedViewValueMap.get(VIEW_PROPERTY_CLUSTER_ID, String.class);
+        	if (clusterId == null || clusterId.length() == 0) {
+        		clusterId = currentlyEstablishedView.getResource().getName();
+        	}
+        	Date date = establishedViewValueMap.get(VIEW_PROPERTY_CLUSTER_ID_DEFINED_AT, Date.class);
+        	if (date!=null) {
+        		clusterIdDefinedAt = Calendar.getInstance();
+        		clusterIdDefinedAt.setTime(date);
+        	}
+        	clusterIdDefinedBy = establishedViewValueMap.get(VIEW_PROPERTY_CLUSTER_ID_DEFINED_BY, String.class);
+        }
+        if (clusterId == null || clusterId.length() == 0) {
+        	clusterId = newViewId;
+        	clusterIdDefinedAt = Calendar.getInstance();
+        }
+        votingMap.put(VIEW_PROPERTY_CLUSTER_ID, clusterId);
+        if (clusterIdDefinedAt != null) {
+        	votingMap.put(VIEW_PROPERTY_CLUSTER_ID_DEFINED_AT, clusterIdDefinedAt);
+        }
+        if (clusterIdDefinedBy == null || clusterIdDefinedBy.length() == 0) {
+        	clusterIdDefinedBy = initiatorId;
+        }
+        votingMap.put(VIEW_PROPERTY_CLUSTER_ID_DEFINED_BY, clusterIdDefinedBy);
+        
         final Resource membersResource = resourceResolver.create(votingResource, "members", null);
         final Iterator<String> it = liveInstances.iterator();
         while (it.hasNext()) {

Modified: sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/View.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/View.java?rev=1537422&r1=1537421&r2=1537422&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/View.java (original)
+++ sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/View.java Thu Oct 31 10:04:37 2013
@@ -25,6 +25,7 @@ import java.util.Set;
 import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.discovery.impl.Config;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -34,6 +35,10 @@ import org.slf4j.LoggerFactory;
  */
 public class View {
 
+    protected static final String VIEW_PROPERTY_CLUSTER_ID = "clusterId";
+    protected static final String VIEW_PROPERTY_CLUSTER_ID_DEFINED_AT = "clusterIdDefinedAt";
+    protected static final String VIEW_PROPERTY_CLUSTER_ID_DEFINED_BY = "clusterIdDefinedBy";
+    
     /**
      * use static logger to avoid frequent initialization as is potentially the
      * case with ClusterViewResource.
@@ -76,7 +81,13 @@ public class View {
      * @return the id of this view
      */
     public String getViewId() {
-        return getResource().getName();
+    	final ValueMap props = getResource().adaptTo(ValueMap.class);
+    	final String clusterId = props.get(VIEW_PROPERTY_CLUSTER_ID, String.class);
+    	if (clusterId != null && clusterId.length() > 0) {
+    		return clusterId;
+    	} else {
+    		return getResource().getName();
+    	}
     }
 
     /**

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=1537422&r1=1537421&r2=1537422&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 Thu Oct 31 10:04:37 2013
@@ -19,6 +19,7 @@
 package org.apache.sling.discovery.impl.cluster;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
@@ -74,6 +75,81 @@ public class ClusterTest {
     }
 
     @Test
+    public void testStableClusterId() 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);
+        instance2 = Instance.newClusterInstance("/var/discovery/impl/", "secondInstance", instance1,
+                false, 1, 1);
+        assertNotNull(instance1);
+        assertNotNull(instance2);
+
+        String clusterId1 = instance1.getClusterViewService()
+                .getClusterView().getId();
+        String clusterId2 = instance2.getClusterViewService()
+                .getClusterView().getId();
+        // the cluster ids must differ
+        assertNotEquals(clusterId1, clusterId2);
+        assertEquals(1, instance1.getClusterViewService().getClusterView().getInstances().size());
+        assertEquals(1, instance2.getClusterViewService().getClusterView().getInstances().size());
+
+        // let the sync/voting happen
+        instance1.runHeartbeatOnce();
+        instance2.runHeartbeatOnce();
+        Thread.sleep(500);
+        instance1.runHeartbeatOnce();
+        instance2.runHeartbeatOnce();
+        Thread.sleep(500);
+        instance1.runHeartbeatOnce();
+        instance2.runHeartbeatOnce();
+        
+        String newClusterId1 = instance1.getClusterViewService()
+                .getClusterView().getId();
+        String newClusterId2 = instance2.getClusterViewService()
+                .getClusterView().getId();
+        // both cluster ids must be the same
+        assertEquals(newClusterId1, newClusterId1);
+        
+        // either instance1 or instance2 must have kept the cluster id
+        if (!newClusterId1.equals(clusterId1)) {
+        	assertEquals(newClusterId2, clusterId2);
+        }
+        instance1.dumpRepo();
+        assertEquals(2, instance1.getClusterViewService().getClusterView().getInstances().size());
+        assertEquals(2, instance2.getClusterViewService().getClusterView().getInstances().size());
+        
+        // let instance2 'die' by now longer doing heartbeats
+        instance2.stopHeartbeats(); // would actually not be necessary as it was never started.. this test only runs heartbeats manually
+        instance1.runHeartbeatOnce();
+        Thread.sleep(500);
+        instance1.runHeartbeatOnce();
+        Thread.sleep(500);
+        instance1.runHeartbeatOnce();
+        Thread.sleep(500);
+        instance1.runHeartbeatOnce();
+        Thread.sleep(500);
+        instance1.runHeartbeatOnce();
+        Thread.sleep(500);
+        instance1.runHeartbeatOnce();
+        // the cluster should now have size 1
+        assertEquals(1, instance1.getClusterViewService().getClusterView().getInstances().size());
+        // the instance 2 should be in isolated mode as it is no longer in the established view
+        // hence also size 1
+        assertEquals(1, instance2.getClusterViewService().getClusterView().getInstances().size());
+
+        // but the cluster id must have remained stable
+        instance1.dumpRepo();
+        String actualClusterId = instance1.getClusterViewService()
+                .getClusterView().getId();
+        System.err.println("expected cluster id: "+newClusterId1);
+        System.err.println("actual   cluster id: "+actualClusterId);
+		assertEquals(newClusterId1, actualClusterId);
+    }
+    
+    @Test
     public void testClusterView() throws Exception {
         assertNotNull(instance1);
         assertNotNull(instance2);