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

com.taobao.tair.impl.ConfigServer Maven / Gradle / Ivy

/**
 * (C) 2007-2010 Taobao Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */
package com.taobao.tair.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.common.IoSession;

import com.taobao.tair.comm.ResponseListener;
import com.taobao.tair.comm.TairClient;
import com.taobao.tair.comm.TairClientFactory;
import com.taobao.tair.etc.TairClientException;
import com.taobao.tair.etc.TairConstant;
import com.taobao.tair.etc.TairUtil;
import com.taobao.tair.packet.BasePacket;
import com.taobao.tair.packet.PacketStreamer;
import com.taobao.tair.packet.RequestGetGroupPacket;
import com.taobao.tair.packet.RequestQueryInfoPacket;
import com.taobao.tair.packet.ResponseGetGroupPacket;
import com.taobao.tair.packet.ResponseQueryInfoPacket;

public class ConfigServer implements ResponseListener {
  private static final Log log = LogFactory.getLog(ConfigServer.class);
  private static final int MURMURHASH_M = 0x5bd1e995;
  private String groupName = null;
  private int configVersion = 0;
  private AtomicLong retrieveLastTime = new AtomicLong(0);

  private List configServerList = new ArrayList();

  private List serverList;
  private PacketStreamer pstream;

  private int bucketCount = 0;
  private int copyCount = 0;

  private Set aliveNodes;
  
  private int masterFailCount;
  
  private final int MAX_MASTER_FAILCOUNT = 3;
  
  private TairClientFactory factory;

  public ConfigServer(TairClientFactory factory, String groupName, List configServerList,
      PacketStreamer pstream) {
    this.groupName = groupName;
    this.pstream = pstream;
    this.masterFailCount = 0;
    this.factory = factory;
    
    for (String host : configServerList)
      this.configServerList.add(host.trim());
  }
  
  protected void resetConfigVersion() {
	  this.configVersion = 0;
  }
  
  protected int findServerIdx(byte[] keyByte) {
    long hash = murMurHash(keyByte); // cast to int is safe
    log.debug("hashcode: " + hash + ", bucket count: " + bucketCount);
    if ((serverList != null) && (serverList.size() > 0))
        return (int)(hash %= bucketCount);
    return 0;
  }

  public long getServer(byte[] keyByte, boolean isRead) {
	if (serverList == null || serverList.size() == 0) {
		log.error("server list is empty");
		return 0;
	}
	int serverIdx = findServerIdx(keyByte); 

	long serverIp = 0;
	serverIp = serverList.get(serverIdx);
	log.debug("oroginal target server: " + 
			TairUtil.idToAddress(serverIp) + 
			" alive server: " + aliveNodes);
	
	if (!aliveNodes.contains(serverIp)) {
		serverIp = 0;
		log.warn("master server " + TairUtil.idToAddress(serverIp) + " had down");
	}
	
	if (serverIp == 0 && isRead) {
		for (int i  = 1; i < copyCount; ++i) {
			int copyServerIdx = serverIdx + i * bucketCount;
			serverIp = serverList.get(copyServerIdx);
			log.debug("read operation try: " + TairUtil.idToAddress(serverIp));
			if (aliveNodes.contains(serverIp)) {
				
				break;
			} else {
				serverIp = 0;
			}
		}
		if (serverIp == 0) {
			log.warn("slave servers also"+ " had down");
		}
	}
    return serverIp;
  }
  
  public Map grabGroupConfigMap() {
	  RequestGetGroupPacket request = new RequestGetGroupPacket(null);
	  request.setGroupName(groupName);
	  // force get group info, if client version equals server version, cs return empty
	  request.setConfigVersion(0);
	  
	  for (String addr  : configServerList) {
		  log.info("send request to " + addr);
		  ResponseGetGroupPacket response = null;
	      try {
	        TairClient client = factory.get(addr,
	            TairConstant.DEFAULT_CS_CONN_TIMEOUT, pstream);
	        response = (ResponseGetGroupPacket) client.invoke(request, TairConstant.DEFAULT_CS_TIMEOUT);
	      } catch (Exception e) {
	        log.error("get config failed from: " + addr, e);
	        continue;
	      }
	      if (response != null) {
	    	  return response.getConfigMap();
	      }
	  }
	  log.error("get config map null");
	  return null;
  }

