All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy