All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.kv.impl.util.TopologyPrinter Maven / Gradle / Ivy

Go to download

NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.

The newest version!
/*-
 * Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle NoSQL
 * Database made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle NoSQL Database for a copy of the license and
 * additional information.
 */

package oracle.kv.impl.util;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import oracle.kv.impl.admin.param.AdminParams;
import oracle.kv.impl.admin.param.ArbNodeParams;
import oracle.kv.impl.admin.param.Parameters;
import oracle.kv.impl.admin.param.RepNodeParams;
import oracle.kv.impl.admin.param.StorageNodeParams;
import oracle.kv.impl.admin.topo.LogDirectory;
import oracle.kv.impl.admin.topo.StorageDirectory;
import oracle.kv.impl.admin.topo.TopologyCandidate;
import oracle.kv.impl.measurement.LatencyInfo;
import oracle.kv.impl.monitor.views.PerfEvent;
import oracle.kv.impl.monitor.views.ServiceChange;
import oracle.kv.impl.param.Parameter;
import oracle.kv.impl.param.ParameterMap;
import oracle.kv.impl.param.SizeParameter;
import oracle.kv.impl.topo.ArbNode;
import oracle.kv.impl.topo.ArbNodeId;
import oracle.kv.impl.topo.Datacenter;
import oracle.kv.impl.topo.DatacenterId;
import oracle.kv.impl.topo.Partition;
import oracle.kv.impl.topo.PartitionId;
import oracle.kv.impl.topo.RepGroup;
import oracle.kv.impl.topo.RepGroupId;
import oracle.kv.impl.topo.RepNode;
import oracle.kv.impl.topo.RepNodeId;
import oracle.kv.impl.topo.ResourceId;
import oracle.kv.impl.topo.StorageNode;
import oracle.kv.impl.topo.StorageNodeId;
import oracle.kv.impl.topo.Topology;
import oracle.kv.util.GenerateConfig;

import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;

/**
 * Prints a Topology for visualization.
 */
public final class TopologyPrinter {

    public enum Filter { STORE, DC, RN, SN, SHARD, STATUS, PERF, AN }
    public static final EnumSet all =
        EnumSet.allOf(Filter.class);
    public static final EnumSet components =
        EnumSet.of(Filter.STORE, Filter.DC, Filter.RN, Filter.SN, Filter.SHARD, Filter.AN);
    /**
     * Private constructor to satisfy CheckStyle and to prevent
     * instantiation of this utility class.
     */
    private TopologyPrinter() {
        throw new AssertionError("Instantiated utility class " +
                                 TopologyPrinter.class);
    }

    /**
     * Dumps the topology to "out".
     * @param params SN capacity and RN mount points are stored in the
     * Parameters class from the Admin DB, and is not available in the topology
     * itself. If params is not null, use it to display that kind of
     * information.
     * @param verbose if true, print partitions for each shard.
     */
    public static void printTopology(Topology t,
                                     PrintStream out,
                                     Parameters params,
                                     EnumSet filter,
                                     Map statusMap,
                                     Map perfMap,
                                     boolean verbose) {
        printTopology(t, out, params, filter, verbose, null, null, statusMap,
                      perfMap);
    }

    /**
     * Dumps the topology to "out".
     *
     * This method can be called on deployed and not-yet-deployed topologies.
     * The latter are tricky, because the Parameters may not contain a
     * RepNodeParams for new RNs. Some information of interest is only available
     * in the RepNodeParam, and not the topology, such as:
     * - ha ports: calculated at deploy time
     * - mount point mappings: in a special map in the candidate
     *
     * This method has to take care to check whether the params-type information
     * is available yet.
     *
     * @param params SN capacity and RN mount points are stored in the
     * Parameters class from the Admin DB, and is not available in the topology
     * itself. If params is not null, use it to display that kind of
     * information.
     * @param filter is used to selectively print portions of the topology.
     * The default is the entire thing.
     * @param verbose if true, print partitions for each shard.
     */
    private static void printTopology(Topology t,
                                      PrintStream out,
                                      Parameters params,
                                      EnumSet filter,
                                      boolean verbose,
                                      Map
                                                                storageDirMap,
                                      Map
                                                                rnLogDirMap,
                                      Map statusMap,
                                      Map perfMap) {

        int indent = 0;
        final int indentAmount = 2;
        final boolean showStatus = filter.contains(Filter.STATUS) &&
            (statusMap != null);
        final boolean showPerf = filter.contains(Filter.PERF) &&
            (perfMap != null);

        /*
         * Display the store name
         */
        final String storeName = t.getKVStoreName();
        if (filter.contains(Filter.STORE)) {
            out.println("store=" + storeName + "  numPartitions=" +
                        t.getPartitionMap().size() + " sequence=" +
                        t.getSequenceNumber());
            indent += indentAmount;
        }

        /*
         * Display datacenters, sorted by data center ID
         */
        if (filter.contains(Filter.DC)) {
            final List dcList = t.getSortedDatacenters();
            for (final Datacenter dc : dcList) {
                out.println(makeWhiteSpace(indent) +
                            DatacenterId.DATACENTER_PREFIX + ": " + dc);
            }
            if (dcList.size() > 0) {
                out.println();
            }
        }

        /*
         * Display SNs, sorted by SN id.
         */
        final Map> snMap =
            new TreeMap>();
        for (StorageNodeId snid : t.getStorageNodeMap().getAllIds()) {
            snMap.put(snid, new ArrayList());
        }
        final List rnList = t.getSortedRepNodes();
        for (RepNode rn: rnList) {
            final List l = snMap.get(rn.getStorageNodeId());
            l.add(rn.getResourceId());
        }

        for (Entry> entry : snMap.entrySet()) {
            final StorageNodeId snId = entry.getKey();
            String capacityInfo = null;
            StorageNodeParams snp = null;
            if (params != null) {
                snp = params.get(snId);
                if (snp != null) {
                    capacityInfo = " capacity=" + snp.getCapacity();
                }
            }
            if (filter.contains(Filter.SN)) {
                out.print(makeWhiteSpace(indent) + "sn=" + t.get(snId));
                /*
                 * TODO : Yet to add details corresponding to admin storage
                 * dirs for this SN.
                 */
                if (capacityInfo != null) {
                    out.print(capacityInfo);
                }
                if (showStatus) {
                    out.println(" " + getStatus(statusMap, snId));
                } else {
                    out.println();
                }

                indent += indentAmount;
            }

            /* List all the RNs on a given SN */
            if (filter.contains(Filter.RN)) {
                final List rnsWithMountPoints =
                    new ArrayList();
                for (RepNodeId rnId : entry.getValue()) {
                    String oneRN = "[" + rnId + "]";

                    if (showStatus) {
                        oneRN += " " + getStatus(statusMap, rnId, params);
                    }

                    if (!verbose) {
                        out.println(makeWhiteSpace(indent) + oneRN);
                        if (showPerf) {
                            out.println
                                (makeWhiteSpace((indent + 1) * indentAmount) +
                                 getPerf(perfMap, rnId));
                        }
                        continue;
                    }

                    /*
                     * If this is verbose mode, display the root directory or
                     * storage directory, if those are available. Root dir SNs
                     * will be displayed first.
                     *
                     * Storage directory and RN log Directory information is
                     * available in two places, depending on whether this
                     * topology is deployed or not. If not deployed, it's
                     * in the topology candidate assigned storage directory
                     * and RN log dir map, because that information is more
                     * up to date for a candidate. If there is no map, then this
                     * is a deployed topo, and we should look in the params.
                     */
                    printStorageRNLogMountPoints(storageDirMap, rnLogDirMap,
                                                 rnsWithMountPoints,
                                                 params, rnId, oneRN,
                                                 out, indent, indentAmount,
                                                 showPerf, perfMap, snp);
                }
                for (String s : rnsWithMountPoints) {
                    out.println(makeWhiteSpace(indent) + s);
                }
            }

            /* List all the ANs on a given SN */
            if (filter.contains(Filter.AN)) {
                for (ArbNodeId anId : t.getHostedArbNodeIds(snId)) {
                    String oneAN = "[" + anId + "]";

                    if (showStatus) {
                        oneAN += " " + getStatus(statusMap, anId, params);
                    }

                    if (!verbose) {
                        out.println(makeWhiteSpace(indent) + oneAN);
                    } else {
                        out.print(makeWhiteSpace(indent) + oneAN);
                        if (snp == null) {
                            out.println();
                        } else {
                            out.println("  " + snp.getRootDirPath());
                        }
                    }
                }
            }

            if (filter.contains(Filter.SN)) {
                indent -= indentAmount;
            }
        }

        /*
         * Display rep groups (shards), sorted by ID
         */
        if (filter.contains(Filter.SHARD)) {
            out.println();
            final Map> partToRG =
                sortPartitions(t);

            out.println(makeWhiteSpace(indent) + "numShards="
                        + partToRG.size());

            for (Map.Entry> entry :
                     partToRG.entrySet()) {

                final RepGroupId rgId = entry.getKey();
                final List partIds = entry.getValue();
                final RepGroup rg = t.get(rgId);
                out.println(makeWhiteSpace(indent) + "shard=" + rg +
                            " num partitions=" + partIds.size());

                if (filter.contains(Filter.RN) ||
                    filter.contains(Filter.AN)) {
                    indent += indentAmount;
                }

                if (filter.contains(Filter.RN)) {
                    final List rns =
                        new ArrayList(rg.getRepNodes());
                    Collections.sort(rns);
                    for (RepNode rn: rns) {
                        out.print(makeWhiteSpace(indent) + rn);
                        if (verbose && params != null) {
                            final RepNodeParams rnp =
                                params.get(rn.getResourceId());
                            if (rnp != null) {
                                out.print(" haPort=" + rnp.getJENodeHostPort());
                            }
                        }
                        out.println();
                    }
                }

                if (filter.contains(Filter.AN)) {
                    final List ans =
                        new ArrayList(rg.getArbNodes());
                    Collections.sort(ans);
                    for (ArbNode an: ans) {
                        out.print(makeWhiteSpace(indent) + an);
                        if (verbose && params != null) {
                            final ArbNodeParams anp =
                                params.get(an.getResourceId());
                            if (anp != null) {
                                out.print(" haPort=" + anp.getJENodeHostPort());
                            }
                        }
                        out.println();
                    }
                }

                if (verbose) {
                    out.println(makeWhiteSpace(indent) + "partitions=" +
                                listPartitions(partIds));
                }
                if (filter.contains(Filter.RN) ||
                    filter.contains(Filter.AN)) {
                    indent -= indentAmount;
                }
            }
        }
    }

