#!/user/bin/perl -w
#/* Copyright (C) 2000-2005 MySQL AB
#  This program 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 2 of the License, or
#  (at your option) any later version.

#  This program 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 this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# Version 1.1


####################### Includes ############################
use DBI;
use Getopt::Long;
####################### Globals ############################
our $my_host='localhost'; 
our $my_port=3306;
our $my_user='root';
our $my_pass='';
our $dbhM='';
our $transCounter=0;
our $my_database='TESTER';
our $createLFGAlways=0;
our $createLFGInitial=0;
our $useDiskData=0;
our $numberOfUndo=1;
our $sizeOfUndo=300;
our $nameOfLFG="lg1";
our $createTableSpaceAlways=0;
our $createTableSpaceInitial=0;
our $numberOfData=1;
our $sizeOfData=500;
our $nameOfTS="ts1";
our $my_table=$my_database.t1;
our $our_sockPath='/tmp/mysql.sock';
our $our_useSock=0;


####################### Sub Pototypes ############################

sub CollectCommandPromptInfo(); # Collect and process command-line
sub Connect();                  # Make connection to MySQLD
sub Disconnect();               # Disconnect from MySQLD
sub CreateDB();                 # Create the database
sub CreateLFG();                # Create the Log File Group
sub AddUndo();                  # Add Undo files to the LFG
sub CreateTS();                 # Create the Table Space
sub AddData();                  # Add Data files to the TS
sub CreateTable();              # Create the table;
sub InsertData();               # Insert data into the table
sub DropDB();            # Delete from the table and drop database
sub DropTS();                   # Drop TS and data files
sub DropLFG();                  # Drop Log File Group
sub main();                     # Main program driver

######################## Program Main ###########################

main();


sub main ()
{
  $loopCounter=0;
  CollectCommandPromptInfo();
  while(! -e "/tmp/stop.ini")
  {
    print "\n\n ********* Start New Loop ***********\n";
    Connect();

    CreateDB();

    if ($useDiskData && $createLFGAlways || $createLFGInitial){
      $createLFGInitial=0;
      CreateLFG();
      if ($numberOfUndo > 1){AddUndo();}
    }

    if ($useDiskData &&  $createTableSpaceAlways ||
        $createTableSpaceInitial){
      $createTableSpaceInitial = 0;
      CreateTS();
      if ($numberOfData > 1){AddData();}
    }
    
    CreateTable();

    InsertData();

    DropDB();

    if ($useDiskData &&  $createTableSpaceAlways){
      DropTS();
    }

    if ($useDiskData && $createLFGAlways){
      DropLFG();
    }

    Disconnect();
    #sleep 25;
    print "\n\n ************ End Loop **************\n";
    
    $transCounter++;

    if ( -e "/tmp/stop.ini"){
      print "\n\nStop file stop.ini detected. Exiting program\n";
      print "Total Transaction for cid_ndb_dd = $transCounter\n";
    }
    $loopCounter++;
  }
  print "Total loops completed = $loopCounter\n";
}
######################  Collect Command Prompt Info #############

sub Usage ()

