mirror of https://github.com/apache/cassandra
move per-datacenter replication factor into datacenters.properties
patch by jbellis; reviewed by eevans for CASSANDRA-994 git-svn-id: https://svn.apache.org/repos/asf/cassandra/trunk@938568 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
40df0ce87e
commit
2acfb43599
|
|
@ -0,0 +1,20 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# datacenter=replication factor
|
||||||
|
dc1=3
|
||||||
|
dc2=5
|
||||||
|
dc3=1
|
||||||
|
|
@ -1,173 +0,0 @@
|
||||||
package org.apache.cassandra.locator;
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import org.apache.cassandra.utils.XMLUtils;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DataCenterEndpointSnitch
|
|
||||||
* <p/>
|
|
||||||
* This class basically reads the configuration and sets the IP Ranges to a
|
|
||||||
* hashMap which can be read later. this class also provides a way to compare 2
|
|
||||||
* Endpoints and also get details from the same.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DatacenterEndpointSnitch extends AbstractRackAwareSnitch
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* This Map will contain the information of the Endpoints and its Location
|
|
||||||
* (Datacenter and RAC)
|
|
||||||
*/
|
|
||||||
private Map<Byte, Map<Byte, String>> ipDC = new HashMap<Byte, Map<Byte, String>>();
|
|
||||||
private Map<Byte, Map<Byte, String>> ipRAC = new HashMap<Byte, Map<Byte, String>>();
|
|
||||||
private Map<String, Integer> dcRepFactor = new HashMap<String, Integer>();
|
|
||||||
|
|
||||||
private XMLUtils xmlUtils;
|
|
||||||
private Map<String, Integer> quorumDCMap = new HashMap<String, Integer>();
|
|
||||||
/**
|
|
||||||
* The default rack property file to be read.
|
|
||||||
*/
|
|
||||||
private static String DEFAULT_RACK_CONFIG_FILE = "/etc/cassandra/DC-Config.xml";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to the logger.
|
|
||||||
*/
|
|
||||||
private static Logger logger_ = LoggerFactory.getLogger(DatacenterEndpointSnitch.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor, intialize XML config and read the config in...
|
|
||||||
*/
|
|
||||||
public DatacenterEndpointSnitch() throws IOException, ParserConfigurationException, SAXException
|
|
||||||
{
|
|
||||||
xmlUtils = new XMLUtils(DEFAULT_RACK_CONFIG_FILE);
|
|
||||||
reloadConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the rack for which an endpoint resides in
|
|
||||||
*/
|
|
||||||
public String getRack(InetAddress endpoint) throws UnknownHostException
|
|
||||||
{
|
|
||||||
byte[] ip = getIPAddress(endpoint.getHostAddress());
|
|
||||||
return ipRAC.get(ip[1]).get(ip[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the datacenter for which an endpoint resides in
|
|
||||||
*/
|
|
||||||
public String getDatacenter(InetAddress endpoint) throws UnknownHostException
|
|
||||||
{
|
|
||||||
byte[] ip = getIPAddress(endpoint.getHostAddress());
|
|
||||||
return ipDC.get(ip[1]).get(ip[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will load the configuration from the xml file. Mandatory
|
|
||||||
* fields are Atleast 1 DC and 1RAC configurations. Name of the DC/RAC, IP
|
|
||||||
* Quadrents for RAC and DC.
|
|
||||||
* <p/>
|
|
||||||
* This method will not be called everytime
|
|
||||||
*/
|
|
||||||
public void reloadConfiguration() throws IOException
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String[] dcNames = xmlUtils.getNodeValues("/Endpoints/DataCenter/name");
|
|
||||||
for (String dcName : dcNames)
|
|
||||||
{
|
|
||||||
// Parse the Datacenter Quaderant.
|
|
||||||
String dcXPath = "/Endpoints/DataCenter[name='" + dcName + "']";
|
|
||||||
String dcIPQuad = xmlUtils.getNodeValue(dcXPath + "/ip2ndQuad");
|
|
||||||
String replicationFactor = xmlUtils.getNodeValue(dcXPath + "/replicationFactor");
|
|
||||||
byte dcByte = intToByte(Integer.parseInt(dcIPQuad));
|
|
||||||
// Parse the replication factor for a DC
|
|
||||||
int dcReF = Integer.parseInt(replicationFactor);
|
|
||||||
dcRepFactor.put(dcName, dcReF);
|
|
||||||
quorumDCMap.put(dcName, (dcReF / 2 + 1));
|
|
||||||
String[] racNames = xmlUtils.getNodeValues(dcXPath + "/rack/name");
|
|
||||||
Map<Byte, String> dcRackMap = ipDC.get(dcByte);
|
|
||||||
if (null == dcRackMap)
|
|
||||||
{
|
|
||||||
dcRackMap = new HashMap<Byte, String>();
|
|
||||||
}
|
|
||||||
Map<Byte, String> rackDcMap = ipRAC.get(dcByte);
|
|
||||||
if (null == rackDcMap)
|
|
||||||
{
|
|
||||||
rackDcMap = new HashMap<Byte, String>();
|
|
||||||
}
|
|
||||||
for (String racName : racNames)
|
|
||||||
{
|
|
||||||
// Parse the RAC ip Quaderant.
|
|
||||||
String racIPQuad = xmlUtils.getNodeValue(dcXPath + "/rack[name = '" + racName + "']/ip3rdQuad");
|
|
||||||
byte racByte = intToByte(Integer.parseInt(racIPQuad));
|
|
||||||
dcRackMap.put(racByte, dcName);
|
|
||||||
rackDcMap.put(racByte, racName);
|
|
||||||
}
|
|
||||||
ipDC.put(dcByte, dcRackMap);
|
|
||||||
ipRAC.put(dcByte, rackDcMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ioe)
|
|
||||||
{
|
|
||||||
throw new IOException("Could not process " + DEFAULT_RACK_CONFIG_FILE, ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a DC replication map, the key will be the dc name and the value
|
|
||||||
* will be the replication factor of that Datacenter.
|
|
||||||
*/
|
|
||||||
public HashMap<String, Integer> getMapReplicationFactor()
|
|
||||||
{
|
|
||||||
return new HashMap<String, Integer>(dcRepFactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a DC replication map, the key will be the dc name and the value
|
|
||||||
* will be the replication factor of that Datacenter.
|
|
||||||
*/
|
|
||||||
public HashMap<String, Integer> getMapQuorumFactor()
|
|
||||||
{
|
|
||||||
return new HashMap<String, Integer>(quorumDCMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] getIPAddress(String host) throws UnknownHostException
|
|
||||||
{
|
|
||||||
InetAddress ia = InetAddress.getByName(host);
|
|
||||||
return ia.getAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte intToByte(int n)
|
|
||||||
{
|
|
||||||
return (byte) (n & 0x000000ff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -21,13 +21,16 @@ package org.apache.cassandra.locator;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.IOError;
|
import java.io.IOError;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.net.URL;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.apache.cassandra.config.ConfigurationException;
|
||||||
import org.apache.cassandra.dht.Token;
|
import org.apache.cassandra.dht.Token;
|
||||||
import org.apache.cassandra.service.*;
|
import org.apache.cassandra.service.*;
|
||||||
import org.apache.cassandra.thrift.ConsistencyLevel;
|
import org.apache.cassandra.thrift.ConsistencyLevel;
|
||||||
|
|
@ -50,6 +53,7 @@ public class DatacenterShardStrategy extends AbstractReplicationStrategy
|
||||||
ArrayList<Token> tokens;
|
ArrayList<Token> tokens;
|
||||||
|
|
||||||
private List<InetAddress> localEndpoints = new ArrayList<InetAddress>();
|
private List<InetAddress> localEndpoints = new ArrayList<InetAddress>();
|
||||||
|
private static final String DATACENTER_PROPERTIES_FILENAME = "datacenters.properties";
|
||||||
|
|
||||||
private List<InetAddress> getLocalEndpoints()
|
private List<InetAddress> getLocalEndpoints()
|
||||||
{
|
{
|
||||||
|
|
@ -65,15 +69,15 @@ public class DatacenterShardStrategy extends AbstractReplicationStrategy
|
||||||
* This Method will get the required information of the Endpoint from the
|
* This Method will get the required information of the Endpoint from the
|
||||||
* DataCenterEndpointSnitch and poopulates this singleton class.
|
* DataCenterEndpointSnitch and poopulates this singleton class.
|
||||||
*/
|
*/
|
||||||
private synchronized void loadEndpoints(TokenMetadata metadata) throws IOException
|
private synchronized void loadEndpoints(TokenMetadata metadata) throws UnknownHostException
|
||||||
{
|
{
|
||||||
this.tokens = new ArrayList<Token>(metadata.sortedTokens());
|
this.tokens = new ArrayList<Token>(metadata.sortedTokens());
|
||||||
String localDC = ((DatacenterEndpointSnitch)snitch_).getDatacenter(InetAddress.getLocalHost());
|
String localDC = ((AbstractRackAwareSnitch)snitch_).getDatacenter(InetAddress.getLocalHost());
|
||||||
dcMap = new HashMap<String, List<Token>>();
|
dcMap = new HashMap<String, List<Token>>();
|
||||||
for (Token token : this.tokens)
|
for (Token token : this.tokens)
|
||||||
{
|
{
|
||||||
InetAddress endpoint = metadata.getEndpoint(token);
|
InetAddress endpoint = metadata.getEndpoint(token);
|
||||||
String dataCenter = ((DatacenterEndpointSnitch)snitch_).getDatacenter(endpoint);
|
String dataCenter = ((AbstractRackAwareSnitch)snitch_).getDatacenter(endpoint);
|
||||||
if (dataCenter.equals(localDC))
|
if (dataCenter.equals(localDC))
|
||||||
{
|
{
|
||||||
localEndpoints.add(endpoint);
|
localEndpoints.add(endpoint);
|
||||||
|
|
@ -92,7 +96,6 @@ public class DatacenterShardStrategy extends AbstractReplicationStrategy
|
||||||
Collections.sort(valueList);
|
Collections.sort(valueList);
|
||||||
dcMap.put(entry.getKey(), valueList);
|
dcMap.put(entry.getKey(), valueList);
|
||||||
}
|
}
|
||||||
dcReplicationFactor = ((DatacenterEndpointSnitch)snitch_).getMapReplicationFactor();
|
|
||||||
for (Entry<String, Integer> entry : dcReplicationFactor.entrySet())
|
for (Entry<String, Integer> entry : dcReplicationFactor.entrySet())
|
||||||
{
|
{
|
||||||
String datacenter = entry.getKey();
|
String datacenter = entry.getKey();
|
||||||
|
|
@ -105,13 +108,33 @@ public class DatacenterShardStrategy extends AbstractReplicationStrategy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DatacenterShardStrategy(TokenMetadata tokenMetadata, IEndpointSnitch snitch)
|
public DatacenterShardStrategy(TokenMetadata tokenMetadata, IEndpointSnitch snitch) throws ConfigurationException
|
||||||
throws UnknownHostException
|
|
||||||
{
|
{
|
||||||
super(tokenMetadata, snitch);
|
super(tokenMetadata, snitch);
|
||||||
if ((!(snitch instanceof DatacenterEndpointSnitch)))
|
if (!(snitch instanceof AbstractRackAwareSnitch))
|
||||||
{
|
{
|
||||||
throw new IllegalArgumentException("DatacenterShardStrategy requires DatacenterEndpointSnitch");
|
throw new IllegalArgumentException("DatacenterShardStrategy requires a rack-aware endpointsnitch");
|
||||||
|
}
|
||||||
|
|
||||||
|
// load replication factors for each DC
|
||||||
|
ClassLoader loader = PropertyFileSnitch.class.getClassLoader();
|
||||||
|
URL scpurl = loader.getResource(DATACENTER_PROPERTIES_FILENAME);
|
||||||
|
if (scpurl == null)
|
||||||
|
throw new ConfigurationException("unable to locate " + DATACENTER_PROPERTIES_FILENAME);
|
||||||
|
|
||||||
|
String rackPropertyFilename = scpurl.getFile();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Properties p = new Properties();
|
||||||
|
p.load(new FileReader(rackPropertyFilename));
|
||||||
|
for (Entry<Object, Object> entry : p.entrySet())
|
||||||
|
{
|
||||||
|
dcReplicationFactor.put((String)entry.getKey(), Integer.valueOf((String)entry.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
throw new ConfigurationException("Could not process " + rackPropertyFilename, ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -224,4 +247,9 @@ public class DatacenterShardStrategy extends AbstractReplicationStrategy
|
||||||
}
|
}
|
||||||
return super.getWriteResponseHandler(blockFor, consistency_level, table);
|
return super.getWriteResponseHandler(blockFor, consistency_level, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getReplicationFactor(String datacenter)
|
||||||
|
{
|
||||||
|
return dcReplicationFactor.get(datacenter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||||
import org.apache.cassandra.locator.DatacenterEndpointSnitch;
|
import org.apache.cassandra.locator.AbstractRackAwareSnitch;
|
||||||
import org.apache.cassandra.net.Message;
|
import org.apache.cassandra.net.Message;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -41,14 +41,14 @@ public class DatacenterSyncWriteResponseHandler extends WriteResponseHandler
|
||||||
{
|
{
|
||||||
private final Map<String, Integer> dcResponses = new HashMap<String, Integer>();
|
private final Map<String, Integer> dcResponses = new HashMap<String, Integer>();
|
||||||
private final Map<String, Integer> responseCounts;
|
private final Map<String, Integer> responseCounts;
|
||||||
private final DatacenterEndpointSnitch endpointSnitch;
|
private final AbstractRackAwareSnitch endpointSnitch;
|
||||||
|
|
||||||
public DatacenterSyncWriteResponseHandler(Map<String, Integer> responseCounts, String table)
|
public DatacenterSyncWriteResponseHandler(Map<String, Integer> responseCounts, String table)
|
||||||
{
|
{
|
||||||
// Response is been managed by the map so make it 1 for the superclass.
|
// Response is been managed by the map so make it 1 for the superclass.
|
||||||
super(1, table);
|
super(1, table);
|
||||||
this.responseCounts = responseCounts;
|
this.responseCounts = responseCounts;
|
||||||
endpointSnitch = (DatacenterEndpointSnitch) DatabaseDescriptor.getEndpointSnitch();
|
endpointSnitch = (AbstractRackAwareSnitch) DatabaseDescriptor.getEndpointSnitch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import java.net.UnknownHostException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||||
import org.apache.cassandra.locator.DatacenterEndpointSnitch;
|
import org.apache.cassandra.locator.AbstractRackAwareSnitch;
|
||||||
import org.apache.cassandra.net.Message;
|
import org.apache.cassandra.net.Message;
|
||||||
import org.apache.cassandra.utils.FBUtilities;
|
import org.apache.cassandra.utils.FBUtilities;
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ import org.apache.cassandra.utils.FBUtilities;
|
||||||
public class DatacenterWriteResponseHandler extends WriteResponseHandler
|
public class DatacenterWriteResponseHandler extends WriteResponseHandler
|
||||||
{
|
{
|
||||||
private final AtomicInteger blockFor;
|
private final AtomicInteger blockFor;
|
||||||
private final DatacenterEndpointSnitch endpointsnitch;
|
private final AbstractRackAwareSnitch endpointsnitch;
|
||||||
private final InetAddress localEndpoint;
|
private final InetAddress localEndpoint;
|
||||||
|
|
||||||
public DatacenterWriteResponseHandler(int blockFor, String table)
|
public DatacenterWriteResponseHandler(int blockFor, String table)
|
||||||
|
|
@ -49,7 +49,7 @@ public class DatacenterWriteResponseHandler extends WriteResponseHandler
|
||||||
// Response is been managed by the map so the waitlist size really doesnt matter.
|
// Response is been managed by the map so the waitlist size really doesnt matter.
|
||||||
super(blockFor, table);
|
super(blockFor, table);
|
||||||
this.blockFor = new AtomicInteger(blockFor);
|
this.blockFor = new AtomicInteger(blockFor);
|
||||||
endpointsnitch = (DatacenterEndpointSnitch) DatabaseDescriptor.getEndpointSnitch();
|
endpointsnitch = (AbstractRackAwareSnitch) DatabaseDescriptor.getEndpointSnitch();
|
||||||
localEndpoint = FBUtilities.getLocalAddress();
|
localEndpoint = FBUtilities.getLocalAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# datacenter=replication factor
|
||||||
|
dc1=3
|
||||||
|
dc2=5
|
||||||
|
dc3=1
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package org.apache.cassandra.locator;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.apache.cassandra.config.ConfigurationException;
|
||||||
|
|
||||||
|
public class DatacenterStrategyTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testProperties() throws ConfigurationException
|
||||||
|
{
|
||||||
|
DatacenterShardStrategy strategy = new DatacenterShardStrategy(new TokenMetadata(), new RackInferringSnitch());
|
||||||
|
assert strategy.getReplicationFactor("dc1") == 3;
|
||||||
|
assert strategy.getReplicationFactor("dc2") == 5;
|
||||||
|
assert strategy.getReplicationFactor("dc3") == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue