Repository: cassandra
Updated Branches:
  refs/heads/cassandra-2.1 728f677b0 -> f67b7a477


Auto reload GossipingPropertyFileSnitch config

Patch by Danield Shelepov, reviewed by Tyler Hobbs for CASSANDRA-5897


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/f67b7a47
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/f67b7a47
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/f67b7a47

Branch: refs/heads/cassandra-2.1
Commit: f67b7a477ae08fe7c8be2bb61eeecb0a7cc55e62
Parents: 728f677
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Thu Mar 6 11:22:47 2014 -0600
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Thu Mar 6 11:22:47 2014 -0600

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 .../org/apache/cassandra/locator/Ec2Snitch.java |   2 +-
 .../locator/GossipingPropertyFileSnitch.java    | 104 ++++++++++++++++---
 .../cassandra/locator/PropertyFileSnitch.java   |   2 +-
 .../cassandra/locator/SnitchProperties.java     |  10 +-
 test/conf/cassandra-rackdc.properties.mod       |  17 +++
 .../GossipingPropertyFileSnitchTest.java        |  59 +++++++++++
 .../YamlFileNetworkTopologySnitchTest.java      |   2 +-
 8 files changed, 175 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/f67b7a47/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index b933bad..af7f2fd 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 2.1.0-beta2
+ * Auto reload GossipingPropertyFileSnitch config (CASSANDRA-5897)
  * Fix overflow of memtable_total_space_in_mb (CASSANDRA-6573)
  * Fix ABTC NPE (CASSANDRA-6692)
  * Allow nodetool to use a file or prompt for password (CASSANDRA-6660)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f67b7a47/src/java/org/apache/cassandra/locator/Ec2Snitch.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/locator/Ec2Snitch.java 
b/src/java/org/apache/cassandra/locator/Ec2Snitch.java
index 216a224..59eb27b 100644
--- a/src/java/org/apache/cassandra/locator/Ec2Snitch.java
+++ b/src/java/org/apache/cassandra/locator/Ec2Snitch.java
@@ -62,7 +62,7 @@ public class Ec2Snitch extends AbstractNetworkTopologySnitch
         if (ec2region.endsWith("1"))
             ec2region = az.substring(0, az.length() - 3);
 
-        String datacenterSuffix = SnitchProperties.get("dc_suffix", "");
+        String datacenterSuffix = (new SnitchProperties()).get("dc_suffix", 
"");
         ec2region = ec2region.concat(datacenterSuffix);
         logger.info("EC2Snitch using region: {}, zone: {}.", ec2region, 
ec2zone);
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f67b7a47/src/java/org/apache/cassandra/locator/GossipingPropertyFileSnitch.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/locator/GossipingPropertyFileSnitch.java 
b/src/java/org/apache/cassandra/locator/GossipingPropertyFileSnitch.java
index 83c1efe..720e804 100644
--- a/src/java/org/apache/cassandra/locator/GossipingPropertyFileSnitch.java
+++ b/src/java/org/apache/cassandra/locator/GossipingPropertyFileSnitch.java
@@ -19,6 +19,7 @@
 package org.apache.cassandra.locator;
 
 import java.net.InetAddress;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.Map;
 
 import org.slf4j.Logger;
@@ -29,8 +30,10 @@ import 
org.apache.cassandra.exceptions.ConfigurationException;
 import org.apache.cassandra.gms.ApplicationState;
 import org.apache.cassandra.gms.EndpointState;
 import org.apache.cassandra.gms.Gossiper;
-import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.service.StorageService;
+import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.ResourceWatcher;
+import org.apache.cassandra.utils.WrappedRunnable;
 
 
 public class GossipingPropertyFileSnitch extends 
AbstractNetworkTopologySnitch// implements IEndpointStateChangeSubscriber
@@ -38,23 +41,30 @@ public class GossipingPropertyFileSnitch extends 
AbstractNetworkTopologySnitch//
     private static final Logger logger = 
LoggerFactory.getLogger(GossipingPropertyFileSnitch.class);
 
     private PropertyFileSnitch psnitch;
-    private String myDC;
-    private String myRack;
+
+    private volatile String myDC;
+    private volatile String myRack;
+    private volatile boolean preferLocal;
+    private AtomicReference<ReconnectableSnitchHelper> snitchHelperReference;
+    private volatile boolean gossipStarted;
+
     private Map<InetAddress, Map<String, String>> savedEndpoints;
-    private String DEFAULT_DC = "UNKNOWN_DC";
-    private String DEFAULT_RACK = "UNKNOWN_RACK";
-    private final boolean preferLocal;
+    private static final String DEFAULT_DC = "UNKNOWN_DC";
+    private static final String DEFAULT_RACK = "UNKNOWN_RACK";
 
