Author: stefanegli
Date: Wed May 29 18:54:56 2013
New Revision: 1487591

URL: http://svn.apache.org/r1487591
Log:
SLING-2892 : add a simple paranoia check to detect situation with 
duplicate/identical sling.ids in a cluster

Modified:
    sling/trunk/bundles/extensions/discovery/impl/pom.xml
    
sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java
    
sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/MockedResource.java

Modified: sling/trunk/bundles/extensions/discovery/impl/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/pom.xml?rev=1487591&r1=1487590&r2=1487591&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/discovery/impl/pom.xml (original)
+++ sling/trunk/bundles/extensions/discovery/impl/pom.xml Wed May 29 18:54:56 
2013
@@ -29,7 +29,7 @@
 
     <artifactId>org.apache.sling.discovery.impl</artifactId>
     <packaging>bundle</packaging>
-    <version>0.1.0-SNAPSHOT</version>
+    <version>0.1.0-R1486590_FUTURE3</version>
 
     <name>Apache Sling Resource-Based Discovery Service</name>
     <description>Implementation of Apache Sling Discovery based on Sling 
Resource providing a ClusterView through resource-clustering (eg jackrabbit 
clustering) and a TopologyView through HTTP POST heartbeats announcing 
sub-topologies to each other.</description>
@@ -114,7 +114,7 @@
                <dependency>
                        <groupId>org.apache.sling</groupId>
                        <artifactId>org.apache.sling.discovery.api</artifactId>
-                       <version>1.0.1-SNAPSHOT</version>
+                       <version>0.1.0-R1484784</version>
             <scope>provided</scope>
                </dependency>
                <dependency>

Modified: 
sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java?rev=1487591&r1=1487590&r2=1487591&view=diff
==============================================================================
--- 
sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java
 (original)
+++ 
sling/trunk/bundles/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java
 Wed May 29 18:54:56 2013
@@ -103,6 +103,12 @@ public class HeartbeatHandler implements
     /** lock object for synchronizing the run method **/
     private final Object lock = new Object();
     
+    /** SLING-2892: remember first heartbeat written to repository by this 
instance **/
+    private long firstHeartbeatWritten = -1;
+    
+    /** SLING-2892: remember the value of the heartbeat this instance has 
written the last time **/
+    private Calendar lastHeartbeatWritten = null;
+    
     @Activate
     protected void activate(ComponentContext context) {
         slingId = slingSettingsService.getSlingId();
@@ -209,6 +215,7 @@ public class HeartbeatHandler implements
     private void issueClusterLocalHeartbeat() {
         ResourceResolver resourceResolver = null;
         final String myClusterNodePath = getLocalClusterNodePath();
+        final Calendar currentTime = Calendar.getInstance();
         try {
             resourceResolver = getResourceResolver();
             if (resourceResolver == null) {
@@ -219,7 +226,36 @@ public class HeartbeatHandler implements
             final Resource resource = ResourceHelper.getOrCreateResource(
                     resourceResolver, myClusterNodePath);
             final ModifiableValueMap resourceMap = 
resource.adaptTo(ModifiableValueMap.class);
-            resourceMap.put("lastHeartbeat", Calendar.getInstance());
+            
+            if (firstHeartbeatWritten!=-1 && lastHeartbeatWritten!=null) {
+               // SLING-2892: additional paranoia check
+               // after the first heartbeat, check if there's someone else 
using
+               // the same sling.id in this cluster
+               final long timeSinceFirstHeartbeat = 
+                               System.currentTimeMillis() - 
firstHeartbeatWritten;
+               if (timeSinceFirstHeartbeat > 2*config.getHeartbeatInterval()) {
+                       // but wait at least 2 heartbeat intervals to handle 
the situation
+                       // where a bundle is refreshed, and startup cases.
+                       final Calendar lastHeartbeat = 
resourceMap.get("lastHeartbeat", Calendar.class);
+                       if (lastHeartbeat!=null) {
+                               // if there is a heartbeat value, check if it 
is what I've written 
+                               // the last time
+                               if 
(!lastHeartbeatWritten.getTime().equals(lastHeartbeat.getTime())) {
+                                       // then we've likely hit the situation 
where there is another
+                                       // sling instance accessing the same 
repository (ie in the same cluster)
+                                       // using the same sling.id - hence 
writing to the same
+                                       // resource
+                                       
logger.error("issueClusterLocalHeartbeat: SLING-2892: Detected unexpected, 
concurrent update of: "+
+                                                       myClusterNodePath+" 
'lastHeartbeat'. If not done manually, " +
+                                                       "this likely indicates 
that there is more than 1 instance running in this cluster" +
+                                                       " with the same 
sling.id. My sling.id is "+slingId+"." +
+                                                       " Check for 
sling.id.file in your installation of all instances in this cluster " +
+                                                       "to verify this! 
Duplicate sling.ids are not allowed within a cluster!");
+                               }
+                       }
+               }
+            }
+            resourceMap.put("lastHeartbeat", currentTime);
             if (resetLeaderElectionId || 
!resourceMap.containsKey("leaderElectionId")) {
                 int maxLongLength = String.valueOf(Long.MAX_VALUE).length();
                 String currentTimeMillisStr = String.format("%0"
@@ -247,6 +283,13 @@ public class HeartbeatHandler implements
             }
             resourceResolver.commit();
 
+            // SLING-2892: only in success case: remember the last heartbeat 
value written
+            lastHeartbeatWritten = currentTime;
+            // and set the first heartbeat written value - if it is not 
already set
+            if (firstHeartbeatWritten==-1) {
+               firstHeartbeatWritten = System.currentTimeMillis();
+            }
+
         } catch (LoginException e) {
             logger.error("issueHeartbeat: could not log in administratively: "
                     + e, e);

Modified: 
sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/MockedResource.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/MockedResource.java?rev=1487591&r1=1487590&r2=1487591&view=diff
==============================================================================
--- 
sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/MockedResource.java
 (original)
+++ 
sling/trunk/bundles/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/MockedResource.java
 Wed May 29 18:54:56 2013
@@ -191,7 +191,7 @@ public class MockedResource extends Synt
                 }
                 
                 public Object get(Object arg0) {
-                    throw new UnsupportedOperationException();
+                       throw new UnsupportedOperationException();
                 }
                 
                 public Set<Entry<String, Object>> entrySet() {
@@ -221,7 +221,24 @@ public class MockedResource extends Synt
                 }
                 
                 public <T> T get(String name, Class<T> type) {
-                    throw new UnsupportedOperationException();
+                    Session session = getSession();
+                    try{
+                        final Node node = session.getNode(getPath());
+                        if (node==null) {
+                               return null;
+                        }
+                        Property p = node.getProperty(name);
+                        if (p==null) {
+                               return null;
+                        }
+                        if (type.equals(Calendar.class)) {
+                               return (T) p.getDate();
+                        } else {
+                            throw new UnsupportedOperationException();
+                        }
+                    } catch(RepositoryException e) {
+                       throw new RuntimeException(e);
+                    }
                 }
             };
         } else {


Reply via email to