com.senseidb.search.node.SenseiServer Maven / Gradle / Ivy
The newest version!
/**
* This software is licensed to you under the Apache License, Version 2.0 (the
* "Apache License").
*
* LinkedIn's contributions are made under the Apache License. If you contribute
* to the Software, the contributions will be deemed to have been made under the
* Apache License, unless you expressly indicate otherwise. Please do not make any
* contributions that would be inconsistent with the Apache License.
*
* You may obtain a copy of the Apache License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, this software
* distributed under the Apache License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Apache
* License for the specific language governing permissions and limitations for the
* software governed under the Apache License.
*
* © 2012 LinkedIn Corp. All Rights Reserved.
*/
package com.senseidb.search.node;
import com.senseidb.metrics.MetricFactory;
import java.io.File;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import javax.management.StandardMBean;
import org.apache.log4j.Logger;
import org.mortbay.jetty.Server;
import proj.zoie.api.DataProvider;
import com.linkedin.norbert.javacompat.cluster.ClusterClient;
import com.linkedin.norbert.javacompat.cluster.Node;
import com.linkedin.norbert.javacompat.network.NetworkServer;
import com.linkedin.norbert.network.NetworkingException;
import com.senseidb.conf.SenseiServerBuilder;
import com.senseidb.jmx.JmxUtil;
import com.senseidb.plugin.SenseiPluginRegistry;
import com.senseidb.search.req.AbstractSenseiRequest;
import com.senseidb.search.req.AbstractSenseiResult;
import com.senseidb.svc.impl.AbstractSenseiCoreService;
import com.senseidb.svc.impl.CoreSenseiServiceImpl;
import com.senseidb.svc.impl.SenseiCoreServiceMessageHandler;
import com.senseidb.svc.impl.SysSenseiCoreServiceImpl;
import com.senseidb.util.NetUtil;
public class SenseiServer {
private static final Logger logger = Logger.getLogger(SenseiServer.class);
private static final String AVAILABLE = "available";
private static final String UNAVAILABLE = "unavailable";
private static final String DUMMY_OUT_IP = "74.125.224.0";
private int _id;
private int _port;
private int[] _partitions;
private NetworkServer _networkServer;
private ClusterClient _clusterClient;
private final SenseiCore _core;
protected volatile Node _serverNode;
private final List> _externalSvc;
//private Server _adminServer;
protected volatile boolean _available = false;
private final SenseiPluginRegistry pluginRegistry;
public SenseiServer(int id, int port, int[] partitions,
NetworkServer networkServer,
ClusterClient clusterClient,
SenseiZoieFactory> zoieSystemFactory,
SenseiIndexingManager indexingManager,
SenseiQueryBuilderFactory queryBuilderFactory,
List> externalSvc, SenseiPluginRegistry pluginRegistry)
{
this(port,networkServer,clusterClient,new SenseiCore(id, partitions,zoieSystemFactory, indexingManager, queryBuilderFactory),externalSvc, pluginRegistry);
}
public SenseiServer(int port,
NetworkServer networkServer,
ClusterClient clusterClient,
SenseiCore senseiCore,
List> externalSvc, SenseiPluginRegistry pluginRegistry)
{
_core = senseiCore;
this.pluginRegistry = pluginRegistry;
_id = senseiCore.getNodeId();
_port = port;
_partitions = senseiCore.getPartitions();
_networkServer = networkServer;
_clusterClient = clusterClient;
_externalSvc = externalSvc;
}
private static String help(){
StringBuffer buffer = new StringBuffer();
buffer.append("Usage: [availability]\n");
buffer.append("====================================\n");
buffer.append("conf.dir - server configuration directory, required\n");
buffer.append("availability - \"available\" or \"unavailable\", optional default is \"available\"\n");
buffer.append("====================================\n");
return buffer.toString();
}
/*
public Collection> getZoieSystems(){
return _core.zoieSystems;
}
*/
public DataProvider getDataProvider()
{
return _core.getDataProvider();
}
public SenseiCore getSenseiCore()
{
return _core;
}
/*
public void setAdminServer(Server server)
{
_adminServer = server;
}
public SenseiNodeInfo getSenseiNodeInfo()
{
StringBuffer adminLink = new StringBuffer();
if (_adminServer != null && _adminServer.getConnectors() != null && _adminServer.getConnectors().length != 0)
{
adminLink.append("http://").append(_adminServer.getConnectors()[0].getHost()).append(":")
.append(_adminServer.getConnectors()[0].getPort());
}
return new SenseiNodeInfo(_id, _partitions, _serverNode.getUrl(), adminLink.toString());
}
*/
public void shutdown(){
try {
logger.info("shutting down node...");
try
{
_core.shutdown();
pluginRegistry.stop();
_clusterClient.removeNode(_id);
_clusterClient.shutdown();
_serverNode = null;
_core.getPluggableSearchEngineManager().close();
} catch (Exception e)
{
logger.warn(e.getMessage());
} finally
{
if (_networkServer != null)
{
_networkServer.shutdown();
}
}
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
MetricFactory.stop();
JmxUtil.unregisterMBeans();
}
public void start(boolean available) throws Exception {
MetricFactory.start();
_core.start();
// ClusterClient clusterClient = ClusterClientFactory.newInstance().newZookeeperClient();
String clusterName = _clusterClient.getServiceName();
logger.info("Cluster Name: " + clusterName);
logger.info("Cluster info: " + _clusterClient.toString());
AbstractSenseiCoreService coreSenseiService = new CoreSenseiServiceImpl(_core);
AbstractSenseiCoreService sysSenseiCoreService = new SysSenseiCoreServiceImpl(_core);
// create the zookeeper cluster client
// SenseiClusterClientImpl senseiClusterClient = new SenseiClusterClientImpl(clusterName, zookeeperURL, zookeeperTimeout, false);
SenseiCoreServiceMessageHandler senseiMsgHandler = new SenseiCoreServiceMessageHandler(coreSenseiService);
SenseiCoreServiceMessageHandler senseiSysMsgHandler = new SenseiCoreServiceMessageHandler(sysSenseiCoreService);
_networkServer.registerHandler(senseiMsgHandler, coreSenseiService.getSerializer());
_networkServer.registerHandler(senseiSysMsgHandler, sysSenseiCoreService.getSerializer());
_networkServer.registerHandler(senseiMsgHandler, CoreSenseiServiceImpl.JAVA_SERIALIZER);
_networkServer.registerHandler(senseiSysMsgHandler, SysSenseiCoreServiceImpl.JAVA_SERIALIZER);
if (_externalSvc!=null){
for (AbstractSenseiCoreService svc : _externalSvc){
_networkServer.registerHandler(new SenseiCoreServiceMessageHandler(svc), svc.getSerializer());
}
}
HashSet partition = new HashSet();
for (int partId : _partitions){
partition.add(partId);
}
boolean nodeExists = false;
try
{
logger.info("waiting to connect to cluster...");
_clusterClient.awaitConnectionUninterruptibly();
_serverNode = _clusterClient.getNodeWithId(_id);
nodeExists = (_serverNode != null);
if (!nodeExists) {
String ipAddr = getLocalIpAddress();
logger.info("Node id : " + _id + " IP address : " + ipAddr);
_serverNode = _clusterClient.addNode(_id, ipAddr, partition);
logger.info("added node id: " + _id);
} else
{
// node exists
}
} catch (Exception e)
{
logger.error(e.getMessage(), e);
throw e;
}
try
{
logger.info("binding server ...");
_networkServer.bind(_id, available);
// exponential backoff
Thread.sleep(1000);
_available = available;
logger.info("started [markAvailable=" + available + "] ...");
if (nodeExists)
{
logger.warn("existing node found, will try to overwrite.");
try
{
// remove node above
_clusterClient.removeNode(_id);
_serverNode = null;
} catch (Exception e)
{
logger.error("problem removing old node: " + e.getMessage(), e);
}
String ipAddr = getLocalIpAddress();
_serverNode = _clusterClient.addNode(_id, ipAddr, partition);
Thread.sleep(1000);
logger.info("added node id: " + _id);
}
} catch (NetworkingException e)
{
logger.error(e.getMessage(), e);
try
{
if (!nodeExists)
{
_clusterClient.removeNode(_id);
_serverNode = null;
}
} catch (Exception ex)
{
logger.warn(ex.getMessage());
} finally
{
try
{
_networkServer.shutdown();
_networkServer = null;
} finally
{
_clusterClient.shutdown();
_clusterClient = null;
}
}
throw e;
}
SenseiServerAdminMBean senseiAdminMBean = getAdminMBean();
StandardMBean bean = new StandardMBean(senseiAdminMBean, SenseiServerAdminMBean.class);
JmxUtil.registerMBean(bean, "name", "sensei-server-"+_id);
}
private String getLocalIpAddress() throws SocketException,
UnknownHostException {
String addr = NetUtil.getHostAddress();
return String.format("%s:%d", addr, _port);
}
private SenseiServerAdminMBean getAdminMBean()
{
return new SenseiServerAdminMBean(){
@Override
public int getId()
{
return _id;
}
@Override
public int getPort()
{
return _port;
}
@Override
public String getPartitions()
{
StringBuffer sb = new StringBuffer();
if(_partitions.length > 0) sb.append(String.valueOf(_partitions[0]));
for(int i = 1; i < _partitions.length; i++)
{
sb.append(',');
sb.append(String.valueOf(_partitions[i]));
}
return sb.toString();
}
@Override
public boolean isAvailable()
{
return SenseiServer.this.isAvailable();
}
@Override
public void setAvailable(boolean available)
{
SenseiServer.this.setAvailable(available);
}
};
}
public void setAvailable(boolean available){
if (available)
{
logger.info("making available node " + _id + " @port:" + _port + " for partitions: " + Arrays.toString(_partitions));
_networkServer.markAvailable();
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
}
} else
{
logger.info("making unavailable node " + _id + " @port:" + _port + " for partitions: " + Arrays.toString(_partitions));
_networkServer.markUnavailable();
}
_available = available;
}
public boolean isAvailable()
{
if (_serverNode != null && _serverNode.isAvailable() == _available)
return _available;
try
{
Thread.sleep(1000);
_serverNode = _clusterClient.getNodeWithId(_id);
if (_serverNode != null && _serverNode.isAvailable() == _available)
return _available;
} catch (Exception e)
{
logger.error(e.getMessage(), e);
}
_available = (_serverNode != null ? _serverNode.isAvailable() : false);
return _available;
}
/*private static void loadJars(File extDir)
{
File[] jarfiles = extDir.listFiles(new FilenameFilter(){
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".jar");
}
});
if (jarfiles!=null && jarfiles.length > 0){
try{
URL[] jarURLs = new URL[jarfiles.length];
ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();
for (int i=0;i