+    private static final int DEFAULT_REFRESH_PERIOD_IN_SECONDS = 60;
+    
     public GossipingPropertyFileSnitch() throws ConfigurationException
     {
-        myDC = SnitchProperties.get("dc", null);
-        myRack = SnitchProperties.get("rack", null);
-        if (myDC == null || myRack == null)
-            throw new ConfigurationException("DC or rack not found in snitch 
properties, check your configuration in: " + 
SnitchProperties.RACKDC_PROPERTY_FILENAME);
+        this(DEFAULT_REFRESH_PERIOD_IN_SECONDS);
+    }
+
+    public GossipingPropertyFileSnitch(int refreshPeriodInSeconds) throws 
ConfigurationException
+    {
+        snitchHelperReference = new 
AtomicReference<ReconnectableSnitchHelper>();
+
+        reloadConfiguration();
 
-        myDC = myDC.trim();
-        myRack = myRack.trim();
-        preferLocal = 
Boolean.parseBoolean(SnitchProperties.get("prefer_local", "false"));
         try
         {
             psnitch = new PropertyFileSnitch();
@@ -64,6 +74,23 @@ public class GossipingPropertyFileSnitch extends 
AbstractNetworkTopologySnitch//
         {
             logger.info("Unable to load {}; compatibility mode disabled", 
PropertyFileSnitch.SNITCH_PROPERTIES_FILENAME);
         }
+
+        try
+        {
+            
FBUtilities.resourceToFile(SnitchProperties.RACKDC_PROPERTY_FILENAME);
+            Runnable runnable = new WrappedRunnable()
+            {
+                protected void runMayThrow() throws ConfigurationException
+                {
+                    reloadConfiguration();
+                }
+            };
+            ResourceWatcher.watch(SnitchProperties.RACKDC_PROPERTY_FILENAME, 
runnable, refreshPeriodInSeconds * 1000);
+        }
+        catch (ConfigurationException ex)
+        {
+            logger.error("{} found, but does not look like a plain file. Will 
not watch it for changes", SnitchProperties.RACKDC_PROPERTY_FILENAME);
+        }
     }
 
     /**
@@ -125,8 +152,55 @@ public class GossipingPropertyFileSnitch extends 
AbstractNetworkTopologySnitch//
     public void gossiperStarting()
     {
         super.gossiperStarting();
+
         
Gossiper.instance.addLocalApplicationState(ApplicationState.INTERNAL_IP,
-                                                   
StorageService.instance.valueFactory.internalIP(FBUtilities.getLocalAddress().getHostAddress()));
-        Gossiper.instance.register(new ReconnectableSnitchHelper(this, myDC, 
preferLocal));
+                
StorageService.instance.valueFactory.internalIP(FBUtilities.getLocalAddress().getHostAddress()));
+
+        reloadGossiperState();
+
+        gossipStarted = true;
+    }
+    
+    private void reloadConfiguration() throws ConfigurationException
+    {
+        final SnitchProperties properties = new SnitchProperties();
+
+        String newDc = properties.get("dc", null);
+        String newRack = properties.get("rack", null);
+        if (newDc == null || newRack == null)
+            throw new ConfigurationException("DC or rack not found in snitch 
properties, check your configuration in: " + 
SnitchProperties.RACKDC_PROPERTY_FILENAME);
+
+        newDc = newDc.trim();
+        newRack = newRack.trim();
+        final boolean newPreferLocal = 
Boolean.parseBoolean(properties.get("prefer_local", "false"));
+
+        if (myDC != newDc || myRack != newRack || (preferLocal != 
newPreferLocal))
+        {
+            myDC = newDc;
+            myRack = newRack;
+            preferLocal = newPreferLocal;
+
+            reloadGossiperState();
+
+            if (StorageService.instance != null)
+                
StorageService.instance.getTokenMetadata().invalidateCachedRings();
+
+            if (gossipStarted)
+                StorageService.instance.gossipSnitchInfo();
+        }
+    }
+
+    private void reloadGossiperState()
+    {
+        if (Gossiper.instance != null)
+        {
+            ReconnectableSnitchHelper pendingHelper = new 
ReconnectableSnitchHelper(this, myDC, preferLocal);
+            Gossiper.instance.register(pendingHelper);
+            
+            pendingHelper = snitchHelperReference.getAndSet(pendingHelper);
+            if (pendingHelper != null)
+                Gossiper.instance.unregister(pendingHelper);
+        }
+        // else this will eventually rerun at gossiperStarting()
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f67b7a47/src/java/org/apache/cassandra/locator/PropertyFileSnitch.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/locator/PropertyFileSnitch.java 
b/src/java/org/apache/cassandra/locator/PropertyFileSnitch.java
index 90dddcc..d235369 100644
--- a/src/java/org/apache/cassandra/locator/PropertyFileSnitch.java
+++ b/src/java/org/apache/cassandra/locator/PropertyFileSnitch.java
@@ -73,7 +73,7 @@ public class PropertyFileSnitch extends 
AbstractNetworkTopologySnitch
         }
         catch (ConfigurationException ex)
         {
-            logger.debug("{} found, but does not look like a plain file. Will 
not watch it for changes", SNITCH_PROPERTIES_FILENAME);
+            logger.error("{} found, but does not look like a plain file. Will 
not watch it for changes", SNITCH_PROPERTIES_FILENAME);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f67b7a47/src/java/org/apache/cassandra/locator/SnitchProperties.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/locator/SnitchProperties.java 
b/src/java/org/apache/cassandra/locator/SnitchProperties.java
index a8b2d03..57541d4 100644
--- a/src/java/org/apache/cassandra/locator/SnitchProperties.java
+++ b/src/java/org/apache/cassandra/locator/SnitchProperties.java
@@ -28,10 +28,12 @@ public class SnitchProperties
 {
     private static final Logger logger = 
LoggerFactory.getLogger(SnitchProperties.class);
     public static final String RACKDC_PROPERTY_FILENAME = 
"cassandra-rackdc.properties";
-    private static Properties properties = new Properties();
 
-    static
+    private Properties properties;
+
+    public SnitchProperties()
     {
+        properties = new Properties();
         InputStream stream = 
SnitchProperties.class.getClassLoader().getResourceAsStream(RACKDC_PROPERTY_FILENAME);
         try
         {
@@ -49,9 +51,9 @@ public class SnitchProperties
     }
 
     /**
-     * Get a snitch property value or return null if not defined.
+     * Get a snitch property value or return defaultValue if not defined.
      */
-    public static String get(String propertyName, String defaultValue)
+    public String get(String propertyName, String defaultValue)
     {
         return properties.getProperty(propertyName, defaultValue);
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f67b7a47/test/conf/cassandra-rackdc.properties.mod
----------------------------------------------------------------------
diff --git a/test/conf/cassandra-rackdc.properties.mod 
b/test/conf/cassandra-rackdc.properties.mod
new file mode 100644
index 0000000..457ad65
--- /dev/null
+++ b/test/conf/cassandra-rackdc.properties.mod
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+dc=DC2
+rack=RAC2

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f67b7a47/test/unit/org/apache/cassandra/locator/GossipingPropertyFileSnitchTest.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/locator/GossipingPropertyFileSnitchTest.java 
b/test/unit/org/apache/cassandra/locator/GossipingPropertyFileSnitchTest.java
new file mode 100644
index 0000000..9026ebf
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/locator/GossipingPropertyFileSnitchTest.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.locator;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apache.cassandra.utils.FBUtilities;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link GossipingPropertyFileSnitch}.
+ */
+public class GossipingPropertyFileSnitchTest
+{
+    @Test
+    public void testAutoReloadConfig() throws Exception
+    {
+        String confFile = 
FBUtilities.resourceToFile(SnitchProperties.RACKDC_PROPERTY_FILENAME);
+        
+        final GossipingPropertyFileSnitch snitch = new 
GossipingPropertyFileSnitch(/*refreshPeriodInSeconds*/1);
+        YamlFileNetworkTopologySnitchTest.checkEndpoint(snitch, 
FBUtilities.getBroadcastAddress().getHostAddress(), "DC1", "RAC1");
+
+        final Path effectiveFile = Paths.get(confFile);
+        final Path backupFile = Paths.get(confFile + ".bak");
+        final Path modifiedFile = Paths.get(confFile + ".mod");
+        
+        try
+        {
+            Files.copy(effectiveFile, backupFile);
+            Files.copy(modifiedFile, effectiveFile, 
java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+            
+            Thread.sleep(1500);
+            
+            YamlFileNetworkTopologySnitchTest.checkEndpoint(snitch, 
FBUtilities.getBroadcastAddress().getHostAddress(), "DC2", "RAC2");
+        }
+        finally
+        {
+            Files.copy(backupFile, effectiveFile, 
java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+            Files.delete(backupFile);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/f67b7a47/test/unit/org/apache/cassandra/locator/YamlFileNetworkTopologySnitchTest.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/locator/YamlFileNetworkTopologySnitchTest.java 
b/test/unit/org/apache/cassandra/locator/YamlFileNetworkTopologySnitchTest.java
index be1c24b..af1a7e9 100644
--- 
a/test/unit/org/apache/cassandra/locator/YamlFileNetworkTopologySnitchTest.java
+++ 
b/test/unit/org/apache/cassandra/locator/YamlFileNetworkTopologySnitchTest.java
@@ -88,7 +88,7 @@ public class YamlFileNetworkTopologySnitchTest
      * @param expectedRack
      *            expected rack
      */
-    private void checkEndpoint(final AbstractNetworkTopologySnitch snitch,
+    public static void checkEndpoint(final AbstractNetworkTopologySnitch 
snitch,
             final String endpointString, final String expectedDatacenter,
             final String expectedRack)
     {

Reply via email to