mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-2.0' into cassandra-2.1
Conflicts: CHANGES.txt
This commit is contained in:
commit
5bd6a756e1
|
|
@ -1,3 +1,7 @@
|
|||
2.1.0-rc1
|
||||
Merged from 2.0:
|
||||
* Add Google Compute Engine snitch (CASSANDRA-7132)
|
||||
|
||||
2.1.0-beta2
|
||||
* Increase default CL space to 8GB (CASSANDRA-7031)
|
||||
* Add range tombstones to read repair digests (CASSANDRA-6863)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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.io.DataInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.cassandra.db.SystemKeyspace;
|
||||
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.io.util.FileUtils;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
/**
|
||||
* A snitch that assumes an GCE region is a DC and an GCE availability_zone
|
||||
* is a rack. This information is available in the config for the node.
|
||||
*/
|
||||
public class GoogleCloudSnitch extends AbstractNetworkTopologySnitch
|
||||
{
|
||||
protected static final Logger logger = LoggerFactory.getLogger(GoogleCloudSnitch.class);
|
||||
protected static final String ZONE_NAME_QUERY_URL = "http://metadata.google.internal/computeMetadata/v1/instance/zone";
|
||||
private static final String DEFAULT_DC = "UNKNOWN-DC";
|
||||
private static final String DEFAULT_RACK = "UNKNOWN-RACK";
|
||||
private Map<InetAddress, Map<String, String>> savedEndpoints;
|
||||
protected String gceZone;
|
||||
protected String gceRegion;
|
||||
|
||||
public GoogleCloudSnitch() throws IOException, ConfigurationException
|
||||
{
|
||||
String response = gceApiCall(ZONE_NAME_QUERY_URL);
|
||||
String[] splits = response.split("/");
|
||||
String az = splits[splits.length - 1];
|
||||
|
||||
// Split "us-central1-a" or "asia-east1-a" into "us-central1"/"a" and "asia-east1"/"a".
|
||||
splits = az.split("-");
|
||||
gceZone = splits[splits.length - 1];
|
||||
|
||||
int lastRegionIndex = az.lastIndexOf("-");
|
||||
gceRegion = az.substring(0, lastRegionIndex);
|
||||
|
||||
String datacenterSuffix = (new SnitchProperties()).get("dc_suffix", "");
|
||||
gceRegion = gceRegion.concat(datacenterSuffix);
|
||||
logger.info("GCESnitch using region: {}, zone: {}.", gceRegion, gceZone);
|
||||
}
|
||||
|
||||
String gceApiCall(String url) throws IOException, ConfigurationException
|
||||
{
|
||||
// Populate the region and zone by introspection, fail if 404 on metadata
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
DataInputStream d = null;
|
||||
try
|
||||
{
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("Metadata-Flavor", "Google");
|
||||
if (conn.getResponseCode() != 200)
|
||||
throw new ConfigurationException("GoogleCloudSnitch was unable to execute the API call. Not a gce node?");
|
||||
|
||||
// Read the information.
|
||||
int cl = conn.getContentLength();
|
||||
byte[] b = new byte[cl];
|
||||
d = new DataInputStream((FilterInputStream) conn.getContent());
|
||||
d.readFully(b);
|
||||
return new String(b, StandardCharsets.UTF_8);
|
||||
}
|
||||
finally
|
||||
{
|
||||
FileUtils.close(d);
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public String getRack(InetAddress endpoint)
|
||||
{
|
||||
if (endpoint.equals(FBUtilities.getBroadcastAddress()))
|
||||
return gceZone;
|
||||
EndpointState state = Gossiper.instance.getEndpointStateForEndpoint(endpoint);
|
||||
if (state == null || state.getApplicationState(ApplicationState.RACK) == null)
|
||||
{
|
||||
if (savedEndpoints == null)
|
||||
savedEndpoints = SystemKeyspace.loadDcRackInfo();
|
||||
if (savedEndpoints.containsKey(endpoint))
|
||||
return savedEndpoints.get(endpoint).get("rack");
|
||||
return DEFAULT_RACK;
|
||||
}
|
||||
return state.getApplicationState(ApplicationState.RACK).value;
|
||||
}
|
||||
|
||||
public String getDatacenter(InetAddress endpoint)
|
||||
{
|
||||
if (endpoint.equals(FBUtilities.getBroadcastAddress()))
|
||||
return gceRegion;
|
||||
EndpointState state = Gossiper.instance.getEndpointStateForEndpoint(endpoint);
|
||||
if (state == null || state.getApplicationState(ApplicationState.DC) == null)
|
||||
{
|
||||
if (savedEndpoints == null)
|
||||
savedEndpoints = SystemKeyspace.loadDcRackInfo();
|
||||
if (savedEndpoints.containsKey(endpoint))
|
||||
return savedEndpoints.get(endpoint).get("data_center");
|
||||
return DEFAULT_DC;
|
||||
}
|
||||
return state.getApplicationState(ApplicationState.DC).value;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
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.Map;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.SchemaLoader;
|
||||
import org.apache.cassandra.db.Keyspace;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.gms.ApplicationState;
|
||||
import org.apache.cassandra.gms.Gossiper;
|
||||
import org.apache.cassandra.gms.VersionedValue;
|
||||
import org.apache.cassandra.net.MessagingService;
|
||||
import org.apache.cassandra.net.OutboundTcpConnectionPool;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class GoogleCloudSnitchTest
|
||||
{
|
||||
private static String az;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws Exception
|
||||
{
|
||||
SchemaLoader.mkdirs();
|
||||
SchemaLoader.cleanup();
|
||||
Keyspace.setInitialized();
|
||||
StorageService.instance.initServer(0);
|
||||
}
|
||||
|
||||
private class TestGoogleCloudSnitch extends GoogleCloudSnitch
|
||||
{
|
||||
public TestGoogleCloudSnitch() throws IOException, ConfigurationException
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
String gceApiCall(String url) throws IOException, ConfigurationException
|
||||
{
|
||||
return az;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRac() throws IOException, ConfigurationException
|
||||
{
|
||||
az = "us-central1-a";
|
||||
GoogleCloudSnitch snitch = new TestGoogleCloudSnitch();
|
||||
InetAddress local = InetAddress.getByName("127.0.0.1");
|
||||
InetAddress nonlocal = InetAddress.getByName("127.0.0.7");
|
||||
|
||||
Gossiper.instance.addSavedEndpoint(nonlocal);
|
||||
Map<ApplicationState,VersionedValue> stateMap = Gossiper.instance.getEndpointStateForEndpoint(nonlocal).getApplicationStateMap();
|
||||
stateMap.put(ApplicationState.DC, StorageService.instance.valueFactory.datacenter("europe-west1"));
|
||||
stateMap.put(ApplicationState.RACK, StorageService.instance.valueFactory.datacenter("a"));
|
||||
|
||||
assertEquals("europe-west1", snitch.getDatacenter(nonlocal));
|
||||
assertEquals("a", snitch.getRack(nonlocal));
|
||||
|
||||
assertEquals("us-central1", snitch.getDatacenter(local));
|
||||
assertEquals("a", snitch.getRack(local));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewRegions() throws IOException, ConfigurationException
|
||||
{
|
||||
az = "asia-east1-a";
|
||||
GoogleCloudSnitch snitch = new TestGoogleCloudSnitch();
|
||||
InetAddress local = InetAddress.getByName("127.0.0.1");
|
||||
assertEquals("asia-east1", snitch.getDatacenter(local));
|
||||
assertEquals("a", snitch.getRack(local));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown()
|
||||
{
|
||||
StorageService.instance.stopClient();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue