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.apache.log4j.Logger; 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 AbstractEndpointSnitch { /** * 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_ = Logger.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 getRackForEndPoint(InetAddress endPoint) throws UnknownHostException { byte[] ipQuads = getIPAddress(endPoint.getHostAddress()); return ipRAC.get(ipQuads[1]).get(ipQuads[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); } } /** * This methood will return ture if the hosts are in the same RAC else * false. */ public boolean isOnSameRack(InetAddress host, InetAddress host2) throws UnknownHostException { /* * Look at the IP Address of the two hosts. Compare the 2nd and 3rd * octet. If they are the same then the hosts are in the same rack else * different racks. */ byte[] ip = getIPAddress(host.getHostAddress()); byte[] ip2 = getIPAddress(host2.getHostAddress()); return ipRAC.get(ip[1]).get(ip[2]) .equals(ipRAC.get(ip2[1]).get(ip2[2])); } /** * This methood will return ture if the hosts are in the same DC else false. */ public boolean isInSameDataCenter(InetAddress host, InetAddress host2) throws UnknownHostException { /* * Look at the IP Address of the two hosts. Compare the 2nd and 3rd * octet and get the DC Name. If they are the same then the hosts are in * the same datacenter else different datacenter. */ byte[] ip = getIPAddress(host.getHostAddress()); byte[] ip2 = getIPAddress(host2.getHostAddress()); return ipDC.get(ip[1]).get(ip[2]).equals(ipDC.get(ip2[1]).get(ip2[2])); } /** * 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); } public String getLocation(InetAddress endpoint) throws UnknownHostException { byte[] ipQuads = getIPAddress(endpoint.getHostAddress()); return ipDC.get(ipQuads[1]).get(ipQuads[2]); } }