Author: jbellis
Date: Thu May 27 13:28:42 2010
New Revision: 948829

URL: http://svn.apache.org/viewvc?rev=948829&view=rev
Log:
Add ResourceWatcher to generalize reloading Strategy configurations.  patch by 
Jon Hermes and jbellis for CASSANDRA-1105

Added:
    cassandra/trunk/src/java/org/apache/cassandra/utils/ResourceWatcher.java
Removed:
    
cassandra/trunk/src/java/org/apache/cassandra/locator/PropertyFileSnitchMBean.java
Modified:
    
cassandra/trunk/src/java/org/apache/cassandra/locator/DatacenterShardStrategy.java
    
cassandra/trunk/src/java/org/apache/cassandra/locator/PropertyFileSnitch.java
    cassandra/trunk/src/java/org/apache/cassandra/utils/FBUtilities.java

Modified: 
cassandra/trunk/src/java/org/apache/cassandra/locator/DatacenterShardStrategy.java
URL: 
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/locator/DatacenterShardStrategy.java?rev=948829&r1=948828&r2=948829&view=diff
==============================================================================
--- 
cassandra/trunk/src/java/org/apache/cassandra/locator/DatacenterShardStrategy.java
 (original)
+++ 
cassandra/trunk/src/java/org/apache/cassandra/locator/DatacenterShardStrategy.java
 Thu May 27 13:28:42 2010
@@ -1,4 +1,5 @@
 package org.apache.cassandra.locator;
+
 /*
  * 
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -21,11 +22,7 @@ package org.apache.cassandra.locator;
  */
 
 
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.IOError;
 import java.net.InetAddress;
-import java.net.URL;
 import java.util.*;
 import java.util.Map.Entry;
 
@@ -33,9 +30,11 @@ import com.google.common.collect.Multima
 import org.apache.cassandra.config.ConfigurationException;
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.dht.Token;
+import org.apache.cassandra.utils.ResourceWatcher;
 import org.apache.cassandra.service.*;
 import org.apache.cassandra.thrift.ConsistencyLevel;
 import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.WrappedRunnable;
 
 /**
  * This Replication Strategy takes a property file that gives the intended
@@ -63,38 +62,36 @@ public class DatacenterShardStrategy ext
         if ((!(snitch instanceof AbstractRackAwareSnitch)))
             throw new IllegalArgumentException("DatacenterShardStrategy 
requires a rack-aware endpointsnitch");
         this.snitch = (AbstractRackAwareSnitch)snitch;
-
-        ClassLoader loader = PropertyFileSnitch.class.getClassLoader();
-        URL scpurl = loader.getResource(DATACENTER_PROPERTY_FILENAME);
-        if (scpurl == null)
-        {
-            throw new RuntimeException("unable to locate " + 
DATACENTER_PROPERTY_FILENAME);
-        }
-        String dcPropertyFile = scpurl.getFile();
-        try
-        {
-            Properties props = new Properties();
-            props.load(new FileReader(dcPropertyFile));
-            for (Object key : props.keySet())
+        
+        reloadConfiguration();
+        Runnable runnable = new WrappedRunnable()
+        {
+            protected void runMayThrow() throws ConfigurationException
             {
-                String[] keys = ((String)key).split(":");
-                Map<String, Integer> map = datacenters.get(keys[0]);
-                if (null == map)
-                {
-                    map = new HashMap<String, Integer>();
-                }
-                map.put(keys[1], Integer.parseInt((String)props.get(key)));
-                datacenters.put(keys[0], map);
+                reloadConfiguration();
             }
-        }
-        catch (IOException ioe)
-        {
-            throw new IOError(ioe);
-        }
+        };
+        ResourceWatcher.watch(DATACENTER_PROPERTY_FILENAME, runnable, 60 * 
1000);
 
         loadEndpoints(tokenMetadata);
     }
 
+    public void reloadConfiguration() throws ConfigurationException
+    {
+        Properties props = 
PropertyFileSnitch.resourceToProperties(DATACENTER_PROPERTY_FILENAME);
+        for (Object key : props.keySet())
+        {
+            String[] keys = ((String)key).split(":");
+            Map<String, Integer> map = datacenters.get(keys[0]);
+            if (null == map)
+            {
+                map = new HashMap<String, Integer>();
+            }
+            map.put(keys[1], Integer.parseInt((String)props.get(key)));
+            datacenters.put(keys[0], map);
+        }
+    }
+
     private synchronized void loadEndpoints(TokenMetadata metadata) throws 
ConfigurationException
     {
         String localDC = 
snitch.getDatacenter(DatabaseDescriptor.getListenAddress());

Modified: 
cassandra/trunk/src/java/org/apache/cassandra/locator/PropertyFileSnitch.java
URL: 
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/locator/PropertyFileSnitch.java?rev=948829&r1=948828&r2=948829&view=diff
==============================================================================
--- 
cassandra/trunk/src/java/org/apache/cassandra/locator/PropertyFileSnitch.java 
(original)
+++ 
cassandra/trunk/src/java/org/apache/cassandra/locator/PropertyFileSnitch.java 
Thu May 27 13:28:42 2010
@@ -20,18 +20,14 @@ package org.apache.cassandra.locator;
 
 import java.io.FileReader;
 import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.net.UnknownHostException;
-import java.net.URL;
+import java.net.InetAddress;
 import java.util.Properties;
 import java.util.StringTokenizer;
 
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import java.net.InetAddress;
-
 import org.apache.cassandra.config.ConfigurationException;
+import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.ResourceWatcher;
+import org.apache.cassandra.utils.WrappedRunnable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,11 +36,11 @@ import org.slf4j.LoggerFactory;
  * <p/>
  * Based on a properties file configuration.
  */