{
   die "\n\nProgram: Create Insert Drop Cluster Disk Data Stress Test\n
       usage: cid_ndb_dd.pl
         -he [--help]            :print usage

         -ho [--host=string]     :host name     (default localhost)

         -u  [--user=string]     :user's name   (default root)

         -po [--port=int]        :port          (default 3306)

         -so [--socket]          :Connect using socket (default false)

         -sp [--spath=string]    :socket path and file name
                                  (default /tmp/mysql.sock)

         -pa [--pass=string]     :password | Note: leave -pa empty or do not 
                                             include for blank password 
                                             (default null/BLANK)

         -d  [--database=string] :database name (default TESTER)

         -w  [--withDiskData]    :flag program to use Disk Data. If flaged 
                                  to use Disk Data the -i or -a must be used
                                  to create a LFG unless LFG already exists. 
                                  Then the -l option should be used to tell 
                                  the program the LFG name unless LFG name is 
                                  default (lg1). In addition, --intT or --tsc
                                  must be used to create TS unless a TS 
                                  already exists. IF TS exists then -tsn 
                                  should be used to tell the progam the TS
                                  name unless the TS name is defaults (ts1).
                                  (default false)

          -intL [--intLFGcreate]  :flag that Log File Group should be created
                                  but not dropped during test execution. Note 
                                  that if flag is set, then -c is also set. 
                                  If you want the Tables Space dropped and 
                                  created each interation, then the -tsc flag 
                                  should be set (default false)

         -a  [--alwaysCLFG]       :flag that Log File Group should be created
                                  and dropped on every test iteration. Note 
                                  that if flag is set, -tsc flag is also set. 
                                  (default false)

         -l    [--lfgname=string] :Log File Group name (default lg1)

         -numU [--numUndo=int]    :number of Log File Group Undo Files 
                                  (default/min 1)

         -sizeU[--sizeUndo=int]   :size of Undo file(s) in MB 
                                   (default/min 300)   

         -tsn  [--tsname=string]  :name of the table space (default ts1)

         -tsc  [--tscAlways]      :flag to always create and drop Table Space

         -intT [--intTScreate]    :flag to create Tables Space. TS should be 
                                  created but not dropped during test
                                  execution. 

         -numD [--numData=int     :number of TS data file(s) to create 
                                  (default/min 1)

         -sizeD[--sizeData=int]   :side of TS data file(s) in MB 
                                  (default/min 500)\n";

}
################# Collect command-line info and process ##################

sub CollectCommandPromptInfo ()
{

  if (!GetOptions("help"=>\$help,
                  "host:s"=>\$my_host,
                  "user:s"=>\$my_user,
                  "port:i"=>\$my_port,
                  "pass:s"=>\$my_pass,
                  "socket"=>\$our_useSock,
                  "spath:s"=>\$our_sockPath,
                  "database:s"=>\$my_database,
                  "withDiskData"=>\$useDiskData,
                  "intLFGcreate"=>\$createLFGInitial,
                  "alwaysCLFG"=>\$createLFGAlways,
                  "lfgname:s"=>\$nameOfLFG,
                  "numUndo:i"=>\$numberOfUndo,
                  "sizeUndo:i"=>\$sizeOfUndo,
                  "tsname:s"=>\$nameOfTS,
                  "tscAlways"=>\$createTableSpaceAlways,
                  "intTScreate"=>\$createTableSpaceInitial,
                  "numData:i"=>\$numberOfData,
                  "sizeData:i"=>\$sizeOfData))
  {
    Usage();
  }
  # print "createLFGInitial = $createLFGInitial\n";

  if ($help){Usage();}

  if ($our_useSock){
    $ENV{MYSQL_UNIX_PORT} = $our_sockPath;
  }

  ############ Ensure some stuff for Disk Data Usage ################## 
  if ($useDiskData){
    if ($createLFGInitial == 0 && 
        $createLFGAlways == 0  &&
        $createTableSpaceAlways == 0 &&
        $createTableSpaceInitial == 0){
      $createLFGAlways = 1;
      $createTableSpaceAlways = 1;
    }
    if ($sizeOfData < 500){$sizeOfData = 500;}
    $sizeOfData = $sizeOfData.M;
    if ($sizeOfUndo < 300){$sizeOfUndo = 300;}
    $sizeOfUndo = $sizeOfUndo.M;
    if ($numberOfUndo < 1){$numberOfUndo = 1;}
    if ($numberOfData < 1){$numberOfData = 1;}
    if ($createLFGInitial){$createTableSpaceInitial = 1;}
    if ($createLFGAlways){$createTableSpaceAlways = 1;}
  }

  ########## Show the user command line values for debugging #########
  print "*********************************************\n";
  print "************ Command-line values ************\n";
  print "*********************************************\n";
  print "host ..................... $my_host\n";
  print "user ..................... $my_user\n";
  print "password ................. $my_pass\n" if ($my_pass ne '');
  print "password ................. BLANK\n" if ($my_pass eq '');
  print "port ..................... $my_port\n";
  print "Use Socket To Connect .... TRUE\n" if ($our_useSock);
  print "Use Socket To Connect .... FALSE\n" if (!$our_useSock);
  print "Socket Path .............. $our_sockPath\n" if ($our_useSock);
  print "database ................. $my_database\n";
  print "use Disk Data ............ TRUE\n" if ($useDiskData);
  print "use Disk Data ............ FALSE\n" if (!$useDiskData);
  print "LFG name ................. $nameOfLFG\n" if ($useDiskData);
  print "create LFG initially ..... TRUE\n" if ($useDiskData && 
                                                $createLFGInitial);
  print "create LFG initially ..... FALSE\n" if ($useDiskData && 
                                                 !$createLFGInitial);
  print "create/drop LFG .......... TRUE\n" if ($useDiskData && 
                                                $createLFGAlways);
  print "create/drop LFG .......... FALSE\n" if ($useDiskData && 
                                                 !$createLFGAlways);
  print "number LFG Undo file(s)... $numberOfUndo\n" if ($useDiskData && 
                                                         $createLFGInitial ||
                                                         $createLFGAlways);
  print "size of Undo file(s) ..... $sizeOfUndo\n" if ($useDiskData && 
                                                       $createLFGInitial || 
                                                       $createLFGAlways);
  print "TS name .................. $nameOfTS\n" if ($useDiskData);
  print "create TS initially ...... TRUE\n" if ($useDiskData && 
                                                $createTableSpaceInitial);
  print "create TS initially ...... FALSE\n" if ($useDiskData && 
                                                 !$createTableSpaceInitial);
  print "create/drop TS ........... TRUE\n" if ($useDiskData && 
                                                $createTableSpaceAlways);
  print "create/drop TS ........... FALSE\n" if ($useDiskData && 
                                                 !$createTableSpaceAlways);
  print "number TS Data file(s).... $numberOfData\n" if ($useDiskData && 
                                                        $createTableSpaceInitial || 
                                                        $createTableSpaceAlways);
  print "size of Data file(s) ..... $sizeOfData\n" if ($useDiskData && 
                                                       $createTableSpaceInitial || 
                                                       $createTableSpaceAlways);
  print "*********************************************\n";

  #### Some value checking #####
  if ($my_host eq '' || $my_port == 0 || $my_user eq '' || $my_database eq ''){
    Usage();
  }

  ### Some Disk Data value checking ####
  if ($useDiskData){
    if($nameOfLFG eq '' || $nameOfTS eq ''){
      Usage();
    }
  }
  $my_table=$my_database.'.t1';
  #die;
}

######################  Connect to MySQLD ######################

sub Connect ()
{
  if (!$our_useSock){
    $dbhM = DBI->connect("dbi:mysql:database=mysql;host=$my_host;port=$my_port",
                         "$my_user", "$my_pass")
      or die "Can't connect to MySQL process! Error: $DBI::errstr\n";
  }
  else{
    $dbhM = DBI->connect("DBI:mysql:database=mysql;host=$my_host",
                        "$my_user", "$my_pass", {'RaiseError' => 1})
      or die "Can't connect to MySQL process! Error: $DBI::errstr\n";
  }
  print "Connected to MySQLD\n";
}

######################  Disconnect from MySQLD ################

sub Disconnect ()
{
  $dbhM->disconnect()
    or warn " Disconnection failed: $DBI::errstr\n";
  print "Disconnected from MySQLD\n";
}

######################  Create Database  ######################

sub CreateDB ()
{

 $sth = $dbhM->prepare("DROP DATABASE IF EXISTS $my_database;")
    or die "Prepare Drop DB: ", $dbhM->errstr;
  $sth->execute()
    or die "Drop DB Error: ", $sth->errstr;
  $sth->finish();

  $sth = $dbhM->prepare("CREATE DATABASE $my_database;")
    or die "Prepare Create DB error: ", $dbhM->errstr;
  $sth->execute()
    or die "Create DB Error: ", $sth->errstr;
  $sth->finish();

  $sth = $dbhM->prepare("USE $my_database;")
    or die "Prepare error: ", $dbhM->errstr;
  $sth->execute()
    or die "Create DB Error: ", $sth->errstr;
  $sth->finish();
  print "Database Created.\n";
}

######################  Create Log File Group ######################

sub CreateLFG ()
{
  print "Creating Log File Group $nameOfLFG undo size $sizeOfUndo....\n";
  $sth = $dbhM->prepare("CREATE LOGFILE GROUP $nameOfLFG
                         ADD UNDOFILE './$nameOfLFG/undofile.dat'
                         INITIAL_SIZE $sizeOfUndo
                         UNDO_BUFFER_SIZE = 4M
                         ENGINE=NDB;")
    or die "Prepare CREATE LOGFILE GROUP error: ", $dbhM->errstr;
  $sth->execute()
    or die "CREATE LOGFILE GROUP error: ", $sth->errstr;
  $sth->finish();
  print "Log File Group $nameOfLFG Created!\n";
}

######################  Add LFG Undo Files  ######################

sub AddUndo ()
{
  $count = $numberOfUndo - 1;
  print "Adding additional undo files, please stand by....\n";
  while ( $count > 0){
   $file="undofile".$count.".dat";
   print "Adding $file..\n";
   $sth = $dbhM->prepare("ALTER LOGFILE GROUP $nameOfLFG
                          ADD UNDOFILE './$nameOfLFG/$file'
                          INITIAL_SIZE $sizeOfUndo
                          ENGINE=NDB;")
     or die "Prepare ALTER LOGFILE GROUP error: ", $dbhM->errstr;
   $sth->execute()
     or die "ALTER LOGFILE GROUP error: ", $sth->errstr;
   $sth->finish();
   $count--;
  }
  print "Additional Undo File(s) Created!!\n";
}

######################  Create Table Space ######################

sub CreateTS()
{
  print "Creating Table Space $nameOfTS\n";

  $sth = $dbhM->prepare("CREATE TABLESPACE $nameOfTS
                         ADD DATAFILE './$nameOfTS/datafile.dat'
                         USE LOGFILE GROUP $nameOfLFG
                         INITIAL_SIZE $sizeOfData
                         ENGINE=NDB;")
    or die "Prepare CREATE TABLESPACE error: ", $dbhM->errstr;
  $sth->execute()
    or die "CREATE TABLESPACE error: ", $sth->errstr;
  $sth->finish();
  print "Table Space $nameOfTS Created!\n";
}

######################  Add table space data files  ###################

sub AddData ()
{
  print "Creating additional data file(s) please stand by...\n";
  #print "The Number of data files = $numberOfData\n";
  $count = $numberOfData - 1;
  while  ($count > 0){
    $file="datafile".$count.".dat";
    print "Add data file $file\n";
    $sth = $dbhM->prepare("ALTER TABLESPACE $nameOfTS
                           ADD DATAFILE './$nameOfTS/$file'
                           INITIAL_SIZE = $sizeOfData
                           ENGINE=NDB;")
      or die "Prepare ALTER TABLE SPACE error: ", $dbhM->errstr;
    $sth->execute()
      or die "ALTER TABLE SPACE error: ", $sth->errstr;
    $sth->finish();
    $count--;
   }
   print "Additional Data File(s) Created!!\n";
 }

######################  Create Table  ######################

sub CreateTable ()
{
  print "Creating $my_table, please stand by....\n";

  if (!$useDiskData){
    $sth = $dbhM->prepare("CREATE TABLE $my_table (c1 INT NOT NULL AUTO_INCREMENT, 
                           c2 CHAR(4), c3 FLOAT, c4 DOUBLE, c5 BIT(4), 
                           c6 VARCHAR(100), PRIMARY KEY (c1))ENGINE=NDB;")
      or die "Prepare error: ", $dbhM->errstr;
  }
  else{
    $sth = $dbhM->prepare("CREATE TABLE $my_table (c1 INT NOT NULL AUTO_INCREMENT,
                           c2 CHAR(4), c3 FLOAT, c4 DOUBLE, c5 BIT(4), 
                           c6 VARCHAR(100), PRIMARY KEY (c1)) TABLESPACE 
                           $nameOfTS STORAGE DISK ENGINE=NDB;")
      or die "Prepare error: ", $dbhM->errstr;
  }
 
  $sth->execute()
    or die "Create Table Error: ", $sth->errstr;
  $sth->finish();
  print "Table $my_table Created!!!!!\n";
}

######################  Insert Data  ######################

sub InsertData ()
{
   print "Inserting data\n";

   $ran = int(rand(800));
   if ($ran < 100){$ran = 100;}

   $ran = $ran * $numberOfData;
   $sth = $dbhM->prepare("INSERT INTO $my_table VALUES(NULL ,'txt',3.00008,                                                   145.00, b'1111','Testing Disk Data');")
     or die "Prepare Insert Error: ", $dbhM->errstr;

 
  $count = $ran;
  while ($count > 0){
    $sth->execute()
      or die "Insert Data Error: ", $sth->errstr;
   print ".";
   $count--;
   }

   $sth->finish();
   print "\n$ran rows of data inserted.....\n";
}

######################  Delete and drop section ######################

sub DropDB ()
{
  sleep 5;

  $sth = $dbhM->prepare("DELETE FROM $my_table")
    or die "Prepare delete from error: ", $dbhM->errstr;
  $sth->execute()
    or die "Delete Error: ", $sth->errstr;
  $sth->finish();
  print "Data Deleted.\n";

  $sth = $dbhM->prepare("DROP TABLE $my_table")
    or die "Prepare drop table error: ", $dbhM->errstr;
  $sth->execute()
    or die "Drop table error: ", $sth->errstr;
  $sth->finish();
  print "Table $my_table Dropped.\n";

 $sth = $dbhM->prepare("DROP DATABASE $my_database;")
    or die "Prepare drop error: ", $dbhM->errstr;
  $sth->execute()
    or die "drop error: ", $sth->errstr;
  print "Database $my_database  Dropped.\n";

}

######################  Drop Table Space section ######################
sub DropTS ()
{
  if ($numberOfData > 1){
    $count = $numberOfData - 1;
    while ($count > 0){
      $file="datafile".$count.".dat";
      print "Removing $file..\n";
      $sth = $dbhM->prepare("ALTER TABLESPACE $nameOfTS
                             DROP DATAFILE './$nameOfTS/$file'
                             ENGINE = NDB;")
        or die "Prepare drop data file loop error: ", $dbhM->errstr;
      $sth->execute()
        or die "Drop Data file Error: ", $sth->errstr;
      $sth->finish();
      $count--;
    }
  }
  
  print "Removing datafile.dat\n";
  $sth = $dbhM->prepare("ALTER TABLESPACE $nameOfTS
                         DROP DATAFILE './$nameOfTS/datafile.dat'
                         ENGINE = NDB;")
    or die "Prepare drop data file error: ", $dbhM->errstr;
  $sth->execute()
    or die "Drop Data file Error: ", $sth->errstr;
  $sth->finish();
  print "Data File(s) Dropped.........\n";

 $sth = $dbhM->prepare("DROP TABLESPACE  $nameOfTS ENGINE = NDB;")
    or die "Prepare drop table space error: ", $dbhM->errstr;
  $sth->execute()
    or die "Drop table space Error: ", $sth->errstr;
  $sth->finish();
  print "Tables Space $nameOfTS Dropped!!\n";
}

######################  Drop LFG section ######################
sub DropLFG ()
{
  $sth = $dbhM->prepare("DROP LOGFILE GROUP $nameOfLFG ENGINE=NDB;")
     or die "Prepare drop LFG error: ", $dbhM->errstr;
  $sth->execute()
     or die "Drop LFG Error: ", $sth->errstr;
  $sth->finish();
  print "Log File Group $nameOfLFG Dropped!!!\n";

}