  public boolean retrieveConfigure() {
    retrieveLastTime.set(System.currentTimeMillis());

    RequestGetGroupPacket packet = new RequestGetGroupPacket(null);

    packet.setGroupName(groupName);
    packet.setConfigVersion(configVersion);


    boolean initSuccess = false;

    for (int i = 0; i < configServerList.size(); i++) {
      String addr = configServerList.get(i);

      log.info("init configs from configserver: " + addr);

      BasePacket returnPacket = null;
      try {
        TairClient client = factory.get(addr,
            TairConstant.DEFAULT_CS_CONN_TIMEOUT, pstream);
        returnPacket = (BasePacket) client.invoke(packet,
            TairConstant.DEFAULT_CS_TIMEOUT);
      } catch (Exception e) {
        log.error("get config failed from: " + addr, e);
        continue;
      }

      if ((returnPacket != null)
          && returnPacket instanceof ResponseGetGroupPacket) {
        ResponseGetGroupPacket r = (ResponseGetGroupPacket) returnPacket;

        configVersion = r.getConfigVersion();
        bucketCount = r.getBucketCount();
        copyCount = r.getCopyCount();
        aliveNodes = r.getAliveNodes();

        if (aliveNodes == null || aliveNodes.isEmpty()) {
          log.error("fatal error, no datanode is alive");
          continue;
        }

        if (log.isInfoEnabled()) {
          for (Long id : aliveNodes) {
            log.info("alive datanode: " + TairUtil.idToAddress(id));
          }
        }

        if (bucketCount <= 0 || copyCount <= 0)
          throw new IllegalArgumentException("bucket count or copy count can not be 0");



        if ((r.getServerList() != null)
            && (r.getServerList().size() > 0)) {
          this.serverList = r.getServerList();
          if (log.isDebugEnabled()) {
            for (int idx = 0; idx < r.getServerList().size(); idx++) {
              log.debug("+++ " + idx + " => "
                  + TairUtil.idToAddress(r.getServerList().get(idx)));
            }
          }
          if ((this.serverList.size() % bucketCount) != 0) {
            log.error("server size % bucket number != 0, server size: "
                + this.serverList.size()
                + ", bucket number"
                + bucketCount
                + ", copyCount: " + copyCount);
          } else {
            log.warn("configuration inited with version: " + configVersion
                + ", bucket count: " + bucketCount + ", copyCount: "
                + copyCount);
            initSuccess = true;
            break;
          }
        } else {
          log.warn("server list from config server is null or size is 0");
        }

      } else {
        log.error("retrive from config server " + addr
            + " failed, result: " + returnPacket);
      }
    }

    return initSuccess;
  }


  public MapretrieveStat(int qtype, String groupName, long serverId) {

    RequestQueryInfoPacket packet = new RequestQueryInfoPacket(null);

    packet.setGroupName(groupName);
    packet.setQtype(qtype);
    packet.setServerId(serverId);
    Map  statInfo = null;

    for (int i = 0; i < configServerList.size(); i++) {
      String addr = configServerList.get(i);

      BasePacket returnPacket = null;
      try {
        TairClient client = factory.get(addr,
            TairConstant.DEFAULT_CS_CONN_TIMEOUT, pstream);
        returnPacket = (BasePacket) client.invoke(packet,
            TairConstant.DEFAULT_CS_TIMEOUT);
      } catch (Exception e) {
        log.error("get stat failed " + addr, e);
        continue;
      }

      if ((returnPacket != null)
          && returnPacket instanceof ResponseQueryInfoPacket) {
        ResponseQueryInfoPacket r = (ResponseQueryInfoPacket) returnPacket;
        statInfo = r.getKv();

        break;
      } else {
        log.error("retrive stat from config server " + addr
            + " failed, result: " + returnPacket);
      }

    }

    return statInfo;
  }

