/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.samza.zk;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Objects;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkBadVersionException;
import org.I0Itec.zkclient.exception.ZkInterruptedException;
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
import org.apache.commons.lang3.StringUtils;
import org.apache.samza.SamzaException;
import org.apache.samza.container.TaskName;
import org.apache.samza.job.model.JobModel;
import org.apache.samza.metrics.MetricsRegistry;
import org.apache.samza.runtime.LocationId;
import org.apache.samza.serializers.model.SamzaObjectMapper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Util class to help manage Zk connection and ZkClient.
 * It also provides additional utility methods for read/write/subscribe/unsubscribe access to the ZK tree.
 *
 * <p>
 *  <b>Note on ZkClient:</b>
 *  {@link ZkClient} consists of two threads - I/O thread and Event thread.
 *  I/O thread manages heartbeats to the Zookeeper server in the ensemble and handles responses to synchronous methods
 *  in Zookeeper API.
 *  Event thread typically receives all the Watcher events and delivers to registered listeners. It, also, handles
 *  responses to asynchronous methods in Zookeeper API.
 * </p>
 *
 * <p>
 *  <b>Note on Session disconnect handling:</b>
 *  After the session has timed out, and restored we may still get some notifications from before (from the old
 *  session). To avoid this, we add a currentGeneration member, which starts with 0, and is increased each time
 *  a new session is established. Current value of this member is passed to each Listener when it is created.
 *  So if the Callback from this Listener comes with an old generation id - we ignore it.
 * </p>
 *
 * <p>
 *   <b>Note on Session Management:</b>
 *   Session management, if needed, should be handled by the caller. This can be done by implementing
 *   {@link org.I0Itec.zkclient.IZkStateListener} and subscribing this listener to the current ZkClient. Note: The connection state change
 *   callbacks are invoked in the context of the Event thread of the ZkClient. So, it is advised to do non-blocking
 *   processing in the callbacks.
 * </p>
 */
public class ZkUtils {
  private static final Logger LOG = LoggerFactory.getLogger(ZkUtils.class);
  /* package private */static final String ZK_PROTOCOL_VERSION = "1.0";

  private final ZkClient zkClient;
  private volatile String ephemeralPath = null;
  private final ZkKeyBuilder keyBuilder;
  private final int connectionTimeoutMs;
  private final AtomicInteger currentGeneration;
  private final ZkUtilsMetrics metrics;
  private final int sessionTimeoutMs;

  public void incGeneration() {
    currentGeneration.incrementAndGet();
  }

  public int getGeneration() {
    return currentGeneration.get();
  }

  public ZkUtils(ZkKeyBuilder zkKeyBuilder, ZkClient zkClient, int connectionTimeoutMs, int sessionTimeOutMs, MetricsRegistry metricsRegistry) {
    this.keyBuilder = zkKeyBuilder;
    this.connectionTimeoutMs = connectionTimeoutMs;
    this.zkClient = zkClient;
    this.metrics = new ZkUtilsMetrics(metricsRegistry);
    this.currentGeneration = new AtomicInteger(0);
    this.sessionTimeoutMs = sessionTimeOutMs;
  }

  public void connect() throws ZkInterruptedException {
    boolean isConnected = zkClient.waitUntilConnected(connectionTimeoutMs, TimeUnit.MILLISECONDS);
    if (!isConnected) {
      metrics.zkConnectionError.inc();
      throw new RuntimeException("Unable to connect to Zookeeper within connectionTimeout " + connectionTimeoutMs + "ms. Shutting down!");
    }
  }

  // reset all zk-session specific state
  public synchronized void unregister() {
    ephemeralPath = null;
  }

  public ZkClient getZkClient() {
    return zkClient;
  }

  public ZkKeyBuilder getKeyBuilder() {
    return keyBuilder;
  }

