Permalink
Browse files

Merge branch 'cassandra-2.1' into trunk

  • Loading branch information...
2 parents e30d6dc + f67b7a4 commit 9371892374ddb8cc1d495ec4d38554603ec78a3a @thobbs thobbs committed Mar 6, 2014
View
@@ -4,6 +4,7 @@
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)
View
@@ -93,7 +93,7 @@
<property name="test.long.timeout" value="600000" />
<!-- http://cobertura.sourceforge.net/ -->
- <property name="cobertura.version" value="1.9.4.1"/>
+ <property name="cobertura.version" value="2.0.2"/>
<property name="cobertura.build.dir" value="${build.dir}/cobertura"/>
<property name="cobertura.report.dir" value="${cobertura.build.dir}/report"/>
<property name="cobertura.classes.dir" value="${cobertura.build.dir}/classes"/>
@@ -62,7 +62,7 @@ public Ec2Snitch() throws IOException, ConfigurationException
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);
}
@@ -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,32 +30,41 @@
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
{
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 GossipingPropertyFileSnitch() throws ConfigurationException
{
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 String getRack(InetAddress endpoint)
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()
}
}
@@ -73,7 +73,7 @@ protected void runMayThrow() throws ConfigurationException
}
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);
}
}
@@ -28,10 +28,12 @@
{
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 @@
}
/**
- * 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);
}
@@ -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
@@ -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);
+ }
+ }
+}
@@ -88,7 +88,7 @@ public void testBasic() throws Exception
* @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)
{

0 comments on commit 9371892

Please sign in to comment.