/*                          
 *      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.singlenode;

import java.sql.Connection;
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 delete one row sequentially from 1 to 5000 rows
 *      on table t1 through single SQL nodes
 * 
 *      @author hirohama
 */
public class Delete02T1Benchmark implements Benchmark {
    /**
     *  Count of connection
     */
    private static int conCount = 0;
    
    /**
     *  The number of delete data
     */
    private static final int deleteNumber = 5000;
    
    /**
     *  Value of primary key
     */
    private int key = 0;

    /**
     *  ID of Connection
     */
    private int conId = 0;
    
    /**
     *  Name of the component
     */
    private String benchmarkName = null;
    
    /**
     *  Labels which benchmark component mesures
     */
    private String[] optionLabels = {"status", "primary-key", "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;
            dataSource = DataSourceManager.getDataSource("mysql_con1");
            conCount++;
            this.conId = 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>
     *  delete from t2 where c1 = ${key};<br>
     *  commit;<br>
     *  <br>
     *  ${key} is randomly decided from 1 to 100.<br>
     *  Rollback and Retry in case exception occures before commit.<br>
     *  Return Primary Key and Value of retry number as logging.<br>
     */
    public String[] execute() {
        if (this.key == 0) {
            this.key = deleteNumber / conCount * (this.conId - 1) + 1;
        } else {
            key++;
        }
        return doExecute(key, 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 key, int retry) {
        try {
            this.con.setAutoCommit(false);
            this.con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
            String q2 = "delete from t1 where c1 = " + key;
            this.stmt.executeUpdate(q2);
            this.con.commit();
            return new String[]{"commit", String.valueOf(key),
                    String.valueOf(retry)};
        } catch (SQLException ex) {
            if (this.con != null) {
                try {
                    this.con.rollback();
                    return doExecute(++key, ++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");
            }
        }
    }
}