  /**
   * Returns a ZK generated identifier for this client.
   * If the current client is registering for the first time, it creates an ephemeral sequential node in the ZK tree
   * If the current client has already registered and is still within the same session, it returns the already existing
   * value for the ephemeralPath
   *
   * @param data Object that should be written as data in the registered ephemeral ZK node
   * @return String representing the absolute ephemeralPath of this client in the current session
   */
  public synchronized String registerProcessorAndGetId(final ProcessorData data) {
    final long startTimeMs = System.currentTimeMillis();
    final long retryTimeOutMs = 2 * sessionTimeoutMs;
    String processorId = data.getProcessorId();
    if (ephemeralPath == null) {
      ephemeralPath = zkClient.createEphemeralSequential(keyBuilder.getProcessorsPath() + "/", data.toString());
      LOG.info("Created ephemeral path: {} for processor: {} in zookeeper.", ephemeralPath, data);
      while (true) {
        ProcessorNode processorNode = new ProcessorNode(data, ephemeralPath);
        // Determine if there are duplicate processors with this.processorId after registration.
        if (!isValidRegisteredProcessor(processorNode)) {
          long currentTimeMs = System.currentTimeMillis();
          if ((currentTimeMs - startTimeMs) < retryTimeOutMs) {
            LOG.info("Processor: {} is duplicate. Retrying registration again.", processorId);
            timeDelay(1000);
          } else {
            LOG.info("Processor: {} is duplicate. Deleting zookeeper node at path: {}.", processorId, ephemeralPath);
            zkClient.delete(ephemeralPath);
            metrics.deletions.inc();
            throw new SamzaException(String.format("Processor: %s is duplicate in the group. Registration failed.", processorId));
          }
        } else {
          break;
        }
      }
    } else {
      LOG.info("Ephemeral path: {} exists for processor: {} in zookeeper.", ephemeralPath, data);
    }
    return ephemeralPath;
  }

  public void timeDelay(int sleepTimeInMillis) {
    try {
      Thread.sleep(sleepTimeInMillis);
    } catch (InterruptedException e) {
      LOG.error("Interrupted exception on wait.", e);
      Thread.interrupted();
    }
  }

  /**
   * Deletes the ephemeral node of a processor in zookeeper.
   * @param processorId uniqueId identifying the stream processor to delete.
   */
  public synchronized void deleteProcessorNode(String processorId) {
    try {
      if (ephemeralPath != null) {
        LOG.info("Deleting the ephemeral node: {} of the processor: {} in zookeeper.", ephemeralPath, processorId);
        zkClient.delete(ephemeralPath);
      }
    } catch (Exception e) {
      LOG.error("Exception occurred on deletion of ephemeral node: {}.", ephemeralPath, e);
    }
  }

  /**
   * Determines the validity of processor registered with zookeeper.
   *
   * If there are multiple processors registered with same processorId,
   * the processor with lexicographically smallest zookeeperPath is considered valid
   * and all the remaining processors are invalid.
   *
   * Two processors will not have smallest zookeeperPath because of sequentialId guarantees
   * of zookeeper for ephemeral nodes.
   *
   * @param processor to check for validity condition in processors group.
   * @return true if the processor is valid. false otherwise.
   */
  private boolean isValidRegisteredProcessor(final ProcessorNode processor) {
    String processorId = processor.getProcessorData().getProcessorId();
    List<ProcessorNode> processorNodes = getAllProcessorNodes().stream()
                                                               .filter(processorNode -> processorNode.processorData.getProcessorId().equals(processorId))
                                                               .collect(Collectors.toList());
    // Check for duplicate processor condition(if more than one processor exist for this processorId).
    if (processorNodes.size() > 1) {
      // There exists more than processor for provided `processorId`.
      LOG.debug("Processor nodes in zookeeper: {} for processorId: {}.", processorNodes, processorId);
      // Get all ephemeral processor paths
      TreeSet<String> sortedProcessorPaths = processorNodes.stream()
                                                           .map(ProcessorNode::getEphemeralPath)
                                                           .collect(Collectors.toCollection(TreeSet::new));
      // Check if smallest path is equal to this processor's ephemeralPath.
      return sortedProcessorPaths.first().equals(processor.getEphemeralPath());
    }
    // There're no duplicate processors. This is a valid registered processor.
    return true;
  }