-public class PropertyFileSnitch extends AbstractRackAwareSnitch implements 
PropertyFileSnitchMBean {
+public class PropertyFileSnitch extends AbstractRackAwareSnitch {
     /**
      * A list of properties with keys being host:port and values being 
datacenter:rack
      */
-    private Properties hostProperties = new Properties();
+    private volatile Properties hostProperties = new Properties();
 
     /**
      * The default rack property file to be read.
@@ -56,18 +52,16 @@ public class PropertyFileSnitch extends 
      */
     private static Logger logger_ = 
LoggerFactory.getLogger(PropertyFileSnitch.class);
 
-    public PropertyFileSnitch() throws ConfigurationException
-    {
+    public PropertyFileSnitch() throws ConfigurationException {
         reloadConfiguration();
-        try
-        {
-            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-            mbs.registerMBean(this, new ObjectName(MBEAN_OBJECT_NAME));
-        }
-        catch (Exception e)
+        Runnable runnable = new WrappedRunnable()
         {
-            throw new RuntimeException(e);
-        }
+            protected void runMayThrow() throws ConfigurationException
+            {
+                reloadConfiguration();
+            }
+        };
+        ResourceWatcher.watch(RACK_PROPERTY_FILENAME, runnable, 60 * 1000);
     }
 
     /**
@@ -115,40 +109,25 @@ public class PropertyFileSnitch extends 
         return getEndpointInfo(endpoint)[1];
     }
 
-    /**
-     * @return the <tt>String</tt> representation of the configuration
-     */
-    public String displayConfiguration() {
-        StringBuffer configurationString = new StringBuffer("Current rack 
configuration\n=================\n");
-        for (Object key: hostProperties.keySet()) {
-            String endpoint = (String) key;
-            String value = hostProperties.getProperty(endpoint);
-            
configurationString.append(endpoint).append("=").append(value).append("\n");
-        }
-        return configurationString.toString();
-    }
-
-    /**
-     * Reloads the configuration from the file
-     */
     public void reloadConfiguration() throws ConfigurationException
     {
-        ClassLoader loader = PropertyFileSnitch.class.getClassLoader();
-        URL scpurl = loader.getResource(RACK_PROPERTY_FILENAME);
-        if (scpurl == null)
-            throw new ConfigurationException("unable to locate " + 
RACK_PROPERTY_FILENAME);
+        hostProperties = resourceToProperties(RACK_PROPERTY_FILENAME);
+    }
 
-        String rackPropertyFilename = scpurl.getFile();
+    public static Properties resourceToProperties(String filename) throws 
ConfigurationException
+    {
+        String rackPropertyFilename = FBUtilities.resourceToFile(filename);
 
+        Properties localHostProperties;
         try
         {
-            Properties localHostProperties = new Properties();
+            localHostProperties = new Properties();
             localHostProperties.load(new FileReader(rackPropertyFilename));
-            hostProperties = localHostProperties;
         }
-        catch (IOException ioe)
+        catch (IOException e)
         {
-            throw new ConfigurationException("Could not process " + 
rackPropertyFilename, ioe);
+            throw new ConfigurationException("Unable to load " + 
rackPropertyFilename, e);
         }
+        return localHostProperties;
     }
 }

Modified: cassandra/trunk/src/java/org/apache/cassandra/utils/FBUtilities.java
URL: 
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/utils/FBUtilities.java?rev=948829&r1=948828&r2=948829&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/utils/FBUtilities.java 
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/utils/FBUtilities.java Thu 
May 27 13:28:42 2010
@@ -21,6 +21,7 @@ package org.apache.cassandra.utils;
 import java.io.*;
 import java.math.BigInteger;
 import java.net.InetAddress;
+import java.net.URL;
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
@@ -33,6 +34,8 @@ import java.util.zip.DataFormatException
 import java.util.zip.Deflater;
 import java.util.zip.Inflater;
 
+import org.apache.cassandra.config.ConfigurationException;
+import org.apache.cassandra.locator.PropertyFileSnitch;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -548,4 +551,14 @@ public class FBUtilities
         ByteBuffer.wrap(bytes).putLong(n);
         return bytes;
     }
+
+    public static String resourceToFile(String filename) throws 
ConfigurationException
+    {
+        ClassLoader loader = PropertyFileSnitch.class.getClassLoader();
+        URL scpurl = loader.getResource(filename);
+        if (scpurl == null)
+            throw new ConfigurationException("unable to locate " + filename);
+
+        return scpurl.getFile();
+    }
 }

