Package org.voltdb.client

Source Code of org.voltdb.client.ClientStatsFusionLoader$Loader

/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB L.L.C.
*
* VoltDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VoltDB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.voltdb.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.List;

import org.apache.log4j.Logger;
import org.voltdb.VoltTable;

import au.com.bytecode.opencsv.CSVReader;

import com.google.gdata.client.ClientLoginAccountType;
import com.google.gdata.client.GoogleService;
import com.google.gdata.client.Service.GDataRequest;
import com.google.gdata.client.Service.GDataRequest.RequestType;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ContentType;
import com.google.gdata.util.ServiceException;

import edu.brown.catalog.CatalogUtil;

/**
* Polls a Distributer instance for IO and procedure invocation information and ELTs the results
* to a database via JDBC.
*
*/
public class ClientStatsFusionLoader implements ClientStatsLoader {
    private static final Logger LOG = Logger.getLogger(ClientStatsFusionLoader.class);
   
    private final StatsUploaderSettings m_settings;
    private final String m_applicationName;
    private final String m_subApplicationName;
    private final int m_pollInterval;
    private final Distributer m_distributer;
    private int m_instanceId = -1;
    private final Thread m_loadThread = new Thread(new Loader(), "Client stats loader");

    private static final String instancesTable = "clientInstances";
    private static final String connectionStatsTable = "clientConnectionStats";
    private static final String procedureStatsTable = "clientProcedureStats";

    private static String instancesTableId;
    private static String connectionStatsTableId;
    private static String procedureStatsTableId;
   
    private static final String createInstanceStatement = "INSERT INTO %s " +
            "(instanceId, clusterStartTime, clusterLeaderAddress, applicationName, subApplicationName, " +
            "numHosts, numSites, numPartitions) VALUES " +
            "('%d', '%s', '%d', '%s', '%s', '%d', '%d', '%d');";

    private static final String createInstancesTable = "CREATE TABLE " + instancesTable +
            " (instanceId:NUMBER, clusterStartTime:DATETIME, clusterLeaderAddress:NUMBER, " +
            "applicationName:STRING, subApplicationName:STRING, numHosts:NUMBER, " +
            "numSites:NUMBER, numPartitions:NUMBER);";
   
    private static final String insertConnectionStatsStatement = "INSERT INTO %s " +
            "(instanceId, tsEvent, hostname, connectionId, serverHostId, serverHostname, " +
            "serverConnectionId, numInvocations, numAborts, numFailures, numThrottled, numBytesRead, " +
            "numMessagesRead, numBytesWritten, numMessagesWritten) VALUES" +
            "('%d', '%s', '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d');";

    private static final String createConnectionStatsTable = "CREATE TABLE " + connectionStatsTable +
            " (instanceId:NUMBER, tsEvent:DATETIME, hostname:STRING, connectionId:NUMBER, " +
            "serverHostId:NUMBER, serverHostname:STRING, serverConnectionId:NUMBER, " +
            "numInvocations:NUMBER, numAborts:NUMBER, numFailures:NUMBER, numThrottled:NUMBER, " +
            "numBytesRead:NUMBER, numMessagesRead:NUMBER, numBytesWritten:NUMBER, " +
            "numMessagesWritten:NUMBER);";
   
    private static final String insertProcedureStatsStatement = "INSERT INTO %s" +
            "(instanceId, tsEvent, hostname, connectionId, serverHostId, serverHostname, " +
            "serverConnectionId, procedureName, roundtripAvg, roundtripMin, roundtripMax, " +
            "clusterRoundtripAvg, clusterRoundtripMin, clusterRoundtripMax, " +
            "numInvocations, numAborts, numFailures, numRestarts) VALUES " +
            "('%d', '%s', '%s', '%d', '%d', '%s', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d');";