  /**
   * Fetches all the ephemeral processor nodes of a standalone job from zookeeper.
   * @return a list of {@link ProcessorNode}, where each ProcessorNode represents a registered stream processor.
   */
  List<ProcessorNode> getAllProcessorNodes() {
    List<String> processorZNodes = getSortedActiveProcessorsZnodes();
    LOG.debug("Active ProcessorZNodes in zookeeper: {}.", processorZNodes);
    List<ProcessorNode> processorNodes = new ArrayList<>();
    for (String processorZNode: processorZNodes) {
      String ephemeralProcessorPath = String.format("%s/%s", keyBuilder.getProcessorsPath(), processorZNode);
      String data = readProcessorData(ephemeralProcessorPath);
      if (data != null) {
        processorNodes.add(new ProcessorNode(new ProcessorData(data), ephemeralProcessorPath));
      }
    }
    return processorNodes;
  }

  public void writeTaskLocality(TaskName taskName, LocationId locationId) {
    String taskLocalityPath = String.format("%s/%s", keyBuilder.getTaskLocalityPath(), taskName);
    validatePaths(new String[] {taskLocalityPath});
    writeData(taskLocalityPath, locationId.getId());
  }

  public Map<TaskName, LocationId> readTaskLocality() {
    Map<TaskName, LocationId> taskLocality = new HashMap<>();
    String taskLocalityPath = keyBuilder.getTaskLocalityPath();
    List<String> tasks = new ArrayList<>();
    if (zkClient.exists(taskLocalityPath)) {
      tasks = zkClient.getChildren(taskLocalityPath);
    }
    for (String taskName : tasks) {
      String taskPath = String.format("%s/%s", keyBuilder.getTaskLocalityPath(), taskName);
      String locationId = zkClient.readData(taskPath, true);
      if (locationId != null) {
        taskLocality.put(new TaskName(taskName), new LocationId(locationId));
      }
    }
    return taskLocality;
  }

  /**
   * Method is used to get the <i>sorted</i> list of currently active/registered processors (znodes)
   *
   * @return List of absolute ZK node paths
   */
  public List<String> getSortedActiveProcessorsZnodes() {
    List<String> znodeIds = zkClient.getChildren(keyBuilder.getProcessorsPath());
    if (znodeIds.size() > 0) {
      Collections.sort(znodeIds);
      LOG.info("Found these children - " + znodeIds);
    }
    return znodeIds;
  }

  /**
   * Method is used to read processor's data from the znode
   * @param fullPath absolute path to the znode
   * @return processor's data
   * @throws SamzaException when fullPath doesn't exist in zookeeper
   * or problems with connecting to zookeeper.
   */
  private String readProcessorData(String fullPath) {
    try {
      String data = zkClient.readData(fullPath, true);
      metrics.reads.inc();
      return data;
    } catch (Exception e) {
      throw new SamzaException(String.format("Cannot read ZK node: %s", fullPath), e);
    }
  }

  /**
   * Method is used to get the list of currently active/registered processor ids
   * @return List of processorIds
   */
  public List<String> getSortedActiveProcessorsIDs() {
    return getActiveProcessorsIDs(getSortedActiveProcessorsZnodes());
  }