    /**
     * Print the topology information in JSON format. The example format:
     * {
     * "storeName" : "mystore",
     * "numPartitions" : 20,
     * "sequenceNumber" : 30,
     * "zns" : [ {
     *   "resourceId" : "zn1",
     *   "name" : "1",
     *   "repFactor" : 1,
     *   "type" : "PRIMARY",
     *   "allowArbiters" : false,
     *   "masterAffinity" : false
     *   }, {
     *   "resourceId" : "zn2",
     *   "name" : "2",
     *   "repFactor" : 1,
     *   "type" : "PRIMARY",
     *   "allowArbiters" : false,
     *   "masterAffinity" : false
     *   }, {
     *   "resourceId" : "zn3",
     *   "name" : "3",
     *   "repFactor" : 1,
     *   "type" : "PRIMARY",
     *   "allowArbiters" : false,
     *   "masterAffinity" : false
     * } ],
     * "sns" : [ {
     *   "resourceId" : "sn1",
     *   "hostname" : "localhost",
     *   "registryPort" : 20000,
     *   "zone" : {
     *     "resourceId" : "zn1",
     *     "name" : "1",
     *     "repFactor" : 1,
     *     "type" : "PRIMARY",
     *     "allowArbiters" : false,
     *     "masterAffinity" : false
     *   },
     *   "capacity" : "1",
     *   "rns" : [ {
     *     "resourceId" : "rg1-rn1"
     *   } ],
     *   "ans" : [ ]
     *   }, {
     *   "resourceId" : "sn2",
     *   "hostname" : "localhost",
     *   "registryPort" : 21000,
     *   "zone" : {
     *     "resourceId" : "zn2",
     *     "name" : "2",
     *     "repFactor" : 1,
     *     "type" : "PRIMARY",
     *     "allowArbiters" : false,
     *     "masterAffinity" : false
     *   },
     *   "capacity" : "1",
     *   "rns" : [ {
     *     "resourceId" : "rg1-rn2"
     *   } ],
     *   "ans" : [ ]
     *   }, {
     *   "resourceId" : "sn3",
     *   "hostname" : "localhost",
     *   "registryPort" : 22000,
     *   "zone" : {
     *     "resourceId" : "zn3",
     *     "name" : "3",
     *     "repFactor" : 1,
     *     "type" : "PRIMARY",
     *     "allowArbiters" : false,
     *     "masterAffinity" : false
     *   },
     *   "capacity" : "1",
     *   "rns" : [ {
     *     "resourceId" : "rg1-rn3"
     *   } ],
     *   "ans" : [ ]
     * } ],
     * "shards" : [ {
     *   "resourceId" : "rg1",
     *   "numPartitions" : 20,
     *   "rns" : [ {
     *     "resourceId" : "rg1-rn1",
     *     "snId" : "sn1"
     *   }, {
     *     "resourceId" : "rg1-rn2",
     *     "snId" : "sn2"
     *   }, {
     *     "resourceId" : "rg1-rn3",
     *     "snId" : "sn3"
     *   } ],
     *   "ans" : [ ]
     * } ]
     * }
     * @param t the topology instance
     * @param params the parameter value set
     * @param filter filter to control the output result set
     * @param verbose whether to show verbose output
     * @return JSON object representing the topology result
     */
    public static ObjectNode
        printTopologyJson(Topology t,
                          Parameters params,
                          EnumSet filter,
                          boolean verbose) {
        final ObjectNode jsonTop = JsonUtils.createObjectNode();

        /* Consolidate store related information */
        final String storeName = t.getKVStoreName();
        if (filter.contains(Filter.STORE)) {
            jsonTop.put("storeName", storeName);
            jsonTop.put("numPartitions", t.getPartitionMap().size());
            jsonTop.put("sequenceNumber", t.getSequenceNumber());
        }

        /* Consolidate DC related information */
        final ArrayNode dcArray =
                jsonTop.putArray(DatacenterId.DATACENTER_PREFIX + "s");
        if (filter.contains(Filter.DC)) {
            final List dcList = t.getSortedDatacenters();
            for (final Datacenter dc : dcList) {
                dcArray.add(dc.toJson());
            }
        }

        /* Create and order the SN map */
        final Map> snMap =
            new TreeMap>();
        for (StorageNodeId snid : t.getStorageNodeMap().getAllIds()) {
            snMap.put(snid, new ArrayList());
        }
        final List rnList = t.getSortedRepNodes();
        for (RepNode rn: rnList) {
            final List l = snMap.get(rn.getStorageNodeId());
            l.add(rn.getResourceId());
        }

        /* Consolidate SN information */
        final ArrayNode snArray = jsonTop.putArray("sns");
        for (Entry> entry :
             snMap.entrySet()) {

            final StorageNodeId snId = entry.getKey();
            String capacityInfo = null;
            String rootDirPath = null;
            StorageNodeParams snp = null;
            if (params != null) {
                snp = params.get(snId);
                if (snp != null) {
                    capacityInfo = snp.getCapacity() + "";
                    rootDirPath = snp.getRootDirPath() + "";
                }
            }

            ObjectNode snNode = JsonUtils.createObjectNode();
            /* Report individual SN information */
            if (filter.contains(Filter.SN)) {
                snNode = t.get(snId).toJson();
                if (capacityInfo != null) {
                    snNode.put("capacity", capacityInfo);
                }
                if (rootDirPath != null) {
                    snNode.put("rootDirPath", rootDirPath);
                }
            }

            /* Report individual RN information */
            if (filter.contains(Filter.RN)) {
                final ArrayNode rnArray = snNode.putArray("rns");
                for (RepNodeId rnId : entry.getValue()) {
                    final ObjectNode rnNode = JsonUtils.createObjectNode();
                    rnNode.put("resourceId", rnId.toString());

                    /* Report storage directory related information */
                    if (verbose) {
                        String storageDirPath = null;
                        long storageDirSize = 0L;
                        String rnlogDirPath = null;
                        if (params != null) {
                            final RepNodeParams rnp = params.get(rnId);
                            if (rnp != null) {
                                storageDirPath =
                                    rnp.getStorageDirectoryPath();
                                storageDirSize =
                                    rnp.getStorageDirectorySize();
                                rnlogDirPath =
                                    rnp.getLogDirectoryPath();
                            }
                        }

                        final String storageDirEnvPath;
                        if (storageDirPath == null) {
                            if (snp != null) {
                                /*
                                 * RN environment under kvroot
                                 * Full path will be :
                                 *     $kvroot////env
                                 */
                                storageDirEnvPath =
                                    snp.getRootDirPath() + "/" +
                                    t.getKVStoreName() + "/" +
                                    snId.getFullName() + "/" +
                                    rnId.getFullName() + "/" + "env";
                                rnNode.put("storageDirPath",
                                           snp.getRootDirPath());
                                rnNode.put("storageDirEnvPath",
                                        storageDirEnvPath);
                                rnNode.put("storageDirSize",
                                           storageDirSize);
                            }
                        } else {
                            /*
                             * RN environment under storageDir
                             * Full path will be :
                             *     $storageDir//env
                             */
                            storageDirEnvPath = storageDirPath + "/" +
                                                 rnId.getFullName() + "/" +
                                                 "env";
                            rnNode.put("storageDirPath", storageDirPath);
                            rnNode.put("storageNodeEnvPath",
                                       storageDirEnvPath);
                            rnNode.put("storageDirSize", storageDirSize);
                        }

                        if (rnlogDirPath != null) {
                            /*
                             * RNLogDir is specified, else logs will be
                             * kvroot/kvstore/log directory.
                             * 
                             * Since logs are by default generated in
                             * kvstore/log on SN start up so no need
                             * to add information for topology JSON output.
                             */
                            rnNode.put("logDirPath", rnlogDirPath);
                        }
                    }
                    rnArray.add(rnNode);
                }
            }

            /* Report arbiter related information */
            final ArrayNode anArray = snNode.putArray("ans");
            if (filter.contains(Filter.AN)) {
                for (ArbNodeId anId : t.getHostedArbNodeIds(snId)) {
                    final ObjectNode anNode = JsonUtils.createObjectNode();
                    anNode.put("resourceId", anId.toString());

                    if (verbose) {
                        if (snp != null) {
                            anNode.put("storageDirPath",
                                       snp.getRootDirPath());
                        }
                    }
                    anArray.add(anNode);
                }
            }
            snArray.add(snNode);
        }

        /* Consolidate sharding results */
        final ArrayNode shardArray = jsonTop.putArray("shards");
        if (filter.contains(Filter.SHARD)) {

            final Map> partToRG =
                TopologyPrinter.sortPartitions(t);
            for (Map.Entry> entry :
                     partToRG.entrySet()) {
                final RepGroupId rgId = entry.getKey();
                final List partIds = entry.getValue();
                final RepGroup rg = t.get(rgId);
                final ObjectNode shardNode = rg.toJson();
                shardNode.put("numPartitions", partIds.size());

                if (filter.contains(Filter.RN)) {
                    final List rns =
                        new ArrayList(rg.getRepNodes());
                    Collections.sort(rns);
                    final ArrayNode rnArray = shardNode.putArray("rns");
                    for (RepNode rn: rns) {
                        final ObjectNode rnNode = rn.toJson();
                        if (verbose && params != null) {
                            final RepNodeParams rnp =
                                params.get(rn.getResourceId());
                            if (rnp != null) {
                                rnNode.put("haPort",
                                           rnp.getJENodeHostPort());
                            }
                        }
                        rnArray.add(rnNode);
                    }
                }

                if (filter.contains(Filter.AN)) {
                    final List ans =
                        new ArrayList(rg.getArbNodes());
                    Collections.sort(ans);
                    final ArrayNode anArray = shardNode.putArray("ans");
                    for (ArbNode an: ans) {
                        final ObjectNode anNode = an.toJson();
                        if (verbose && params != null) {
                            final ArbNodeParams anp =
                                params.get(an.getResourceId());
                            if (anp != null) {
                                anNode.put("haPort",
                                           anp.getJENodeHostPort());
                            }
                        }
                        anArray.add(anNode);
                    }
                }

                if (verbose) {
                    shardNode.put("partition",
                                  TopologyPrinter.listPartitions(partIds));
                }
                shardArray.add(shardNode);
            }
        }
        return jsonTop;
    }