Added: cassandra/trunk/src/java/org/apache/cassandra/utils/ResourceWatcher.java
URL: 
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/utils/ResourceWatcher.java?rev=948829&view=auto
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/utils/ResourceWatcher.java 
(added)
+++ cassandra/trunk/src/java/org/apache/cassandra/utils/ResourceWatcher.java 
Thu May 27 13:28:42 2010
@@ -0,0 +1,51 @@
+package org.apache.cassandra.utils;
+
+import java.io.File;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ResourceWatcher
+{
+    private static Timer timer = new Timer("RESOURCE-WATCHER");
+
+    public static void watch(String resource, Runnable callback, int period)
+    {
+        timer.schedule(new WatchedResource(resource, callback), period, 
period);
+    }
+    
+    public static class WatchedResource extends TimerTask
+    {
+        private static Logger logger = 
LoggerFactory.getLogger(WatchedResource.class);
+        private String resource;
+        private Runnable callback;
+        private long lastLoaded;
+
+        public WatchedResource(String resource, Runnable callback)
+        {
+            this.resource = resource;
+            this.callback = callback;
+            lastLoaded = 0;
+        }
+
+        public void run()
+        {
+            try
+            {
+                String filename = FBUtilities.resourceToFile(resource);
+                long lastModified = new File(filename).lastModified();
+                if (lastModified > lastLoaded)
+                {
+                    callback.run();
+                    lastLoaded = lastModified;
+                }
+            }
+            catch (Throwable t)
+            {
+                logger.error(String.format("Timed run of %s failed.", 
callback.getClass()), t);
+            }
+        }
+    }
+}


Reply via email to