  /**
   * Method is used to get the <i>sorted</i> list of processors ids for a given list of znodes
   * @param znodeIds - list of relative paths of the children's znodes
   * @return List of processor ids for a given list of znodes
   */
  public List<String> getActiveProcessorsIDs(List<String> znodeIds) {
    String processorPath = keyBuilder.getProcessorsPath();
    List<String> processorIds = new ArrayList<>(znodeIds.size());
    if (znodeIds.size() > 0) {
      for (String child : znodeIds) {
        String fullPath = String.format("%s/%s", processorPath, child);
        String processorData = readProcessorData(fullPath);
        if (processorData != null) {
          processorIds.add(new ProcessorData(processorData).getProcessorId());
        }
      }
      Collections.sort(processorIds);
      LOG.info("Found these children - " + znodeIds);
      LOG.info("Found these processorIds - " + processorIds);
    }
    return processorIds;
  }

  /* Wrapper for standard I0Itec methods */
  public void unsubscribeDataChanges(String path, IZkDataListener dataListener) {
    zkClient.unsubscribeDataChanges(path, dataListener);
  }

  public void subscribeDataChanges(String path, IZkDataListener dataListener) {
    zkClient.subscribeDataChanges(path, dataListener);
    metrics.subscriptions.inc();
  }

  public void subscribeChildChanges(String path, IZkChildListener listener) {
    zkClient.subscribeChildChanges(path, listener);
    metrics.subscriptions.inc();
  }

  public void unsubscribeChildChanges(String path, IZkChildListener childListener) {
    zkClient.unsubscribeChildChanges(path, childListener);
  }

  public void writeData(String path, Object object) {
    zkClient.writeData(path, object);
    metrics.writes.inc();
  }

  public boolean exists(String path) {
    return zkClient.exists(path);
  }

  public void close() {
    try {
      zkClient.close();
    } catch (ZkInterruptedException e) {
      LOG.warn("Interrupted when closing zkClient. Clearing the interrupted status and retrying.", e);
      Thread.interrupted();
      zkClient.close();
      Thread.currentThread().interrupt();
    }
  }

  /**
   * A generation-aware {@link IZkChildListener} that only responds to events that occur in the current-generation.
   * Each generation is identified by a generation-id which is scoped to the currently active Zk session and
   * is incremented each time a session expires. This ensures that events corresponding to the previous generation
   * are not acted on.
   */
  public abstract static class GenerationAwareZkChildListener implements IZkChildListener {
    private final int generation;
    private final ZkUtils zkUtils;
    private final String listenerName;

    public GenerationAwareZkChildListener(ZkUtils zkUtils, String listenerName) {
      generation = zkUtils.getGeneration();
      this.zkUtils = zkUtils;
      this.listenerName = listenerName;
    }

    @Override
    public void handleChildChange(String barrierParticipantPath, List<String> participantIds) throws Exception {
      int currentGeneration = zkUtils.getGeneration();
      if (currentGeneration != generation) {
        LOG.warn(String.format("Skipping handleChildChange for %s from wrong generation. Current generation: %s; " +
            "Callback generation: %s", listenerName, currentGeneration, generation));
        return;
      }
      doHandleChildChange(barrierParticipantPath, participantIds);
    }

    public abstract void doHandleChildChange(String path, List<String> children) throws Exception;
  }

  /**
   * A generation-aware {@link IZkDataListener} that only responds to events that occur in the current-generation.
   * Each generation is identified by a generation-id which is scoped to the currently active Zk session and
   * is incremented each time a session expires. This ensures that events corresponding to the previous generation
   * are not acted on.
   */
  public abstract static class GenerationAwareZkDataListener implements IZkDataListener {
    private final int generation;
    private final ZkUtils zkUtils;
    private final String listenerName;

    public GenerationAwareZkDataListener(ZkUtils zkUtils, String listenerName) {
      generation = zkUtils.getGeneration();
      this.zkUtils = zkUtils;
      this.listenerName = listenerName;
    }

    @Override
    public void handleDataChange(String path, Object data) {
      if (!isValid()) {
        LOG.warn(String.format("Skipping handleDataChange for %s from wrong generation. Current generation: %s; " +
            "Callback generation: %s", listenerName, zkUtils.getGeneration(), generation));
      } else {
        doHandleDataChange(path, data);
      }
    }

