#!/bin/sh # # Copyright 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 echo "######################################################################" echo "#" echo "# Test Bug#10178 - failure to find a row in heap table by concurrent UPDATEs" echo "#" ####################################################################### # # Settings. CAUTION: Paths are not space safe. # # BASEDIR="install directory" # DATADIR="databases directory e.g. $BASEDIR/var" MYSQLD="$BASEDIR/libexec/mysqld" MYSQLC="$BASEDIR/bin/mysql" MYSQLA="$BASEDIR/bin/mysqladmin" MYSQLT="$BASEDIR/bin/mysqltest" PORT_1="${MYSQL_TCP_PORT:+--port=$MYSQL_TCP_PORT}" SOCK_1="${MYSQL_UNIX_PORT:+--socket=$MYSQL_UNIX_PORT}" USER_1="-u root -D test" CLNT_1="-v" DATA_1="--basedir=$BASEDIR --datadir=$DATADIR" SERV_1="--log-error --core" DBUG_1="--debug=t:d:i:O,$DATADIR/mysqld.trace" DBUG_1= #"--debug=d,thrlock:i:O,$DATADIR/mysqld.trace" cd $DATADIR || exit $? rm -f *.trace *.err core* test/#sql* bug10178* echo "######################################################################" echo "#" echo "# Starting database server." "$MYSQLD" $PORT_1 $SOCK_1 $DATA_1 $SERV_1 $DBUG_1 & SERV_1_PID=$! echo "Process_id $SERV_1_PID" echo sleep 5 echo "######################################################################" echo "#" echo "# Running test." cat < bug10178-1.c /* bug10178-1.c Copyright 2005 probably by Andrei Elkin, see bug report #10178 on bugs.mysql.com. (Slightly) modified by Ingo Struewing, MySQL AB Bug#10178 - failure to find a row in heap table by concurrent UPDATEs */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #define TRUE 1 #define FALSE 0 #define N_DIM 3 #define CMD_LEN 4096 #define MAX_TABLES 256 const double rand_denom=1.0/((double)RAND_MAX + 1.0); #define drand() ((double)rand()*rand_denom) #define error_mysql(m) fprintf (stderr, "MySQL server: %s\n", mysql_error (m)); volatile int stop = 0; volatile int sigint = 0; void catch_int (int sig) { sigint = sig; signal (SIGINT, catch_int); signal (SIGTERM, catch_int); } int n_tuples = 0; struct { char db_host[64]; int db_port; char db_name[64]; char db_user[64]; char db_pswd[64]; int n_users; int n_tables; int n_rows; int modulus; int query_min; int query_max; int create; int index; } config = { .db_host = "localhost.localdomain", .db_port = 3304, .db_name = "comm", .db_user = "test", .db_pswd = "testpass", .n_users = 16, .n_tables = 40, .n_rows = 2, .modulus = 32771, .query_min = 8, .query_max = 100, .create = 1, .index = 1 }; struct my_thread { pthread_t thread; int id; int prim_key; int row[N_DIM]; char cmd[CMD_LEN]; int cmd_len; MYSQL *mysql; MYSQL_RES *mysql_result; FILE * log_file; } *my_threads = NULL; struct my_table { int prim_key; int row[N_DIM]; int rows; char *name; } *my_tables = NULL; MYSQL *connect_mysql (MYSQL *mysql, char *db_name) { mysql = mysql_init (mysql); if (!mysql) return NULL; if (!mysql_real_connect (mysql, config.db_host, config.db_user, config.db_pswd, db_name, config.db_port, NULL, 0)) { fprintf (stderr, "MySQL server: %s\n", mysql_error (mysql)); mysql_close (mysql); return NULL; } return mysql; } static inline int get_table (void) { return (config.n_tables * drand()); } static int run_update (struct my_thread *thread) { int key, table; key = (n_tuples) * drand() + 1; table = get_table (); thread->cmd_len = snprintf(thread->cmd, CMD_LEN, "UPDATE %s SET " "count = count + 1 " "WHERE col_key = %d ", my_tables[table].name, key); if (mysql_query (thread->mysql, thread->cmd)) { error (0, errno, "Error in query: %s\n: %s", thread->cmd, mysql_error(thread->mysql)); return -1; } else { thread->mysql_result = mysql_store_result (thread->mysql); if (mysql_affected_rows(thread->mysql) == 0) { error (0, errno, "NO ROWS ARE AFFECTED, WHY? query: %s\n: %s", thread->cmd, mysql_error(thread->mysql)); stop = 1; }; mysql_free_result(thread->mysql_result); } return 0; } void *user_thread (void *thr) { int n_ops = 0; int err = 0; struct timeval connect; struct my_thread *thread = (struct my_thread *) thr; if (!thread) error (-1, errno, "Null thread pointer in user_thread"); while (!stop) { n_ops = config.query_min + (config.query_max - config.query_min)*drand(); while (!(thread->mysql = connect_mysql(NULL, config.db_name)) && !stop) { error (0, errno, "Thread %d: unable to connect to database", thread->id); sleep (1); } gettimeofday (&connect, NULL); mysql_select_db (thread->mysql, config.db_name); while (n_ops-- && !stop) { err = run_update(thread); }; mysql_close (thread->mysql); mysql_thread_end (); } return NULL; } static int create_table (MYSQL *mysql, struct my_table * my_tables, int i) { char cmd[CMD_LEN]; char *name = my_tables[i].name; static int t_num = 0; printf ("%s[%d] ", name, t_num); snprintf (cmd, CMD_LEN, "create table %s( " "col_key int not null primary key, " "count double not null, " "index tbl_ind%s (col_key) " ") type=heap " "MIN_ROWS = 1 MAX_ROWS = %d", name, name, config.n_rows); if (mysql_query (mysql, cmd)) error (-1, errno, "%s failed to create table '%s': %s", cmd, name, mysql_error(mysql)); t_num++; return t_num; } static int fill_table (MYSQL *mysql, int n) { char cmd[CMD_LEN]; char *name = my_tables[n].name; int i; printf ("%s ", name); fflush (stdout); for (i = 0; i < config.n_rows; i++) { snprintf (cmd, CMD_LEN, "INSERT INTO %s VALUES (%d, 0)", name, i+1); if (mysql_query (mysql, cmd)) { error_mysql(mysql); error (-1, errno, "Failed to insert row into %s: %s", my_tables[n].name, mysql_error(mysql)); } my_tables[n].rows++; } return 0; } int comm_create () { MYSQL *mysql = NULL; char cmd[CMD_LEN]; struct timeval begin; int i; puts ("Connecting to server:"); mysql = connect_mysql (mysql, NULL); if (!mysql) error (-1, errno, "Unable to connect to server"); puts ("ok"); my_tables = (struct my_table *) realloc (my_tables, config.n_tables * sizeof (struct my_table)); if (NULL == my_tables) error (-1, errno, "Failed to allocate memory for table structure array"); memset (my_tables, 0, config.n_tables * sizeof (struct my_table)); for (i = 0; i < config.n_tables; i++) { snprintf (cmd, CMD_LEN, "t%d", i); my_tables[i].name = strdup (cmd); my_tables[i].prim_key = 1; } char *table_types[] = {}; unsigned char table_len = 0; char *p_type = "heap"; if (config.create==1) { snprintf (cmd, CMD_LEN, "drop database %s", config.db_name); mysql_query (mysql, cmd); snprintf (cmd, CMD_LEN, "create database %s", config.db_name); if (mysql_query (mysql, cmd)) { error (-1, errno, "Failed to create database %s: %s", config.db_name, mysql_error(mysql)); } mysql_select_db (mysql, config.db_name); puts ("Creating tables:"); gettimeofday (&begin, NULL); table_types[table_len] = p_type; while (*p_type != '\0') { if (*p_type == ',') { *p_type = '\0'; table_types[++table_len] = ++p_type; } else { p_type++; } } for (i = 0; i < config.n_tables; i++) create_table(mysql, my_tables, i); for (i = 0; i < config.n_tables; i++) fill_table (mysql, i); putchar('\n'); putchar('\n'); } n_tuples = config.n_rows; mysql_select_db (mysql, config.db_name); mysql_close (mysql); return 0; } int main (int argc, char *argv[]) { int i; config.n_users = atoi(argv[1]); strcpy(config.db_host,argv[2]); config.db_port = atoi(argv[3]); strcpy(config.db_name,argv[4]); strcpy(config.db_user,argv[5]); strcpy(config.db_pswd,argv[6]); config.n_tables = atoi(argv[7]); config.n_rows = atoi(argv[8]); if (argc > 9) config.create = atoi(argv[9]); if (1 != mysql_thread_safe()) error (1, errno, "This program was not compiled thread safe, exiting."); my_threads = (struct my_thread *) calloc (config.n_users, sizeof (struct my_thread)); comm_create(); for (i = 0; i < config.n_users; i++) { my_threads[i].id = i + 1; pthread_create (&(my_threads[i].thread), NULL, user_thread, my_threads + i); } fflush (stdout); printf ("Running bug test until C-c\n"); sleep(99999); stop = 1; for (i = 0; i < config.n_users; i++) pthread_join (my_threads[i].thread, NULL); return 0; } EOF cc -o bug10178-1.exe `mysql_config --cflags` bug10178-1.c \ `mysql_config --libs | sed s/lmysqlclient/lmysqlclient_r/g` -lpthread trap "echo interrupted" 2 ./bug10178-1.exe 100 localhost "$MYSQL_TCP_PORT" test root "" 1 1 # 0 echo sleep 2 echo "######################################################################" echo "#" echo "# Stopping database server." "$MYSQLA" $PORT_1 $SOCK_1 -u root shutdown sleep 3 echo "# End of Test." echo "#" echo "######################################################################"