    private static void printStorageRNLogMountPoints(
                                          Map
                                                              storageDirMap,
                                          Map
                                                              rnLogDirMap,
                                          List rnsWithMountPoints,
                                          Parameters params, RepNodeId rnId,
                                          String oneRN,
                                          PrintStream out,
                                          int indent,
                                          int indentAmount,
                                          boolean showPerf,
                                          Map perfMap,
                                          StorageNodeParams snp) {
        String storageDirPath = null;
        long storageDirSize = 0L;
        if (storageDirMap != null) {
            final StorageDirectory sd = storageDirMap.get(rnId);
            if (sd != null) {
                storageDirPath = sd.getPath();
                storageDirSize = sd.getSize();
            }
        } else {
            if (params != null) {
                final RepNodeParams rnp = params.get(rnId);
                if (rnp != null) {
                    storageDirPath = rnp.getStorageDirectoryPath();
                    storageDirSize = rnp.getStorageDirectorySize();
                }
            }
        }

        String rnLogDirPath = null;
        if (rnLogDirMap != null) {
            final LogDirectory sd = rnLogDirMap.get(rnId);
            if (sd != null) {
                rnLogDirPath = sd.getPath();
            }
        } else {
            if (params != null) {
                final RepNodeParams rnp = params.get(rnId);
                if (rnp != null) {
                    rnLogDirPath = rnp.getLogDirectoryPath();
                }
            }
        }

        printMountPoints(storageDirPath, storageDirSize,
                         rnLogDirPath, rnsWithMountPoints,
                         rnId, oneRN, out, indent, indentAmount,
                         showPerf, perfMap, snp);
    }