    public void handleDataDeleted(String dataPath) throws Exception {
      if (!isValid()) {
        LOG.warn(String.format("Skipping handleDataDeleted for %s from wrong generation. Current generation: %s; " +
            "Callback generation: %s", listenerName, zkUtils.getGeneration(), generation));
      } else {
        doHandleDataDeleted(dataPath);
      }
    }

    public abstract void doHandleDataChange(String path, Object data);

    public abstract void doHandleDataDeleted(String path);

    private boolean isValid() {
      return generation == zkUtils.getGeneration();
    }
  }

  /**
    * subscribe for changes of JobModel version
    * @param dataListener describe this
    */
  public void subscribeToJobModelVersionChange(GenerationAwareZkDataListener dataListener) {
    LOG.info(" subscribing for jm version change at:" + keyBuilder.getJobModelVersionPath());
    zkClient.subscribeDataChanges(keyBuilder.getJobModelVersionPath(), dataListener);
    metrics.subscriptions.inc();
  }

  /**
   * Publishes new job model into ZK.
   * This call should FAIL if the node already exists.
   * @param jobModelVersion  version of the jobModeL to publish
   * @param jobModel jobModel to publish
   *
   */
  public void publishJobModel(String jobModelVersion, JobModel jobModel) {
    try {
      ObjectMapper mmapper = SamzaObjectMapper.getObjectMapper();
      String jobModelStr = mmapper.writerWithDefaultPrettyPrinter().writeValueAsString(jobModel);
      LOG.info("jobModelAsString=" + jobModelStr);
      zkClient.createPersistent(keyBuilder.getJobModelPath(jobModelVersion), jobModelStr);
      LOG.info("wrote jobModel path =" + keyBuilder.getJobModelPath(jobModelVersion));
    } catch (Exception e) {
      LOG.error("JobModel publish failed for version=" + jobModelVersion, e);
      throw new SamzaException(e);
    }
  }

  /**
   * get the job model from ZK by version
   * @param jobModelVersion jobModel version to get
   * @return job model for this version
   */
  public JobModel getJobModel(String jobModelVersion) {
    LOG.info("Read the model ver=" + jobModelVersion + " from " + keyBuilder.getJobModelPath(jobModelVersion));
    Object data = zkClient.readData(keyBuilder.getJobModelPath(jobModelVersion));
    metrics.reads.inc();
    ObjectMapper mmapper = SamzaObjectMapper.getObjectMapper();
    JobModel jm;
    try {
      jm = mmapper.readValue((String) data, JobModel.class);
    } catch (IOException e) {
      throw new SamzaException("failed to read JobModel from ZK", e);
    }
    return jm;
  }

  /**
   * read the jobmodel version from ZK
   * @return jobmodel version as a string
   */
  public String getJobModelVersion() {
    String jobModelVersion = zkClient.readData(keyBuilder.getJobModelVersionPath(), true);
    metrics.reads.inc();
    return jobModelVersion;
  }

  /**
   * Generates the next JobModel version that should be used by a processor group in a rebalancing phase
   * for coordination.
   * @param currentJobModelVersion the current version of JobModel.
   * @return the next JobModel version.
   */
  public String getNextJobModelVersion(String currentJobModelVersion) {
    if (currentJobModelVersion == null) {
      return  "1";
    } else {
      /**
       * There's inconsistency between the maximum published jobModel version and value stored in jobModelVersion
       * zookeeper node. Short term fix is to read all published jobModel versions and choose the maximum version. If there's a
       * inconsistency, update the jobModelVersionPath with maximum published jobModelVersion.
       */
      List<String> publishedJobModelVersions = zkClient.getChildren(keyBuilder.getJobModelPathPrefix());
      metrics.reads.inc(publishedJobModelVersions.size());
      String maxPublishedJMVersion = publishedJobModelVersions.stream()
                                                              .max(Comparator.comparingInt(Integer::valueOf)).orElse("0");
      return Integer.toString(Math.max(Integer.valueOf(currentJobModelVersion), Integer.valueOf(maxPublishedJMVersion)) + 1);
    }
  }

