Package edu.brown.hstore

Source Code of edu.brown.hstore.HStoreSiteStatus

package edu.brown.hstore;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.Procedure;

import edu.brown.hstore.callbacks.PartitionCountingCallback;
import edu.brown.hstore.cmdlog.CommandLogWriter;
import edu.brown.hstore.conf.HStoreConf;
import edu.brown.hstore.txns.AbstractTransaction;
import edu.brown.hstore.txns.DependencyTracker;
import edu.brown.hstore.txns.LocalTransaction;
import edu.brown.hstore.util.TransactionCounter;
import edu.brown.interfaces.Shutdownable;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.logging.RingBufferAppender;
import edu.brown.profilers.AbstractProfiler;
import edu.brown.profilers.HStoreSiteProfiler;
import edu.brown.profilers.PartitionExecutorProfiler;
import edu.brown.profilers.ProfileMeasurement;
import edu.brown.profilers.ProfileMeasurementUtil;
import edu.brown.profilers.TransactionProfiler;
import edu.brown.statistics.Histogram;
import edu.brown.statistics.ObjectHistogram;
import edu.brown.utils.CollectionUtil;
import edu.brown.utils.EventObservable;
import edu.brown.utils.EventObserver;
import edu.brown.utils.ExceptionHandlingRunnable;
import edu.brown.utils.StringBoxUtil;
import edu.brown.utils.StringUtil;
import edu.brown.utils.TableUtil;

