Package com.cloudera.flume.master

Source Code of com.cloudera.flume.master.ZooKeeperConfigStore

/**
* Licensed to Cloudera, Inc. under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  Cloudera, Inc. 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 com.cloudera.flume.master;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.avro.Schema;
import org.apache.avro.Schema.Type;
import org.apache.avro.file.DataFileStream;
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.generic.GenericArray;
import org.apache.avro.generic.GenericData;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
import org.apache.avro.util.Utf8;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cloudera.flume.conf.FlumeConfigData;
import com.cloudera.flume.conf.avro.AvroFlumeChokeMap;
import com.cloudera.flume.conf.avro.AvroFlumeConfigData;
import com.cloudera.flume.conf.avro.AvroFlumeConfigDataMap;
import com.cloudera.flume.conf.avro.AvroFlumeNodeMap;
import com.cloudera.flume.master.ZKClient.InitCallback;
import com.cloudera.util.Clock;
import com.cloudera.util.Pair;
import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;

/**
* ZooKeeper based store for node configuration.
*/
public class ZooKeeperConfigStore extends ConfigStore implements Watcher {
  ZKClient client = null;
  final Map<String, FlumeConfigData> cfgs = new HashMap<String, FlumeConfigData>();
  ListMultimap<String, String> nodeMap = ArrayListMultimap
      .<String, String> create();
  Map<String, Map<String, Integer>> chokeMap = new HashMap<String, Map<String, Integer>>();

  static final Logger LOG = LoggerFactory.getLogger(ZooKeeperConfigStore.class);
  final static String CFGS_PATH = "/flume-cfgs";
  final static String NODEMAPS_PATH = "/flume-nodes";
  final static String CHOKEMAP_PATH = "/flume-chokemap";

  // Tracks the version number of each config
  ZooKeeperCounter zkCounter;
  long currentVersion = -1;

  ZooKeeperService zkService = null;

  /**
   * Constructs a new ZooKeeperConfigStore, using the system-wide
   * ZooKeeperService
   */
  public ZooKeeperConfigStore() {
    this(ZooKeeperService.get());
  }

  /**
   * Exists so that we can control the ZooKeeperService, for testing purposes.
   */
  protected ZooKeeperConfigStore(ZooKeeperService zooKeeperService) {
    this.zkService = zooKeeperService;
  }

  /**
   * Reads the standard configuration and initialises client and optionally
   * server accordingly.
   */
  @Override
  public void init() throws IOException, InterruptedException {
    Preconditions.checkArgument(this.zkService != null,
        "ZooKeeperService is null in init");
    connect();
  }

  /**
   * Connect to an ensemble and load the configs / nodemaps
   */
  protected synchronized void connect() throws IOException,
      InterruptedException {
    Preconditions.checkState(zkService.isInitialised(),
        "ZooKeeperService not initialised in ZKCS.connect()");
    if (client != null) {
      client.getZK().close();
    }
    InitCallback cb = new InitCallback() {
      /*
       * Synchronization notes: from this method, the callback comes from the
       * same thread. That's not guaranteed afterwards, because this gets called
       * again on SessionExpiredException.
       *
       * It tries to take the ZKCS.this lock (in loadConfigs). Therefore BE
       * AWARE of potential deadlocks between threads. The vast majority of the
       * invocations to ZKClient in this class will be under the ZKCS.this lock
       * and therefore thread-safe.
       */
      @Override
      public void success(ZKClient client) throws IOException {
        client.getZK().register(ZooKeeperConfigStore.this);

        loadConfigs(CFGS_PATH);
        loadNodeMaps(NODEMAPS_PATH);
        loadChokeMap(CHOKEMAP_PATH);
      }
    };

    client = zkService.createClient();
    client.init(cb);
    try {
      ZooKeeperConfigStore.this.zkCounter = new ZooKeeperCounter(
          this.zkService, "/counters-config_version");
    } catch (KeeperException e) {
      throw new IOException("Couldn't create ZooKeeperCounter!", e);
    } catch (InterruptedException e) {
      throw new IOException("Couldn't create ZooKeeperCounter!", e);
    }
  }

