From: Jonas Oreland Date: September 28 2011 10:32am Subject: bzr push into mysql-5.1-telco-7.1 branch (jonas.oreland:4293 to 4294) List-Archive: http://lists.mysql.com/commits/141182 Message-Id: <20110928103213.78E62915DFB@perch.localdomain> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4294 Jonas Oreland 2011-09-28 [merge] ndb - merge 70 to 71 added: storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.cpp storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.h modified: mysql-test/suite/ndb_binlog/t/ndb_binlog_log_transaction_id-master.opt mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch_trans.cnf storage/ndb/include/portlib/NdbMutex.h storage/ndb/src/common/portlib/CMakeLists.txt storage/ndb/src/common/portlib/Makefile.am storage/ndb/src/common/portlib/NdbCondition.c storage/ndb/src/common/portlib/NdbMutex.c storage/ndb/src/common/portlib/NdbThread.c storage/ndb/src/common/util/ndb_init.cpp storage/ndb/src/kernel/vm/ArrayPool.hpp storage/ndb/src/kernel/vm/Emulator.cpp storage/ndb/src/mgmsrv/MgmtSrvr.cpp storage/ndb/test/ndbapi/testNdbApi.cpp storage/ndb/test/ndbapi/testRestartGci.cpp storage/ndb/test/ndbapi/test_event.cpp storage/ndb/test/run-test/daily-basic-tests.txt storage/ndb/test/tools/hugoJoin.cpp 4293 Craig L Russell 2011-09-26 Add support for value handling for jdbc 5.1.17 added: storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBatching.java storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBindValuesImpl.java modified: storage/ndb/clusterj/clusterj-jdbc/Makefile.am storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/InterceptorImpl.java storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/QueryExecutionContextJDBCImpl.java storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/SQLExecutor.java storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerImpl.java storage/ndb/clusterj/clusterj-jdbc/src/test/java/jdbctest/BatchDeleteQueryAllPrimitivesTest.java storage/ndb/clusterj/clusterj-jdbc/src/test/java/jdbctest/BigIntegerTypesTest.java storage/ndb/clusterj/clusterj-jdbc/src/test/resources/clusterj.properties === modified file 'mysql-test/suite/ndb_binlog/t/ndb_binlog_log_transaction_id-master.opt' --- a/mysql-test/suite/ndb_binlog/t/ndb_binlog_log_transaction_id-master.opt 2011-09-07 22:50:01 +0000 +++ b/mysql-test/suite/ndb_binlog/t/ndb_binlog_log_transaction_id-master.opt 2011-09-28 09:40:14 +0000 @@ -1 +1 @@ ---ndb-log-transaction-id +--ndb-log-transaction-id --log-bin-use-v1-row-events=false === modified file 'mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch_trans.cnf' --- a/mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch_trans.cnf 2011-09-07 22:50:01 +0000 +++ b/mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch_trans.cnf 2011-09-28 09:40:14 +0000 @@ -11,10 +11,14 @@ # Potential infinite loops are broken by both servers # on each cluster having the same server-id +[cluster_config.slave] +mysqld=, + [mysqld] log-slave-updates ndb-log-apply-status ndb-log-transaction-id +log-bin-use-v1-row-events=false [mysqld.1.1] server-id= 1 === modified file 'storage/ndb/include/portlib/NdbMutex.h' --- a/storage/ndb/include/portlib/NdbMutex.h 2011-06-30 16:04:23 +0000 +++ b/storage/ndb/include/portlib/NdbMutex.h 2011-09-28 10:18:35 +0000 @@ -29,11 +29,12 @@ extern "C" { #else #include #endif -#ifndef NDB_MUTEX_STAT +#if !defined NDB_MUTEX_STAT && !defined NDB_MUTEX_DEADLOCK_DETECTOR typedef pthread_mutex_t NdbMutex; #else typedef struct { pthread_mutex_t mutex; +#ifdef NDB_MUTEX_STAT unsigned cnt_lock; unsigned cnt_lock_contention; unsigned cnt_trylock_ok; @@ -46,6 +47,10 @@ typedef struct { unsigned long long max_hold_time_ns; unsigned long long lock_start_time_ns; char name[32]; +#endif +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + struct ndb_mutex_state * m_mutex_state; +#endif } NdbMutex; #endif === modified file 'storage/ndb/src/common/portlib/CMakeLists.txt' --- a/storage/ndb/src/common/portlib/CMakeLists.txt 2011-07-04 16:30:34 +0000 +++ b/storage/ndb/src/common/portlib/CMakeLists.txt 2011-09-28 10:18:35 +0000 @@ -27,7 +27,7 @@ ADD_CONVENIENCE_LIBRARY(ndbportlib NdbEnv.c NdbThread.c NdbHost.c NdbTCP.cpp NdbMem.c NdbConfig.c NdbTick.c NdbDir.cpp ndb_daemon.cc ${EXTRA_SRC} - NdbNuma.cpp) + NdbNuma.cpp NdbMutex_DeadlockDetector.cpp) TARGET_LINK_LIBRARIES(ndbportlib mysys ${LIBSOCKET}) ADD_EXECUTABLE(NdbDir-t === modified file 'storage/ndb/src/common/portlib/Makefile.am' --- a/storage/ndb/src/common/portlib/Makefile.am 2011-06-30 15:59:25 +0000 +++ b/storage/ndb/src/common/portlib/Makefile.am 2011-09-27 17:28:13 +0000 @@ -21,7 +21,8 @@ libportlib_la_SOURCES = \ NdbCondition.c NdbMutex.c NdbTick.c \ NdbEnv.c NdbThread.c NdbHost.c NdbTCP.cpp \ ndb_daemon.cc NdbMem.c \ - NdbConfig.c NdbDir.cpp ndb_socket.cpp + NdbConfig.c NdbDir.cpp ndb_socket.cpp \ + NdbMutex_DeadlockDetector.cpp include $(top_srcdir)/storage/ndb/config/common.mk.am include $(top_srcdir)/storage/ndb/config/type_util.mk.am === modified file 'storage/ndb/src/common/portlib/NdbCondition.c' --- a/storage/ndb/src/common/portlib/NdbCondition.c 2011-06-30 16:04:23 +0000 +++ b/storage/ndb/src/common/portlib/NdbCondition.c 2011-09-28 10:18:35 +0000 @@ -27,6 +27,10 @@ static int init = 0; static int clock_id = CLOCK_REALTIME; #endif +#if defined NDB_MUTEX_STAT || defined NDB_MUTEX_DEADLOCK_DETECTOR +#define NDB_MUTEX_STRUCT +#endif + void NdbCondition_initialize(int need_monotonic) { @@ -129,7 +133,7 @@ NdbCondition_Wait(struct NdbCondition* p if (p_cond == NULL || p_mutex == NULL) return 1; -#ifdef NDB_MUTEX_STAT +#ifdef NDB_MUTEX_STRUCT result = pthread_cond_wait(&p_cond->cond, &p_mutex->mutex); #else result = pthread_cond_wait(&p_cond->cond, p_mutex); @@ -187,17 +191,23 @@ NdbCondition_WaitTimeoutAbs(struct NdbCo const struct timespec * abstime) { #ifdef NDB_WIN + /** + * mysys windows wrapper of pthread_cond_timedwait + * does not have a const argument for the timespec + */ struct timespec tmp = *abstime; - abstime = &tmp; + struct timespec * waitarg = &tmp; +#else + const struct timespec * waitarg = abstime; #endif if (p_cond == NULL || p_mutex == NULL) return 1; -#ifdef NDB_MUTEX_STAT - return pthread_cond_timedwait(&p_cond->cond, &p_mutex->mutex, abstime); +#ifdef NDB_MUTEX_STRUCT + return pthread_cond_timedwait(&p_cond->cond, &p_mutex->mutex, waitarg); #else - return pthread_cond_timedwait(&p_cond->cond, p_mutex, abstime); + return pthread_cond_timedwait(&p_cond->cond, p_mutex, waitarg); #endif } === modified file 'storage/ndb/src/common/portlib/NdbMutex.c' --- a/storage/ndb/src/common/portlib/NdbMutex.c 2011-06-30 16:04:23 +0000 +++ b/storage/ndb/src/common/portlib/NdbMutex.c 2011-09-28 10:18:35 +0000 @@ -21,10 +21,34 @@ #include #include +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR +#include "NdbMutex_DeadlockDetector.h" +#endif + #ifdef NDB_MUTEX_STAT static FILE * statout = 0; #endif +#if defined NDB_MUTEX_STAT || defined NDB_MUTEX_DEADLOCK_DETECTOR +#define NDB_MUTEX_STRUCT +#endif + +void +NdbMutex_SysInit() +{ +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + NdbMutex_DeadlockDetectorInit(); +#endif +} + +void +NdbMutex_SysEnd() +{ +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + NdbMutex_DeadlockDetectorEnd(); +#endif +} + NdbMutex* NdbMutex_Create() { return NdbMutex_CreateWithName(0); @@ -59,12 +83,15 @@ int NdbMutex_InitWithName(NdbMutex* pNdb int result; pthread_mutex_t * p; DBUG_ENTER("NdbMutex_Init"); + (void)name; -#ifdef NDB_MUTEX_STAT +#ifdef NDB_MUTEX_STRUCT bzero(pNdbMutex, sizeof(NdbMutex)); + p = &pNdbMutex->mutex; + +#ifdef NDB_MUTEX_STAT pNdbMutex->min_lock_wait_time_ns = ~(Uint64)0; pNdbMutex->min_hold_time_ns = ~(Uint64)0; - p = &pNdbMutex->mutex; if (name == 0) { snprintf(pNdbMutex->name, sizeof(pNdbMutex->name), "%p", @@ -79,9 +106,10 @@ int NdbMutex_InitWithName(NdbMutex* pNdb { statout = stdout; } +#endif + #else p = pNdbMutex; - (void)name; #endif #if defined(VM_TRACE) && \ @@ -99,6 +127,13 @@ int NdbMutex_InitWithName(NdbMutex* pNdb #else result = pthread_mutex_init(p, 0); #endif + +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + if (result == 0) + { + ndb_mutex_created(pNdbMutex); + } +#endif DBUG_RETURN(result); } @@ -109,7 +144,11 @@ int NdbMutex_Destroy(NdbMutex* p_mutex) if (p_mutex == NULL) return -1; -#ifdef NDB_MUTEX_STAT +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + ndb_mutex_destoyed(p_mutex); +#endif + +#ifdef NDB_MUTEX_STRUCT result = pthread_mutex_destroy(&p_mutex->mutex); #else result = pthread_mutex_destroy(p_mutex); @@ -201,11 +240,17 @@ int NdbMutex_Lock(NdbMutex* p_mutex) p_mutex->cnt_lock++; p_mutex->lock_start_time_ns = stop; } +#elif defined NDB_MUTEX_STRUCT + result = pthread_mutex_lock(&p_mutex->mutex); #else result = pthread_mutex_lock(p_mutex); #endif assert(result == 0); +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + ndb_mutex_locked(p_mutex); +#endif + return result; } @@ -234,11 +279,17 @@ int NdbMutex_Unlock(NdbMutex* p_mutex) dumpstat(p_mutex); } } +#elif defined NDB_MUTEX_STRUCT + result = pthread_mutex_unlock(&p_mutex->mutex); #else result = pthread_mutex_unlock(p_mutex); #endif assert(result == 0); +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + ndb_mutex_unlocked(p_mutex); +#endif + return result; } @@ -261,11 +312,21 @@ int NdbMutex_Trylock(NdbMutex* p_mutex) { __sync_fetch_and_add(&p_mutex->cnt_trylock_nok, 1); } +#elif defined NDB_MUTEX_STRUCT + result = pthread_mutex_trylock(&p_mutex->mutex); #else result = pthread_mutex_trylock(p_mutex); #endif assert(result == 0 || result == EBUSY); +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + if (result == 0) + { + ndb_mutex_try_locked(p_mutex); + } +#endif + + return result; } === added file 'storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.cpp' --- a/storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.cpp 1970-01-01 00:00:00 +0000 +++ b/storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.cpp 2011-09-27 17:28:13 +0000 @@ -0,0 +1,422 @@ +/* + Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + +#include "NdbMutex_DeadlockDetector.h" + +#define NDB_THREAD_TLS_SELF NDB_THREAD_TLS_MAX + +static NdbMutex g_mutex_no_mutex; // We need a mutex to assign numbers to mutexes... +static nmdd_mask g_mutex_no_mask = { 0, 0 }; + +static unsigned alloc_mutex_no(); +static void release_mutex_no(unsigned no); + +static NdbMutex* get_element(struct nmdd_mutex_array *, unsigned i); +static void add_mutex_to_array(struct nmdd_mutex_array *, NdbMutex*); +static void remove_mutex_from_array(struct nmdd_mutex_array *, NdbMutex*); + +static void set_bit(struct nmdd_mask *, unsigned no); +static void clear_bit(struct nmdd_mask* , unsigned no); +static bool check_bit(const struct nmdd_mask* , unsigned no); + +static void release(struct nmdd_mutex_array *); +static void release(struct nmdd_mask*); + +extern "C" +void +NdbMutex_DeadlockDetectorInit() +{ + NdbMutex_Init(&g_mutex_no_mutex); +} + +extern "C" +void +NdbMutex_DeadlockDetectorEnd() +{ + release(&g_mutex_no_mask); +} + +extern "C" +void +ndb_mutex_created(NdbMutex* p) +{ + p->m_mutex_state = (ndb_mutex_state*)malloc(sizeof(ndb_mutex_state)); + bzero(p->m_mutex_state, sizeof(ndb_mutex_state)); + + /** + * Assign mutex no + */ + p->m_mutex_state->m_no = alloc_mutex_no(); +} + +extern "C" +void +ndb_mutex_destoyed(NdbMutex* p) +{ + unsigned no = p->m_mutex_state->m_no; + + /** + * In order to be able to reuse mutex_no, + * we need to clear this no from all mutexes that has it in before map... + * this is all mutexes in after map + */ + for (unsigned i = 0; im_mutex_state->m_locked_after_list.m_used; i++) + { + NdbMutex * m = get_element(&p->m_mutex_state->m_locked_after_list, i); + assert(check_bit(&p->m_mutex_state->m_locked_after_mask, m->m_mutex_state->m_no)); + + /** + * And we need to lock it while doing this + */ + NdbMutex_Lock(m); + assert(check_bit(&m->m_mutex_state->m_locked_before_mask, no)); + clear_bit(&m->m_mutex_state->m_locked_before_mask, no); + remove_mutex_from_array(&m->m_mutex_state->m_locked_before_list, p); + NdbMutex_Unlock(m); + } + + /** + * And we need to remove ourselfs from after list of mutexes in out before list + */ + for (unsigned i = 0; im_mutex_state->m_locked_before_list.m_used; i++) + { + NdbMutex * m = get_element(&p->m_mutex_state->m_locked_before_list, i); + NdbMutex_Lock(m); + assert(check_bit(&m->m_mutex_state->m_locked_after_mask, no)); + clear_bit(&m->m_mutex_state->m_locked_after_mask, no); + remove_mutex_from_array(&m->m_mutex_state->m_locked_after_list, p); + NdbMutex_Unlock(m); + } + + release(&p->m_mutex_state->m_locked_before_mask); + release(&p->m_mutex_state->m_locked_before_list); + release(&p->m_mutex_state->m_locked_after_mask); + release(&p->m_mutex_state->m_locked_after_list); + release_mutex_no(no); +} + +static +ndb_mutex_thr_state* +get_thr() +{ + void * p = NdbThread_GetTlsKey(NDB_THREAD_TLS_SELF); + return (ndb_mutex_thr_state*)p; +} + +#define INC_SIZE 16 + +static +void +add_lock_to_thread(ndb_mutex_thr_state * t, NdbMutex * m) +{ + add_mutex_to_array(&t->m_mutexes_locked, m); +} + +static +void +add_lock_to_mutex_before_list(ndb_mutex_state * m1, NdbMutex * m2) +{ + assert(m1 != m2->m_mutex_state); + unsigned no = m2->m_mutex_state->m_no; + if (!check_bit(&m1->m_locked_before_mask, no)) + { + set_bit(&m1->m_locked_before_mask, no); + add_mutex_to_array(&m1->m_locked_before_list, m2); + } +} + +static +void +add_lock_to_mutex_after_list(ndb_mutex_state * m1, NdbMutex* m2) +{ + assert(m1 != m2->m_mutex_state); + unsigned no = m2->m_mutex_state->m_no; + if (!check_bit(&m1->m_locked_after_mask, no)) + { + set_bit(&m1->m_locked_after_mask, no); + add_mutex_to_array(&m1->m_locked_after_list, m2); + } +} + +extern "C" +void +ndb_mutex_locked(NdbMutex* p) +{ + ndb_mutex_state * m = p->m_mutex_state; + ndb_mutex_thr_state * thr = get_thr(); + if (thr == 0) + { + /** + * These are threads not started with NdbThread_Create(...) + * e.g mysql-server threads...ignore these for now + */ + return; + } + + for (unsigned i = 0; i < thr->m_mutexes_locked.m_used; i++) + { + /** + * We want to lock m + * Check that none of the mutex we curreny have locked + * have m in their *before* list + */ + NdbMutex * h = get_element(&thr->m_mutexes_locked, i); + if (check_bit(&h->m_mutex_state->m_locked_before_mask, m->m_no)) + { + abort(); + } + + /** + * Add h to m's list of before-locks + */ + add_lock_to_mutex_before_list(m, h); + + /** + * Add m to h's list of after locks + */ + add_lock_to_mutex_after_list(h->m_mutex_state, p); + } + + add_lock_to_thread(thr, p); +} + +extern "C" +void +ndb_mutex_unlocked(NdbMutex* m) +{ + ndb_mutex_thr_state * thr = get_thr(); + if (thr == 0) + { + /** + * These are threads not started with NdbThread_Create(...) + * e.g mysql-server threads...ignore these for now + */ + return; + } + unsigned pos = thr->m_mutexes_locked.m_used; + assert(pos > 0); + assert(get_element(&thr->m_mutexes_locked, pos-1) == m); + thr->m_mutexes_locked.m_used --; +} + +extern "C" +void +ndb_mutex_try_locked(NdbMutex* p) +{ + +} + +extern "C" +void +ndb_mutex_thread_init(struct ndb_mutex_thr_state* p) +{ + bzero(p, sizeof(* p)); + NdbThread_SetTlsKey(NDB_THREAD_TLS_SELF, p); +} + +extern "C" +void +ndb_mutex_thread_exit() +{ + ndb_mutex_thr_state * thr = get_thr(); + if (thr == 0) + { + /** + * These are threads not started with NdbThread_Create(...) + * e.g mysql-server threads...ignore these for now + */ + return; + } + release(&thr->m_mutexes_locked); +} + +/** + * util + */ +static +void +set_bit(nmdd_mask * mask, unsigned no) +{ + unsigned byte_no = no / 8; + unsigned bit_no = no & 7; + if (byte_no >= mask->m_len) + { + unsigned new_len = mask->m_len + INC_SIZE; + if (byte_no >= new_len) + { + new_len = byte_no + 1; + } + unsigned char * new_arr = (unsigned char*)malloc(new_len); + bzero(new_arr, new_len); + if (mask->m_len != 0) + { + memcpy(new_arr, mask->m_mask, mask->m_len); + free(mask->m_mask); + } + mask->m_len = new_len; + mask->m_mask = new_arr; + } + + mask->m_mask[byte_no] |= (1 << bit_no); +} + +static +void +clear_bit(nmdd_mask * mask, unsigned no) +{ + unsigned byte_no = no / 8; + unsigned bit_no = no & 7; + if (byte_no >= mask->m_len) + { + return; + } + + mask->m_mask[byte_no] &= ~(unsigned char)(1 << bit_no); +} + +static +bool +check_bit(const nmdd_mask * mask, unsigned no) +{ + unsigned byte_no = no / 8; + unsigned bit_no = no & 7; + if (byte_no >= mask->m_len) + { + return false; + } + + return (mask->m_mask[byte_no] & (1 << bit_no)) != 0; +} + +static +void +release(nmdd_mask * mask) +{ + if (mask->m_len != 0) + { + free(mask->m_mask); + } +} + +static +NdbMutex* +get_element(nmdd_mutex_array* arr, unsigned i) +{ + assert(i < arr->m_used); + return arr->m_array[i]; +} + +static +void +add_mutex_to_array(nmdd_mutex_array* arr, NdbMutex* m) +{ + unsigned pos = arr->m_used; + if (arr->m_used == arr->m_array_len) + { + unsigned new_len = arr->m_array_len + INC_SIZE; + NdbMutex** new_arr = (NdbMutex**)malloc(new_len * sizeof(NdbMutex*)); + if (arr->m_array_len != 0) + { + memcpy(new_arr, arr->m_array, arr->m_array_len * sizeof(NdbMutex*)); + free(arr->m_array); + } + arr->m_array = new_arr; + arr->m_array_len = new_len; + } + for (unsigned i = 0; im_used; i++) + assert(arr->m_array[i] != m); + + arr->m_array[pos] = m; + arr->m_used++; +} + +static +void +remove_mutex_from_array(nmdd_mutex_array* arr, NdbMutex* m) +{ + for (unsigned i = 0; i < arr->m_used; i++) + { + unsigned idx = arr->m_used - i - 1; + if (arr->m_array[idx] == m) + { + memmove(arr->m_array+idx, + arr->m_array + idx + 1, + i * sizeof(NdbMutex*)); + arr->m_used--; + return; + } + } + assert(false); +} + +static +void +release(nmdd_mutex_array* arr) +{ + if (arr->m_array_len) + { + free(arr->m_array); + } +} + +static +unsigned +ff(unsigned char b) +{ + for (unsigned i = 0; i<8; i++) + if ((b & (1 << i)) == 0) + return i; + assert(false); +} + +static +unsigned +alloc_mutex_no() +{ + Guard g(&g_mutex_no_mutex); + unsigned no = 0; + + for (unsigned i = 0; i < g_mutex_no_mask.m_len; i++) + { + if (g_mutex_no_mask.m_mask[i] != 255) + { + no = (8 * i) + ff(g_mutex_no_mask.m_mask[i]); + goto found; + } + } + + no = 8 * g_mutex_no_mask.m_len; +found: + set_bit(&g_mutex_no_mask, no); + assert(check_bit(&g_mutex_no_mask, no)); + return no; +} + +static +void +release_mutex_no(unsigned no) +{ + Guard g(&g_mutex_no_mutex); + assert(check_bit(&g_mutex_no_mask, no)); + clear_bit(&g_mutex_no_mask, no); +} + +#endif === added file 'storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.h' --- a/storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.h 1970-01-01 00:00:00 +0000 +++ b/storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.h 2011-09-27 17:28:13 +0000 @@ -0,0 +1,73 @@ +/* + Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef NDB_MUTEX_DEADLOCK_DETECTOR_H +#define NDB_MUTEX_DEADLOCK_DETECTOR_H + +#include + +struct nmdd_mask +{ + unsigned char * m_mask; + unsigned m_len; +}; + +struct nmdd_mutex_array +{ + NdbMutex ** m_array; + unsigned m_used; + unsigned m_array_len; +}; + +struct ndb_mutex_state +{ + struct nmdd_mask m_locked_before_mask; /* mutexes held when locking this mutex */ + struct nmdd_mutex_array m_locked_before_list; /* mutexes held when locking this mutex */ + + struct nmdd_mutex_array m_locked_after_list; /* mutexes locked when holding this mutex*/ + struct nmdd_mask m_locked_after_mask; /* mask (for quick check) */ + + unsigned m_no; /* my mutex "id" (for access in masks) */ +}; + +struct ndb_mutex_thr_state +{ + struct nmdd_mutex_array m_mutexes_locked; +}; + +#ifdef __cplusplus +extern "C" { +#endif + + void NdbMutex_DeadlockDetectorInit(); + void NdbMutex_DeadlockDetectorEnd(); + + void ndb_mutex_created(NdbMutex*); + void ndb_mutex_destoyed(NdbMutex*); + void ndb_mutex_locked(NdbMutex*); + void ndb_mutex_unlocked(NdbMutex*); + void ndb_mutex_try_locked(NdbMutex*); + + void ndb_mutex_thread_init(struct ndb_mutex_thr_state*); + void ndb_mutex_thread_exit(); + +#ifdef __cplusplus +} +#endif + + +#endif === modified file 'storage/ndb/src/common/portlib/NdbThread.c' --- a/storage/ndb/src/common/portlib/NdbThread.c 2011-02-01 23:27:25 +0000 +++ b/storage/ndb/src/common/portlib/NdbThread.c 2011-09-27 17:28:13 +0000 @@ -38,6 +38,10 @@ #include #endif +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR +#include "NdbMutex_DeadlockDetector.h" +#endif + static int g_min_prio = 0; static int g_max_prio = 0; static int g_prio = 0; @@ -65,6 +69,9 @@ struct NdbThread char thread_name[16]; NDB_THREAD_FUNC * func; void * object; +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + struct ndb_mutex_thr_state m_mutex_thr_state; +#endif }; #ifdef NDB_SHM_TRANSPORTER @@ -141,6 +148,11 @@ ndb_thread_wrapper(void* _ss){ void *ret; struct NdbThread * ss = (struct NdbThread *)_ss; settid(ss); + +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + ndb_mutex_thread_init(&ss->m_mutex_thr_state); +#endif + NdbMutex_Lock(g_ndb_thread_mutex); ss->inited = 1; NdbCondition_Signal(g_ndb_thread_condition); @@ -154,6 +166,7 @@ ndb_thread_wrapper(void* _ss){ } } +static struct NdbThread* g_main_thread = 0; struct NdbThread* NdbThread_CreateObject(const char * name) @@ -161,6 +174,15 @@ NdbThread_CreateObject(const char * name struct NdbThread* tmpThread; DBUG_ENTER("NdbThread_Create"); + if (g_main_thread != 0) + { + if (name) + { + strnmov(g_main_thread->thread_name, name, sizeof(tmpThread->thread_name)); + } + DBUG_RETURN(g_main_thread); + } + tmpThread = (struct NdbThread*)NdbMem_Allocate(sizeof(struct NdbThread)); if (tmpThread == NULL) DBUG_RETURN(NULL); @@ -183,7 +205,12 @@ NdbThread_CreateObject(const char * name settid(tmpThread); tmpThread->inited = 1; - return tmpThread; +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + ndb_mutex_thread_init(&tmpThread->m_mutex_thr_state); +#endif + + g_main_thread = tmpThread; + DBUG_RETURN(tmpThread); } struct NdbThread* @@ -239,7 +266,7 @@ NdbThread_Create(NDB_THREAD_FUNC *p_thre tmpThread->object= p_thread_arg; NdbMutex_Lock(g_ndb_thread_mutex); - result = pthread_create(&tmpThread->thread, + result = pthread_create(&tmpThread->thread, &thread_attr, ndb_thread_wrapper, tmpThread); @@ -250,7 +277,7 @@ NdbThread_Create(NDB_THREAD_FUNC *p_thre { NdbMem_Free((char *)tmpThread); NdbMutex_Unlock(g_ndb_thread_mutex); - return 0; + DBUG_RETURN(0); } if (thread_prio == NDB_THREAD_PRIO_HIGH && f_high_prio_set) @@ -471,7 +498,11 @@ NdbThread_LockCPU(struct NdbThread* pThr return error_no; } +#ifndef NDB_MUTEX_DEADLOCK_DETECTOR static pthread_key(void*, tls_keys[NDB_THREAD_TLS_MAX]); +#else +static pthread_key(void*, tls_keys[NDB_THREAD_TLS_MAX + 1]); +#endif void *NdbThread_GetTlsKey(NDB_THREAD_TLS key) { @@ -490,6 +521,10 @@ NdbThread_Init() g_ndb_thread_condition = NdbCondition_Create(); pthread_key_create(&(tls_keys[NDB_THREAD_TLS_JAM]), NULL); pthread_key_create(&(tls_keys[NDB_THREAD_TLS_THREAD]), NULL); +#ifdef NDB_MUTEX_DEADLOCK_DETECTOR + pthread_key_create(&(tls_keys[NDB_THREAD_TLS_MAX]), NULL); +#endif + NdbThread_CreateObject(0); return 0; } === modified file 'storage/ndb/src/common/util/ndb_init.cpp' --- a/storage/ndb/src/common/util/ndb_init.cpp 2011-02-01 23:27:25 +0000 +++ b/storage/ndb/src/common/util/ndb_init.cpp 2011-09-27 17:28:13 +0000 @@ -32,6 +32,8 @@ int g_ndb_init_need_monotonic = 0; static int ndb_init_called = 0; +extern "C" void NdbMutex_SysInit(); +extern "C" void NdbMutex_SysEnd(); extern "C" void NdbCondition_initialize(int need_monotonic); extern "C" void NdbTick_Init(int need_monotonic); extern "C" int NdbThread_Init(); @@ -45,6 +47,7 @@ void ndb_init_internal() { NdbOut_Init(); + NdbMutex_SysInit(); if (!g_ndb_connection_mutex) g_ndb_connection_mutex = NdbMutex_Create(); if (!g_eventLogger) @@ -88,7 +91,6 @@ ndb_init() void ndb_end_internal() { - NdbThread_End(); if (g_ndb_connection_mutex) { NdbMutex_Destroy(g_ndb_connection_mutex); @@ -96,6 +98,9 @@ ndb_end_internal() } if (g_eventLogger) destroy_event_logger(&g_eventLogger); + + NdbThread_End(); + NdbMutex_SysEnd(); } void === modified file 'storage/ndb/src/kernel/vm/ArrayPool.hpp' --- a/storage/ndb/src/kernel/vm/ArrayPool.hpp 2011-06-30 15:59:25 +0000 +++ b/storage/ndb/src/kernel/vm/ArrayPool.hpp 2011-09-27 06:44:06 +0000 @@ -1385,7 +1385,7 @@ UnsafeArrayPool::getPtrForce(ConstPtr template class SafeArrayPool : public ArrayPool { public: - SafeArrayPool(NdbMutex* mutex = 0); + SafeArrayPool(); ~SafeArrayPool(); int lock(); int unlock(); @@ -1393,6 +1393,8 @@ public: void release(Uint32 i); void release(Ptr&); + void setMutex(NdbMutex* mutex = 0); + private: NdbMutex* m_mutex; bool m_mutex_owner; @@ -1403,7 +1405,16 @@ private: template inline -SafeArrayPool::SafeArrayPool(NdbMutex* mutex) +SafeArrayPool::SafeArrayPool() +{ + m_mutex = 0; + m_mutex_owner = false; +} + +template +inline +void +SafeArrayPool::setMutex(NdbMutex* mutex) { if (mutex != 0) { m_mutex = mutex; === modified file 'storage/ndb/src/kernel/vm/Emulator.cpp' --- a/storage/ndb/src/kernel/vm/Emulator.cpp 2011-06-30 15:59:25 +0000 +++ b/storage/ndb/src/kernel/vm/Emulator.cpp 2011-09-27 06:44:06 +0000 @@ -89,6 +89,7 @@ EmulatorData::create(){ theSimBlockList = new SimBlockList(); m_socket_server = new SocketServer(); m_mem_manager = new Ndbd_mem_manager(); + globalData.m_global_page_pool.setMutex(); if (theConfiguration == NULL || theWatchDog == NULL || === modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.cpp' --- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp 2011-09-26 07:43:46 +0000 +++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp 2011-09-28 10:18:35 +0000 @@ -528,8 +528,6 @@ MgmtSrvr::start() { DBUG_ENTER("MgmtSrvr::start"); - Guard g(m_local_config_mutex); - /* Start transporter */ if(!start_transporter(m_local_config)) { === modified file 'storage/ndb/test/ndbapi/testNdbApi.cpp' --- a/storage/ndb/test/ndbapi/testNdbApi.cpp 2011-09-19 12:08:00 +0000 +++ b/storage/ndb/test/ndbapi/testNdbApi.cpp 2011-09-27 05:37:30 +0000 @@ -4580,8 +4580,17 @@ public: m_id(id), m_res(res) { m_res.lock(m_id); } - ~Reserve(){ + + void unlock() { m_res.unlock(m_id); + m_id = 0; + } + + ~Reserve(){ + if (m_id) + { + m_res.unlock(m_id); + } } }; }; @@ -4644,6 +4653,8 @@ int runNdbClusterConnect(NDBT_Context* c { const Uint32 api_nodes = ctx->getProperty("API_NODES"); const Uint32 step_no = step->getStepNo(); + const Uint32 timeout_after_first_alive = ctx->getProperty("TimeoutAfterFirst", + 30); if (step_no > api_nodes) { // Don't run with more threads than API node slots @@ -4652,8 +4663,8 @@ int runNdbClusterConnect(NDBT_Context* c // Get connectstring from main connection char constr[256]; - if(!ctx->m_cluster_connection.get_connectstring(constr, - sizeof(constr))) + if (!ctx->m_cluster_connection.get_connectstring(constr, + sizeof(constr))) { g_err << "Too short buffer for connectstring" << endl; return NDBT_FAILED; @@ -4661,9 +4672,17 @@ int runNdbClusterConnect(NDBT_Context* c Uint32 l = 0; const Uint32 loops = ctx->getNumLoops(); - while (l < loops) + while (l < loops && !ctx->isTestStopped()) { g_info << "loop: " << l << endl; + if (ctx->getProperty("WAIT") > 0) + { + ndbout_c("thread %u waiting", step_no); + ctx->incProperty("WAITING"); + while (ctx->getProperty("WAIT") > 0 && !ctx->isTestStopped()) + NdbSleep_MilliSleep(10); + ndbout_c("thread %u waiting complete", step_no); + } Ndb_cluster_connection con(constr); const int retries = 12; @@ -4679,11 +4698,12 @@ int runNdbClusterConnect(NDBT_Context* c NodeIdReservations::Reserve res(g_reservations, con.node_id()); const int timeout = 30; - const int timeout_after_first_alive = 30; - if (con.wait_until_ready(timeout, timeout_after_first_alive) != 0) + int ret = con.wait_until_ready(timeout, timeout_after_first_alive); + if (! (ret == 0 || (timeout_after_first_alive == 0 && ret > 0))) { g_err << "Cluster connection was not ready, nodeid: " << con.node_id() << endl; + abort(); return NDBT_FAILED; } @@ -4699,12 +4719,153 @@ int runNdbClusterConnect(NDBT_Context* c NdbSleep_MilliSleep(10 + rand() % max_sleep); l++; + res.unlock(); // make sure it's called before ~Ndb_cluster_connection + } + + ctx->incProperty("runNdbClusterConnect_FINISHED"); + + return NDBT_OK; +} + +int +runRestarts(NDBT_Context* ctx, NDBT_Step* step) +{ + int result = NDBT_OK; + Uint32 threads = ctx->getProperty("API_NODES", (unsigned)0); + Uint32 sr = ctx->getProperty("ClusterRestart", (unsigned)0); + Uint32 master = ctx->getProperty("Master", (unsigned)0); + Uint32 slow = ctx->getProperty("SlowNR", (unsigned)0); + NdbRestarter restarter; + + if (restarter.waitClusterStarted() != 0) + { + g_err << "Cluster failed to start" << endl; + return NDBT_FAILED; + } + + if (sr == 0 && restarter.getNumDbNodes() < 2) + return NDBT_OK; + + while (ctx->getProperty("runNdbClusterConnect_FINISHED") < threads + && !ctx->isTestStopped()) + { + ndbout_c("%u %u", + ctx->getProperty("runNdbClusterConnect_FINISHED"), + threads); + if (sr == 0) + { + int id = rand() % restarter.getNumDbNodes(); + int nodeId = restarter.getDbNodeId(id); + if (master == 1) + { + nodeId = restarter.getMasterNodeId(); + } + else if (master == 2) + { + nodeId = restarter.getRandomNotMasterNodeId(rand()); + } + ndbout << "Restart node " << nodeId + << "(master: " << restarter.getMasterNodeId() << ")" + << endl; + if (restarter.restartOneDbNode(nodeId, false, true, true) != 0) + { + g_err << "Failed to restartNextDbNode" << endl; + result = NDBT_FAILED; + break; + } + + if (restarter.waitNodesNoStart(&nodeId, 1)) + { + g_err << "Failed to waitNodesNoStart" << endl; + result = NDBT_FAILED; + break; + } + + if (slow) + { + /** + * Block starting node in sp4 + */ + int dump[] = { 71, 4 }; + restarter.dumpStateOneNode(nodeId, dump, NDB_ARRAY_SIZE(dump)); + } + + if (restarter.startNodes(&nodeId, 1)) + { + g_err << "Failed to start node" << endl; + result = NDBT_FAILED; + break; + } + + if (slow) + { + Uint32 blockTime = 3 * 60 * 1000; + Uint64 end = NdbTick_CurrentMillisecond() + blockTime; + while (ctx->getProperty("runNdbClusterConnect_FINISHED") < threads + && !ctx->isTestStopped() && + NdbTick_CurrentMillisecond() < end) + { + NdbSleep_MilliSleep(100); + } + + // unblock + int dump[] = { 71 }; + restarter.dumpStateOneNode(nodeId, dump, NDB_ARRAY_SIZE(dump)); + } + } + else + { + ndbout << "Blocking threads" << endl; + ctx->setProperty("WAITING", Uint32(0)); + ctx->setProperty("WAIT", 1); + while (ctx->getProperty("WAITING") < + (threads - ctx->getProperty("runNdbClusterConnect_FINISHED")) && + !ctx->isTestStopped()) + { + NdbSleep_MilliSleep(10); + } + + ndbout << "Restart cluster" << endl; + if (restarter.restartAll(NdbRestarter::NRRF_NOSTART | + NdbRestarter::NRRF_ABORT) != 0) + { + g_err << "Failed to restartAll" << endl; + result = NDBT_FAILED; + break; + } + + ctx->setProperty("WAITING", Uint32(0)); + ctx->setProperty("WAIT", Uint32(0)); + + ndbout << "Starting cluster" << endl; + restarter.startAll(); + } + + if (restarter.waitClusterStarted() != 0) + { + g_err << "Cluster failed to start" << endl; + result = NDBT_FAILED; + break; + } + } + + return result; +} + +int runCheckAllNodesStarted(NDBT_Context* ctx, NDBT_Step* step){ + NdbRestarter restarter; + + if (restarter.waitClusterStarted(1) != 0) + { + g_err << "All nodes was not started " << endl; + return NDBT_FAILED; } return NDBT_OK; } + static bool check_connect_no_such_host() { @@ -5040,7 +5201,50 @@ TESTCASE("NdbClusterConnectionConnect", { INITIALIZER(runNdbClusterConnectionConnect); } - +TESTCASE("NdbClusterConnectNR", + "Make sure that every Ndb_cluster_connection get a unique nodeid") +{ + TC_PROPERTY("TimeoutAfterFirst", (Uint32)0); + INITIALIZER(runNdbClusterConnectInit); + STEPS(runNdbClusterConnect, MAX_NODES); + STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong +} +TESTCASE("NdbClusterConnectNR_master", + "Make sure that every Ndb_cluster_connection get a unique nodeid") +{ + TC_PROPERTY("Master", 1); + TC_PROPERTY("TimeoutAfterFirst", (Uint32)0); + INITIALIZER(runNdbClusterConnectInit); + STEPS(runNdbClusterConnect, MAX_NODES); + STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong +} +TESTCASE("NdbClusterConnectNR_non_master", + "Make sure that every Ndb_cluster_connection get a unique nodeid") +{ + TC_PROPERTY("Master", 2); + TC_PROPERTY("TimeoutAfterFirst", (Uint32)0); + INITIALIZER(runNdbClusterConnectInit); + STEPS(runNdbClusterConnect, MAX_NODES); + STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong +} +TESTCASE("NdbClusterConnectNR_slow", + "Make sure that every Ndb_cluster_connection get a unique nodeid") +{ + TC_PROPERTY("Master", 2); + TC_PROPERTY("TimeoutAfterFirst", (Uint32)0); + TC_PROPERTY("SlowNR", 1); + INITIALIZER(runNdbClusterConnectInit); + STEPS(runNdbClusterConnect, MAX_NODES); + STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong +} +TESTCASE("NdbClusterConnectSR", + "Make sure that every Ndb_cluster_connection get a unique nodeid") +{ + TC_PROPERTY("ClusterRestart", (Uint32)1); + INITIALIZER(runNdbClusterConnectInit); + STEPS(runNdbClusterConnect, MAX_NODES); + STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong +} NDBT_TESTSUITE_END(testNdbApi); int main(int argc, const char** argv){ === modified file 'storage/ndb/test/ndbapi/testRestartGci.cpp' --- a/storage/ndb/test/ndbapi/testRestartGci.cpp 2011-06-30 15:59:25 +0000 +++ b/storage/ndb/test/ndbapi/testRestartGci.cpp 2011-09-28 10:04:03 +0000 @@ -546,7 +546,7 @@ int runUpdateVerifyGCI(NDBT_Context* ctx CHECK(rowGci != NULL); /* Define an update op to set the next GCI */ - CHECK(hugoOps.pkUpdateRecord(pNdb, 0, 1, loopCount+1) == 0); + CHECK(hugoOps.pkUpdateRecord(pNdb, 0, 1, (int)(loopCount+1)) == 0); if (hugoOps.execute_Commit(pNdb) != 0) { === modified file 'storage/ndb/test/ndbapi/test_event.cpp' --- a/storage/ndb/test/ndbapi/test_event.cpp 2011-06-30 15:59:25 +0000 +++ b/storage/ndb/test/ndbapi/test_event.cpp 2011-09-28 10:04:03 +0000 @@ -168,7 +168,7 @@ Uint32 setAnyValue(Ndb* ndb, NdbTransact { /* XOR 2 32bit words of transid together */ Uint64 transId = trans->getTransactionId(); - return transId ^ (transId >> 32); + return (Uint32)(transId ^ (transId >> 32)); } bool checkAnyValueTransId(Uint64 transId, Uint32 anyValue) === modified file 'storage/ndb/test/run-test/daily-basic-tests.txt' --- a/storage/ndb/test/run-test/daily-basic-tests.txt 2011-09-09 10:48:14 +0000 +++ b/storage/ndb/test/run-test/daily-basic-tests.txt 2011-09-27 05:37:30 +0000 @@ -1753,3 +1753,24 @@ max-time: 500 cmd: testAsynchMultiwait args: -n AsynchMultiwaitWakeup T1 +# alloc node id +max-time: 500 +cmd: testNdbApi +args: -n NdbClusterConnect T1 + +max-time: 500 +cmd: testNdbApi +args: -n NdbClusterConnectionConnect T1 + +max-time: 500 +cmd: testNdbApi +args: -n NdbClusterConnectNR_non_master T1 + +max-time: 500 +cmd: testNdbApi +args: -n NdbClusterConnectNR_slow T1 + +max-time: 500 +cmd: testNdbApi +args: -n NdbClusterConnectSR T1 + === modified file 'storage/ndb/test/tools/hugoJoin.cpp' --- a/storage/ndb/test/tools/hugoJoin.cpp 2011-04-06 14:16:13 +0000 +++ b/storage/ndb/test/tools/hugoJoin.cpp 2011-09-28 09:54:05 +0000 @@ -192,7 +192,7 @@ int main(int argc, char** argv){ } HugoQueryBuilder builder(&MyNdb, tables.getBase(), mask); builder.setJoinLevel(_depth); - const NdbQueryDef * q = builder.createQuery(&MyNdb); + const NdbQueryDef * q = builder.createQuery(); if (_verbose >= 2) { q->print(); ndbout << endl; No bundle (reason: useless for push emails).