    public static void printMountPoints(String dirPath, long dirSize,
                                   String logDirPath,
                                   List rnsWithMountPoints,
                                   RepNodeId rnId,
                                   String oneRN,
                                   PrintStream out,
                                   int indent,
                                   int indentAmount,
                                   boolean showPerf,
                                   Map perfMap,
                                   StorageNodeParams snp) {
        String topologyOutput = "";
        final String storagesize = getSizeInUnits(dirSize);
        if (dirPath == null) {
            topologyOutput = oneRN;
            if (snp == null) {
                out.println();
            } else {
                topologyOutput += " storagedir=" + snp.getRootDirPath() +
                                  " size=" + storagesize;
            }
        } else {
            /*
             * Make a description of the RN and its storage
             * directory and display it below
             */
            topologyOutput += oneRN + " storagedir=" + dirPath +
                              " size=" + storagesize;
        }

        if (logDirPath == null) {
            if (snp == null) {
                out.println();
            } else {
                topologyOutput += " logdir=" + snp.getRootDirPath();
            }
        } else {
            /*
             * Make a description of the RN and its rn log
             * directory and display it below
             */
            topologyOutput += " logdir=" + logDirPath;
        }

        rnsWithMountPoints.add(topologyOutput);

        if (showPerf) {
            rnsWithMountPoints.add
                (makeWhiteSpace((indent - 1) * indentAmount) +
                 getPerf(perfMap, rnId));
        }
    }

    public static String getSizeInUnits(long value) {
        if (value == 0) {
            return "NOT-SPECIFIED";
        }

        final long valueinKB = Math.abs(value/1024);
        final long valueinMB = Math.abs(value/(1024*1024));
        final long valueinGB = Math.abs(value/(1024*1024*1024));

        String prefix = value < 0 ? "-" : "";
        if (valueinGB > 0) {
            return prefix + valueinGB + " GB";
        }
        if (valueinMB > 0) {
            return prefix + valueinMB + " MB";
        }
        if (valueinKB > 0) {
            return prefix + valueinKB + " KB";
        }
        return prefix + value + " Bytes";
    }