  /**
   * Convert a configuration map into an Avro-serialized byte array
   */
  static protected byte[] serializeConfigs(Map<String, FlumeConfigData> cfgs)
      throws IOException {
    Map<CharSequence, AvroFlumeConfigData> map = new HashMap<CharSequence, AvroFlumeConfigData>();
    for (Entry<String, FlumeConfigData> e : cfgs.entrySet()) {
      AvroFlumeConfigData avroConfig = MasterClientServerAvro.configToAvro(e
          .getValue());

      map.put(new Utf8(e.getKey()), avroConfig);
    }

    AvroFlumeConfigDataMap avromap = new AvroFlumeConfigDataMap();
    avromap.configs = map;

    DatumWriter<AvroFlumeConfigDataMap> datumWriter = new SpecificDatumWriter<AvroFlumeConfigDataMap>();
    datumWriter.setSchema(avromap.getSchema());
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataFileWriter<AvroFlumeConfigDataMap> fileWriter = new DataFileWriter<AvroFlumeConfigDataMap>(
        datumWriter);
    fileWriter.create(avromap.getSchema(), baos);
    fileWriter.append(avromap);
    fileWriter.close();
    return baos.toByteArray();
  }

  /**
   * Convert an Avro-serialized byte array into a configuration map
   */
  static protected Map<String, FlumeConfigData> deserializeConfigs(byte[] cfg)
      throws IOException {
    DatumReader<AvroFlumeConfigDataMap> reader = new SpecificDatumReader<AvroFlumeConfigDataMap>();
    reader.setSchema(AvroFlumeConfigDataMap.SCHEMA$);
    DataFileStream<AvroFlumeConfigDataMap> fileStream = new DataFileStream<AvroFlumeConfigDataMap>(
        new ByteArrayInputStream(cfg), reader);
    AvroFlumeConfigDataMap cfgmap = fileStream.next();
    fileStream.close();
    Map<String, FlumeConfigData> ret = new HashMap<String, FlumeConfigData>();
    for (Entry<CharSequence, AvroFlumeConfigData> e : cfgmap.configs.entrySet()) {
      ret.put(e.getKey().toString(), MasterClientServerAvro.configFromAvro(e
          .getValue()));
    }

    return ret;
  }