  public void checkConfigVersion(int version) {
    if (version == configVersion) {
      return;
    }

    if (retrieveLastTime.get() > (System.currentTimeMillis() - 5000)) {
      log.debug("last check time is less than 5 seconds, need not sync");
      return;
    }

    retrieveLastTime.set(System.currentTimeMillis());

    RequestGetGroupPacket packet = new RequestGetGroupPacket(null);

    packet.setGroupName(groupName);
    packet.setConfigVersion(configVersion);

    for (int i = 0; i < configServerList.size(); i++) {
      if (i == 0 && masterFailCount > MAX_MASTER_FAILCOUNT) {
    	  masterFailCount = 0;
    	  continue;
      }
      
      String host = configServerList.get(i);
      try {
        TairClient client = factory.get(host,
            TairConstant.DEFAULT_CS_CONN_TIMEOUT, pstream);
        client.invokeAsync(packet, TairConstant.DEFAULT_CS_TIMEOUT, this);
        break;
      } catch (TairClientException e) {
        log.error("get client failed", e);
        continue;
      }
    }
  }

  public void responseReceived(Object packet) {

    if ((packet != null) && packet instanceof ResponseGetGroupPacket) {
      ResponseGetGroupPacket r = (ResponseGetGroupPacket) packet;
      r.decode();

      // always sync version
      //if (configVersion >= r.getConfigVersion() && (configVersion - r.getConfigVersion()) < 1000) {
      //	log.debug("sync configure returned, but local version is not older than configserver, local version: "
      //					+ configVersion + ", configserver version: " + r.getConfigVersion());
      //	return;
      //}

      log.warn("configuration synced, oldversion: " + configVersion
          + ", new verion: " + r.getConfigVersion());

      if (configVersion == r.getConfigVersion()) {
        return ;
      }

      aliveNodes = r.getAliveNodes();
      if (aliveNodes == null || aliveNodes.isEmpty()) {
        log.error("empty server table received, still use the old one");
      }

      configVersion = r.getConfigVersion();
      for (Long id : aliveNodes) {
        log.info("alive node: " + TairUtil.idToAddress(id));
      }

      if ((r.getServerList() != null) && (r.getServerList().size() > 0)) {
        this.serverList = r.getServerList();
        if (log.isDebugEnabled()) {
          for (int idx = 0; idx < r.getServerList().size(); idx++) {
            log.debug("+++ " + idx + " => "
                + TairUtil.idToAddress(r.getServerList().get(idx)));
          }
        }
      }else{
        log.error("configuration new verion: " + r.getConfigVersion()+" server list is empty!!!!!");
      }
    }

  }

  public void exceptionCaught(IoSession session, TairClientException exception) {
    log.error("do async request failed", exception);
    if (session.isConnected()) {
    	log.error("session closing");
    	session.close();
    }
    masterFailCount++;
  }

  public void close() {
	  
  }
  private long murMurHash(byte[] key) {
    int len = key.length;
    int h = 97 ^ len;
    int index = 0;

    while (len >= 4) {
      int k = (key[index] & 0xff) | ((key[index + 1] << 8) & 0xff00)
        | ((key[index + 2] << 16) & 0xff0000)
        | (key[index + 3] << 24);

      k *= MURMURHASH_M;
      k ^= (k >>> 24);
      k *= MURMURHASH_M;
      h *= MURMURHASH_M;
      h ^= k;
      index += 4;
      len -= 4;
    }

    switch (len) {
      case 3:
        h ^= (key[index + 2] << 16);

      case 2:
        h ^= (key[index + 1] << 8);

      case 1:
        h ^= key[index];
        h *= MURMURHASH_M;
    }

    h ^= (h >>> 13);
    h *= MURMURHASH_M;
    h ^= (h >>> 15);
    return ((long) h & 0xffffffffL);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy