Package com.alipay.bluewhale.core.daemon.supervisor

Source Code of com.alipay.bluewhale.core.daemon.supervisor.SynchronizeSupervisor

package com.alipay.bluewhale.core.daemon.supervisor;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.apache.thrift7.TException;

import backtype.storm.utils.LocalState;
import backtype.storm.utils.Utils;

import com.alipay.bluewhale.core.callback.RunnableCallback;
import com.alipay.bluewhale.core.cluster.Common;
import com.alipay.bluewhale.core.cluster.StormClusterState;
import com.alipay.bluewhale.core.cluster.StormConfig;
import com.alipay.bluewhale.core.daemon.NodePort;
import com.alipay.bluewhale.core.event.EventManager;
import com.alipay.bluewhale.core.task.LocalAssignment;
import com.alipay.bluewhale.core.task.common.Assignment;
import com.alipay.bluewhale.core.utils.PathUtils;
import com.alipay.bluewhale.core.utils.StormUtils;

/**
* supervisor��SynchronizeSupervisor����
* (1) ����Ҫ���صĴ��롢jar���������ļ���
* (2) ɾ����Щû�б�nimbus���������topology��Դ��
* (3) ��nimbus���䵽��supervisor������д�뵽/storm-local-dir/supervisor/localstate�У�
*     LocalState���Կ�����һ��KV database;
* (4) ��syncProcesses��ӵ���Ӧ���¼�������
*/
class SynchronizeSupervisor extends RunnableCallback {

  private static final Logger LOG = Logger
      .getLogger(SynchronizeSupervisor.class);

  // private Supervisor supervisor;

  private String supervisorId;

  private EventManager eventManager;

  private EventManager processesEventManager;

  private StormClusterState stormClusterState;

  private LocalState localState;

  private Map conf;

  private SyncProcesses syncProcesses;

  /**
   * @param conf
   * @param eventManager
   * @param processesEventManager
   * @param stormClusterState
   * @param supervisorId
   * @param localState
   * @param syncProcesses
   */
  public SynchronizeSupervisor(String supervisorId, Map conf,
      EventManager eventManager, EventManager processesEventManager,
      StormClusterState stormClusterState, LocalState localState,
      SyncProcesses syncProcesses) {
    this.syncProcesses = syncProcesses;
    this.eventManager = eventManager;
    this.processesEventManager = processesEventManager;
    this.stormClusterState = stormClusterState;
    this.conf = conf;
    this.supervisorId = supervisorId;
    this.localState = localState;

  }

  @Override
  public void run() {
    /**
     * Step 1: create SyncCallback
     */
    RunnableCallback syncCallback = new SyncCallback(this, eventManager);

    /**
     * Step 2: create storm-code map stormid to :master-code-dir
     */
    Map<String, String> stormCodeMap = readStormCodeLocations(
        stormClusterState, syncCallback);
    //Set<String> assignedStormIds = null;
    List<String> downloadedTopologyIds = null;
    if (stormCodeMap != null) {

         //assignedStormIds = stormCodeMap.keySet();

      /**
       * Step 3: get topologyIds from
       * STORM-LOCAL-DIR/supervisor/stormdist/
       */
      try {
        downloadedTopologyIds = readDownloadedTopologyIds(conf);
      } catch (IOException e) {
        String errMsg = "Failed to get downloaded topologyids\n";
        LOG.error(errMsg, e);
      }

      /**
       * Step 4: get <port,LocalAssignments> from ZK local node's
       * assignment
       */
      Map<Integer, LocalAssignment> newAssignment = readAssignments(
          stormClusterState, supervisorId, syncCallback);

      LOG.debug("Synchronizing supervisor");
      LOG.debug("Storm code map: " + stormCodeMap);
      LOG.debug("Downloaded storm ids: " + downloadedTopologyIds);
      LOG.debug("New assignment: " + newAssignment);

      // Step 5: download code from ZK

      Set<Entry<String, String>> entryStormCodeSet = stormCodeMap
          .entrySet();
      for (Entry<String, String> entry : entryStormCodeSet) {

        String stormId = entry.getKey();
        String masterCodeDir = entry.getValue();

        if (!downloadedTopologyIds.contains(stormId)) {

          LOG.info("Downloading code for storm id " + stormId
              + " from " + masterCodeDir);

          try {
            downloadStormCode(conf, stormId, masterCodeDir);
          } catch (IOException e) {
            LOG.error(e + " downloadStormCode failed " + "stormId:"
                + stormId + "masterCodeDir:" + masterCodeDir);

          } catch (TException e) {
            LOG.error(e + " downloadStormCode failed " + "stormId:"
                + stormId + "masterCodeDir:" + masterCodeDir);
          }
          LOG.info("Finished downloading code for storm id "
              + stormId + " from " + masterCodeDir);
        }

      }

      /**
       * Step 5: remove any downloaded code that's no longer assigned or
       * active
       */
      for (Iterator<String> it = downloadedTopologyIds.iterator(); it.hasNext();) {
        String topologyId = it.next();

        if (!stormCodeMap.containsKey(topologyId)) {

          LOG.info("Removing code for storm id " + topologyId);

          String path = null;
          try {
            path = StormConfig.supervisor_stormdist_root(conf,
                topologyId);
            PathUtils.rmr(path);
          } catch (IOException e) {
            String errMsg = "rmr the path:" + path + "failed\n";
            LOG.error(errMsg, e);
          }
        }
      }

      LOG.debug("Writing new assignment " + newAssignment);
      try {
        localState.put(Common.LS_LOCAL_ASSIGNMENTS, newAssignment);
      } catch (IOException e) {
        LOG.error("put LS_LOCAL_ASSIGNMENTS " + newAssignment
            + " of localState failed");
      }
    }

    processesEventManager.add(syncProcesses);

  }

  /**
   * download code ; two cluster mode: local and distributed
   *
   * @param conf
   * @param stormId
   * @param masterCodeDir
   * @param clusterMode
   * @throws IOException
   */
  private void downloadStormCode(Map conf, String stormId,
      String masterCodeDir) throws IOException, TException {
    String clusterMode = StormConfig.cluster_mode(conf);

    if (clusterMode.endsWith("local")) {
      downloadLocalStormCode(conf, stormId, masterCodeDir);

    } else if (clusterMode.endsWith("distributed")) {
      downloadDistributeStormCode(conf, stormId, masterCodeDir);
    }
  }

  private void downloadLocalStormCode(Map conf, String stormId,
      String masterCodeDir) throws IOException, TException {

    // STORM-LOCAL-DIR/supervisor/stormdist/storm-id
    String stormroot = StormConfig.supervisor_stormdist_root(conf, stormId);

    FileUtils.copyDirectory(new File(masterCodeDir), new File(stormroot));

    ClassLoader classloader = Thread.currentThread()
        .getContextClassLoader();

    String resourcesJar = resourcesJar();

    URL url = classloader.getResource(StormConfig.RESOURCES_SUBDIR);

    String targetDir = stormroot + '/' + StormConfig.RESOURCES_SUBDIR;

    if (resourcesJar != null) {

      LOG.info("Extracting resources from jar at " + resourcesJar
          + " to " + targetDir);

//      StormUtils.extract_dir_from_jar(resourcesJar,
//          StormConfig.RESOURCES_SUBDIR, stormroot);// extract dir
      // from jar;;
      // util.clj
    } else if (url != null) {

      LOG.info("Copying resources at " + url.toString() + " to "
          + targetDir);

      FileUtils.copyDirectory(new File(url.getFile()), (new File(
          targetDir)));

    }
  }

  private void downloadDistributeStormCode(Map conf, String stormId,
      String masterCodeDir) throws IOException, TException {

    // STORM_LOCAL_DIR/supervisor/tmp/(UUID)
    String tmproot = StormConfig.supervisorTmpDir(conf) + "/"
        + UUID.randomUUID().toString();
    FileUtils.forceMkdir(new File(tmproot));

    // STORM_LOCAL_DIR/supervisor/stormdist/stormId
    String stormroot = StormConfig.supervisor_stormdist_root(conf, stormId);

    // masterCodeDir/stormjar.jar
    String masterStormjarPath = StormConfig
        .masterStormjarPath(masterCodeDir);
    // tmproot/stormjar.jar
    String localFileJarTmp = StormConfig.supervisor_stormjar_path(tmproot);
    // load stormjar.jar
    Utils.downloadFromMaster(conf, masterStormjarPath, localFileJarTmp);// load
    // storm.jar

    // masterCodeDir/stormcode.ser
    String masterStormcodePath = StormConfig
        .masterStormcodePath(masterCodeDir);
    // tmproot/stormcode.ser
    String localFileCodeTmp = StormConfig
        .supervisor_stormcode_path(tmproot);
    // load stormcode.ser
    Utils.downloadFromMaster(conf, masterStormcodePath, localFileCodeTmp);

    // masterCodeDir/stormconf.ser
    String masterStormConfPath = StormConfig
        .masterStormconfPath(masterCodeDir);
    // tmproot/stormconf.ser
    String localFileConfTmp = StormConfig
        .supervisor_sotrmconf_path(tmproot);
    // load conf
    Utils.downloadFromMaster(conf, masterStormConfPath, localFileConfTmp);

    // extract dir from jar
//    StormUtils.extract_dir_from_jar(localFileJarTmp,
//        StormConfig.RESOURCES_SUBDIR, tmproot);

    FileUtils.moveDirectory(new File(tmproot), new File(stormroot));

  }

  private String resourcesJar() {

    String path = System.getProperty("java.class.path");
    if (path == null) {
      return null;
    }

    String[] paths = path.split(File.pathSeparator);

    List<String> jarPaths = new ArrayList<String>();
    for (String s : paths) {
      if (s.endsWith(".jar")) {
        jarPaths.add(s);
      }
    }

    /**
     * FIXME, this place seems exist problem
     */
    List<String> rtn = new ArrayList<String>();
    int size = jarPaths.size();
    for (int i = 0; i < size; i++) {
      if (StormUtils.zipContainsDir(jarPaths.get(i),
          StormConfig.RESOURCES_SUBDIR)) {
        rtn.add(jarPaths.get(i));
      }
    }

    if (rtn.size() == 0)
      return null;

    return rtn.get(0);
  }

  /**
   * get mastercodedir for every storm(topology)
   *
   * @param stormClusterState
   * @param callback
   * @returns Map: <stormid, master-code-dir> from zookeeper
   */
  private Map<String, String> readStormCodeLocations(
      StormClusterState stormClusterState, RunnableCallback callback) {

    Map<String, String> rtn = null;

    /**
     * set callback to StormZkClusterState.assignments_callback return zk's
     * /assignments children get all storm-ids
     */
    List<String> topologyids = stormClusterState.assignments(callback);

    if (topologyids != null) {
      rtn = new HashMap<String, String>();
      for (String topologyid : topologyids) {
        Assignment assignmenInfo = stormClusterState.assignment_info(
            topologyid, callback);

        rtn.put(topologyid, assignmenInfo.getMasterCodeDir());
      }
    }
    return rtn;
  }

  /**
   * a port must be assigned one topology
   *
   * @param stormClusterState
   * @param supervisorId
   * @param callback
   * @returns map: {port,LocalAssignment}
   */
  private Map<Integer, LocalAssignment> readAssignments(
      StormClusterState stormClusterState, String supervisorId,
      RunnableCallback callback) {

    Map<Integer, LocalAssignment> portLA = null;

    /**
     * set callback to StormZkClusterState.assignments_callback return zk's
     * /assignments children get all storm-ids
     */
    List<String> topologyIds = stormClusterState.assignments(callback);
    if (topologyIds != null) {
      portLA = new HashMap<Integer, LocalAssignment>();
      for (String topologyId : topologyIds) {
        // FIXME forѭ�������zk�������Ƿ����һ��
        // get local node's <port, LocalAssignment> from ZK
        Map<Integer, LocalAssignment> portTasks = readMyTasks(
            stormClusterState, topologyId, supervisorId, callback);
        if (portTasks == null) {
          continue;
        }
        // a port must be assigned one storm
        Set<Entry<Integer, LocalAssignment>> entrySet = portTasks
            .entrySet();
        for (Entry<Integer, LocalAssignment> entry : entrySet) {

          Integer port = entry.getKey();

          LocalAssignment la = entry.getValue();

          if (!portLA.containsKey(port)) {
            portLA.put(port, la);
          } else {
            throw new RuntimeException(
                "Should not have multiple topologys assigned to one port");
          }
        }
      }
    }
    return portLA;
  }

  /**
   * get topologyids form supervisor local dir
   *
   * @param conf
   * @throws IOException
   * @returns Set<String>: stormids
   */

  @SuppressWarnings("rawtypes")
  private List<String> readDownloadedTopologyIds(Map conf) throws IOException {

    // get the path: STORM-LOCAL-DIR/supervisor/stormdist/
    String path = StormConfig.supervisor_stormdist_root(conf);

    List<String> topologyids = PathUtils.read_dir_contents(path);

    return topologyids;
  }

  /**
   * read assignment_info from zk , and get local node's tasks
   *
   * @param stormClusterState
   * @param topologyId
   * @param supervisorId
   * @param callback
   * @return Map: {port, LocalAssignment}
   */
  private Map<Integer, LocalAssignment> readMyTasks(
      StormClusterState stormClusterState, String topologyId,
      String supervisorId, RunnableCallback callback) {

    Map<Integer, LocalAssignment> portTasks = null;

    Assignment assignmenInfo = stormClusterState.assignment_info(
        topologyId, callback);

    if (assignmenInfo != null) {
      Map<Integer, NodePort> taskToNodeport = assignmenInfo
          .getTaskToNodeport();

      if (taskToNodeport != null) {

        portTasks = new HashMap<Integer, LocalAssignment>();

        Set<Entry<Integer, NodePort>> entrySet = taskToNodeport
            .entrySet();

        for (Iterator<Entry<Integer, NodePort>> it = entrySet
            .iterator(); it.hasNext();) {

          Entry<Integer, NodePort> entry = it.next();

          Integer taskId = entry.getKey();

          NodePort nodePort = entry.getValue();

          int port = nodePort.getPort();

          String node = nodePort.getNode();

          if (!node.equals(supervisorId)) {
            // not localhost
            continue;
          }

          if (portTasks.containsKey(port)) {

            LocalAssignment la = portTasks.get(port);

            Set<Integer> taskIds = la.getTaskIds();

            taskIds.add(taskId);

          } else {

            Set<Integer> taskIds = new HashSet<Integer>();

            taskIds.add(taskId);

            LocalAssignment la = new LocalAssignment(topologyId,
                taskIds);

            portTasks.put(port, la);
          }
        }
      }

    }

    return portTasks;
  }
}
TOP

Related Classes of com.alipay.bluewhale.core.daemon.supervisor.SynchronizeSupervisor

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.