com.gemstone.gemfire.cache.client.internal.AutoConnectionSourceImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
TIBCO ComputeDB store based off Pivotal GemFireXD
/*
* Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
*
* Licensed 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. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.cache.client.internal;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import com.gemstone.gemfire.cache.client.NoAvailableLocatorsException;
import com.gemstone.gemfire.cache.client.internal.PoolImpl.PoolTask;
import com.gemstone.gemfire.cache.client.internal.locator.ClientConnectionRequest;
import com.gemstone.gemfire.cache.client.internal.locator.GetAllServersRequest;
import com.gemstone.gemfire.cache.client.internal.locator.ClientConnectionResponse;
import com.gemstone.gemfire.cache.client.internal.locator.GetAllServersResponse;
import com.gemstone.gemfire.cache.client.internal.locator.ClientReplacementRequest;
import com.gemstone.gemfire.cache.client.internal.locator.LocatorListRequest;
import com.gemstone.gemfire.cache.client.internal.locator.LocatorListResponse;
import com.gemstone.gemfire.cache.client.internal.locator.QueueConnectionRequest;
import com.gemstone.gemfire.cache.client.internal.locator.QueueConnectionResponse;
import com.gemstone.gemfire.cache.client.internal.locator.ServerLocationRequest;
import com.gemstone.gemfire.cache.client.internal.locator.ServerLocationResponse;
import com.gemstone.gemfire.distributed.internal.ServerLocation;
import com.gemstone.gemfire.distributed.internal.tcpserver.TcpClient;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.cache.tier.sockets.ClientProxyMembershipID;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
/**
* A connection source which uses locators to find
* the least loaded server.
* @author dsmith
* @since 5.7
*
*/
public class AutoConnectionSourceImpl implements ConnectionSource {
protected static final LocatorListRequest LOCATOR_LIST_REQUEST = new LocatorListRequest();
private static final Comparator SOCKET_ADDRESS_COMPARATOR = new Comparator() {
public int compare(InetSocketAddress o1,InetSocketAddress o2){
//shouldn't happen, but if it does we'll say they're the same.
if(o1.getAddress() == null || o2.getAddress() == null) {
return 0;
}
int result = o1.getAddress().getCanonicalHostName().compareTo(o1.getAddress().getCanonicalHostName());
if(result != 0) {
return result;
}
else return o1.getPort() - o2.getPort();
}
};
protected final List initialLocators;
private final String serverGroup;
private AtomicReference locators = new AtomicReference();
protected InternalPool pool;
private final int connectionTimeout;
private long pingInterval;
private volatile LocatorDiscoveryCallback locatorCallback = new LocatorDiscoveryCallbackAdapter();
private volatile boolean isBalanced = true;
/**
* key is the InetSocketAddress of the locator.
* value will be an exception if we have already found the locator to be dead.
* value will be null if we last saw him alive.
*/
private final Map locatorState = new HashMap();
/**
* @param contacts
* @param serverGroup
* @param handshakeTimeout
*/
public AutoConnectionSourceImpl(Listcontacts, String serverGroup, int handshakeTimeout) {
ArrayList tmpContacts = new ArrayList(contacts);
this.locators.set(new LocatorList(tmpContacts));
this.initialLocators = Collections.unmodifiableList(tmpContacts);
this.connectionTimeout = handshakeTimeout;
this.serverGroup = serverGroup;
}
public boolean isBalanced() {
return isBalanced;
}
public ServerLocation findReplacementServer(ServerLocation currentServer, Set/**/ excludedServers) {
if(PoolImpl.TEST_DURABLE_IS_NET_DOWN) {
return null;
}
ClientReplacementRequest request = new ClientReplacementRequest(currentServer, excludedServers, serverGroup);
ClientConnectionResponse response = (ClientConnectionResponse) queryLocators(request);
if (response==null) {
// why log a warning if we are going to throw the caller and exception?
//getLogger().warning("Unable to connect to any locators in the list " + locators);
throw new NoAvailableLocatorsException("Unable to connect to any locators in the list " + locators);
}
// if(getLogger().fineEnabled()) {
// getLogger().fine("Received client connection response with server " + response.getServer());
// }
return response.getServer();
}
public ServerLocation findServer(Set excludedServers) {
if(PoolImpl.TEST_DURABLE_IS_NET_DOWN) {
return null;
}
ClientConnectionRequest request = new ClientConnectionRequest(excludedServers, serverGroup);
ClientConnectionResponse response = (ClientConnectionResponse) queryLocators(request);
if (response==null) {
// why log a warning if we are going to throw the caller and exception?
//getLogger().warning("Unable to connect to any locators in the list " + locators);
throw new NoAvailableLocatorsException("Unable to connect to any locators in the list " + locators);
}
// if(getLogger().fineEnabled()) {
// getLogger().fine("Received client connection response with server " + response.getServer());
// }
return response.getServer();
}
public ArrayList findAllServers() {
if (PoolImpl.TEST_DURABLE_IS_NET_DOWN) {
return null;
}
GetAllServersRequest request = new GetAllServersRequest(serverGroup);
GetAllServersResponse response = (GetAllServersResponse)queryLocators(request);
if(response != null){
return response.getServers();
}else {
return null ;
}
}
public List/* ServerLocation */findServersForQueue(
Set/* */excludedServers, int numServers,
ClientProxyMembershipID proxyId, boolean findDurableQueue) {
if(PoolImpl.TEST_DURABLE_IS_NET_DOWN) {
return new ArrayList();
}
QueueConnectionRequest request = new QueueConnectionRequest(proxyId,numServers,excludedServers, serverGroup,findDurableQueue);
QueueConnectionResponse response = (QueueConnectionResponse) queryLocators(request);
if (response==null) {
// why log a warning if we are going to throw the caller and exception?
//getLogger().warning("Unable to connect to any locators in the list " + locators);
throw new NoAvailableLocatorsException("Unable to connect to any locators in the list " + locators);
}
//TODO - do this logic on the server side, return one list in the message.
List result = response.getServers();
// if(getLogger().fineEnabled()) {
// getLogger().fine("Received queue connection response with server " + result+" excludeList:"+excludedServers);
// }
return result;
}
private ServerLocationResponse queryOneLocator(InetSocketAddress locator, ServerLocationRequest request) {
InetAddress addr = locator.getAddress();
int port = locator.getPort();
Object returnObj = null;
try {
pool.getStats().incLocatorRequests();
returnObj = TcpClient.requestToServer(addr, port, request, connectionTimeout);
ServerLocationResponse response = (ServerLocationResponse)returnObj;
pool.getStats().incLocatorResponses();
if(response != null) {
reportLiveLocator(locator);
}
return response;
} catch(IOException ioe) {
reportDeadLocator(locator, ioe);
return null;
} catch (ClassNotFoundException e) {
getLogger().warning(LocalizedStrings.AutoConnectionSourceImpl_RECEIVED_EXCEPTION_FROM_LOCATOR_0, locator, e);
return null;
} catch (ClassCastException e) {
if (getLogger().fineEnabled()) {
getLogger().fine("Received odd response object from the locator: " + returnObj);
}
reportDeadLocator(locator, e);
return null;
}
}
protected ServerLocationResponse queryLocators(ServerLocationRequest request) {
Iterator controllerItr = locators.get().iterator();
ServerLocationResponse response = null;
do {
InetSocketAddress locator = (InetSocketAddress) controllerItr.next();
LogWriterI18n log = getLogger();
if (log.fineEnabled()) {
log.fine("Sending query to locator " + locator + ": " + request);
}
response = queryOneLocator(locator, request);
if (log.fineEnabled()) {
log.fine("Received query response from locator " + locator + ": " + response);
}
} while(controllerItr.hasNext() && (response == null || !response.hasResult()));
if(response == null) {
return null;
}
return response;
}
protected void updateLocatorList(LocatorListResponse response) {
if (response == null) return;
isBalanced = response.isBalanced();
ArrayList locatorResponse = response.getLocators();
ArrayList newLocators = new ArrayList(locatorResponse.size());
Set badLocators = new HashSet(initialLocators);
for(Iterator itr = locatorResponse.iterator(); itr.hasNext(); ) {
ServerLocation locator = itr.next();
InetSocketAddress address = new InetSocketAddress(locator.getHostName(), locator.getPort());
newLocators.add(address);
badLocators.remove(address);
}
newLocators.addAll(badLocators);
if(getLogger().infoEnabled()) {
LocatorList oldLocators = (LocatorList) locators.get();
ArrayList removedLocators = new ArrayList(oldLocators.getLocators());
removedLocators.removeAll(newLocators);
ArrayList addedLocators = new ArrayList(newLocators);
addedLocators.removeAll(oldLocators.getLocators());
if(!addedLocators.isEmpty()) {
locatorCallback.locatorsDiscovered(Collections.unmodifiableList(addedLocators));
getLogger().info(LocalizedStrings.AutoConnectionSourceImpl_AUTOCONNECTIONSOURCE_DISCOVERED_NEW_LOCATORS_0, addedLocators);
}
if(!removedLocators.isEmpty()) {
locatorCallback.locatorsRemoved(Collections.unmodifiableList(removedLocators));
getLogger().info(LocalizedStrings.AutoConnectionSourceImpl_AUTOCONNECTIONSOURCE_DROPPING_PREVIOUSLY_DISCOVERED_LOCATORS_0, removedLocators);
}
}
LocatorList newLocatorList = new LocatorList(newLocators);
locators.set(newLocatorList);
pool.getStats().setLocatorCount(newLocators.size());
}
public void start(InternalPool pool) {
this.pool = pool;
pool.getStats().setInitialContacts(((LocatorList)locators.get()).size());
this.pingInterval = pool.getPingInterval();
pool.getBackgroundProcessor().scheduleWithFixedDelay(new UpdateLocatorListTask(), 0, pingInterval, TimeUnit.MILLISECONDS);
}
public void stop() {
}
public void setLocatorDiscoveryCallback(LocatorDiscoveryCallback callback) {
this.locatorCallback = callback;
}
private synchronized void reportLiveLocator(InetSocketAddress l) {
Object prevState = this.locatorState.put(l, null);
if (prevState != null) {
getLogger().info(LocalizedStrings.AutoConnectionSourceImpl_COMMUNICATION_HAS_BEEN_RESTORED_WITH_LOCATOR_0, l);
}
}
private synchronized void reportDeadLocator(InetSocketAddress l, Exception ex) {
Object prevState = this.locatorState.put(l, ex);
if (prevState == null) {
if (ex instanceof ConnectException) {
getLogger().info(LocalizedStrings.AutoConnectionSourceImpl_LOCATOR_0_IS_NOT_RUNNING, l,ex);
} else {
getLogger().info(
LocalizedStrings.AutoConnectionSourceImpl_COMMUNICATION_WITH_LOCATOR_0_FAILED_WITH_1,
new Object[] {l, ex},ex);
}
}
}
/** A list of locators, which
* remembers the last known good locator.
*/
private static class LocatorList {
protected final List locators;
protected final AtomicInteger currentLocatorIndex = new AtomicInteger();
public LocatorList(List locators) {
Collections.sort(locators, SOCKET_ADDRESS_COMPARATOR);
this.locators = Collections.unmodifiableList(locators);
}
public Collection getLocators() {
return locators;
}
public int size() {
return locators.size();
}
public Iterator iterator() {
return new LocatorIterator();
}
@Override
public String toString() {
return locators.toString();
}
/**
* An iterator which iterates all of the controllers,
* starting at the last known good controller.
*
*/
protected class LocatorIterator implements Iterator {
private int startLocator= currentLocatorIndex.get();
private int locatorNum = 0;
public boolean hasNext() {
return locatorNum < locators.size();
}
public InetSocketAddress next() {
if(!hasNext()) {
return null;
} else {
int index = (locatorNum + startLocator) % locators.size();
InetSocketAddress nextLocator = locators.get(index);
currentLocatorIndex.set(index);
locatorNum++;
return nextLocator;
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
private LogWriterI18n getLogger() {
return pool.getLoggerI18n();
}
protected class UpdateLocatorListTask extends PoolTask {
@Override
public void run2() {
if(pool.getCancelCriterion().cancelInProgress() != null) {
return;
}
LocatorListResponse response = (LocatorListResponse) queryLocators(LOCATOR_LIST_REQUEST);
updateLocatorList(response);
}
@Override
public LogWriterI18n getLogger() {
return pool.getLoggerI18n();
}
}
}