Auto reload GossipingPropertyFileSnitch config

Patch by Danield Shelepov, reviewed by Tyler Hobbs for CASSANDRA-5897
This commit is contained in:
Tyler Hobbs 2014-03-06 11:22:47 -06:00
parent 728f677b0f
commit f67b7a477a
8 changed files with 176 additions and 23 deletions

View File

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

View File

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

View File

@ -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 Map<InetAddress, Map<String, String>> savedEndpoints;
private String DEFAULT_DC = "UNKNOWN_DC";
private String DEFAULT_RACK = "UNKNOWN_RACK";
private final boolean preferLocal;
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 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()
}
}

View File

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

View File

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

View File

@ -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

View File

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

View File

@ -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)
{