    private static final String createProcedureStatsTable = "CREATE TABLE " + procedureStatsTable +
            " (instanceId:NUMBER, tsEvent:DATETIME, hostname:STRING, connectionId:NUMBER, " +
            "serverHostId:NUMBER, serverHostname:STRING, serverConnectionId:NUMBER, " +
            "procedureName:STRING, roundtripAvg:NUMBER, roundtripMin:NUMBER, " +
            "roundtripMax:NUMBER, clusterRoundtripAvg:NUMBER, clusterRoundtripMin:NUMBER, " +
            "clusterRoundtripMax:NUMBER, numInvocations:NUMBER, numAborts:NUMBER, " +
            "numFailures:NUMBER, numRestarts:NUMBER);";
   
    /**
     * Google Fusion Tables API URL.
     * All requests to the Google Fusion Tables service begin with this URL.
     */
    private static final String SERVICE_URL = "https://www.google.com/fusiontables/api/query";
   
    /**
     * Service to handle requests to Google Fusion Tables.
     */
    private GoogleService service;
   
    /**
     * Returns the results of running a Fusion Tables SQL query.
     *
     * @param  query the SQL query to send to Fusion Tables
     * @param  isUsingEncId includes the encrypted table ID in the result if {@code true}, otherwise
     *         includes the numeric table ID
     * @return the results from the Fusion Tables SQL query
     * @throws IOException when there is an error writing to or reading from GData service
     * @throws ServiceException when the request to the Fusion Tables service fails
     * @see    com.google.gdata.util.ServiceException
     */
    public QueryResults runQuery(String query) throws IOException, ServiceException {

      String lowercaseQuery = query.toLowerCase();
      String encodedQuery = URLEncoder.encode(query, "UTF-8");

      GDataRequest request;
      // If the query is a select, describe, or show query, run a GET request.
      if (lowercaseQuery.startsWith("select") ||
          lowercaseQuery.startsWith("describe") ||
          lowercaseQuery.startsWith("show")) {
        URL url = new URL(SERVICE_URL + "?sql=" + encodedQuery + "&encid=true");
        request = service.getRequestFactory().getRequest(RequestType.QUERY, url,
            ContentType.TEXT_PLAIN);
      } else {
        // Otherwise, run a POST request.
        URL url = new URL(SERVICE_URL + "?encid=true");
        request = service.getRequestFactory().getRequest(RequestType.INSERT, url,
            new ContentType("application/x-www-form-urlencoded"));
        OutputStreamWriter writer = new OutputStreamWriter(request.getRequestStream());
        writer.append("sql=" + encodedQuery);
        writer.flush();
      }

      request.execute();

      return getResults(request);
    }
   
    /**
     * Returns the Fusion Tables CSV response as a {@code QueryResults} object.
     *
     * @return an object containing a list of column names and a list of row values from the
     *         Fusion Tables response
     */
    private QueryResults getResults(GDataRequest request)
        throws IOException {
      InputStreamReader inputStreamReader = new InputStreamReader(request.getResponseStream());
      BufferedReader bufferedStreamReader = new BufferedReader(inputStreamReader);
      CSVReader reader = new CSVReader(bufferedStreamReader);
      // The first line is the column names, and the remaining lines are the rows.
      List<String[]> csvLines = reader.readAll();
      List<String> columns = Arrays.asList(csvLines.get(0));
      List<String[]> rows = csvLines.subList(1, csvLines.size());
      QueryResults results = new QueryResults(columns, rows);
      return results;
    }
   
    /**
     * Result of a Fusion Table query.
     */
    private static class QueryResults {
      final List<String> columnNames;
      final List<String[]> rows;

      public QueryResults(List<String> columnNames, List<String[]> rows) {
        this.columnNames = columnNames;
        this.rows = rows;
      }

     /**
      * Prints the query results.
      *
      * @param the results from the query
      */
     public void print() {
       String sep = "";
       for (int i = 0; i < columnNames.size(); i++) {
         System.out.print(sep + columnNames.get(i));
         sep = ", ";
       }
       System.out.println();

       for (int i = 0; i < rows.size(); i++) {
         String[] rowValues = rows.get(i);
         sep = "";
         for (int j = 0; j < rowValues.length; j++) {
           System.out.print(sep + rowValues[j]);
           sep = ", ";
         }
         System.out.println();
       }
     }
    }
   
