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);


Reply via email to