Package edu.brown.api

Source Code of edu.brown.api.ControlPipe

package edu.brown.api;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.voltdb.VoltSystemProcedure;
import org.voltdb.client.Client;
import org.voltdb.sysprocs.Shutdown;

import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.profilers.ProfileMeasurement;
import edu.brown.profilers.ProfileMeasurementUtil;

/**
* Implements the simple state machine for the BenchmarkComponents's remote
* controller protocol. This allows the BenchmarkController to control a
* BenchmarkComponent. Hypothetically, you can extend this and override the
* answerPoll() and answerStart() methods for other clients.
*/
public class ControlPipe implements Runnable {
    private static final Logger LOG = Logger.getLogger(ControlPipe.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    static {
        LoggerUtil.setupLogging();
        LoggerUtil.attachObserver(LOG, debug);
    }
   
    private final InputStream in;
    private final BenchmarkComponent cmp;
    private boolean stop = false;
   
    /**
     * If this is set to true, then we will not wait for the START command
     * to come from the BenchmarkController. This used for testing/debugging
     */
    private boolean autoStart;
   
    public ControlPipe(BenchmarkComponent component, InputStream in, boolean autoStart) {
        this.cmp = component;
        this.in = in;
        this.autoStart = autoStart;
    }
   
    public void run() {
        final Thread self = Thread.currentThread();
        self.setName(String.format("client-%02d", cmp.getClientId()));

        boolean profile = cmp.getHStoreConf().client.profiling;
        if (profile) cmp.worker.enableProfiling(true);
       
        final Client client = cmp.getClientHandle();
        final Thread workerThread = new Thread(cmp.worker);
        workerThread.setDaemon(true);
       
        // transition to ready and send ready message
        if (cmp.m_controlState == ControlState.PREPARING) {
            cmp.printControlMessage(ControlState.READY);
            cmp.m_controlState = ControlState.READY;
        } else {
            LOG.error("Not starting prepared!");
            LOG.error(cmp.m_controlState + " " + cmp.m_reason);
        }
       
        final BufferedReader in = new BufferedReader(new InputStreamReader(this.in));
        final Pattern p = Pattern.compile(" ");
        ControlCommand command = null;
        while (this.stop == false) {
            if (this.autoStart) {
                command = ControlCommand.START;
                this.autoStart = false;
            } else {
                try {
                    command = ControlCommand.get(p.split(in.readLine())[0]);
                    if (debug.val)
                        LOG.debug(String.format("Recieved Message: '%s'", command));
                } catch (final IOException e) {
                    // Hm. quit?
                    throw new RuntimeException("Error on standard input", e);
                }
            }
            if (command == null) continue;
            if (debug.val) LOG.debug("ControlPipe Command = " + command);

            // HACK: Convert a SHUTDOWN to a STOP if we're not the first client
            if (command == ControlCommand.SHUTDOWN && cmp.getClientId() != 0) {
                command = ControlCommand.STOP;
            }
           
            switch (command) {
                case START: {
                    if (cmp.m_controlState != ControlState.READY) {
                        cmp.setState(ControlState.ERROR, command + " when not " + ControlState.READY);
                        cmp.answerWithError();
                        continue;
                    }
                    workerThread.start();
                    if (cmp.m_tickThread != null) cmp.m_tickThread.start();
                    cmp.m_controlState = ControlState.RUNNING;
                    cmp.answerOk();
                    break;
                }
                case POLL: {
                    if (cmp.m_controlState != ControlState.RUNNING) {
                        cmp.setState(ControlState.ERROR, command + " when not " + ControlState.RUNNING);
                        cmp.answerWithError();
                        continue;
                    }
                    cmp.answerPoll();
                   
                    // Dump Profiling Info
                    if (profile) System.err.println(this.getProfileInfo());
                   
                    // Call tick on the client if we're not polling ourselves
                    if (cmp.m_tickInterval < 0) {
                        if (debug.val) LOG.debug("Got poll message! Calling tick()!");
                        cmp.invokeTickCallback(cmp.m_tickCounter++);
                    }
                    if (debug.val)
                        LOG.debug(String.format("CLIENT QUEUE TIME: %.2fms / %.2fms avg",
                                                client.getQueueTime().getTotalThinkTimeMS(),
                                                client.getQueueTime().getAverageThinkTimeMS()));
                    break;
                }
                case DUMP_TXNS: {
                    if (cmp.m_controlState != ControlState.PAUSED) {
                        cmp.setState(ControlState.ERROR, command + " when not " + ControlState.PAUSED);
                        cmp.answerWithError();
                        continue;
                    }
                    if (debug.val) LOG.debug("DUMP TRANSACTIONS!");
                    cmp.answerDumpTxns();
                    break;
                }
                case CLEAR: {
                    cmp.invokeClearCallback();
                    cmp.answerOk();
                    break;
                }
                case PAUSE: {
                    assert(cmp.m_controlState == ControlState.RUNNING) : "Unexpected " + cmp.m_controlState;
                    if (debug.val) LOG.debug("Pausing client " + cmp.getClientId());
                   
                    // Enable the lock and then change our state
                    try {
                        if (debug.val) LOG.debug("Acquiring pause lock");
                        cmp.m_pauseLock.acquire();
                    } catch (InterruptedException ex) {
                        LOG.fatal("Unexpected interuption!", ex);
                        throw new RuntimeException(ex);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                   
                    // Change the current state
                    cmp.m_controlState = ControlState.PAUSED;
                   
                    // Then tell the client to drain
                    ProfileMeasurement pm = new ProfileMeasurement();
                    try {
                        if (debug.val) LOG.debug("Draining connection queue for client " + cmp.getClientId());
                        pm.start();
                        cmp.getClientHandle().drain();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    } finally {
                        pm.stop();
                        if (debug.val) LOG.debug("Drain Queue Time: " + ProfileMeasurementUtil.debug(pm));
                    }
                    break;
                }
                case SHUTDOWN: {
                    if (debug.val) LOG.debug("Shutting down client + cluster");
                    this.stop = true;
                    if (cmp.m_controlState == ControlState.RUNNING || cmp.m_controlState == ControlState.PAUSED) {
                        cmp.invokeStopCallback();
                        try {
                            client.drain();
                            client.callProcedure(VoltSystemProcedure.procCallName(Shutdown.class));
                            client.close();
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                   
                    break;
                }
                case STOP: {
                    this.stop = true;
                    if (cmp.m_controlState == ControlState.RUNNING || cmp.m_controlState == ControlState.PAUSED) {
                        if (debug.val) LOG.debug("Stopping client");
                        cmp.invokeStopCallback();
                       
                        try {
                            if (cmp.m_sampler != null) {
                                cmp.m_sampler.setShouldStop();
                                cmp.m_sampler.join();
                            }
                            client.close();
                            if (cmp.m_checkTables) {
                                cmp.checkTables();
                            }
                        } catch (InterruptedException e) {
                            // Ignore...
                        }
                    } else {
                        LOG.fatal("STOP when not RUNNING");
                    }
                    break;
                }
                default: {
                    throw new RuntimeException("Error on standard input: unknown command " + command);
                }
            } // SWITCH
        }
    }
   
    private String getProfileInfo() {
        return (String.format("Client #%02d - %s / %s",
                cmp.getClientId(), cmp.worker.getExecuteTime().debug(), cmp.worker.getBlockedTime().debug()));
    }

}
TOP

Related Classes of edu.brown.api.ControlPipe

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.