    public static void main(String[] args) throws Exception {
        /*GoogleService service = new GoogleService("fusiontables", "h-store.ClientStatsFusionLoader");
        service.setUserCredentials("hstore.dev@gmail.com", "hstore!321", ClientLoginAccountType.GOOGLE);
       
        boolean useEncId = true;

        System.out.println("--- Create a table ---");
        QueryResults results = ClientStatsFusionLoader.run("CREATE TABLE demo (name:STRING, date:DATETIME)", useEncId, service);
        results.print();
        String tableId = (results.rows.get(0))[0];

        System.out.println("--- Insert data into the table ---");
        results = ClientStatsFusionLoader.run("INSERT INTO " + tableId + " (name, date) VALUES ('bob', '1/1/2012')",
            useEncId, service);
        results.print();

        System.out.println("--- Insert more data into the table ---");
        results = ClientStatsFusionLoader.run("INSERT INTO " + tableId + " (name, date) VALUES ('george', '1/4/2012')",
            useEncId, service);
        results.print();

        System.out.println("--- Select data from the table ---");
        results = ClientStatsFusionLoader.run("SELECT * FROM " + tableId + " WHERE date > '1/3/2012'", useEncId, service);
        results.print();

        System.out.println("--- Drop the table ---");
        results = ClientStatsFusionLoader.run("DROP TABLE " + tableId, useEncId, service);
        results.print();*/
       
        /*// start the connection with Fusion Tables
        GoogleService service = new GoogleService("fusiontables", "h-store.ClientStatsFusionLoader");
        service.setUserCredentials("hstore.dev@gmail.com", "hstore!321", ClientLoginAccountType.GOOGLE);
       
        // create the test table if it does not already exist
        // find info on tables so we know which one is the test table
        QueryResults results = ClientStatsFusionLoader.run("SHOW TABLES", true, service);
        results.print();
       
        // find the table ID of the test table
        String tableId = null;
        for (String[] row : results.rows) {
            if (row[1].equals("TestTable")) {
                tableId = row[0];
            }
        }
        if (tableId == null) {
            System.out.println("Could not find the test table so creating it");
            results = ClientStatsFusionLoader.run("CREATE TABLE TestTable (int:NUMBER, time:DATETIME)", true, service);
            results.print();
        }
       
        // find info on tables so we know which one is the test table
        results = ClientStatsFusionLoader.run("SHOW TABLES", true, service);
        results.print();
       
        // find the table ID of the test table
        tableId = null;
        for (String[] row : results.rows) {
            if (row[1].equals("TestTable")) {
                tableId = row[0];
            }
        }
        if (tableId == null) {
            throw new RuntimeException("Could not find the test table!");
        }
       
        // find the next instance id (auto increment DNE)
        int instanceId = -1;
        results = ClientStatsFusionLoader.run(String.format("SELECT * FROM %s", tableId), true, service);
        results.print();
        for (String[] row : results.rows) {
            int currentId = Integer.parseInt(row[0]);
            if (currentId > instanceId) {
                instanceId = currentId;
            }
        }
        ++instanceId;
        System.out.println(instanceId);
       
        // insert a time stamp into the test table
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        System.out.println(timestamp);
        String stmt = String.format("insert into %s (int, time) values ('%d', '%s');", tableId, instanceId, timestamp);
        results = ClientStatsFusionLoader.run(stmt, true, service);
        results.print();*/
    }
   