    /**
     * Get a Json version of the topology. The format is:
     * {
     *    "name" : ,
     *    "store" : ,
     *    "numPartitions" : ,
     *    "sequence" : ,
     *    "zone" : {
     *      "id" : ,
     *      "name" : ,
     *      "repfactor" : ,
     *      "type" : {@literal }
     *    }
     *    "sns" : [
     *      {
     *        "id" : ,
     *        "zone_id" : ,
     *        "host" : ,
     *        "port" : ,
     *        "capacity" : ,
     *        "rns" : [, ,...]
     *        "ans" : [,...]
     *      },
     *      ...
     *    ],
     *    "shards" : [
     *      {
     *        "id" : ,
     *        "numPartitions" : ,
     *        "rns" : [, ,...]
     *        "ans" : [,...]
     *      },
     *    ...
     *    ]
     * }
     * @param topo to be displayed topology
     * @param params SN capacity and RN mount points are stored in the
     * Parameters class from the Admin DB, and is not available in the topology
     * itself. If params is not null, use it to display that kind of
     * information.
     * @return Json node to display the topology
     */
    public static ObjectNode getTopoJson(Topology topo, Parameters params) {
        final ObjectNode json = JsonUtils.createObjectNode();
        json.put("store", topo.getKVStoreName());
        json.put("numPartitions", topo.getPartitionMap().size());
        json.put("sequence", topo.getSequenceNumber());
        final List dcList = topo.getSortedDatacenters();
        final ArrayNode zoneNodes = json.putArray("zone");
        for (Datacenter dc : dcList) {
            final ObjectNode zoneNode = JsonUtils.createObjectNode();
            zoneNode.put("id", dc.getResourceId().toString());
            zoneNode.put("name", dc.getName());
            zoneNode.put("repfactor", dc.getRepFactor());
            zoneNode.put("type", dc.getDatacenterType().name());
            zoneNodes.add(zoneNode);
        }
        final ArrayNode snNodes = json.putArray("sns");
        List snList = topo.getSortedStorageNodes();
        for (StorageNode sn : snList) {
            final StorageNodeId snId = sn.getResourceId();
            final ObjectNode snNode = JsonUtils.createObjectNode();
            snNode.put("id", snId.toString());
            snNode.put("zone_id", sn.getDatacenterId().toString());
            snNode.put("host", sn.getHostname());
            snNode.put("port", sn.getRegistryPort());
            if (params != null) {
                final StorageNodeParams snp = params.get(snId);
                snNode.put("capacity", snp.getCapacity());
            }
            final Set rnIds = topo.getHostedRepNodeIds(snId);
            final ArrayNode rnNodes = snNode.putArray("rns");
            for (RepNodeId rnId : rnIds) {
                rnNodes.add(rnId.toString());
            }
            final Set anIds = topo.getHostedArbNodeIds(snId);
            final ArrayNode anNodes = snNode.putArray("ans");
            for (ArbNodeId anId : anIds) {
                anNodes.add(anId.toString());
            }
            snNodes.add(snNode);
        }
        final ArrayNode rgNodes = json.putArray("shards");
        final Map> partToRG =
            sortPartitions(topo);
        for (Map.Entry> entry :
            partToRG.entrySet()) {

            final ObjectNode rgNode = JsonUtils.createObjectNode();
            final RepGroupId rgId = entry.getKey();
            rgNode.put("id", rgId.toString());
            final List partIds = entry.getValue();
            rgNode.put("numPartitions", partIds.size());
            final RepGroup rg = topo.get(rgId);
            final List rns = new ArrayList<>(rg.getRepNodes());
            Collections.sort(rns);
            final ArrayNode rnNodes = rgNode.putArray("rns");
            for (RepNode rn : rns) {
                rnNodes.add(rn.getResourceId().toString());
            }
            final List ans = new ArrayList<>(rg.getArbNodes());
            Collections.sort(ans);
            final ArrayNode anNodes = rgNode.putArray("ans");
            for (ArbNode an : ans) {
                anNodes.add(an.getResourceId().toString());
            }
            rgNodes.add(rgNode);
        }
        return json;
    }

    /* Format service status information. */
    private static String getStatus(Map statusMap,
                                    ResourceId rId) {
        final ServiceChange change = statusMap.get(rId);
        if (change == null) {
            return "UNREPORTED";
        }


        return change.getStatus().toString();
    }

    private static String getStatus(Map statusMap,
                                    RepNodeId rnId,
                                    Parameters params) {
        final String status = getStatus(statusMap, rnId);

        /* RNs may be disabled by a stop-RNs plan */
        if (params != null) {
            final RepNodeParams rnp = params.get(rnId);
            if (rnp != null) {
                if (rnp.isDisabled()) {
                    return "Stopped/" + status;
                }
            }
        }

        return status;
    }


