Package org.apache.olio.services

Source Code of org.apache.olio.services.Thin

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.olio.services;

import com.sun.faban.common.Command;
import com.sun.faban.common.CommandHandle;
import com.sun.faban.common.Utilities;
import com.sun.faban.common.NameValuePair;
import com.sun.faban.harness.*;

import com.sun.faban.harness.services.ServiceContext;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.List;

/**
* This class implements the service to start/stop Thin instances.
* It also provides functionality to transfer the portion of the thin
* error logs for a run to the run output directory.
* The user can specify the number of thins to start. It will use
* port numbers starting from the user-specified value for the instances.
* Note that the same starting port# must be specified for ALL hosts
* We just pick the first host's port (if not specified, defaults to 3000).
* It can be used by any benchmark to manage thin servers and
* perform these operations remotely using this Service.
*
* @author Shanti Subramanyam
* Based on LighttpdService provided in faban sample services.
*
*/
public class Thin {
    private ServiceContext ctx;
    private Logger logger = Logger.getLogger(Thin.class.getName());

    private static final int PORT = 3000;
    private final String logName = "thin.log";
    private final String pidName = "thin.pid";
    private String logFileNames[];
    private static String pidFileNames[];
  
    private String[] myServers;
  private List<NameValuePair<Integer>> hostPorts;
    private String thinCmd, appDir, logsDir, pidsDir;
    private static int numInstances, startPort;
    CommandHandle thinHandles[];
    private boolean skipLogs = false;

    public Thin(ServiceContext ctx) throws ConfigurationException {
    this.ctx = ctx;
    String pidFile, errlogFile;

        myServers = ctx.getUniqueHosts();
        hostPorts = ctx.getUniqueHostPorts();
    startPort = hostPorts.get(0).value;
    if (startPort == 0)
      startPort = PORT;
        thinCmd = ctx.getProperty("cmdPath");
        if (thinCmd != null && thinCmd.trim().length() > 0) {
            if (!thinCmd.endsWith(" "))
                thinCmd = thinCmd + " ";
        } else {
            throw new ConfigurationException("cmdPath not set. Cannot start/stop thin");
        }
        pidsDir = ctx.getProperty("pidsDir");
        if (pidsDir != null && pidsDir.trim().length() > 0) {
            if (!pidsDir.endsWith(File.separator))
                pidsDir = pidsDir + File.separator;
        } else {
            throw new ConfigurationException("pidsDir not set. Cannot start/stop thin");
        }

        String ni = ctx.getProperty("numInstances");
        if (ni != null)
            numInstances = Integer.parseInt(ni);
    if (numInstances == 0)
      numInstances = 1;
    appDir = ctx.getProperty("appDir");
    if (appDir == null || appDir.trim().length() <= 0) {
      logger.warning("appDir property not set. Assuming /export/home/oliorails");
      appDir = "/export/home/oliorails";
        }
        logsDir = ctx.getProperty("logsDir");
        if (logsDir != null && logsDir.trim().length() > 0) {
            if (!logsDir.endsWith(File.separator))
                logsDir = logsDir + File.separator;
        } else {
            skipLogs = true;
        }

        pidFile = pidsDir + pidName;
    errlogFile = logsDir + logName;

        //Create all the pid and log filenames
        logFileNames = new String[numInstances];
        pidFileNames = new String[numInstances];
        for (int i = 0; i < numInstances; i++) {
            logFileNames[i] = logsDir + "thin." + (startPort + i) ".log";
            pidFileNames[i] = pidsDir + "thin." + (startPort + i) + ".pid";
        }

        thinCmd = thinCmd + "-p " + startPort + " -d -e production -s " + numInstances +
                " --log " + errlogFile + " --pid " + pidFile + " start";
        thinHandles = new CommandHandle[myServers.length];
    }