    public ClientStatsFusionLoader(
            StatsUploaderSettings settings,
            Distributer distributer) {
        LOG.debug("database user: " + settings.databaseUser);
        LOG.debug("database pass: " + settings.databasePass);
       
        m_settings = settings;
        m_applicationName = settings.applicationName;
        m_subApplicationName = settings.subApplicationName;
        m_pollInterval = settings.pollInterval;
        m_distributer = distributer;
       
        service = new GoogleService("fusiontables", "h-store.ClientStatsFusionLoader");
        try {
            service.setUserCredentials(settings.databaseUser, settings.databasePass, ClientLoginAccountType.GOOGLE);
        } catch (Exception e) {
            LOG.debug("Could not connect to Fusion Tables site");
            String msg = "Failed to connect to Google FusionTables reporting server with message:\n";
            msg += e.getMessage();
            throw new RuntimeException(msg);
        }
       
        QueryResults results = null;
        try {
            results = runQuery("SHOW TABLES;");
        } catch (Exception e) {
            String msg = "Failed to query Google FusionTables server for tables with message:\n";
            msg += e.getMessage();
            throw new RuntimeException(msg);
        }
        LOG.debug("Queried for tables");
       
        for (String[] row : results.rows) {
            if (row[1].equals(instancesTable)) {
                instancesTableId = row[0];
            }
            else if (row[1].equals(connectionStatsTable)) {
                connectionStatsTableId = row[0];
            }
            else if (row[1].equals(procedureStatsTable)) {
                procedureStatsTableId = row[0];
            }
        }
        LOG.debug("Found H-Store tables");
       
        try {
            if (instancesTableId == null) {
                LOG.debug("Could not find the instances table so creating it as " + instancesTable);
                results = runQuery(createInstancesTable);
                results.print();
            }
            if (connectionStatsTableId == null) {
                LOG.debug("Could not find the connection stats table so creating it as " + connectionStatsTable);
                results = runQuery(createConnectionStatsTable);
                results.print();
            }
            if (procedureStatsTableId == null) {
                LOG.debug("Could not find the procedure stats table so creating it as " + procedureStatsTable);
                results = runQuery(createProcedureStatsTable);
                results.print();
            }
        } catch (Exception e) {
            String msg = "Failed to create new Google FusionTable with message:\n";
            msg += e.getMessage();
            throw new RuntimeException(msg);
        }
        LOG.debug("Connection established to Fusion Tables site!");
    }
   
    public void start(long startTime, int leaderAddress) throws IOException, ServiceException {
        Timestamp timestamp = new Timestamp(startTime);
        if (LOG.isDebugEnabled())
            LOG.debug(String.format("Cluster Start Time: %s [%d]", timestamp, startTime));
       
        QueryResults results = runQuery(String.format("SELECT instanceId FROM %s;", instancesTableId));
        for (String[] row : results.rows) {
            int currentId = Integer.parseInt(row[0]);
            if (currentId > m_instanceId) {
                m_instanceId = currentId;
            }
        }
        ++m_instanceId;
       
        runQuery(String.format(createInstanceStatement,
                instancesTableId,
                m_instanceId,
                timestamp,
                leaderAddress,
                m_applicationName,
                m_subApplicationName == null ? "null" : m_subApplicationName,
                CatalogUtil.getNumberOfHosts(m_settings.getCatalog()),
                CatalogUtil.getNumberOfSites(m_settings.getCatalog()),
                CatalogUtil.getNumberOfPartitions(m_settings.getCatalog())));
        m_loadThread.setDaemon(true);
        m_loadThread.start();
        if (LOG.isDebugEnabled())
            LOG.debug("ClientStatsLoader has been started");
    }

    public synchronized void stop() throws InterruptedException {
        m_shouldStop = true;
        notifyAll();
        while (!m_stopped) {
            wait();
        }
    }

    private boolean m_shouldStop = false;
    private boolean m_stopped = false;