    private static String getStatus(Map statusMap,
                                    ArbNodeId anId,
                                    Parameters params) {
        final String status = getStatus(statusMap, anId);

        /* ANs may be disabled by a stop-service plan */
        if (params != null) {
            final ArbNodeParams anp = params.get(anId);
            if (anp != null) {
                if (anp.isDisabled()) {
                    return "Stopped/" + status;
                }
            }
        }

        return status;
    }

    /* Format performance information. */
    private static String getPerf(Map perfMap,
                                    ResourceId rId) {
        final PerfEvent perf = perfMap.get(rId);
        if (perf == null) {
            return "No performance info available";
        }

        final StringBuilder sb = new StringBuilder();
        final LatencyInfo singleCum = perf.getSingleCum();
        final LatencyInfo multiCum = perf.getMultiCum();
        sb.append("   single-op avg latency=").
            append(singleCum.getLatency().getAvg()).append(" ms");

        sb.append("   multi-op avg latency=").
            append(multiCum.getLatency().getAvg()).append(" ms");

        if (perf.needsAlert()) {
            sb.append("[ALERT]");
        }

        return sb.toString();
    }

    /**
     * List the partitions ordered by number, and in range form. For example,
     * gaps would be shown like this:
     * 10-40,45-95,100
     */
    public static String listPartitions(List partIds) {

        if (partIds.isEmpty()) {
            return "";
        }

        Collections.sort(partIds, new Comparator() {
                @Override
                public int compare(PartitionId o1, PartitionId o2) {
                   return o1.getPartitionId() - o2.getPartitionId();
                }});

        int first = partIds.get(0).getPartitionId();
        int last = first;
        final StringBuilder sb = new StringBuilder();
        sb.append(first);
        for (PartitionId p : partIds) {
            final int pId = p.getPartitionId();

            if (pId == last) {
                continue;
            }

            if (pId == last + 1) {
                last = pId;
                continue;
            }

            if (last > first) {
                sb.append("-").append(last);
            }

            first = pId;
            last = first;
            sb.append(",").append(first);
        }
        if (last > first) {
            sb.append("-").append(last);
        }
        return sb.toString();
    }

    /**
     * Returns the Topology as a String.
     */
    public static String printTopology(Topology t,
                                       Parameters params,
                                       boolean verbose) {
        final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        printTopology(t, new PrintStream(outStream), params, all, verbose,
                      null, null, null, null);
        return outStream.toString();
    }

    /**
     * Returns the Topology as a String, for logging messages.
     */
    public static String printTopology(Topology t) {
        return printTopology(t, null, false);
    }

    public static String printTopology(TopologyCandidate tc,
                                       Parameters params,
                                       boolean verbose) {
        final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        printTopology(tc.getTopology(), new PrintStream(outStream), params,
                      all, verbose, tc.getStorageDirAssignments(params),
                      tc.getRNLogDirAssignments(params),
                      null, null);
        return outStream.toString();
    }


    private static String makeWhiteSpace(int indent) {
        String ret = "";
        for (int i = 0; i < indent; i++) {
            ret += " ";
        }
        return ret;
    }

    /**
     * Return a map of rep groups to partitions ids, so one can tell the
     * number of partitions assigned to each rep group.
     */
    public static
        Map> sortPartitions(Topology t) {

        final Map> partToRG =
            new TreeMap>(new RGComparator());

        for (RepGroup rg: t.getRepGroupMap().getAll()) {
            partToRG.put(rg.getResourceId(), new ArrayList());
        }

        for (Partition p : t.getPartitionMap().getAll()) {
            final List pIds = partToRG.get(p.getRepGroupId());
            pIds.add(p.getResourceId());
        }
        return partToRG;
    }

    private static class RGComparator implements Comparator {

        @Override
        public int compare(RepGroupId o1, RepGroupId o2) {
           return (o1.getGroupId() - o2.getGroupId());
        }
    }

