Package com.linkedin.d2.quorum

Source Code of com.linkedin.d2.quorum.ZKQuorum

/*
   Copyright (c) 2012 LinkedIn Corp.

   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.
*/

package com.linkedin.d2.quorum;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.zookeeper.server.quorum.QuorumPeer;
import org.apache.zookeeper.server.quorum.QuorumPeer.LearnerType;
import org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;
import org.apache.zookeeper.server.ZooKeeperServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;

import com.linkedin.d2.discovery.stores.zk.ZKTestUtil;

public class ZKQuorum
{
  private static final Logger         _log = LoggerFactory.getLogger(ZKQuorum.class);

  public static final int             CONNECTION_TIMEOUT = 10000;
  private static final String         HOST = "127.0.0.1";
  private Map<Integer, ZKPeer>        _peers;
  private Map<Long, QuorumServer>     _peersView;
  private  int                        _peerCount;
  private String                      _hosts;

  /**
   * Initializes n quorum peers which will form a ZooKeeper ensemble.
   * @param n - number of peers in the ensemble ( for test stability, set peer number in a quorum to 7+ (7, 9 or 11) )
   */

  public ZKQuorum(int ttlPeersCount) throws IOException, Exception
  {
    _peers = new HashMap<Integer, ZKPeer>();
    _peersView = new HashMap<Long, QuorumServer>();
    _peerCount = ttlPeersCount;
    _hosts = "";

    if (ttlPeersCount < 7)
    {
      throw new Exception("ZK Quorum Failure. Too few peers in the quorum:" + ttlPeersCount + ". For test stability, increase number of quorum peers (recommended number - 7 or 9 or 11).");
    }

    // Create peer views and list of hosts
    for (int i = 1; i <= _peerCount; ++i)
    {
      createNewPeerData(i);
    }

    for (int i = 1; i <= _peerCount; ++i)
    {
      setQuorumPeer(i);
    }
  }

  private void createNewPeerData(int id)
  {
    int clientPort = ZKTestUtil.getRandomPort();
    int quorumPort = ZKTestUtil.getRandomPort() + 1000;
    int electionPort = ZKTestUtil.getRandomPort() + 1001;
    ZKPeer zkpeer = new ZKPeer(id, ZKTestUtil.createTempDir("zkdata"+id), ZKTestUtil.createTempDir("zklog"+id), HOST, clientPort, quorumPort, electionPort);
    _peers.put(id, zkpeer);
    _peersView.put(Long.valueOf(id), new QuorumServer(id,
                                                     new InetSocketAddress(HOST, quorumPort),
                                                     new InetSocketAddress(HOST, electionPort),
                                                     LearnerType.PARTICIPANT));

    _log.info("Created peer #" + id + " with ports:" + clientPort + "/" + quorumPort + "/" + electionPort + "  peer server addr:"+_peersView.get(Long.valueOf(id)).addr+"  peer server electionAddr:"+_peersView.get(Long.valueOf(id)).electionAddr);
  }

  private void setPeer(int id) throws Exception
  {
    try
    {
      _peers.get(id).setQuorumPeer(_peerCount, _peersView);
    }
    catch (java.net.BindException e)
    {
      _log.info("Removing peer#" + getQuorumPeerPortsInfo(id) + " from peers. Got BindException", e);
      recreatePeer(id);
    }
    _hosts += ((_hosts.length() > 0) ? "," : "") + HOST + ":" + _peers.get(id).getClientPort();
  }