  /**
   * publish the version number of the next JobModel
   * @param oldVersion - used to validate, that no one has changed the version in the meanwhile.
   * @param newVersion - new version.
   */
  public void publishJobModelVersion(String oldVersion, String newVersion) {
    Stat stat = new Stat();
    String currentVersion = zkClient.readData(keyBuilder.getJobModelVersionPath(), stat);
    metrics.reads.inc();
    LOG.info("publishing new version: " + newVersion + "; oldVersion = " + oldVersion + "(" + stat
        .getVersion() + ")");

    if (currentVersion != null && !currentVersion.equals(oldVersion)) {
      throw new SamzaException(
          "Someone changed JobModelVersion while the leader was generating one: expected" + oldVersion + ", got " + currentVersion);
    }
    // data version is the ZK version of the data from the ZK.
    int dataVersion = stat.getVersion();
    try {
      stat = zkClient.writeDataReturnStat(keyBuilder.getJobModelVersionPath(), newVersion, dataVersion);
      metrics.writes.inc();
    } catch (Exception e) {
      String msg = "publish job model version failed for new version = " + newVersion + "; old version = " + oldVersion;
      LOG.error(msg, e);
      throw new SamzaException(msg, e);
    }
    LOG.info("published new version: " + newVersion + "; expected data version = " + (dataVersion + 1) +
        "(actual data version after update = " + stat.getVersion() + ")");
  }

  // validate that Zk protocol currently used by the job is the same as in this participant
  public void validateZkVersion() {

    // Version of the protocol is written into root znode. If root does not exist yet we need to create one.
    String rootPath = keyBuilder.getRootPath();
    if (!zkClient.exists(rootPath)) {
      try {
        // attempt to create the root with the correct version
        zkClient.createPersistent(rootPath, ZK_PROTOCOL_VERSION);
        LOG.info("Created zk root node: " + rootPath + " with zk version " + ZK_PROTOCOL_VERSION);
        return;
      } catch (ZkNodeExistsException e) {
        // ignoring
        LOG.warn("root path " + rootPath + " already exists.");
      }
    }
    // if exists, verify the version
    Stat stat = new Stat();
    String version = zkClient.readData(rootPath, stat);
    if (version == null) {
      // for backward compatibility, if no value - assume 1.0
      try {
        zkClient.writeData(rootPath, "1.0", stat.getVersion());
      } catch (ZkBadVersionException e) {
        // if the write failed with ZkBadVersionException it means someone else already wrote a version, so we can ignore it.
      }
      // re-read the updated version
      version = zkClient.readData(rootPath);
    }
    LOG.info("Current version for zk root node: " + rootPath + " is " + version + ", expected version is " + ZK_PROTOCOL_VERSION);
    if (!version.equals(ZK_PROTOCOL_VERSION)) {
      throw new SamzaException("ZK Protocol mismatch. Expected " + ZK_PROTOCOL_VERSION + "; found " + version);
    }
  }

  /**
   * verify that given paths exist in ZK
   * @param paths - paths to verify or create
   */
  public void validatePaths(String[] paths) {
    for (String path : paths) {
      if (!zkClient.exists(path)) {
        zkClient.createPersistent(path, true);
      }
    }
  }

  /**
   * subscribe to the changes in the list of processors in ZK
   * @param listener - will be called when a processor is added or removed.
   */
  public void subscribeToProcessorChange(IZkChildListener listener) {
    LOG.info("Subscribing for child change at:" + keyBuilder.getProcessorsPath());
    zkClient.subscribeChildChanges(keyBuilder.getProcessorsPath(), listener);
    metrics.subscriptions.inc();
  }