  /**
   * Writes an Avro-serialized form of all known node configs to ZK
   */
  protected synchronized void saveConfigs(String prefix) {
    Preconditions.checkNotNull(this.client, "Client is null in saveConfigs");

    try {
      String cfgPath = String.format(prefix + "/cfg-%010d", currentVersion);
      // Create a new
      String znode = client.create(cfgPath, serializeConfigs(cfgs),
          Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

      LOG.info("Created new config at " + znode);
    } catch (KeeperException e) {
      LOG.error("ZooKeeper exception: ", e);
    } catch (InterruptedException e) {
      LOG.error("Interrupted while saving config", e);
    } catch (IOException e) {
      LOG.error("IOException when saving config", e);
    }
  }

  /**
   * This internal method is called at connection time to populate the cache.
   *
   * May be called from either the main Master thread or a ZK-initiated callback
   * so is synchronized to prevent racing.
   */
  synchronized protected void loadConfigs(String prefix) throws IOException {
    try {
      client.ensureExists(prefix, new byte[0]);

      /*
       * We can't use the counter value here because there may have been failed
       * attempts to write a config - so the config sequence will not be
       * continuous.
       */
      String latest = client.getLastSequentialChild(prefix, "cfg-", true);
      String path = prefix + "/" + latest;

      if (latest == null) {
        LOG.debug("No configurations found");
        return;
      }

      long latestVersion = ZKClient.extractSuffix("cfg-", path);

      if (currentVersion == latestVersion) {
        LOG.debug("Trying to load current version, ignoring");
        return;
      }

      cfgs.clear();

      Stat stat = new Stat();
      LOG.info("Loading config from: " + path);
      byte[] cfg = client.getData(path, false, stat);
      if (cfg.length == 0) {
        LOG.info("Config was empty!");
        return;
      }

      cfgs.putAll(deserializeConfigs(cfg));
    } catch (Exception e) {
      throw new IOException("Unexpected exception in loadConfigs", e);
    }
  }

  /**
   * Updates the in-memory cache, and then writes all configs out to ZK
   */
  @Override
  public synchronized void setConfig(String host, String flowid, String source,
      String sink) throws IOException {
    Preconditions.checkArgument(client != null && client.getZK() != null,
        "Attempted to set config but ZK client is not connected!");
    Preconditions.checkArgument(host != null,
        "Attempted to set config but missing hostname!");
    Preconditions.checkArgument(flowid != null, "Attempted to set config "
        + host + " but missing flowid!");
    Preconditions.checkArgument(source != null, "Attempted to set config "
        + host + " but missing source!");
    Preconditions.checkArgument(sink != null, "Attempted to set config " + host
        + " but missing sink!");

    if (client.getZK().getState() != ZooKeeper.States.CONNECTED) {
      throw new IOException("Not connected to ZooKeeper: "
          + client.getZK().getState());
    }

    try {
      currentVersion = zkCounter.incrementAndGet();
    } catch (Exception e) {
      throw new IOException("Could not increment version counter...", e);
    }

    cfgs.put(host, new FlumeConfigData(Clock.unixTime(), source, sink,
        currentVersion, currentVersion, flowid));
    saveConfigs(CFGS_PATH);
  }

  /**
   * Saves a list of configuration updates with as one new configuration -
   * avoids multiple watches getting fired.
   */
  @Override
  public synchronized void bulkSetConfig(Map<String, FlumeConfigData> configs)
      throws IOException {
    Preconditions.checkArgument(client != null && client.getZK() != null);

    if (client.getZK().getState() != ZooKeeper.States.CONNECTED) {
      throw new IOException("Not connected to ZooKeeper: "
          + client.getZK().getState());
    }

    try {
      currentVersion = zkCounter.incrementAndGet();
    } catch (Exception e) {
      throw new IOException("Could not increment version counter...", e);
    }

    for (Entry<String, FlumeConfigData> e : configs.entrySet()) {
      FlumeConfigData f = new FlumeConfigData(Clock.unixTime(), e.getValue()
          .getSourceConfig(), e.getValue().getSinkConfig(), currentVersion,
          currentVersion, e.getValue().getFlowID());
      cfgs.put(e.getKey(), f);
    }
    saveConfigs(CFGS_PATH);
  }

  /**
   * Checks the in-memory cache, but does not go to ZooKeeper to check.
   */
  @Override
  public synchronized FlumeConfigData getConfig(String host) {
    Preconditions.checkArgument(client != null);
    if (cfgs.containsKey(host)) {
      return cfgs.get(host);
    }

    return null;
  }

  @Override
  public synchronized Map<String, FlumeConfigData> getConfigs() {
    return Collections.unmodifiableMap(cfgs);
  }

  /**
   * Converts a nodemap into an Avro-serialized byte array
   */
  static protected byte[] serializeNodeMap(ListMultimap<String, String> nodeMap)
      throws IOException {
    DatumWriter<AvroFlumeNodeMap> datumWriter = new SpecificDatumWriter<AvroFlumeNodeMap>();
    AvroFlumeNodeMap avromap = new AvroFlumeNodeMap();

    Map<CharSequence, List<CharSequence>> map = new HashMap<CharSequence, List<CharSequence>>();
    for (Entry<String, Collection<String>> e : nodeMap.asMap().entrySet()) {
      String name = e.getKey();
      GenericArray<CharSequence> out = new GenericData.Array<CharSequence>(e
          .getValue().size(), Schema.createArray(Schema.create(Type.STRING)));

      for (String s : e.getValue()) {
        out.add(new String(s));
      }

      map.put(name, out);
    }

    avromap.nodemap = map;

    datumWriter.setSchema(avromap.getSchema());
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataFileWriter<AvroFlumeNodeMap> fileWriter = new DataFileWriter<AvroFlumeNodeMap>(
        datumWriter);
    fileWriter.create(avromap.getSchema(), baos);
    fileWriter.append(avromap);
    fileWriter.close();

    return baos.toByteArray();
  }

  /**
   * Converts an Avro-serialized byte array into a nodemap
   */
  static protected List<Pair<String, List<String>>> deserializeNodeMap(
      byte[] data) throws IOException {
    DatumReader<AvroFlumeNodeMap> reader = new SpecificDatumReader<AvroFlumeNodeMap>();
    DataFileStream<AvroFlumeNodeMap> fileStream = new DataFileStream<AvroFlumeNodeMap>(
        new ByteArrayInputStream(data), reader);
    AvroFlumeNodeMap cfgmap = fileStream.next();
    fileStream.close();

    List<Pair<String, List<String>>> ret = new ArrayList<Pair<String, List<String>>>();

    for (Entry<CharSequence, List<CharSequence>> e : cfgmap.nodemap.entrySet()) {
      List<String> list = new ArrayList<String>();
      for (CharSequence c : e.getValue()) {
        list.add(c.toString());
      }
      ret.add(new Pair<String, List<String>>(e.getKey().toString(), list));
    }
    return ret;
  }

  /**
   * Converts a ChokeMap into an Avro-serialized byte array
   */
  static protected byte[] serializeChokeMap(
      Map<String, Map<String, Integer>> chokeMap) throws IOException {
    DatumWriter<AvroFlumeChokeMap> datumWriter = new SpecificDatumWriter<AvroFlumeChokeMap>();
    AvroFlumeChokeMap avromap = new AvroFlumeChokeMap();

    Map<CharSequence, Map<CharSequence, Integer>> map = new HashMap<CharSequence, Map<CharSequence, Integer>>();

    for (Entry<String, Map<String, Integer>> e : chokeMap.entrySet()) {
      String name = e.getKey();

      HashMap<CharSequence, Integer> tempMap = new HashMap<CharSequence, Integer>();

      for (Entry<String, Integer> mape : e.getValue().entrySet()) {
        tempMap.put(new String(mape.getKey()), mape.getValue());
      }

      map.put(name, tempMap);
    }

    avromap.chokemap = map;

    datumWriter.setSchema(avromap.getSchema());
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataFileWriter<AvroFlumeChokeMap> fileWriter = new DataFileWriter<AvroFlumeChokeMap>(
        datumWriter);
    fileWriter.create(avromap.getSchema(), baos);
    fileWriter.append(avromap);
    fileWriter.close();

    return baos.toByteArray();
  }

  /**
   * Converts an Avro-serialized byte array into a chokemap
   */
  static protected Map<String, Map<String, Integer>> deserializeChokeMap(
      byte[] data) throws IOException {
    SpecificDatumReader<AvroFlumeChokeMap> reader = new SpecificDatumReader<AvroFlumeChokeMap>();
    DataFileStream<AvroFlumeChokeMap> fileStream = new DataFileStream<AvroFlumeChokeMap>(
        new ByteArrayInputStream(data), reader);
    AvroFlumeChokeMap chkmap = fileStream.next();
    fileStream.close();
    Map<String, Map<String, Integer>> ret = new HashMap<String, Map<String, Integer>>();

    for (Entry<CharSequence, Map<CharSequence, Integer>> e : chkmap.chokemap
        .entrySet()) {
      HashMap<String, Integer> tempMap = new HashMap<String, Integer>();
      for (Entry<CharSequence, Integer> mape : e.getValue().entrySet()) {
        tempMap.put(mape.getKey().toString(), mape.getValue());
      }
      ret.put(e.getKey().toString(), tempMap);
    }
    return ret;
  }

  /**
   * This internal method is called at connection time to populate the cache.
   *
   * May be called from either the main Master thread or a ZK-initiated callback
   * so is synchronized to prevent racing.
   */
  synchronized protected void loadChokeMap(String prefix) throws IOException {
    Preconditions.checkNotNull(this.client, "Client is null in loadChokeMap");
    // Finds the most recent prefix
    try {
      client.ensureExists(prefix, new byte[0]);
      String latest = client.getLastSequentialChild(prefix, "chokemap", true);
      if (latest == null) {
        LOG.info("No Chokemap found at " + prefix + "/chokemap*");
        return;
      }
      chokeMap.clear(); // reset prior to reload
      String path = prefix + "/" + latest;
      LOG.info("Loading Chokemap from: " + path);
      Stat stat = new Stat();
      byte[] data = client.getData(path, false, stat);

      chokeMap.putAll(deserializeChokeMap(data));
    } catch (Exception e) {
      LOG.error("Unexpected exception in loadChokeMap", e);
      throw new IOException("Unexpected exception in loadChokeMap", e);
    }
  }

  /**
   * Saves the chokeid->chokelimit mappings to ZK.
   */
  protected synchronized void saveChokeMap(String prefix) {
    Preconditions.checkNotNull(this.client, "Client is null in saveChokeMap");
    try {
      client.create(prefix + "/chokemap", serializeChokeMap(this.chokeMap),
          Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
    } catch (KeeperException e) {
      LOG.error("ZooKeeper exception: ", e);
    } catch (InterruptedException e) {
      LOG.error("Interrupted while saving chokemap", e);
    } catch (IOException e) {
      LOG.error("IOException when saving chokemap", e);
    }
  }

  /**
   * Saves the physical->logical node mappings to ZK. Synchronized so that
   * nodeMap does not have to be copied - it is iterated over by
   * serializeNodeMap
   */
  protected synchronized void saveNodeMaps(String prefix) {
    Preconditions.checkNotNull(this.client, "Client is null in saveNodeMaps");
    try {
      client.create(prefix + "/nodes", serializeNodeMap(this.nodeMap),
          Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
    } catch (KeeperException e) {
      LOG.error("ZooKeeper exception: ", e);
    } catch (InterruptedException e) {
      LOG.error("Interrupted while saving config", e);
    } catch (IOException e) {
      LOG.error("IOException when saving config", e);
    }
  }

  /**
   * Loads the physical->logical node mappings from ZK
   */
  protected synchronized void loadNodeMaps(String prefix) throws IOException {
    Preconditions.checkNotNull(this.client, "Client is null in loadNodeMaps");
    // Finds the most recent prefix
    try {
      client.ensureExists(prefix, new byte[0]);
      String latest = client.getLastSequentialChild(prefix, "nodes", true);
      if (latest == null) {
        LOG.info("No nodemaps found at " + prefix + "/nodes*");
        return;
      }
      nodeMap.clear(); // reset prior to reload
      String path = prefix + "/" + latest;
      LOG.info("Loading nodes from: " + path);
      Stat stat = new Stat();
      byte[] data = client.getData(path, false, stat);
      for (Pair<String, List<String>> mapping : deserializeNodeMap(data)) {
        nodeMap.putAll(mapping.getLeft(), mapping.getRight());
      }
    } catch (Exception e) {
      LOG.error("Unexpected exception in loadNodeMaps", e);
      throw new IOException("Unexpected exception in loadNodeMaps", e);
    }
  }

  @Override
  public synchronized void addLogicalNode(String physNode, String logicNode) {
    Preconditions.checkArgument(client != null);
    if (nodeMap.containsEntry(physNode, logicNode)) {
      // already present.
      return;
    }
    nodeMap.put(physNode, logicNode);
    saveNodeMaps(NODEMAPS_PATH);
  }

  @Override
  public synchronized List<String> getLogicalNodes(String physNode) {
    List<String> values;

    values = nodeMap.get(physNode);

    if (values == null) {
      return Collections.emptyList();
    }

    return Collections.unmodifiableList(values);
  }

  @Override
  /**
   * This is called whenever an event is seen on the ZK ensemble that we
   * have registered for. We care particularly about changes to the list of
   * configurations, made by some other peer.
   */
  public synchronized void process(WatchedEvent event) {
    if (client == null) {
      // This is the 'death-rattle' callback, made when we close the client.
      return;
    }
    LOG.debug("Saw ZooKeeper watch event " + event);
    if (event.getType() == Watcher.Event.EventType.NodeChildrenChanged) {
      if (event.getPath().equals(CFGS_PATH)) {
        try {
          LOG.info("Config was updated - reloading");
          loadConfigs(CFGS_PATH);
        } catch (IOException e) {
          LOG.error("IOException when reloading configs", e);
        }
      }
      if (event.getPath().equals(NODEMAPS_PATH)) {
        try {
          LOG.info("Nodemaps were updated - reloading");
          loadNodeMaps(NODEMAPS_PATH);
        } catch (IOException e) {
          LOG.error("IOException when reloading nodemaps", e);
        }
      }
      if (event.getPath().equals(CHOKEMAP_PATH)) {
        try {
          LOG.info("chokemaps were updated - reloading");
          loadChokeMap(CHOKEMAP_PATH);
        } catch (IOException e) {
          LOG.error("IOException when reloading ChokeMap", e);
        }
      }
    }
  }

  @Override
  synchronized public ListMultimap<String, String> getLogicalNodeMap() {
    return Multimaps.unmodifiableListMultimap(nodeMap);
  }

  /**
   * Remove a logical node from the logical node data flow mapping.
   */
  @Override
  synchronized public void removeLogicalNode(String logicNode)
      throws IOException {
    Preconditions.checkArgument(client != null);
    try {
      currentVersion = zkCounter.incrementAndGet();
    } catch (Exception e) {
      throw new IOException("Could not increment version counter...", e);
    }
    cfgs.remove(logicNode);
    saveConfigs(CFGS_PATH);
  }

  /**
   * Removes the mapping of physNode to a particular logicalNode
   */
  @Override
  synchronized public void unmapLogicalNode(String physNode, String logicNode) {
    Preconditions.checkArgument(client != null);
    nodeMap.remove(physNode, logicNode);
    saveNodeMaps(NODEMAPS_PATH);
  }

  @Override
  synchronized public void shutdown() throws IOException {
    // When we shutdown, there is a callback that is made that we wish to
    // ignore. We signal this by setting client = null, before closing the
    // connection. But we want this to be published to the thread that receives
    // the callback, hence the synchronization to guarantee that ordering.
    if (client != null) {
      ZKClient oldClient = client;
      client = null;
      try {
        oldClient.close();
      } catch (InterruptedException e) {
        LOG.warn("Client interrupted when shutting down connection to ZK");
      }
      try {
        zkCounter.shutdown();
      } catch (InterruptedException e) {
        LOG.warn("Counter interrupted when shutting down connection to ZK");
      }
      client = null;
      zkCounter = null;
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void unmapAllLogicalNodes() {
    ListMultimap<String, String> clone = null;
    // create is not thread safe
    synchronized (this) {
      clone = ArrayListMultimap.create(nodeMap);
    }
    for (Entry<String, String> e : clone.entries()) {
      // reject removing a logical node named the same thing as
      // the physical node.
      if (e.getKey().equals(e.getValue())) {
        continue;
      }
      unmapLogicalNode(e.getKey(), e.getValue());
    }

    saveNodeMaps(NODEMAPS_PATH);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void addChokeLimit(String physNode, String chokeID, int limit) {
    if (!chokeMap.containsKey(physNode)) {
      // initialize it
      chokeMap.put(physNode, new HashMap<String, Integer>());
    }
    // now add the entry for this choke

    chokeMap.get(physNode).put(chokeID, limit);
    saveChokeMap(CHOKEMAP_PATH);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Map<String, Integer> getChokeMap(String physNode) {
    if (chokeMap.get(physNode) == null) {
      // initialize it
      chokeMap.put(physNode, new HashMap<String, Integer>());
    }
    return chokeMap.get(physNode);
  }
}
TOP

Related Classes of com.cloudera.flume.master.ZooKeeperConfigStore

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.