Package org.apache.blur.shell

Source Code of org.apache.blur.shell.TopCommand

/**
* 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.blur.shell;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import jline.Terminal;
import jline.console.ConsoleReader;

import org.apache.blur.thirdparty.thrift_0_9_0.TException;
import org.apache.blur.thirdparty.thrift_0_9_0.transport.TTransportException;
import org.apache.blur.thrift.BlurClientManager;
import org.apache.blur.thrift.Connection;
import org.apache.blur.thrift.generated.Blur;
import org.apache.blur.thrift.generated.Blur.Client;
import org.apache.blur.thrift.generated.BlurException;
import org.apache.blur.thrift.generated.Metric;

public class TopCommand extends Command {

  private static final String HELP = ".help";
  private static final String TOP = "top.";
  private static final String LONGNAME = ".longname";
  private static final String SHORTNAME = ".shortname";
  private static final String UNKNOWN = "Unknown";
  private static final String TOP_SHARD_SERVER_SHORTNAME = "top.SHARD_SERVER.shortname";

  public enum SCREEN {
    HELP, TOP
  }

  private static final double ONE_THOUSAND = 1000;
  private static final double ONE_MILLION = ONE_THOUSAND * ONE_THOUSAND;
  private static final double ONE_BILLION = ONE_THOUSAND * ONE_MILLION;
  private static final double ONE_TRILLION = ONE_THOUSAND * ONE_BILLION;
  private static final double ONE_QUADRILLION = ONE_THOUSAND * ONE_TRILLION;

  private int _width = Integer.MAX_VALUE;
  private int _height;

  @Override
  public void doit(PrintWriter out, Blur.Iface client, String[] args) throws CommandException, TException,
      BlurException {
    try {
      doitInternal(out, client, args);
    } finally {
      ConsoleReader reader = this.getConsoleReader();
      if (reader != null) {
        reader.setPrompt(Main.PROMPT);
      }
    }
  }

  public void doitInternal(PrintWriter out, Blur.Iface client, String[] args) throws CommandException, TException,
      BlurException {

    AtomicBoolean quit = new AtomicBoolean();
    AtomicBoolean help = new AtomicBoolean();

    Properties properties = new Properties();
    try {
      properties.load(getClass().getResourceAsStream("top.properties"));
    } catch (IOException e) {
      if (Main.debug) {
        e.printStackTrace();
      }
      throw new CommandException(e.getMessage());
    }

    Map<String, String> metricNames = new HashMap<String, String>();
    Map<String, String> helpMap = new HashMap<String, String>();
    Set<Object> keySet = properties.keySet();
    for (Object k : keySet) {
      String key = k.toString();
      if (isShortName(key)) {
        String shortName = getShortName(key, properties);
        String longName = getLongName(getLongNameKey(key), properties);
        metricNames.put(shortName, longName);
      } else if (isHelpName(key)) {
        int indexOf = key.indexOf(HELP);
        String strKey = key.substring(0, indexOf);
        Object shortNameKey = properties.get(strKey + SHORTNAME);
        Object helpMessage = properties.get(key);
        if (shortNameKey != null && helpMessage != null) {
          helpMap.put(shortNameKey.toString(), helpMessage.toString());
        }
      }
    }

    String labelsStr = properties.getProperty("top.columns");
    String[] labels = resolveShortNames(labelsStr.split(","), properties);

    String sizesStr = properties.getProperty("top.sizes");
    Set<String> sizes = new HashSet<String>(Arrays.asList(resolveShortNames(sizesStr.split(","), properties)));
    Set<String> keys = new HashSet<String>(metricNames.values());

    String cluster;
    if (args.length != 2) {
      cluster = Main.getCluster(client, "Invalid args: " + help());
    } else {
      cluster = args[1];
    }

    ConsoleReader reader = this.getConsoleReader();
    if (reader != null) {
      Terminal terminal = reader.getTerminal();
      _height = terminal.getHeight() - 2;
      _width = terminal.getWidth() - 2;
      try {
        reader.setPrompt("");
        reader.clearScreen();
      } catch (IOException e) {
        if (Main.debug) {
          e.printStackTrace();
        }
      }

      startCommandWatcher(reader, quit, help, this);
    }

    List<String> shardServerList = new ArrayList<String>(client.shardServerList(cluster));
    Collections.sort(shardServerList);
    Map<String, AtomicReference<Client>> shardClients = setupClients(shardServerList);

    String shardServerLabel = properties.getProperty(TOP_SHARD_SERVER_SHORTNAME);
    int longestServerName = Math.max(getSizeOfLongestKey(shardClients), shardServerLabel.length());

    StringBuilder header = new StringBuilder("%" + longestServerName + "s");
    for (int i = 1; i < labels.length; i++) {
      header.append(" %10s");
    }

    do {
      int lineCount = 0;
      StringBuilder output = new StringBuilder();
      if (quit.get()) {
        return;
      } else if (help.get()) {
        showHelp(output, labels, helpMap);
      } else {
        output.append(truncate(String.format(header.toString(), (Object[]) labels)) + "\n");
        lineCount++;
        SERVER:
        for (Entry<String, AtomicReference<Client>> e : new TreeMap<String, AtomicReference<Client>>(shardClients)
            .entrySet()) {
          String shardServer = e.getKey();
          AtomicReference<Client> ref = e.getValue();
          Map<String, Metric> metrics = getMetrics(shardServer, ref, keys);
          if (metrics == null) {
            String line = String.format("%" + longestServerName + "s*%n", shardServer);
            output.append(line);
            lineCount++;
            if (tooLong(lineCount)) {
              break SERVER;
            }
          } else {
            Object[] cols = new Object[labels.length];
            int c = 0;
            cols[c++] = shardServer;
            StringBuilder sb = new StringBuilder("%" + longestServerName + "s");

            for (int i = 1; i < labels.length; i++) {
              String mn = metricNames.get(labels[i]);
              Metric metric = metrics.get(mn);
              Map<String, Double> doubleMap = metric.getDoubleMap();
              Double value = doubleMap.get("oneMinuteRate");
              if (value == null) {
                value = doubleMap.get("value");
              }
              cols[c++] = humanize(value, sizes.contains(mn));
              sb.append(" %10s");
            }
            output.append(truncate(String.format(sb.toString(), cols)) + "\n");
            lineCount++;
            if (tooLong(lineCount)) {
              break SERVER;
            }
          }
        }
      }
      if (reader != null) {
        try {
          reader.clearScreen();
        } catch (IOException e) {
          if (Main.debug) {
            e.printStackTrace();
          }
        }
      }
      out.print(output.toString());
      out.flush();
      if (reader != null) {
        try {
          synchronized (this) {
            wait(3000);
          }
        } catch (InterruptedException e) {
          return;
        }
        Terminal terminal = reader.getTerminal();
        _height = terminal.getHeight() - 2;
        _width = terminal.getWidth() - 2;

        List<String> currentShardServerList = new ArrayList<String>(client.shardServerList(cluster));
        Collections.sort(currentShardServerList);
        if (!shardServerList.equals(currentShardServerList)) {
          close(shardClients);
          shardClients = setupClients(shardServerList);
        }
      }
    } while (reader != null);
  }

  private boolean tooLong(int lineCount) {
    if (lineCount >= _height) {
      return true;
    }
    return false;
  }

  private boolean isHelpName(String key) {
    return key.endsWith(HELP);
  }

  private void close(Map<String, AtomicReference<Client>> shardClients) {
    for (AtomicReference<Client> client : shardClients.values()) {
      tryToClose(client);
    }
  }

  private Map<String, AtomicReference<Client>> setupClients(List<String> shardServerList) {
    Map<String, AtomicReference<Client>> shardClients = new ConcurrentHashMap<String, AtomicReference<Client>>();
    for (String sc : shardServerList) {
      AtomicReference<Client> ref = shardClients.get(sc);
      if (ref == null) {
        ref = new AtomicReference<Client>();
        shardClients.put(sc, ref);
      }
      tryToConnect(sc, ref);
    }
    return shardClients;
  }

  private boolean tryToConnect(String sc, AtomicReference<Client> ref) {
    try {
      Client c = BlurClientManager.newClient(new Connection(sc));
      ref.set(c);
      return true;
    } catch (TTransportException e) {
      ref.set(null);
      if (Main.debug) {
        e.printStackTrace();
      }
    } catch (IOException e) {
      ref.set(null);
      if (Main.debug) {
        e.printStackTrace();
      }
    }
    return false;
  }

  private Map<String, Metric> getMetrics(String sc, AtomicReference<Client> ref, Set<String> keys) {
    if (ref.get() == null) {
      if (!tryToConnect(sc, ref)) {
        return null;
      }
    }
    try {
      return ref.get().metrics(keys);
    } catch (BlurException e) {
      if (Main.debug) {
        e.printStackTrace();
      }
    } catch (TException e) {
      if (Main.debug) {
        e.printStackTrace();
      }
      tryToClose(ref);
    }
    return null;
  }

  private void tryToClose(AtomicReference<Client> ref) {
    Client client = ref.get();
    if (client != null) {
      ref.set(null);
      try {
        client.getInputProtocol().getTransport().close();
      } catch (Exception e) {
        if (Main.debug) {
          e.printStackTrace();
        }
      }
    }
  }

  private String[] resolveShortNames(String[] keys, Properties properties) {
    String[] labels = new String[keys.length];
    int i = 0;
    for (String key : keys) {
      String shortName = properties.getProperty(TOP + key + SHORTNAME);
      labels[i++] = shortName;
    }
    return labels;
  }

  private String getLongNameKey(String key) {
    return key.replace(SHORTNAME, LONGNAME);
  }

  private String getShortName(String key, Properties properties) {
    return properties.getProperty(key, UNKNOWN);
  }

  private String getLongName(String key, Properties properties) {
    return properties.getProperty(key, UNKNOWN);
  }

  private boolean isShortName(String key) {
    return key.endsWith(SHORTNAME);
  }

  private void showHelp(StringBuilder output, Object[] labels, Map<String, String> helpMap) {
    output.append("Help\n");
    for (int i = 0; i < labels.length; i++) {
      String shortName = (String) labels[i];
      String helpMessage = helpMap.get(shortName);
      output.append(String.format("%15s", shortName));
      output.append(" - ");
      output.append(helpMessage);
      output.append('\n');
    }

  }

  private void startCommandWatcher(final ConsoleReader reader, final AtomicBoolean quit, final AtomicBoolean help,
      final Object lock) {
    Thread thread = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          while (true) {
            int readCharacter = reader.readCharacter();
            if (readCharacter == 'q') {
              quit.set(true);
              synchronized (lock) {
                lock.notify();
              }
              return;
            } else if (readCharacter == 'h') {
              help.set(!help.get());
              synchronized (lock) {
                lock.notify();
              }
            }
          }
        } catch (IOException e) {
          if (Main.debug) {
            e.printStackTrace();
          }
        }
      }
    });
    thread.setDaemon(true);
    thread.start();
  }

  private String truncate(String s) {
    return s.substring(0, Math.min(_width, s.length()));
  }

  private String humanize(double value, boolean size) {
    long v = (long) (value / ONE_QUADRILLION);
    if (v > 0) {
      return String.format("%7.2f%s", value / ONE_QUADRILLION, size ? "Q" : "P");
    }
    v = (long) (value / ONE_TRILLION);
    if (v > 0) {
      return String.format("%7.2f%s", value / ONE_TRILLION, "T");
    }
    v = (long) (value / ONE_BILLION);
    if (v > 0) {
      return String.format("%7.2f%s", value / ONE_BILLION, size ? "B" : "G");
    }
    v = (long) (value / ONE_MILLION);
    if (v > 0) {
      return String.format("%7.2f%s", value / ONE_MILLION, "M");
    }
    v = (long) (value / ONE_THOUSAND);
    if (v > 0) {
      return String.format("%7.2f%s", value / ONE_THOUSAND, "K");
    }
    return String.format("%7.2f", value);
  }

  private int getSizeOfLongestKey(Map<String, ?> map) {
    int i = 0;
    for (String s : map.keySet()) {
      int length = s.length();
      if (i < length) {
        i = length;
      }
    }
    return i;
  }

  @Override
  public String description() {
    return "Top for watching shard clusters.";
  }

  @Override
  public String usage() {
    return "[<cluster>]";
  }

  @Override
  public String name() {
    return "top";
  }
}
TOP

Related Classes of org.apache.blur.shell.TopCommand

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.