/**
*
* @author pavlo
*/
public class HStoreSiteStatus extends ExceptionHandlingRunnable implements Shutdownable {
    private static final Logger LOG = Logger.getLogger(HStoreSiteStatus.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    private static final LoggerBoolean trace = new LoggerBoolean();
    static {
        LoggerUtil.attachObserver(LOG, debug, trace);
    }
   
    // ----------------------------------------------------------------------------
    // STATIC CONFIGURATION
    // ----------------------------------------------------------------------------
   
//    private static final String POOL_FORMAT = "Active:%-5d / Idle:%-5d / Created:%-5d / Destroyed:%-5d / Passivated:%-7d";

    private static final Set<TransactionCounter> TXNINFO_COL_DELIMITERS = new HashSet<TransactionCounter>();
    private static final Set<TransactionCounter> TXNINFO_ALWAYS_SHOW = new HashSet<TransactionCounter>();
    private static final Set<TransactionCounter> TXNINFO_EXCLUDES = new HashSet<TransactionCounter>();
    static {
        CollectionUtil.addAll(TXNINFO_COL_DELIMITERS, TransactionCounter.EXECUTED,
                                                      TransactionCounter.MULTI_PARTITION,
                                                      TransactionCounter.MISPREDICTED);
        CollectionUtil.addAll(TXNINFO_ALWAYS_SHOW,    TransactionCounter.MULTI_PARTITION,
                                                      TransactionCounter.SINGLE_PARTITION,
                                                      TransactionCounter.MISPREDICTED);
        CollectionUtil.addAll(TXNINFO_EXCLUDES,       TransactionCounter.SYSPROCS);
    }
   
    // ----------------------------------------------------------------------------
    // RUNTIME VARIABLES
    // ----------------------------------------------------------------------------
   
    private final HStoreSite hstore_site;
    private final HStoreSite.Debug siteDebug;
    private final HStoreConf hstore_conf;
    private final int interval; // milliseconds
   
    /**
     * The list of transactions that were sitting in the queue as finished
     * the last time that we checked.
     */
    private final Set<AbstractTransaction> last_finishedTxns = new HashSet<AbstractTransaction>();
    private final Set<AbstractTransaction> cur_finishedTxns = new HashSet<AbstractTransaction>();
   
    private Integer last_completed = null;
    private AtomicInteger snapshot_ctr = new AtomicInteger(0);
   
    private int inflight_min = Integer.MAX_VALUE;
    private int inflight_max = Integer.MIN_VALUE;
   
    private Integer processing_min = null;
    private Integer processing_max = null;
   
    private Thread self;
    private long startTime;
   
    private ProfileMeasurement lastNetworkIdle = null;
    private ProfileMeasurement lastNetworkProcessing = null;
   
    /**
     * The profiling information for each PartitionExecutor since
     * the last status snapshot
     */
    private final Map<PartitionExecutor, PartitionExecutorProfiler> lastExecMeasurements = new IdentityHashMap<PartitionExecutor, PartitionExecutorProfiler>();

    /**
     * Maintain a set of tuples for the transaction profile times
     */
    private final Map<Procedure, LinkedBlockingDeque<long[]>> txn_profile_queues = new TreeMap<Procedure, LinkedBlockingDeque<long[]>>();
    private final Map<Procedure, long[]> txn_profile_totals = Collections.synchronizedSortedMap(new TreeMap<Procedure, long[]>());
    private TableUtil.Format txn_profile_format;
    private String txn_profiler_header[];
   
    private final Map<String, Object> header = new LinkedHashMap<String, Object>();
   
    private final TreeSet<Thread> sortedThreads = new TreeSet<Thread>(new Comparator<Thread>() {
        @Override
        public int compare(Thread o1, Thread o2) {
            return o1.getName().compareToIgnoreCase(o2.getName());
        }
    });
   
    // ----------------------------------------------------------------------------
    // CONSTRUCTOR
    // ----------------------------------------------------------------------------
   
    /**
     * Constructor
     * @param hstore_site
     * @param hstore_conf
     */
    public HStoreSiteStatus(HStoreSite hstore_site, HStoreConf hstore_conf) {
        this.hstore_site = hstore_site;
        this.siteDebug = hstore_site.getDebugContext();
        this.hstore_conf = hstore_conf;
        this.interval = hstore_conf.site.status_interval;

        // Print a debug message when the first non-sysproc shows up
        this.hstore_site.getStartWorkloadObservable().addObserver(new EventObserver<HStoreSite>() {
            @Override
            public void update(EventObservable<HStoreSite> arg0, HStoreSite arg1) {
//                if (debug.val)
                LOG.info(arg1.getSiteName() + " - " +HStoreConstants.SITE_FIRST_TXN);
                startTime = System.currentTimeMillis();
                HStoreSiteStatus.this.reset();
            }
        });
       
        // Pre-Compute Header
        this.header.put(String.format("%s Status", HStoreSite.class.getSimpleName()), hstore_site.getSiteName());
        this.header.put("Number of Partitions", hstore_site.getLocalPartitionIds().size());
       
        // Pre-Compute TransactionProfile Information
        this.initTxnProfileInfo(hstore_site.getCatalogContext().database);
    }
   
    private void reset() {
        this.lastExecMeasurements.clear();
    }
   
    @Override
    public void runImpl() {
        this.self = Thread.currentThread();
        // self.setName(HStoreThreadManager.getThreadName(hstore_site, HStoreConstants.THREAD_NAME_DEBUGSTATUS));
        // this.hstore_site.getThreadManager().registerProcessingThread();

        if (debug.val)
            LOG.debug(String.format("Invoking HStoreSite status monitor thread [interval=%d, kill=%s]",
                      this.interval, hstore_conf.site.status_kill_if_hung));
        try {
            // Out we go!
            this.printStatus();
           
            // If we're not making progress, bring the whole thing down!
            int completed = TransactionCounter.COMPLETED.get();
            if (hstore_conf.site.status_kill_if_hung && this.last_completed != null &&
                this.last_completed == completed && siteDebug.getInflightTxnCount() > 0) {
                String msg = String.format("HStoreSite #%d is hung! Killing the cluster!", hstore_site.getSiteId());
                LOG.fatal(msg);
                this.hstore_site.getCoordinator().shutdownCluster(new RuntimeException(msg));
            }
            this.last_completed = completed;
        } catch (Throwable ex) {
            ex.printStackTrace();
        }
    }
   
    public void printStatus() {
        LOG.info("STATUS #" + this.snapshot_ctr.incrementAndGet() + "\n" +
                 StringBoxUtil.box(this.snapshot(hstore_conf.site.txn_counters,
                                                 hstore_conf.site.status_exec_info,
                                                 hstore_conf.site.status_thread_info)));
    }
   
    // ----------------------------------------------------------------------------
    // SNAPSHOT PRETTY PRINTER
    // ----------------------------------------------------------------------------
   
    /**
     *
     * @param show_txns
     * @param show_exec
     * @param show_threads
     * @param show_poolinfo
     * @return
     */
    public synchronized String snapshot(boolean show_txns,
                                        boolean show_exec,
                                        boolean show_threads) {
        // ----------------------------------------------------------------------------
        // Site Information
        // ----------------------------------------------------------------------------
        Map<String, Object> siteInfo = this.siteInfo();

        // ----------------------------------------------------------------------------
        // Executor Information
        // ----------------------------------------------------------------------------
        Map<String, Object> execInfo = (show_exec ? this.executorInfo() : null);
       
        // ----------------------------------------------------------------------------
        // Transaction Information
        // ----------------------------------------------------------------------------
        Map<String, String> txnInfo = (show_txns ? this.txnExecInfo() : null);

        // ----------------------------------------------------------------------------
        // Batch Planner Information
        // ----------------------------------------------------------------------------
        Map<String, String> plannerInfo = (hstore_conf.site.planner_profiling ? this.batchPlannerInfo() : null);
       
        // ----------------------------------------------------------------------------
        // Thread Information
        // ----------------------------------------------------------------------------
        Map<String, Object> threadInfo = null;
        Map<String, Object> cpuThreads = null;
        if (show_threads) {
            threadInfo = this.threadInfo();
            HStoreThreadManager threadManager = hstore_site.getThreadManager();
            HStoreThreadManager.Debug threadManagerDebug = threadManager.getDebugContext();
           
            cpuThreads = new LinkedHashMap<String, Object>();
            for (Entry<Integer, Set<Thread>> e : threadManagerDebug.getCPUThreads().entrySet()) {
                TreeSet<String> names = new TreeSet<String>();
                for (Thread t : e.getValue())
                    names.add(t.getName());
                cpuThreads.put("CPU #" + e.getKey(), StringUtil.columns(names.toArray(new String[0])));
            } // FOR
        }

        // ----------------------------------------------------------------------------
        // Transaction Profiling
        // ----------------------------------------------------------------------------
        Map<String, String> txnProfiles = null;
        if (hstore_conf.site.txn_profiling && debug.val) {
            txnProfiles = this.txnProfileInfo();
        }
       
        // ----------------------------------------------------------------------------
        // Object Pool Information
        // ----------------------------------------------------------------------------
//        Map<String, Object> poolInfo = (show_poolinfo ? this.poolInfo() : null);
       
        // ----------------------------------------------------------------------------
        // Dependency Tracker
        // ----------------------------------------------------------------------------
        Map<String, Object> depInfo = this.depTrackerInfo();
       
        return StringUtil.formatMaps(this.header,
                                     siteInfo,
                                     execInfo,
                                     txnInfo,
                                     threadInfo,
                                     cpuThreads,
                                     txnProfiles,
                                     plannerInfo,
//                                     poolInfo,
                                     depInfo);
    }
   
    // ----------------------------------------------------------------------------
    // SITE INFO
    // ----------------------------------------------------------------------------
   
    /**
     *
     * @return
     */
    private Map<String, Object> siteInfo() {
        ProfileMeasurement pm = null;
        String value = null;
       
        Map<String, Object> siteInfo = new LinkedHashMap<String, Object>();
        if (TransactionCounter.COMPLETED.get() > 0) {
            siteInfo.put("Completed Txns", TransactionCounter.COMPLETED.get());
        }
       
        // ClientInterface
        ClientInterface ci = hstore_site.getClientInterface();
        if (ci != null) {
            siteInfo.put("# of Connections", ci.getConnectionCount());
           
            value = String.format("%d txns [limit=%d, release=%d] / " +
                              "%d bytes [limit=%d, release=%d]%s",
                                  ci.getPendingTxnCount(),
                                  ci.getMaxPendingTxnCount(),
                                  ci.getReleasePendingTxnCount(),
                                  ci.getPendingTxnBytes(),
                                  ci.getMaxPendingTxnBytes(),
                                  ci.getReleasePendingTxnBytes(),
                                  (ci.hasBackPressure() ? " / *THROTTLED*" : ""));
            siteInfo.put("Client Interface Queue", value);
            siteInfo.put("BackPressure Counter", ci.getBackPressureCount());
        }
       
        if (hstore_conf.site.profiling && hstore_site.getProfiler() != null) {
            // Compute the approximate arrival rate of transaction
            // requests per second from clients
            HStoreSiteProfiler profiler = hstore_site.getProfiler();
           
            pm = profiler.network_processing;
            double totalTime = System.currentTimeMillis() - startTime;
            double arrivalRate = (totalTime > 0 ? (pm.getInvocations() / totalTime) : 0d);
           
            value = String.format("%.02f txn/sec [total=%d]", arrivalRate, pm.getInvocations());
            siteInfo.put("Arrival Rate", value);
           
            pm = profiler.network_backup_off;
            siteInfo.put("Back Pressure Off", ProfileMeasurementUtil.formatComparison(pm, null, true));
           
            pm = profiler.network_backup_on;
            siteInfo.put("Back Pressure On", ProfileMeasurementUtil.formatComparison(pm, null, true));
        }

       
        // TransactionQueueManager
        TransactionQueueManager queueManager = hstore_site.getTransactionQueueManager();
        TransactionQueueManager.Debug queueManagerDebug = queueManager.getDebugContext();
       
        int inflight_cur = siteDebug.getInflightTxnCount();
        if (inflight_cur < this.inflight_min && inflight_cur > 0) this.inflight_min = inflight_cur;
        if (inflight_cur > this.inflight_max) this.inflight_max = inflight_cur;
       
        // CommandLogWriter
        int inflight_cmdlog = 0;
        CommandLogWriter cmdLogger = hstore_site.getCommandLogWriter();
        if (cmdLogger != null) {
            inflight_cmdlog = cmdLogger.getTotalTxnCount();
        }
       
        siteInfo.put("InFlight Txns",
                      String.format("%d total / %d init / %d queued / %d restart / %d cmdlog / %d deletable " +
                                "[totalMin=%d, totalMax=%d]",
                                    inflight_cur,       // total
                                    queueManagerDebug.getInitQueueSize(), // init
                                    queueManagerDebug.getLockQueueSize(), // queued
                                    queueManagerDebug.getRestartQueueSize(), // restart
                                    inflight_cmdlog,    // cmdlog
                                    this.siteDebug.getDeletableTxnCount(), // deletable
                                    this.inflight_min,  // totalMin
                                    this.inflight_max   // totalMax
        ));
       
       
        if (hstore_conf.site.status_check_for_zombies) {
            this.zombieInfo(siteInfo);
        }
       
        if (hstore_conf.site.profiling) {
            HStoreSiteProfiler profiler = this.hstore_site.getProfiler();
            pm = profiler.network_idle;
            value = ProfileMeasurementUtil.formatComparison(pm, this.lastNetworkIdle, true);
            siteInfo.put("Network Idle", value);
            this.lastNetworkIdle = new ProfileMeasurement(pm);
           
            pm = profiler.network_processing;
            value = ProfileMeasurementUtil.formatComparison(pm, this.lastNetworkProcessing, true);
            siteInfo.put("Network Processing", value);
            this.lastNetworkProcessing = new ProfileMeasurement(pm);
        }
       
        if (hstore_conf.site.exec_postprocessing_threads) {
            int processing_cur = siteDebug.getQueuedResponseCount();
            if (processing_min == null || processing_cur < processing_min) processing_min = processing_cur;
            if (processing_max == null || processing_cur > processing_max) processing_max = processing_cur;
           
            String val = String.format("%-5d [min=%d, max=%d]", processing_cur, processing_min, processing_max);
            int i = 0;
            for (TransactionPostProcessor tpp : hstore_site.getTransactionPostProcessors()) {
                pm = tpp.getExecTime();
                if (pm != null) {
                    val += String.format("\n[%02d] %d total / %.2fms total / %.2fms avg",
                                         i++,
                                         pm.getInvocations(),
                                         pm.getTotalThinkTimeMS(),
                                         pm.getAverageThinkTimeMS());
                }
            } // FOR
           
            siteInfo.put("Post-Processing Txns", val);
        }
       
        // Last Deleted Txns
        Collection<String> lastDeleted = siteDebug.getLastDeletedTxns();
        if (lastDeleted.isEmpty() == false) {
            siteInfo.put("Last Deleted", StringUtil.join("\n", lastDeleted));
        }

        return (siteInfo);
    }
   
    private void zombieInfo(Map<String, Object> siteInfo) {
        // Check to see how many of them are marked as finished but then
        // stick around in the queue longer than they should.
        // There is no guarantee that this will be accurate because txns could be swapped out
        // by the time we get through it all
       
        int inflight_zombies = 0;
        int inflight_local = 0;
        int inflight_remote = 0;
        int inflight_singlep = 0;
       
        this.cur_finishedTxns.clear();
        for (AbstractTransaction ts : this.siteDebug.getInflightTransactions()) {
            if (ts instanceof LocalTransaction) {
                inflight_local++;
                if (ts.isPredictSinglePartition()) inflight_singlep++;
            }
            else {
                inflight_remote++;
            }

            // Check for zombies!
            if (ts.getStatus() != null) {
                if (this.last_finishedTxns.contains(ts)) {
                    inflight_zombies++;
                }
                this.cur_finishedTxns.add(ts);
            }
        } // FOR
       
        // TXN TYPES
        Map<String, Object> m = new LinkedHashMap<String, Object>();
        m.put("Local", String.format("%d total / %.1f%% single-partition",
                                     inflight_local, (inflight_singlep / (double)inflight_local) * 100d));
        m.put("Remote", String.format("%d total", inflight_remote));
        siteInfo.put("InFlight Txn Types", m);

        // ZOMBIE INFO
        String zombieStatus = Integer.toString(inflight_zombies);
        if (inflight_zombies > 0) {
            zombieStatus += "\n";
           
            AbstractTransaction zombie = null;
            Long txnId = null;
            for (AbstractTransaction ts : this.last_finishedTxns) {
                txnId = ts.getTransactionId();
                if (txnId != null) {
                    zombie = ts;
                    break;
                }
            }
            if (zombie != null) {
                if (zombie.isPredictSinglePartition()) {
                    zombieStatus += zombie.debug();
                } else {
                    Map<Integer, String> zombieDebug = hstore_site.getCoordinator().transactionDebug(txnId);
                    List<String> cols = new ArrayList<String>();
                    for (Integer siteId : zombieDebug.keySet()) {
                        cols.add(String.format("SITE %02d\n%s", siteId, zombieDebug.get(siteId)));
                    } // FOR
                    zombieStatus += StringUtil.columns(cols);
                }
            }
        }
        siteInfo.put("Zombie Txns", zombieStatus);

        this.last_finishedTxns.clear();
        this.last_finishedTxns.addAll(this.cur_finishedTxns);
    }

    // ----------------------------------------------------------------------------
    // EXECUTION INFO
    // ----------------------------------------------------------------------------
       
    private Map<String, Object> executorInfo() {
        LinkedHashMap<String, Object> execInfoMaps = new LinkedHashMap<String, Object>();
       
        TransactionQueueManager queueManager = hstore_site.getTransactionQueueManager();
        TransactionQueueManager.Debug queueManagerDebug = queueManager.getDebugContext();
        HStoreThreadManager threadManager = hstore_site.getThreadManager();
        HStoreThreadManager.Debug threadManagerDebug = threadManager.getDebugContext();
       
        PartitionExecutorProfiler total = new PartitionExecutorProfiler();
       
        // EXECUTION ENGINES
        Map<Integer, String> partitionLabels = new HashMap<Integer, String>();
        ObjectHistogram<Integer> invokedTxns = new ObjectHistogram<Integer>();
        Long txn_id = null;
       
        for (int partition : hstore_site.getLocalPartitionIds().values()) {
            String partitionLabel = String.format("%02d", partition);
            partitionLabels.put(partition, partitionLabel);
           
            PartitionExecutor executor = hstore_site.getPartitionExecutor(partition);
            if (executor == null) continue;
            PartitionExecutor.Debug executorDebug = executor.getDebugContext();
            PartitionExecutorProfiler profiler = executorDebug.getProfiler();
            PartitionLockQueue lockQueue = queueManager.getLockQueue(partition);
           
            // Queue Information
            Map<String, Object> m = new LinkedHashMap<String, Object>();
           
            // PartitionLockQueue
            String queueStatus = String.format("%d queued / %3d blocked / %3d spec-exec / %3d restart\n",
                                               lockQueue.size(),
                                               executorDebug.getBlockedWorkCount(),
                                               executorDebug.getBlockedSpecExecCount(),
                                               queueManagerDebug.getRestartQueueSize()
            );
           
            queueStatus += String.format("%s [limit=%d, release=%d] %s",
                                               lockQueue.getQueueState(),
                                               lockQueue.getThrottleThreshold(),
                                               lockQueue.getThrottleRelease(),
                                               (lockQueue.isThrottled() ? "*THROTTLED* " : ""));
            txn_id = queueManagerDebug.getCurrentTransaction(partition);
            if (txn_id != null) {
                AbstractTransaction ts = hstore_site.getTransaction(txn_id);
                if (ts != null) {
                    PartitionCountingCallback<AbstractTransaction> callback = ts.getInitCallback();
                    if (callback != null) {
                        queueStatus += String.format("\nReceivedPartitions=%s / AllPartitions=%s",
                                                      callback.getReceivedPartitions(), callback.getPartitions());
                    }
                }
            }
            m.put("Lock Queue", queueStatus);
           
            if (profiler != null) {
                String inner = String.format("%d current / %d processed\n%s",
                                             executorDebug.getWorkQueueSize(),
                                             profiler.numMessages.getSampleCount(),
                                             profiler.numMessages.toString(30, 20));
                m.put("Work Queue", inner);
            } else {
                m.put("Work Queue", String.format("%d current", executorDebug.getWorkQueueSize()));
            }
           
            txn_id = executorDebug.getCurrentTxnId();
            m.put("Current Txn", String.format("%s / %s", (txn_id != null ? "#"+txn_id : "-"), executorDebug.getExecutionMode()));
            AbstractTransaction current_dtxn = executorDebug.getCurrentDtxn();
            m.put("Current DTXN", (current_dtxn == null ? "-" : current_dtxn));
           
            txn_id = executorDebug.getLastExecutedTxnId();
            m.put("Last Executed Txn", (txn_id != null ? "#"+txn_id : "-"));
           
            txn_id = executorDebug.getLastCommittedTxnId();
            m.put("Last Committed Txn", (txn_id != null ? "#"+txn_id : "-"));
           
            // Partition Executor Profiler Info
            if (hstore_conf.site.exec_profiling) {
                PartitionExecutorProfiler lastProfiler = this.lastExecMeasurements.get(executor);
                PartitionExecutorProfiler nextProfiler = new PartitionExecutorProfiler();
                invokedTxns.put(partition, (int)profiler.txn_time.getInvocations());
               
                AbstractProfiler profilers[] = { profiler, lastProfiler, nextProfiler, total };
                for (ProfileMeasurement pm : profilers[0].getProfileMeasurements()) {
                    String name = pm.getName();
                    ProfileMeasurement inner[] = new ProfileMeasurement[profilers.length];
                    for (int i = 0; i < profilers.length; i++) {
                        if (profilers[i] != null) {
                            inner[i] = (i == 0 ? pm : profilers[i].getProfileMeasurement(name));
                        }
                    } // FOR
                   
                    if (name.startsWith("SP")) {
                        name = StringUtil.title(name.replace("_", " ")).replace("Sp", "SP");
                    } else {
                        name = StringUtil.title(name);
                    }
                    m.put(name + " Time",
                          ProfileMeasurementUtil.formatComparison(inner[0], inner[1], true));
                    inner[2].appendTime(inner[0]);
                    inner[3].appendTime(inner[0]);
                } // FOR
                this.lastExecMeasurements.put(executor, nextProfiler);
            }
           
            String label = "    Partition[" + partitionLabel + "]";
           
            // Get additional partition info
            Thread t = executorDebug.getExecutionThread();
            if (t != null && threadManagerDebug.isRegistered(t)) {
                for (Integer cpu : threadManagerDebug.getCPUIds(t)) {
                    label += "\n       \u2192 CPU *" + cpu + "*";
                } // FOR
            }
           
            execInfoMaps.put(label, StringUtil.formatMaps(m) + "\n");
        } // FOR
       
        if (hstore_conf.site.exec_profiling) {
            for (ProfileMeasurement pm : total.getProfileMeasurements()) {
                String name = pm.getName();
                if (name.startsWith("SP")) {
                    name = StringUtil.title(name.replace("_", " ")).replace("Sp", "SP");
                } else {
                    name = StringUtil.title(name);
                }
               
                execInfoMaps.put(String.format("Total %s Time", name),
                           ProfileMeasurementUtil.formatComparison(pm, null, true));   
            } // FOR
            execInfoMaps.put(" ", null);
        }
       
        // Incoming Partition Distribution
        if (siteDebug.getProfiler() != null) {
            Histogram<Integer> incoming = siteDebug.getProfiler().network_incoming_partitions;
            if (incoming.isEmpty() == false) {
                incoming.setDebugLabels(partitionLabels);
                incoming.enablePercentages();
                execInfoMaps.put("Incoming Txns\nBase Partitions", incoming.toString(50, 10) + "\n");
            }
        }
        if (invokedTxns.isEmpty() == false) {
            invokedTxns.setDebugLabels(partitionLabels);
            invokedTxns.enablePercentages();
            execInfoMaps.put("Invoked Txns", invokedTxns.toString(50, 10) + "\n");
        }
       
        return (execInfoMaps);
    }
   
    private Map<String, Object> depTrackerInfo() {
        Map<String, Object> m = new LinkedHashMap<String, Object>();
        m.put("Dependency Trackers", null);
       
        for (int partition : hstore_site.getLocalPartitionIds()) {
            DependencyTracker depTracker = hstore_site.getDependencyTracker(partition);
            DependencyTracker.Debug depTrackerDbg = depTracker.getDebugContext();
           
            Map<String, Object> inner = new LinkedHashMap<String, Object>();
            boolean found = false;
            for (AbstractTransaction ts : siteDebug.getInflightTransactions()) {
                if ((ts instanceof LocalTransaction) == false ||
                    ts.getBasePartition() != partition ||
                    ts.isPredictSinglePartition()) continue;
                LocalTransaction localTxn = (LocalTransaction)ts;
                if (depTrackerDbg.hasTransactionState(localTxn)) {
                    inner.put(localTxn.toString(), depTrackerDbg.debugMap(localTxn));
                } else {
                    inner.put(localTxn.toString(), "<MISSING>");
                }
                found = true;
            }
            if (found == false) inner.put("<NONE>", null);
            m.put(String.format("Partition %02d", partition), inner);
        } // FOR
       
        return (m);
    }
   
    // ----------------------------------------------------------------------------
    // TRANSACTION EXECUTION INFO
    // ----------------------------------------------------------------------------
   
    /**
     *
     * @return
     */
    private Map<String, String> txnExecInfo() {
        Set<TransactionCounter> cnts_to_include = new TreeSet<TransactionCounter>();
        Collection<Procedure> procs = TransactionCounter.getAllProcedures(hstore_site.getCatalogContext());
        if (procs.isEmpty()) return (null);
        for (TransactionCounter tc : TransactionCounter.values()) {
            if (TXNINFO_ALWAYS_SHOW.contains(tc) || (tc.get() > 0 && TXNINFO_EXCLUDES.contains(tc) == false)) {
                cnts_to_include.add(tc);
            }
        } // FOR
       
        boolean first = true;
        int num_cols = cnts_to_include.size() + 1;
        String header[] = new String[num_cols];
        Object rows[][] = new String[procs.size()+2][];
        String col_delimiters[] = new String[num_cols];
        String row_delimiters[] = new String[rows.length];
        int i = -1;
        int j = 0;
        for (Procedure proc : procs) {
            j = 0;
            rows[++i] = new String[num_cols];
            rows[i][j++] = proc.getName();
            if (first) header[0] = "";
            for (TransactionCounter tc : cnts_to_include) {
                if (first) header[j] = tc.toString().replace("partition", "P");
                Long cnt = tc.get(proc);
                rows[i][j++] = (cnt != null ? cnt.toString() : "-");
            } // FOR
            first = false;
        } // FOR
       
        j = 0;
        rows[++i] = new String[num_cols];
        rows[i+1] = new String[num_cols];
        rows[i][j++] = "TOTAL";
        row_delimiters[i] = "-"; // "\u2015";
       
        for (TransactionCounter tc : cnts_to_include) {
            if (TXNINFO_COL_DELIMITERS.contains(tc)) col_delimiters[j] = " | ";
           
            if (tc == TransactionCounter.COMPLETED || tc == TransactionCounter.RECEIVED) {
                rows[i][j] = Integer.toString(tc.get());
                rows[i+1][j] = "";
            } else {
                Double ratio = tc.ratio();
                rows[i][j] = (ratio == null ? "-" : Integer.toString(tc.get()));
                rows[i+1][j] = (ratio == null ? "-": String.format("%.3f", ratio));
            }
            j++;
        } // FOR
       
        if (debug.val) {
            for (i = 0; i < rows.length; i++) {
                LOG.debug("ROW[" + i + "]: " + Arrays.toString(rows[i]));
            }
        }
        TableUtil.Format f = new TableUtil.Format("  ", col_delimiters, row_delimiters, true, false, true, false, false, false, true, true, null);
        return (TableUtil.tableMap(f, header, rows));
    }
   
    // ----------------------------------------------------------------------------
    // BATCH PLANNER INFO
    // ----------------------------------------------------------------------------
   
    /**
     *
     * @return
     */
    private Map<String, String> batchPlannerInfo() {
        // First get all the BatchPlanners that we have
        Collection<BatchPlanner> bps = new HashSet<BatchPlanner>();
        for (int partition : hstore_site.getLocalPartitionIds().values()) {
            PartitionExecutor executor = hstore_site.getPartitionExecutor(partition);
            if (executor == null) continue;
            PartitionExecutor.Debug dbg = executor.getDebugContext();
            bps.addAll(dbg.getBatchPlanners());
        } // FOR
        Map<Procedure, ProfileMeasurement[]> proc_totals = new HashMap<Procedure, ProfileMeasurement[]>();
        ProfileMeasurement final_totals[] = null;
        int num_cols = 0;
        for (BatchPlanner bp : bps) {
            ProfileMeasurement times[] = bp.getDebugContext().getProfiler().getProfileMeasurements();
           
            Procedure catalog_proc = bp.getProcedure();
            ProfileMeasurement totals[] = proc_totals.get(catalog_proc);
            if (totals == null) {
                num_cols = times.length+2;
                totals = new ProfileMeasurement[num_cols-1];
                final_totals = new ProfileMeasurement[num_cols-1];
                proc_totals.put(catalog_proc, totals);
            }
            for (int i = 0; i < totals.length; i++) {
                if (i == 0) {
                    if (totals[i] == null) totals[i] = new ProfileMeasurement("total");
                } else {
                    if (totals[i] == null)
                        totals[i] = new ProfileMeasurement(times[i-1]);
                    else
                        totals[i].appendTime(times[i-1]);
                    totals[0].appendTime(times[i-1]);
                }
                if (final_totals[i] == null) final_totals[i] = new ProfileMeasurement(totals[i].getName());
            } // FOR
        } // FOR
        if (proc_totals.isEmpty()) return (null);
       
        boolean first = true;
        String header[] = new String[num_cols];
        Object rows[][] = new String[proc_totals.size()+2][];
        String col_delimiters[] = new String[num_cols];
        String row_delimiters[] = new String[rows.length];
        int i = -1;
        int j = 0;
        for (Procedure proc : proc_totals.keySet()) {
            j = 0;
            rows[++i] = new String[num_cols];
            rows[i][j++] = proc.getName();
            if (first) header[0] = "";
            for (ProfileMeasurement pm : proc_totals.get(proc)) {
                if (first) header[j] = pm.getName();
                final_totals[j-1].appendTime(pm);
                rows[i][j] = Long.toString(Math.round(pm.getTotalThinkTimeMS()));
                j++;
            } // FOR
            first = false;
        } // FOR
       
        j = 0;
        rows[++i] = new String[num_cols];
        rows[i+1] = new String[num_cols];
        rows[i][j++] = "TOTAL";
        row_delimiters[i] = "-"; // "\u2015";

        for (int final_idx = 0; final_idx < final_totals.length; final_idx++) {
            if (final_idx == 0) col_delimiters[j] = " | ";
           
            ProfileMeasurement pm = final_totals[final_idx];
            rows[i][j] = Long.toString(Math.round(pm.getTotalThinkTimeMS()));
            rows[i+1][j] = (final_idx > 0 ? String.format("%.3f", pm.getTotalThinkTimeMS() / final_totals[0].getTotalThinkTimeMS()) : "");
            j++;
        } // FOR
       
//        if (debug.val) {
//            for (i = 0; i < rows.length; i++) {
//                LOG.debug("ROW[" + i + "]: " + Arrays.toString(rows[i]));
//            }
//        }
        TableUtil.Format f = new TableUtil.Format("   ", col_delimiters, row_delimiters, true, false, true, false, false, false, true, true, null);
        return (TableUtil.tableMap(f, header, rows));
    }
   
    // ----------------------------------------------------------------------------
    // THREAD INFO
    // ----------------------------------------------------------------------------
   
    /**
     *
     * @return
     */
    private Map<String, Object> threadInfo() {
        HStoreThreadManager threadManager = hstore_site.getThreadManager();
        HStoreThreadManager.Debug threadManagerDebug = threadManager.getDebugContext();
       
        final Map<String, Object> m_thread = new LinkedHashMap<String, Object>();
        final Map<Thread, StackTraceElement[]> threads = Thread.getAllStackTraces();
        sortedThreads.clear();
        sortedThreads.addAll(threads.keySet());
       
        m_thread.put("Number of Threads", threads.size());
        for (Thread t : sortedThreads) {
            StackTraceElement stack[] = threads.get(t);
           
            String name = StringUtil.abbrv(t.getName(), 24, true);
            if (threadManagerDebug.isRegistered(t) == false) {
                name += " *UNREGISTERED*";
            }
           
            String trace = null;
            if (stack.length == 0) {
                trace = "<NO STACK TRACE>";
//            } else if (t.getName().startsWith("Thread-")) {
//                trace = Arrays.toString(stack);
            } else {
                // Find the first line that is interesting to us
                trace = StringUtil.join("\n", stack);
//                for (int i = 0; i < stack.length; i++) {
//                    // if (THREAD_REGEX.matcher(stack[i].getClassName()).matches()) {
//                        trace += stack[i].toString();
////                        break;
////                    }
//                } // FOR
//                if (trace == null) stack[0].toString();
            }
            m_thread.put(name, trace);
        } // FOR
        return (m_thread);
    }
   
    // ----------------------------------------------------------------------------
    // TRANSACTION PROFILING
    // ----------------------------------------------------------------------------
   
    /**
     *
     * @param catalog_db
     */
    private void initTxnProfileInfo(Database catalog_db) {
        TransactionProfiler profiler = new TransactionProfiler();
        ProfileMeasurement fields[] = profiler.getProfileMeasurements();
       
        // COLUMN DELIMITERS
        String last_prefix = null;
        String col_delimiters[] = new String[fields.length*2 + 2];
        int col_idx = 0;
        for (ProfileMeasurement pm : fields) {
            String prefix = pm.getName().split("_")[0];
            assert(prefix.isEmpty() == false);
            if (last_prefix != null && col_idx > 0 && prefix.equals(last_prefix) == false) {
                col_delimiters[col_idx+1] = " | ";       
            }
            col_idx += 2;
            last_prefix = prefix;
        } // FOR
        this.txn_profile_format = new TableUtil.Format("   ", col_delimiters, null,
                                                       true, false, true,
                                                       false, false, false,
                                                       true, true, "-");
       
        // TABLE HEADER
        int idx = 0;
        this.txn_profiler_header = new String[fields.length*2 + 2];
        this.txn_profiler_header[idx++] = "";
        this.txn_profiler_header[idx++] = "txns";
        for (ProfileMeasurement pm : fields) {
            String name = pm.getName();
            this.txn_profiler_header[idx++] = name;
            this.txn_profiler_header[idx++] = name+"_cnt"; // The # of invocations
        } // FOR
       
        // PROCEDURE TOTALS
        for (Procedure catalog_proc : catalog_db.getProcedures()) {
            if (catalog_proc.getSystemproc()) continue;
            this.txn_profile_queues.put(catalog_proc, new LinkedBlockingDeque<long[]>());
           
            long totals[] = new long[fields.length*2 + 1];
            Arrays.fill(totals, 0);
            this.txn_profile_totals.put(catalog_proc, totals);
        } // FOR
    }
   
    /**
     *
     * @param tp
     */
    public void addTxnProfile(Procedure catalog_proc, TransactionProfiler tp) {
        assert(catalog_proc != null);
        assert(tp.isStopped());
        if (trace.val) LOG.info("Calculating TransactionProfile information");

        long tuple[] = tp.getTuple();
        assert(tuple != null);
        if (trace.val) LOG.trace(String.format("Appending TransactionProfile: %s", tp, Arrays.toString(tuple)));
        this.txn_profile_queues.get(catalog_proc).offer(tuple);
    }
   
    private void calculateTxnProfileTotals(Procedure catalog_proc, long totals[]) {
        long tuple[] = null;
        LinkedBlockingDeque<long[]> queue = this.txn_profile_queues.get(catalog_proc);
        while ((tuple = queue.poll()) != null) {
            totals[0]++;
            for (int i = 0, cnt = tuple.length; i < cnt; i++) {
                totals[i+1] += tuple[i];
            } // FOR
        } // FOR
    }
   
    /**
     *
     * TODO: This should be broken out in a separate component that stores the data
     *       down in the EE. That way we can extract it in a variety of ways
     *
     * @return
     */
    private Object[][] generateTxnProfileSnapshot() {
        // TABLE ROWS
        List<Object[]> rows = new ArrayList<Object[]>();
        for (Entry<Procedure, long[]> e : this.txn_profile_totals.entrySet()) {
            long totals[] = e.getValue();
            this.calculateTxnProfileTotals(e.getKey(), totals);
            if (totals[0] == 0) continue;

            int col_idx = 0;
            String row[] = new String[this.txn_profiler_header.length];
            row[col_idx++] = e.getKey().getName();
           
            for (int i = 0; i < totals.length; i++) {
                // # of Txns
                if (i == 0) {
                    row[col_idx++] = Long.toString(totals[i]);
                // Everything Else
                } else {
                    if (totals[i] == 0) {
                        row[col_idx] = null;
                    }
                    // # of Invocations
                    else if (col_idx % 2 != 0) {
                        row[col_idx] = Long.toString(totals[i]);
                    }
                    // Amount of time (convert to ms)
                    else {
                        row[col_idx] = StringUtil.formatTime("%.02f", totals[i], TimeUnit.NANOSECONDS);   
                    }
                    col_idx++;
                }
            } // FOR
            if (debug.val) LOG.debug("ROW[" + rows.size() + "] " + Arrays.toString(row));
            rows.add(row);
        } // FOR
        if (rows.isEmpty()) return (null);
        Object rows_arr[][] = rows.toArray(new String[rows.size()][this.txn_profiler_header.length]);
        assert(rows_arr.length == rows.size());
        return (rows_arr);
    }
   
    private Map<String, String> txnProfileInfo() {
        Object rows[][] = this.generateTxnProfileSnapshot();
        if (rows == null) return (null);
        return (TableUtil.tableMap(this.txn_profile_format, this.txn_profiler_header, rows));
    }
   
//    // ----------------------------------------------------------------------------
//    // OBJECT POOL PROFILING
//    // ----------------------------------------------------------------------------
//    private Map<String, Object> poolInfo() {
//        TypedObjectPool<?> pool = null;
//        TypedPoolableObjectFactory<?> factory = null;
//       
//        // HStoreObjectPools
//        Map<String, TypedObjectPool<?>> pools = hstore_site.getObjectPools().getGlobalPools();
//       
//        // MarkovPathEstimators
//        // pools.put("Estimators", (TypedObjectPool<?>)MarkovEstimator.POOL_ESTIMATORS);
//
//        // TransactionEstimator.States
//        // pools.put("EstimationStates", (TypedObjectPool<?>)MarkovEstimator.POOL_STATES);
//       
//        final Map<String, Object> m_pool = new LinkedHashMap<String, Object>();
//        for (String key : pools.keySet()) {
//            pool = pools.get(key);
//            if (pool == null) continue;
//            factory = (TypedPoolableObjectFactory<?>)pool.getFactory();
//            if (factory.getCreatedCount() > 0) m_pool.put(key, this.formatPoolCounts(pool, factory));
//        } // FOR
//
//        // Partition Specific
//        String labels[] = new String[] {
//            "STATES_TXN_LOCAL",
//            "STATES_TXN_REMOTE",
//            "STATES_TXN_MAPREDUCE",
////            "STATES_DISTRIBUTED",
//        };
//        HStoreObjectPools objPool = hstore_site.getObjectPools();
//        for (int i = 0, cnt = labels.length; i < cnt; i++) {
//            int total_active = 0;
//            int total_idle = 0;
//            int total_created = 0;
//            int total_passivated = 0;
//            int total_destroyed = 0;
//           
//            boolean found = false;
//            for (int p : hstore_site.getLocalPartitionIds()) {
//                pool = null;
//                switch (i) {
//                    case 0:
//                        pool = objPool.getLocalTransactionPool(p);
//                        break;
//                    case 1:
//                        pool = objPool.getRemoteTransactionPool(p);
//                        break;
//                    case 2:
//                        pool = objPool.getMapReduceTransactionPool(p);
//                        break;
////                    case 3:
////                        pool = objPool.getDistributedStatePool(p);
////                        break;
//                } // SWITCH
//                if (pool == null) continue;
//                found = true;
//                factory = (TypedPoolableObjectFactory<?>)pool.getFactory();
//           
//                total_active += pool.getNumActive();
//                total_idle += pool.getNumIdle();
//                total_created += factory.getCreatedCount();
//                total_passivated += factory.getPassivatedCount();
//                total_destroyed += factory.getDestroyedCount();
//            } // FOR (partitions)
//            if (found == false) continue;
//            m_pool.put(labels[i], String.format(POOL_FORMAT, total_active,
//                                                             total_idle,
//                                                             total_created,
//                                                             total_destroyed,
//                                                             total_passivated));
//        } // FOR
//       
//        return (m_pool);
//    }
//   
//   
//    private String formatPoolCounts(TypedObjectPool<?> pool, TypedPoolableObjectFactory<?> factory) {
//        return (String.format(POOL_FORMAT, pool.getNumActive(),
//                                           pool.getNumIdle(),
//                                           factory.getCreatedCount(),
//                                           factory.getDestroyedCount(),
//                                           factory.getPassivatedCount()));
//    }
   
    // ----------------------------------------------------------------------------
    // SHUTDOWN METHODS
    // ----------------------------------------------------------------------------
   
    @Override
    public void prepareShutdown(boolean error) {
        // TODO Auto-generated method stub
       
    }
   
    @Override
    public void shutdown() {
        // Dump LOG buffers...
        LOG.debug("Looking for RingBufferAppender messages...");
        for (String msg : RingBufferAppender.getLoggingMessages(Logger.getRootLogger().getLoggerRepository())) {
            System.out.print(msg);
        } // FOR
       
//        hstore_conf.site.status_show_thread_info = true;
        //this.printStatus();
       
        // Quick Sanity Check!
//        for (int i = 0; i < 2; i++) {
//            Histogram<Long> histogram = new Histogram<Long>();
//            Collection<Integer> localPartitions = hstore_site.getLocalPartitionIds();
//            TransactionQueueManager manager = hstore_site.getTransactionQueueManager();
//            for (Integer p : localPartitions) {
//                Long txn_id = manager.getCurrentTransaction(p);
//                if (txn_id != null) histogram.put(txn_id);
//            } // FOR
//            if (histogram.isEmpty()) break;
//            for (Long txn_id : histogram.values()) {
//                if (histogram.get(txn_id) == localPartitions.size()) continue;
//               
//                Map<String, String> m = new LinkedHashMap<String, String>();
//                m.put("TxnId", "#" + txn_id);
//                for (Integer p : hstore_site.getLocalPartitionIds()) {
//                    Long cur_id = manager.getCurrentTransaction(p);
//                    String status = "MISSING";
//                    if (txn_id == cur_id) {
//                        status = "READY";
//                    } else if (manager.getQueue(p).contains(txn_id)) {
//                        status = "QUEUED";
//                        // status += " / " + manager.getQueue(p);
//                    }
//                    status += " / " + cur_id;
//                    m.put(String.format("  [%02d]", p), status);
//                } // FOR
//                LOG.info(manager.getClass().getSimpleName() + " Status:\n" + StringUtil.formatMaps(m));
//            } // FOR
//            LOG.info("Checking queue again...");
//            manager.checkQueues();
//            break;
//        } // FOR
       
//        if (hstore_conf.site.txn_profiling) {
//            String csv = this.txnProfileCSV();
//            if (csv != null) System.out.println(csv);
//        }
       
//        for (ExecutionSite es : this.executors.values()) {
//            TransactionEstimator te = es.getTransactionEstimator();
//            ProfileMeasurement pm = te.CONSUME;
//            System.out.println(String.format("[%02d] CONSUME %.2fms total / %.2fms avg / %d calls",
//                                              es.getPartitionId(), pm.getTotalThinkTimeMS(), pm.getAverageThinkTimeMS(), pm.getInvocations()));
//            pm = te.CACHE;
//            System.out.println(String.format("     CACHE %.2fms total / %.2fms avg / %d calls",
//                                             pm.getTotalThinkTimeMS(), pm.getAverageThinkTimeMS(), pm.getInvocations()));
//            System.out.println(String.format("     ATTEMPTS %d / SUCCESS %d", te.batch_cache_attempts.get(), te.batch_cache_success.get()));
//        }
        if (this.self != null) this.self.interrupt();
    }
   
    @Override
    public boolean isShuttingDown() {
        return this.hstore_site.isShuttingDown();
    }
} // END CLASS
TOP

Related Classes of edu.brown.hstore.HStoreSiteStatus

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.