    private class Loader implements Runnable {
        @Override
        public void run() {
            long sleepLess = 0;
            synchronized (ClientStatsFusionLoader.this) {
                try {
                    while (true) {
                        if (m_shouldStop) {
                            break;
                        }
                        try {
                            if (m_pollInterval - sleepLess > 0) {
                                ClientStatsFusionLoader.this.wait(m_pollInterval
                                        - sleepLess);
                            }
                        } catch (InterruptedException e) {
                            return;
                        }

                        final long startTime = System.currentTimeMillis();
                        final VoltTable ioStats = m_distributer
                                .getConnectionStats(true);
                        final VoltTable procedureStats = m_distributer
                                .getProcedureStats(true);

                        /**
                         * NOTE FROM FUSION TABLES SITE: You can list up to 500 INSERTs, separated by semicolons, as long as the total size of the
                         * data does not exceed 1 MB and the total number of table cells being added does not exceed 10,000 cells. The calculation may
                         * not be obvious. For example, if you have 100 columns in your table and your INSERT statement includes only 10 columns, the
                         * number of cells being added is still 100.
                         */
                        try {
                            int count = 0;
                            StringBuilder query = new StringBuilder();
                            while (ioStats.advanceRow()) {
                                query.append(String.format(insertConnectionStatsStatement,
                                        connectionStatsTableId,
                                        m_instanceId,
                                        new Timestamp(ioStats.getLong("TIMESTAMP")),
                                        ioStats.getString("HOSTNAME"),
                                        ioStats.getLong("CONNECTION_ID"),
                                        ioStats.getLong("SERVER_HOST_ID"),
                                        ioStats.getString("SERVER_HOSTNAME"),
                                        ioStats.getLong("SERVER_CONNECTION_ID"),
                                        ioStats.getLong("INVOCATIONS_COMPLETED"),
                                        ioStats.getLong("INVOCATIONS_ABORTED"),
                                        ioStats.getLong("INVOCATIONS_FAILED"),
                                        ioStats.getLong("INVOCATIONS_THROTTLED"),
                                        ioStats.getLong("BYTES_READ"),
                                        ioStats.getLong("MESSAGES_READ"),
                                        ioStats.getLong("BYTES_WRITTEN"),
                                        ioStats.getLong("MESSAGES_WRITTEN")));
                                ++count;
                                if (count % 500 == 0) {
                                    runQuery(query.toString());
                                    query = new StringBuilder(query.capacity());
                                }
                            }
                            if (count % 500 > 0) {
                                runQuery(query.toString());
                            }
                        } catch (Exception e) {
                            if (e.getCause() instanceof InterruptedException) {
                                return;
                            }
                            e.printStackTrace();
                        }

                        try {
                            int count = 0;
                            StringBuilder query = new StringBuilder();
                            while (procedureStats.advanceRow()) {
                                query.append(String.format(insertProcedureStatsStatement,
                                        procedureStatsTableId,
                                        m_instanceId,
                                        new Timestamp(procedureStats.getLong("TIMESTAMP")),
                                        procedureStats.getString("HOSTNAME"),
                                        procedureStats.getLong("CONNECTION_ID"),
                                        procedureStats.getLong("SERVER_HOST_ID"),
                                        procedureStats.getString("SERVER_HOSTNAME"),
                                        procedureStats.getLong("SERVER_CONNECTION_ID"),
                                        procedureStats.getString("PROCEDURE_NAME"),
                                        (int) procedureStats.getLong("ROUNDTRIPTIME_AVG"),
                                        (int) procedureStats.getLong("ROUNDTRIPTIME_MIN"),
                                        (int) procedureStats.getLong("ROUNDTRIPTIME_MAX"),
                                        (int) procedureStats.getLong("CLUSTER_ROUNDTRIPTIME_AVG"),
                                        (int) procedureStats.getLong("CLUSTER_ROUNDTRIPTIME_MIN"),
                                        (int) procedureStats.getLong("CLUSTER_ROUNDTRIPTIME_MAX"),
                                        procedureStats.getLong("INVOCATIONS_COMPLETED"),
                                        procedureStats.getLong("INVOCATIONS_ABORTED"),
                                        procedureStats.getLong("INVOCATIONS_FAILED"),
                                        procedureStats.getLong("TIMES_RESTARTED")));
                                ++count;
                                if (count % 500 == 0) {
                                    runQuery(query.toString());
                                    query = new StringBuilder(query.capacity());
                                }
                            }
                            if (count % 500 > 0) {
                                runQuery(query.toString());
                            }
                        } catch (Exception e) {
                            if (e.getCause() instanceof InterruptedException) {
                                return;
                            }
                            e.printStackTrace();
                        }
                        final long endTime = System.currentTimeMillis();
                        sleepLess = endTime - startTime;
                    }
                } finally {
                    m_stopped = true;
                    ClientStatsFusionLoader.this.notifyAll();
                }
            }
        }
    }
}
TOP

Related Classes of org.voltdb.client.ClientStatsFusionLoader$Loader

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.