/*                          
 *      mBench: The Open Source Micro Benchmark Tool 
 *                                             
 *      Distributable under GPL license. 
 *      See terms of license at gnu.org.                 
 *
 *      Copyright (C) 2005 Sumisho Computer Systems Corp.
 */
package jp.co.scs.mbench.component.quadruplenode;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import jp.co.scs.mbench.Benchmark;
import jp.co.scs.mbench.BenchmarkTerminateException;
import jp.co.scs.mbench.jdbc.DataSourceManager;

/**     
 *      Benchmark which retrieve any row from 1 to 60000 rows
 *      on table t1 without using a primary key through single SQL nodes
 * 
 *      @author Masato Koga
 */
public class Select03T1Benchmark implements Benchmark {
    /**
     *  Count of connection
     */
    private static int conCount = 0;
    
    /**
     *  Name of the component
     */
    private String benchmarkName = null;
    
    /**
     *  Labels which benchmark component mesures
     */
    private String[] optionLabels = {"status", "cases", "retry"};
    
    /**
     *  Connection to database
     */
    private Connection con = null;
    
    /**
     *  Statement of SQL
     */
    private Statement stmt = null;
    
    /** 
     *  Get the component name.
     * 
     *  @return Name of component
     */
    public String getBenchmarkName() {
        return this.benchmarkName;
    }

    /**
     *  Set the component name.
     * 
     *  @param benchmarkName Name of component
     */
    public void setBenchmarkName(String benchmarkName) {
        this.benchmarkName = benchmarkName;
    }
    
    /**
     *  Get labels mesured by benchmark component.
     * 
     *  @return Label of items mesured by benchmark component
     */
    public String[] getOptionLabels() {
        return this.optionLabels;
    }
    
    /**
     *  Set labels mesured by benchmark component.
     * 
     *  @param optionLabels Labels which benchmark component mesures
     */
    public void setOptionLabels(String[] optionLabels){
        this.optionLabels = optionLabels;
    }
    
    /**
     *  Initialize. Get datasource and establish connection.
     *  Target SQL node is decided by round-robin algorithm.
     * 
     *  @throws BenchmarkTerminateException
     */
    public synchronized void init() throws BenchmarkTerminateException {
        try {
            DataSource dataSource = null;
            if (conCount % 4 == 0) {
                dataSource = DataSourceManager.getDataSource("mysql_con1");
            } else if (conCount % 4 == 1) {
                dataSource = DataSourceManager.getDataSource("mysql_con2");
            } else if (conCount % 4 == 2) {
                dataSource = DataSourceManager.getDataSource("mysql_con3");
            } else {
                dataSource = DataSourceManager.getDataSource("mysql_con4");
            }
            conCount++;
            
            this.con = dataSource.getConnection();
            this.stmt = con.createStatement();
        } catch (Exception ex) {
            throw new BenchmarkTerminateException(ex);
        }
    }
    
    /**
     *  Execute benchmark transaction.
     *  <br>
     *  A transaction perform;<br>
     *  <br>
     *  start transaction;<br>
     *  select * from t1 where c1 = ${key};<br>
     *  commit;<br>
     *  <br>
     *  ${key} is randomly decided from 1 to 60000.<br>
     *  Rollback and Retry in case exception occures before commit.<br>
     *  Return Primary Key and Value of second column as logging.<br>
     */
    public String[] execute() {
        return doExecute(0);
    }
    
    /**
     *  Disconnect connection.
     */
    public void clean() {
        try {
            if (this.stmt != null) {
                this.stmt.close();
            }
            if (this.con != null) {
                this.con.close();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    
    private String[] doExecute(int retry) {
        try {
            String q1 = "select * from t1 where c2 = 1";
            
            this.con.setAutoCommit(false);
            this.con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
            ResultSet rs = this.stmt.executeQuery(q1);
            int cases = 0;
            while (rs.next()) {
                cases++;
            }
            this.con.commit();
            return new String[]{"commit", String.valueOf(cases), String.valueOf(retry)};
        } catch (SQLException ex) {
            if (this.con != null) {
                try {
                    this.con.rollback();
                    return doExecute(++retry);
                    // return new String[]{"rollback", String.valueOf(key), ex.getMessage()};
                } catch (SQLException ex2) {
                    ex2.printStackTrace();
                    throw new RuntimeException("system error");
                }
            } else {
                throw new RuntimeException("connection lost");
            }
        }
    }
}