    /**
     * Starts up the Thin server.
     */
    public void startup() {
        Command startCmd = new Command(thinCmd);
    startCmd.setWorkingDirectory(appDir);
        startCmd.setStreamHandling(Command.STDOUT, Command.CAPTURE);

        for (int i = 0; i < myServers.length; i++) {
            String server = myServers[i];
            try {
                // Run the command in the foreground and wait for the start
                thinHandles[i] = RunContext.exec(server, startCmd);

                if (checkServerStarted(server)) {
                    logger.fine("Completed thin startup successfully on " +
                            server);
                } else {
                    logger.severe("Failed to find " + pidName + " on " + server);
                }

            } catch (Exception e) {
                logger.log(Level.WARNING, "Failed to start thin server.", e);
            }
        }
    }

    /*
     * Check if server started by looking for pidfiles
     * @param String hostName
     * @return boolean
     */
    private static boolean checkServerStarted(String hostName) throws Exception {
        boolean val = false;
        // We will check pid files for 1st and last instances;

        // Just to make sure we don't wait for ever.
        // We try to read the msg 20 times before we give up
        // Sleep 1 sec between each try. So wait for 20 secs
        int attempts = 20;
        while (attempts > 0) {
            if (RunContext.isFile(hostName, pidFileNames[0]) &&
                    RunContext.isFile(hostName, pidFileNames[numInstances - 1])) {
                val = true;
                break;
            } else {
                // Sleep for some time
                try {
                    Thread.sleep(1000);
                    attempts--;
                } catch (Exception e) {
                    break;
                }
            }
        }
        return (val);
    }

    /*
     * Return thin pids
     * It reads the pid file from the remote server host for the
     * specified instance and returns the pid stored in it.
     * @param String hostName
   * @param int num - the instance# of the thin server
     * @return int pid if pidfile exists, otherwise -1
     * @throws Exception
     */
    private static int getPid(String hostName, int num) throws Exception {
        final String host = hostName;
        final String file = Utilities.convertPath(pidFileNames[num]);
        int pid;

        if ( !RunContext.isFile(host, file)) {
      return -1;
        }
        pid = RunContext.exec(host, new RemoteCallable<Integer>() {

            public Integer call() throws Exception {
                String pidval;

                FileInputStream is = new FileInputStream(file);
                BufferedReader bufR = new BufferedReader(new InputStreamReader(is));
                pidval = bufR.readLine();
                bufR.close();
                return (Integer.parseInt(pidval));
            }
        });
        return (pid);
    }

    /**
     * Shuts down the Thin web server.
     * @throws IOException Error executing the shutdown
     * @throws InterruptedException Interrupted waiting for the shutdown
     */
    public void shutdown() throws IOException, InterruptedException {
        for (String hostName : myServers) {
            //Retrieve the pid values
            for (int i = 0; i < numInstances; i++) {
                int pid = 0;
                try {
                    pid = getPid(hostName, i);
                } catch (Exception ee) {
                    logger.log(Level.WARNING, "Failed to read thin pidfile on " +
                            hostName + " with " + ee);
                    logger.log(Level.FINE, "Exception", ee);
                }
                // Now kill the server
                if (pid <= 0) {
                    continue;
                }
                Command cmd = new Command("kill " + pid);
        logger.fine("Now killing " + pid + " on " + hostName);
                try {
                    RunContext.exec(hostName, cmd);
                } catch (RemoteException re) {
                    logger.log(Level.WARNING, "Failed to stop Thin server(s) on " +
                            hostName);
                    logger.log(Level.FINE, "Exception: ", re);
                }
            }
        }
    }

    /**
     * Clears the Thin server logs
     */
    public void clearLogs() {
        if (skipLogs) return;
        for (String server : myServers) {
            // Clear thin logs
            for (int i = 0; i < logFileNames.length; i++) {
                if (RunContext.isFile(server, logFileNames[i])) {
                    if (!RunContext.deleteFile(server, logFileNames[i])) {
                        logger.log(Level.WARNING, "Delete of " + logFileNames[i] +
                                " failed on " + server);
                    }
                }
            }
        }
    }

    /*
     * transfer log files
     */
    public void getLogs() {
    }
}
TOP

Related Classes of org.apache.olio.services.Thin

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.