    /**
     * Displays information about one or all zones in the given
     * Topology. If the id and name
     * parameters are both null, then this method will simply list
     * the ids and names of all of the zones in the store. Otherwise, this
     * method will display information about the zone having the given
     * id or name; including all of the storage nodes
     * deployed to that zone, and whether the zone consists of secondary zones.
     * Note that if the id and name parameters
     * are both non-null, then the value of the id
     * parameter will be used.
     *
     * @param id The id of the zone whose information should be displayed.
     * @param name The name of the zone whose information should be displayed.
     * @param topo The Topology from which to retrieve the
     * information to display.
     * @param out The OutputStream to which the desired
     * information will be written for display.
     * @param params If not null, then each storage node's
     * capacity and datacenter type are retrieved from this object and
     * displayed with that storage node's information.
     */
    public static void printZoneInfo(DatacenterId id,
                                     String name,
                                     Topology topo,
                                     PrintStream out,
                                     Parameters params) {

        int indent = 0;
        final int indentAmount = 2;
        final boolean showAll =
            ((id == null) && (name == null) ? true : false);
        Datacenter showZone = null;

        /*
         * Display zones, sorted by ID
         */
        final List dcList = topo.getSortedDatacenters();
        for (final Datacenter zone : dcList) {
            if (showAll) {
                out.println(makeWhiteSpace(indent) +
                            DatacenterId.DATACENTER_PREFIX + ": " + zone);
            } else {
                if ((id != null) && id.equals(zone.getResourceId())) {
                    showZone = zone;
                    break;
                } else if ((name != null) && name.equals(zone.getName())) {
                    showZone = zone;
                    break;
                }
            }
        }
        if (showAll) {
            return;
        }

        /* If showZone is null, then the id or name input is unknown */
        if (showZone == null) {
            out.println(makeWhiteSpace(indent) +
                        DatacenterId.DATACENTER_PREFIX +
                        ": unknown id or name");
            return;
        }

        /*
         * For the given zone (id or name), display SNs, sorted by SN id.
         */
        out.println(makeWhiteSpace(indent) +
                    DatacenterId.DATACENTER_PREFIX + ": " + showZone);

        final DatacenterId showZoneId = showZone.getResourceId();
        final List snList = topo.getSortedStorageNodes();
        String capacityInfo = null;
        StorageNodeParams snp = null;
        indent += indentAmount;
        for (StorageNode sn: snList) {
            if (showZoneId.equals(sn.getDatacenterId())) {
                out.print(makeWhiteSpace(indent) + "[" + sn.getResourceId() +
                    "] " + sn.getHostname() + ":" + sn.getRegistryPort());
                if (params != null) {
                    snp = params.get(sn.getResourceId());
                    if (snp != null) {
                        capacityInfo = " capacity=" + snp.getCapacity();
                    }
                }
                if (capacityInfo != null) {
                    out.print(capacityInfo);
                }
                out.println();
            }
        }
    }

    /**
     * Print the admins information in JSON format. The example format:
     *   "admins" : [ {
     *     "resourceId" : "admin1",
     *     "snId" : "sn1",
     *     "storageDirPath" : "/xyz/admin1",
     *     "storageDirSize" : "3221225472",
     *     "storageDirEnvPath" : "/xyz/admin1/env"
     *   }, {
     *     "resourceId" : "admin2",
     *     "snId" : "sn2",
     *     "storageDirPath" : "/xyz/admin2",
     *     "storageDirSize" : "3221225472",
     *     "storageDirEnvPath" : "/xyz/admin2/env"
     *   }, {
     *     "resourceId" : "admin3",
     *     "snId" : "sn3",
     *     "storageDirPath" : "/xyz/admin3",
     *     "storageDirSize" : "3221225472",
     *     "storageDirEnvPath : "/zyz/admin3/env"
     *   } ]
     *
     * @param topology the topology instance
     * @param params the parameter value set
     * @return JSON object representing the topology result
     */
    public static ObjectNode printAdminJSON(Topology topology,
                                            Parameters params) {

        final ObjectNode jsonTop = JsonUtils.createObjectNode();

        final List snIds = topology.getSortedStorageNodeIds();

        /* Consolidate Admin information */
        final ArrayNode snArray = jsonTop.putArray("admins");
        for (StorageNodeId snId : snIds) {

            /*
             * Get the single parameter entries -- StorageNode, Admin
             */
            final StorageNodeParams snp = params.get(snId);
            final AdminParams ap =
                GenerateConfig.getAdminParams(snId, params);
            if (ap == null) {
                /*
                 * This SN does not host an admin
                 */
                continue;
            }

            final ParameterMap adminMountMap = snp.getAdminDirMap();
            final ObjectNode adminNode = JsonUtils.createObjectNode();
            adminNode.put("adminId", ap.getAdminId().getFullName());
            adminNode.put("storageNodeId", snId.getFullName());

            /*
             * adminMountMap contains single entry corresponding to
             * individual admin storage directory.
             */
            String adminDir = null;
            long adminDirSize = 0L;
            if (adminMountMap != null) {
                for (Parameter adminDirParam : adminMountMap) {
                    adminDir = adminDirParam.getName();
                    adminDirSize = SizeParameter.getSize(adminDirParam);
                }
            }

            final String adminDirEnvPath;
            if (adminDir == null) {
                /*
                 * admin environment under kvroot
                 * Full path will be :
                 *     $kvroot////env
                 */
                adminDirEnvPath = snp.getRootDirPath() + "/" +
                                   topology.getKVStoreName() + "/" +
                                   snId.getFullName() + "/" +
                                   ap.getAdminId().getFullName() + "/" +
                                   "env";
                adminNode.put("storageDirPath", snp.getRootDirPath());
                adminNode.put("storageDirEnvPath", adminDirEnvPath);
            } else {
                /*
                 * admin environment under adminDir
                 * Full path will be :
                 *     $adminDir//env
                 */
                adminDirEnvPath = adminDir + "/" +
                                   ap.getAdminId().getFullName() + "/" +
                                   "env";
                adminNode.put("storageDirPath", adminDir);
                adminNode.put("storageDirEnvPath", adminDirEnvPath);
            }
            adminNode.put("storageDirSize", adminDirSize);
            snArray.add(adminNode);
        }
        return jsonTop;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy