mariadb/unittest/mysys/waiting_threads-t.c
Michael Widenius f197991f41 Merge with 5.1-microseconds
A lot of small fixes and new test cases.

client/mysqlbinlog.cc:
  Cast removed
client/mysqltest.cc:
  Added missing DBUG_RETURN
include/my_pthread.h:
  set_timespec_time_nsec() now only takes one argument
mysql-test/t/date_formats.test:
  Remove --disable_ps_protocl as now also ps supports microseconds
mysys/my_uuid.c:
  Changed to use my_interval_timer() instead of my_getsystime()
mysys/waiting_threads.c:
  Changed to use my_hrtime()
sql/field.h:
  Added bool special_const_compare() for fields that may convert values before compare (like year)
sql/field_conv.cc:
  Added test to get optimal copying of identical temporal values.
sql/item.cc:
  Return that item_int is equal if it's positive, even if unsigned flag is different.
  Fixed Item_cache_str::save_in_field() to have identical null check as other similar functions
  Added proper NULL check to Item_cache_int::save_in_field()
sql/item_cmpfunc.cc:
  Don't call convert_constant_item() if there is nothing that is worth converting.
  Simplified test when years should be converted
sql/item_sum.cc:
  Mark cache values in Item_sum_hybrid as not constants to ensure they are not replaced by other cache values in compare_datetime()
sql/item_timefunc.cc:
  Changed sec_to_time() to take a my_decimal argument to ensure we don't loose any sub seconds.
  Added Item_temporal_func::get_time() (This simplifies some things)
sql/mysql_priv.h:
  Added Lazy_string_decimal()
sql/mysqld.cc:
  Added my_decimal constants max_seconds_for_time_type, time_second_part_factor
sql/table.cc:
  Changed expr_arena to be of type CONVENTIONAL_EXECUTION to ensure that we don't loose any items that are created by fix_fields()
sql/tztime.cc:
  TIME_to_gmt_sec() now sets *in_dst_time_gap in case of errors
  This is needed to be able to detect if timestamp is 0
storage/maria/lockman.c:
  Changed from my_getsystime() to set_timespec_time_nsec()
storage/maria/ma_loghandler.c:
  Changed from my_getsystime() to my_hrtime()
storage/maria/ma_recovery.c:
  Changed from my_getsystime() to mmicrosecond_interval_timer()
storage/maria/unittest/trnman-t.c:
  Changed from my_getsystime() to mmicrosecond_interval_timer()
storage/xtradb/handler/ha_innodb.cc:
  Added support for new time,datetime and timestamp
unittest/mysys/thr_template.c:
  my_getsystime() -> my_interval_timer()
unittest/mysys/waiting_threads-t.c:
  my_getsystime() -> my_interval_timer()
2011-05-28 05:11:32 +03:00

291 lines
8.6 KiB
C

/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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; version 2 of the License.
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 */
#include "thr_template.c"
#include <waiting_threads.h>
#include <m_string.h>
struct test_wt_thd {
WT_THD thd;
pthread_mutex_t lock;
} thds[THREADS];
uint i, cnt;
pthread_mutex_t lock;
pthread_cond_t thread_sync;
ulong wt_timeout_short=100, wt_deadlock_search_depth_short=4;
ulong wt_timeout_long=10000, wt_deadlock_search_depth_long=15;
#define reset(ARRAY) bzero(ARRAY, sizeof(ARRAY))
/* see explanation of the kill strategies in waiting_threads.h */
enum { LATEST, RANDOM, YOUNGEST, LOCKS } kill_strategy;
WT_RESOURCE_TYPE restype={ wt_resource_id_memcmp, 0};
#define rnd() ((uint)(my_rnd(&rand) * INT_MAX32))
/*
stress test: wait on a random number of random threads.
it always succeeds (unless crashes or hangs).
*/
pthread_handler_t test_wt(void *arg)
{
int m, n, i, id, res;
struct my_rnd_struct rand;
my_thread_init();
pthread_mutex_lock(&mutex);
id= cnt++;
wt_thd_lazy_init(& thds[id].thd,
& wt_deadlock_search_depth_short, & wt_timeout_short,
& wt_deadlock_search_depth_long, & wt_timeout_long);
/* now, wait for everybody to be ready to run */
if (cnt >= THREADS)
pthread_cond_broadcast(&thread_sync);
else
while (cnt < THREADS)
pthread_cond_wait(&thread_sync, &mutex);
pthread_mutex_unlock(&mutex);
my_rnd_init(&rand, (ulong)(intptr)&m, id);
if (kill_strategy == YOUNGEST)
thds[id].thd.weight= (ulong) ~ my_interval_timer();
if (kill_strategy == LOCKS)
thds[id].thd.weight= 0;
for (m= *(int *)arg; m ; m--)
{
WT_RESOURCE_ID resid;
int blockers[THREADS/10], j, k;
resid.value= id;
resid.type= &restype;
res= 0;
/* prepare for waiting for a random number of random threads */
for (j= n= (rnd() % THREADS)/10; !res && j >= 0; j--)
{
retry:
i= rnd() % (THREADS-1); /* pick a random thread */
if (i >= id) i++; /* with a number from 0 to THREADS-1 excluding ours */
for (k=n; k >=j; k--) /* the one we didn't pick before */
if (blockers[k] == i)
goto retry;
blockers[j]= i;
if (kill_strategy == RANDOM)
thds[id].thd.weight= rnd();
pthread_mutex_lock(& thds[i].lock);
res= wt_thd_will_wait_for(& thds[id].thd, & thds[i].thd, &resid);
pthread_mutex_unlock(& thds[i].lock);
}
if (!res)
{
pthread_mutex_lock(&lock);
res= wt_thd_cond_timedwait(& thds[id].thd, &lock);
pthread_mutex_unlock(&lock);
}
if (res)
{
pthread_mutex_lock(& thds[id].lock);
pthread_mutex_lock(&lock);
wt_thd_release_all(& thds[id].thd);
pthread_mutex_unlock(&lock);
pthread_mutex_unlock(& thds[id].lock);
if (kill_strategy == LOCKS)
thds[id].thd.weight= 0;
if (kill_strategy == YOUNGEST)
thds[id].thd.weight= (ulong)~ my_interval_timer();
}
else if (kill_strategy == LOCKS)
thds[id].thd.weight++;
}
pthread_mutex_lock(&mutex);
/* wait for everybody to finish */
if (!--cnt)
pthread_cond_broadcast(&thread_sync);
else
while (cnt)
pthread_cond_wait(&thread_sync, &mutex);
pthread_mutex_lock(& thds[id].lock);
pthread_mutex_lock(&lock);
wt_thd_release_all(& thds[id].thd);
pthread_mutex_unlock(&lock);
pthread_mutex_unlock(& thds[id].lock);
wt_thd_destroy(& thds[id].thd);
if (!--running_threads) /* now, signal when everybody is done with deinit */
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
DBUG_PRINT("wt", ("exiting"));
my_thread_end();
return 0;
}
void do_one_test()
{
double sum, sum0;
DBUG_ENTER("do_one_test");
reset(wt_cycle_stats);
reset(wt_wait_stats);
wt_success_stats=0;
cnt=0;
test_concurrently("waiting_threads", test_wt, THREADS, CYCLES);
sum=sum0=0;
for (cnt=0; cnt < WT_CYCLE_STATS; cnt++)
sum+= wt_cycle_stats[0][cnt] + wt_cycle_stats[1][cnt];
for (cnt=0; cnt < WT_CYCLE_STATS; cnt++)
if (wt_cycle_stats[0][cnt] + wt_cycle_stats[1][cnt] > 0)
{
sum0+=wt_cycle_stats[0][cnt] + wt_cycle_stats[1][cnt];
diag("deadlock cycles of length %2u: %4u %4u %8.2f %%", cnt,
wt_cycle_stats[0][cnt], wt_cycle_stats[1][cnt], 1e2*sum0/sum);
}
diag("depth exceeded: %u %u",
wt_cycle_stats[0][cnt], wt_cycle_stats[1][cnt]);
for (cnt=0; cnt < WT_WAIT_STATS; cnt++)
if (wt_wait_stats[cnt]>0)
diag("deadlock waits up to %7llu us: %5u",
wt_wait_table[cnt], wt_wait_stats[cnt]);
diag("timed out: %u", wt_wait_stats[cnt]);
diag("successes: %u", wt_success_stats);
DBUG_VOID_RETURN;
}
void do_tests()
{
DBUG_ENTER("do_tests");
if (skip_big_tests)
{
skip(1, "Big test skipped");
return;
}
plan(14);
compile_time_assert(THREADS >= 4);
DBUG_PRINT("wt", ("================= initialization ==================="));
bad= my_atomic_initialize();
ok(!bad, "my_atomic_initialize() returned %d", bad);
pthread_cond_init(&thread_sync, 0);
pthread_mutex_init(&lock, 0);
wt_init();
for (cnt=0; cnt < THREADS; cnt++)
pthread_mutex_init(& thds[cnt].lock, 0);
{
WT_RESOURCE_ID resid[4];
for (i=0; i < array_elements(resid); i++)
{
wt_thd_lazy_init(& thds[i].thd,
& wt_deadlock_search_depth_short, & wt_timeout_short,
& wt_deadlock_search_depth_long, & wt_timeout_long);
resid[i].value= i+1;
resid[i].type= &restype;
}
DBUG_PRINT("wt", ("================= manual test ==================="));
#define ok_wait(X,Y, R) \
ok(wt_thd_will_wait_for(& thds[X].thd, & thds[Y].thd, &resid[R]) == 0, \
"thd[" #X "] will wait for thd[" #Y "]")
#define ok_deadlock(X,Y,R) \
ok(wt_thd_will_wait_for(& thds[X].thd, & thds[Y].thd, &resid[R]) == WT_DEADLOCK, \
"thd[" #X "] will wait for thd[" #Y "] - deadlock")
ok_wait(0,1,0);
ok_wait(0,2,0);
ok_wait(0,3,0);
pthread_mutex_lock(&lock);
bad= wt_thd_cond_timedwait(& thds[0].thd, &lock);
pthread_mutex_unlock(&lock);
ok(bad == WT_TIMEOUT, "timeout test returned %d", bad);
ok_wait(0,1,0);
ok_wait(1,2,1);
ok_deadlock(2,0,2);
pthread_mutex_lock(&lock);
ok(wt_thd_cond_timedwait(& thds[0].thd, &lock) == WT_TIMEOUT, "as always");
ok(wt_thd_cond_timedwait(& thds[1].thd, &lock) == WT_TIMEOUT, "as always");
wt_thd_release_all(& thds[0].thd);
wt_thd_release_all(& thds[1].thd);
wt_thd_release_all(& thds[2].thd);
wt_thd_release_all(& thds[3].thd);
for (i=0; i < array_elements(resid); i++)
{
wt_thd_release_all(& thds[i].thd);
wt_thd_destroy(& thds[i].thd);
}
pthread_mutex_unlock(&lock);
}
wt_deadlock_search_depth_short=6;
wt_timeout_short=1000;
wt_timeout_long= 100;
wt_deadlock_search_depth_long=16;
DBUG_PRINT("wt", ("================= stress test ==================="));
diag("timeout_short=%lu us, deadlock_search_depth_short=%lu",
wt_timeout_short, wt_deadlock_search_depth_short);
diag("timeout_long=%lu us, deadlock_search_depth_long=%lu",
wt_timeout_long, wt_deadlock_search_depth_long);
#ifndef _WIN32
#define test_kill_strategy(X) \
diag("kill strategy: " #X); \
DBUG_EXECUTE("reset_file", \
{ rewind(DBUG_FILE); my_chsize(fileno(DBUG_FILE), 0, 0, MYF(MY_WME)); }); \
DBUG_PRINT("info", ("kill strategy: " #X)); \
kill_strategy=X; \
do_one_test();
#else
#define test_kill_strategy(X) \
diag("kill strategy: " #X); \
DBUG_PRINT("info", ("kill strategy: " #X)); \
kill_strategy=X; \
do_one_test();
#endif
test_kill_strategy(LATEST);
test_kill_strategy(RANDOM);
test_kill_strategy(YOUNGEST);
test_kill_strategy(LOCKS);
DBUG_PRINT("wt", ("================= cleanup ==================="));
for (cnt=0; cnt < THREADS; cnt++)
pthread_mutex_destroy(& thds[cnt].lock);
wt_end();
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&thread_sync);
DBUG_VOID_RETURN;
}