  /**
   * cleanup old data from ZK
   * @param numVersionsToLeave - number of versions to leave
   */
  public void cleanupZK(int numVersionsToLeave) {
    deleteOldBarrierVersions(numVersionsToLeave);
    deleteOldJobModels(numVersionsToLeave);
  }

  void deleteOldJobModels(int numVersionsToLeave) {
    // read current list of JMs
    String path = keyBuilder.getJobModelPathPrefix();
    LOG.info("About to delete jm path=" + path);
    List<String> znodeIds = zkClient.getChildren(path);
    deleteOldVersionPath(path, znodeIds, numVersionsToLeave, new Comparator<String>() {
      @Override
      public int compare(String o1, String o2) {
        // jm version name format is <num>
        return Integer.valueOf(o1) - Integer.valueOf(o2);
      }
    });
  }

  void deleteOldBarrierVersions(int numVersionsToLeave) {
    // read current list of barriers
    String path = keyBuilder.getJobModelVersionBarrierPrefix();
    LOG.info("About to delete old barrier paths from " + path);
    List<String> znodeIds = zkClient.getChildren(path);
    LOG.info("List of all zkNodes: " + znodeIds);
    deleteOldVersionPath(path, znodeIds, numVersionsToLeave,  new Comparator<String>() {
      @Override
      public int compare(String o1, String o2) {
        // barrier's name format is barrier_<num>
        return ZkBarrierForVersionUpgrade.getVersion(o1) - ZkBarrierForVersionUpgrade.getVersion(o2);
      }
    });
  }

  void deleteOldVersionPath(String path, List<String> zNodeIds, int numVersionsToLeave, Comparator<String> c) {
    if (StringUtils.isEmpty(path) || zNodeIds == null) {
      LOG.warn("cannot cleanup empty path or empty list in ZK");
      return;
    }
    if (zNodeIds.size() > numVersionsToLeave) {
      Collections.sort(zNodeIds, c);
      // get the znodes to delete
      int size = zNodeIds.size();
      List<String> zNodesToDelete = zNodeIds.subList(0, zNodeIds.size() - numVersionsToLeave);
      LOG.info("Starting cleanup of barrier version zkNodes. From size=" + size + " to size " + zNodesToDelete.size() + "; numberToLeave=" + numVersionsToLeave);
      for (String znodeId : zNodesToDelete) {
        String pathToDelete = path + "/" + znodeId;
        try {
          LOG.info("deleting " + pathToDelete);
          zkClient.deleteRecursive(pathToDelete);
          metrics.deletions.inc();
        } catch (Exception e) {
          LOG.warn("delete of node " + pathToDelete + " failed.", e);
        }
      }
    }
  }
  /**
   * Represents zookeeper processor node.
   */
  static class ProcessorNode {
    private final ProcessorData processorData;

    // Ex: /test/processors/0000000000
    private final String ephemeralProcessorPath;

    ProcessorNode(ProcessorData processorData, String ephemeralProcessorPath) {
      this.processorData = processorData;
      this.ephemeralProcessorPath = ephemeralProcessorPath;
    }

    ProcessorData getProcessorData() {
      return processorData;
    }

    String getEphemeralPath() {
      return ephemeralProcessorPath;
    }

    @Override
    public String toString() {
      return String.format("[ProcessorData: %s, ephemeralProcessorPath: %s]", processorData, ephemeralProcessorPath);
    }

    @Override
    public int hashCode() {
      return Objects.hash(processorData, ephemeralProcessorPath);
    }

    @Override
    public boolean equals(Object obj) {
      if (obj == null) return false;
      if (getClass() != obj.getClass()) return false;
      final ProcessorNode other = (ProcessorNode) obj;
      return Objects.equals(processorData, other.processorData) && Objects.equals(ephemeralProcessorPath, other.ephemeralProcessorPath);
    }
  }
}