  private void setQuorumPeer(int idthrows Exception
  {
    setPeer(id);
  }

  public int addPeer() throws Exception
  {
    createNewPeerData(++_peerCount);
    setQuorumPeer(_peerCount);

    return _peers.size();
  }

  public ZKPeer get(int id)
  {
    return _peers.get(id);
  }

  public QuorumPeer getQuorumPeer(int id)
  {
    if (isExists(id))
    {
      return _peers.get(id).getPeer();
    }
    return null;
  }

  public int getPeerCount()
  {
    return _peers.size();
  }

  public ZooKeeperServer getPeerZKServer(int id)
  {
    if (isExists(id) && _peers.get(id).getPeer() != null)
    {
      return _peers.get(id).getZKServer();
    }
    return null;
  }

  public String getHosts()
  {
    return _hosts;
  }

  public ZKPeer getQuorumLeader()
  {
    for (Integer id : _peers.keySet())
    {
      if (_peers.get(id).getPeerType().equals("leader"))
      {
        return _peers.get(id);
      }
    }

    return null;
  }

  public ZKPeer getQuorumFollower()
  {
    for (Integer id : _peers.keySet())
    {
      if (_peers.get(id).getPeerType().equals("follower"))
      {
        return _peers.get(id);
      }
    }

    return null;
  }

  private String getQuorumPeerPortsInfo(int id)
  {
    if (isExists(id))
    {
      return _peers.get(id).getPeerPortsInfo();
    }
    return "";
  }

  public boolean isAlive(int id)
  {
    if (isExists(id))
    {
      return _peers.get(id).isAlive();
    }
    return false;
  }

  public Iterator<Integer> iterator()
  {
    return _peers.keySet().iterator();
  }

  public int size()
  {
    return _peers.size();
  }

  public void start(int id) throws Exception
  {
    try
    {
      if (isExists(id))
      {
        _peers.get(id).start();
      }
    }
    catch (java.net.BindException e)
    {
      recreatePeer(id);
    }
  }

  private boolean isExists(int id)
  {
    if (_peers.get(id) != null)
    {
      return true;
    }
    return false;
  }

  public void restart(int id) throws IOException, Exception
  {
    _log.info("Restarting peer #" + getQuorumPeerPortsInfo(id));
    _peers.get(id).shutdown(false);
    setQuorumPeer(id);
    _peers.get(id).start();
  }

  public void restartPeersInTerminatedState() throws Exception
  {
    for (int i=1; i <= _peerCount; i++)
    {
      if (isExists(i))
      {
        if (_peers.get(i).getPeerState().equals("TERMINATED"))
        {
          restart(i);
        }
      }
    }
    waitForAllPeersUp();
  }

  public void startAll() throws IOException, Exception
  {
    for (int id=1; id <= _peerCount; id++)
    {
      if (isExists(id))
      {
        start(id);
        _log.info("Started Quorum peer #" + getQuorumPeerPortsInfo(id));
      }
    }

    waitForAllPeersUp();
  }

  public void waitForAllPeersUp() throws Exception
  {
    for (int id=1; id <= _peerCount; id++)
    {
      if (isExists(id))
      {
        _peers.get(id).waitForServerUp(CONNECTION_TIMEOUT);
      }
    }
    removeFailedPeers();
    assertAllPeersUp();
  }

  private void removeFailedPeers() throws Exception
  {
    for (int id=1; id <= _peerCount; id++)
    {
      if (isExists(id))
      {
        if (_peers.get(id).getPeerState().equals("TERMINATED") || _peers.get(id).getZKServer() == null ||  ! _peers.get(id).isZKServerRunning())
        {
          // Remove failed peer
          _peers.get(id).printPeerStats();
          deletePeer(id);
        }
      }
    }
    if (_peers.size() % 2 == 0 && _peers.size() > 5) // min recommended quorum size is 5
    {
      deletePeer(Collections.min(_peers.keySet()));
    }
  }

  public void assertAllPeersUp()
  {
    printPeersStats();
    for (int id=1; id <= _peerCount; id++)
    {
      if (_peers.containsKey(id))
      {
        assertNotNull(_peers.get(id), "ZK Quorum Failure. Peer #" + id + " is null.");
        assertNotNull(_peers.get(id).getZKServer(), "ZK Quorum Failure. Null ZK Server for Peer #" + getQuorumPeerPortsInfo(id) + ".");
        assertTrue(_peers.get(id).getZKServer().isRunning(), "ZK Quorum Failure. ZK Server is not running. Peer #" + getQuorumPeerPortsInfo(id));
      }
    }
  }

  public boolean areAllPeersUp()
  {
    for (Integer id : _peers.keySet())
    {
      if (_peers.get(id).getZKServer() == null)
      {
        return false;
      }
      else if (!_peers.get(id).getZKServer().isRunning())
      {
        return false;
      }
    }
    return true;
  }

  public void restartAll() throws Exception
  {
    for (int i=1; i <= _peerCount; i++)
    {
      if (isExists(i))
      {
        restart(_peers.get(i).getId());
      }
    }
    waitForAllPeersUp();
  }

  public void shutdown(int id) throws Exception
  {
    shutdown(id, false);
  }

  public void shutdown(int id, boolean removeDir) throws Exception
  {
    if (removeDir)
    {
      deletePeer(id);
    }
    else
    {
      if (_peers.get(id) != null)
      {
        _peers.get(id).shutdown(removeDir);
      }
    }
  }

  public void shutdownAll(boolean removeDirectories) throws Exception
  {
    // Shutdown leader first
    ZKPeer p = getQuorumLeader();
    if (p != null)
    {
      try
      {
        p.shutdown(true);
      }
      catch (Exception e)
      {
        _log.warn("Failed to shutdown peer #"+ getQuorumPeerPortsInfo(p.getId()), e);
      }
    }

    for (int id=1; id <= _peerCount; id++)
    {
      if (isExists(id))
      {
        try
        {
          shutdown(id, removeDirectories);
        }
        catch (Exception e)
        {
          _log.warn("Failed to shutdown peer #" + getQuorumPeerPortsInfo(id), e);
        }
      }
    }
    Thread.sleep(600); // give zk extra time to complete shutdown
  }

  public void deletePeer(int id) throws Exception
  {
    if (isExists(id))
    {
      _log.info("Deleting peer #" + getQuorumPeerPortsInfo(id));
      int clientPort = _peers.get(id).getClientPort();
      _peers.get(id).shutdown(true);
      _peers.get(id).waitForServerDown(900);
      removePeerFromQuorumPeersMap(id, clientPort);
    }
  }

  private void recreatePeer(int id) throws Exception
  {
    _log.info("Recreating peer#" + getQuorumPeerPortsInfo(id));
    _peers.get(id).shutdownPeer();
    _peers.remove(id);
    _peersView.remove(id);
    // Generate new peer
    createNewPeerData(id);
    setQuorumPeer(id);
    _log.info("Recreated peer#" + getQuorumPeerPortsInfo(id));
  }

  public void closeAllPeers()
  {
    for (int id=1; id <= _peerCount; id++)
    {
      if (isExists(id))
      {
        closePeer(id);
      }
    }
  }

  public void closePeer(int id)
  {
    try
    {
      if (_peers.get(id) != null)
      {
        _peers.get(id).close();
      }
    }
    catch (Exception e)
    {
      _log.info("Failed to close peer #" + id, e);
    }
  }

  private void removePeerFromQuorumPeersMap(int id, int clientPort)
  {
    _log.debug("Removing failed peer #" + id);
    _peers.remove(id);
    _peersView.remove(id);
    String failedZk = HOST + ":" + clientPort;
    _hosts = _hosts.replaceAll("[,]*"+failedZk+"[,]*", ((_hosts.indexOf(failedZk) > 0 && _hosts.indexOf(failedZk) + failedZk.length() < _hosts.length()) ? "," : ""));
  }

  public void printPeersStats()
  {
    for (Integer id : _peers.keySet())
    {
      _peers.get(id).printPeerStats();
    }
  }
}
TOP

Related Classes of com.linkedin.d2.quorum.ZKQuorum

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.