Commit f02562b7 authored by tomas@whalegate.ndb.mysql.com's avatar tomas@whalegate.ndb.mysql.com

Merge whalegate.ndb.mysql.com:/home/tomas/cge-5.1

into  whalegate.ndb.mysql.com:/home/tomas/mysql-5.1-new-ndb-bj
parents 4b0d36cc 79e8f3e4
......@@ -139,6 +139,7 @@ public:
/**
* setField - Set bitfield at given position and length (max 32 bits)
* Note : length == 0 not supported.
*/
static void setField(unsigned size, Uint32 data[],
unsigned pos, unsigned len, Uint32 val);
......@@ -146,6 +147,7 @@ public:
/**
* getField - Get bitfield at given position and length
* Note : length == 0 not supported.
*/
static void getField(unsigned size, const Uint32 data[],
unsigned pos, unsigned len, Uint32 dst[]);
......@@ -918,6 +920,9 @@ BitmaskImpl::getField(unsigned size, const Uint32 src[],
unsigned pos, unsigned len, Uint32 dst[])
{
assert(pos + len <= (size << 5));
assert (len != 0);
if (len == 0)
return;
src += (pos >> 5);
Uint32 offset = pos & 31;
......@@ -937,6 +942,9 @@ BitmaskImpl::setField(unsigned size, Uint32 dst[],
unsigned pos, unsigned len, const Uint32 src[])
{
assert(pos + len <= (size << 5));
assert(len != 0);
if (len == 0)
return;
dst += (pos >> 5);
Uint32 offset = pos & 31;
......
......@@ -317,22 +317,32 @@ TCP_Transporter::doSend() {
// Empty the SendBuffers
bool sent_any = true;
while (m_sendBuffer.dataSize > 0)
{
const char * const sendPtr = m_sendBuffer.sendPtr;
const Uint32 sizeToSend = m_sendBuffer.sendDataSize;
if (sizeToSend > 0){
const int nBytesSent = send(theSocket, sendPtr, sizeToSend, 0);
if (nBytesSent > 0) {
if (nBytesSent > 0)
{
sent_any = true;
m_sendBuffer.bytesSent(nBytesSent);
sendCount ++;
sendSize += nBytesSent;
if(sendCount == reportFreq){
if(sendCount == reportFreq)
{
reportSendLen(get_callback_obj(), remoteNodeId, sendCount, sendSize);
sendCount = 0;
sendSize = 0;
}
} else {
}
else
{
if (nBytesSent < 0 && InetErrno == EAGAIN && sent_any)
break;
// Send failed
#if defined DEBUG_TRANSPORTER
g_eventLogger.error("Send Failure(disconnect==%d) to node = %d nBytesSent = %d "
......
......@@ -20,13 +20,38 @@ void
BitmaskImpl::getFieldImpl(const Uint32 src[],
unsigned shiftL, unsigned len, Uint32 dst[])
{
/* Copy whole words of src to dst, shifting src left
* by shiftL. Undefined bits of the last written dst word
* should be zeroed.
*/
assert(shiftL < 32);
unsigned shiftR = 32 - shiftL;
unsigned undefined = shiftL ? ~0 : 0;
/* Merge first word with previously set bits if there's a shift */
* dst = shiftL ? * dst : 0;
/* Treat the zero-shift case separately to avoid
* trampling or reading past the end of src
*/
if (shiftL == 0)
{
while(len >= 32)
{
* dst++ = * src++;
len -=32;
}
if (len != 0)
{
/* Last word has some bits set */
Uint32 mask= ((1 << len) -1); // 0000111
* dst = (* src) & mask;
}
}
else // shiftL !=0, need to build each word from two words shifted
{
while(len >= 32)
{
* dst++ |= (* src) << shiftL;
......@@ -34,15 +59,21 @@ BitmaskImpl::getFieldImpl(const Uint32 src[],
len -= 32;
}
if(len < shiftR)
/* Have space for shiftR more bits in the current dst word
* is that enough?
*/
if(len <= shiftR)
{
/* Fit the remaining bits in the current dst word */
* dst |= ((* src) & ((1 << len) - 1)) << shiftL;
}
else
{
/* Need to write to two dst words */
* dst++ |= ((* src) << shiftL);
* dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined;
}
}
}
void
......@@ -64,370 +95,23 @@ BitmaskImpl::setFieldImpl(Uint32 dst[],
len -= 32;
}
/* Copy last bits */
Uint32 mask = ((1 << len) -1);
* dst = (* dst & ~mask);
if(len < shiftR)
if(len <= shiftR)
{
/* Remaining bits fit in current word */
* dst |= ((* src++) >> shiftL) & mask;
}
else
{
/* Remaining bits update 2 words */
* dst |= ((* src++) >> shiftL);
* dst |= ((* src) & ((1 << (len - shiftR)) - 1)) << shiftR ;
}
}
#ifdef __TEST_BITMASK__
static
void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
{
printf("b'");
for(unsigned i = 0; i<len; i++)
{
if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
printf("1");
else
printf("0");
if((i & 31) == 31)
printf(" ");
}
}
#define DEBUG 0
#include <Vector.hpp>
static void do_test(int bitmask_size);
int
main(int argc, char** argv)
{
int loops = argc > 1 ? atoi(argv[1]) : 1000;
int max_size = argc > 2 ? atoi(argv[2]) : 1000;
for(int i = 0; i<loops; i++)
do_test(1 + (rand() % max_size));
}
struct Alloc
{
Uint32 pos;
Uint32 size;
Vector<Uint32> data;
};
static void require(bool b)
{
if(!b) abort();
}
static
bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
{
Uint32 sz32 = (len + 31) >> 5;
for(int i = 0; i<len; i++)
{
if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
return false;
}
return true;
}
static int val_pos = 0;
static int val[] = { 384, 241, 32,
1,1,1,1, 0,0,0,0, 1,1,1,1, 0,0,0,0,
241 };
static int lrand()
{
#if 0
return val[val_pos++];
#else
return rand();
#endif
}
static
void rand(Uint32 dst[], Uint32 len)
{
for(int i = 0; i<len; i++)
BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
}
static
void simple(int pos, int size)
{
ndbout_c("simple pos: %d size: %d", pos, size);
Vector<Uint32> _mask;
Vector<Uint32> _src;
Vector<Uint32> _dst;
Uint32 sz32 = (size + pos + 32) >> 5;
const Uint32 sz = 4 * sz32;
Uint32 zero = 0;
_mask.fill(sz32+1, zero);
_src.fill(sz32+1, zero);
_dst.fill(sz32+1, zero);
Uint32 * src = _src.getBase();
Uint32 * dst = _dst.getBase();
Uint32 * mask = _mask.getBase();
memset(src, 0x0, sz);
memset(dst, 0x0, sz);
memset(mask, 0xFF, sz);
rand(src, size);
BitmaskImpl::setField(sz32, mask, pos, size, src);
BitmaskImpl::getField(sz32, mask, pos, size, dst);
printf("src: "); print(src, size+31); printf("\n");
printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
printf("dst: "); print(dst, size+31); printf("\n");
require(cmp(src, dst, size+31));
};
static
void simple2(int size, int loops)
{
ndbout_c("simple2 %d - ", size);
Vector<Uint32> _mask;
Vector<Uint32> _src;
Vector<Uint32> _dst;
Uint32 sz32 = (size + 32) >> 5;
Uint32 sz = sz32 << 2;
Uint32 zero = 0;
_mask.fill(sz32+1, zero);
_src.fill(sz32+1, zero);
_dst.fill(sz32+1, zero);
Uint32 * src = _src.getBase();
Uint32 * dst = _dst.getBase();
Uint32 * mask = _mask.getBase();
Vector<Uint32> save;
for(int i = 0; i<loops; i++)
{
memset(mask, 0xFF, sz);
memset(dst, 0xFF, sz);
int len;
int pos = 0;
while(pos+1 < size)
{
memset(src, 0xFF, sz);
while(!(len = rand() % (size - pos)));
BitmaskImpl::setField(sz32, mask, pos, len, src);
if(memcmp(dst, mask, sz))
{
ndbout_c("pos: %d len: %d", pos, len);
print(mask, size);
abort();
}
printf("[ %d %d ]", pos, len);
save.push_back(pos);
save.push_back(len);
pos += len;
}
for(int j = 0; j<save.size(); )
{
pos = save[j++];
len = save[j++];
memset(src, 0xFF, sz);
BitmaskImpl::getField(sz32, mask, pos, len, src);
if(memcmp(dst, src, sz))
{
ndbout_c("pos: %d len: %d", pos, len);
printf("src: "); print(src, size); printf("\n");
printf("dst: "); print(dst, size); printf("\n");
printf("msk: "); print(mask, size); printf("\n");
abort();
}
}
ndbout_c("");
}
}
static void
do_test(int bitmask_size)
{
#if 1
simple(rand() % 33, (rand() % 63)+1);
//#else
Vector<Alloc> alloc_list;
bitmask_size = (bitmask_size + 31) & ~31;
Uint32 sz32 = (bitmask_size >> 5);
Vector<Uint32> alloc_mask;
Vector<Uint32> test_mask;
ndbout_c("Testing bitmask of size %d", bitmask_size);
Uint32 zero = 0;
alloc_mask.fill(sz32, zero);
test_mask.fill(sz32, zero);
for(int i = 0; i<5000; i++)
{
Vector<Uint32> tmp;
tmp.fill(sz32, zero);
int pos = lrand() % (bitmask_size - 1);
int free = 0;
if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
{
// Bit was allocated
// 1) Look up allocation
// 2) Check data
// 3) free it
size_t j;
int min, max;
for(j = 0; j<alloc_list.size(); j++)
{
min = alloc_list[j].pos;
max = min + alloc_list[j].size;
if(pos >= min && pos < max)
{
break;
}
}
require(pos >= min && pos < max);
BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
tmp.getBase());
if(DEBUG)
{
printf("freeing [ %d %d ]", min, max);
printf("- mask: ");
print(tmp.getBase(), max - min);
printf(" save: ");
size_t k;
Alloc& a = alloc_list[j];
for(k = 0; k<a.data.size(); k++)
printf("%.8x ", a.data[k]);
printf("\n");
}
int bytes = (max - min + 7) >> 3;
if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
{
abort();
}
while(min < max)
BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
alloc_list.erase(j);
}
else
{
Vector<Uint32> tmp;
tmp.fill(sz32, zero);
// Bit was free
// 1) Check how much space is avaiable
// 2) Create new allocation of lrandom size
// 3) Fill data with lrandom data
// 4) Update alloc mask
while(pos+free < bitmask_size &&
!BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
free++;
Uint32 sz =
(free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
sz = sz ? sz : 1;
sz = pos + sz == bitmask_size ? sz - 1 : sz;
Alloc a;
a.pos = pos;
a.size = sz;
a.data.fill(((sz+31)>> 5)-1, zero);
if(DEBUG)
printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
for(size_t j = 0; j<sz; j++)
{
BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
if((lrand() % 1000) > 500)
BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
}
if(DEBUG)
{
printf("- mask: ");
print(a.data.getBase(), sz);
printf("\n");
}
BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
a.data.getBase());
alloc_list.push_back(a);
}
}
for(Uint32 i = 0; i<1000; i++)
{
Uint32 sz32 = 10+rand() % 100;
Uint32 zero = 0;
Vector<Uint32> map;
map.fill(sz32, zero);
Uint32 sz = 32 * sz32;
Uint32 start = (rand() % sz);
Uint32 stop = start + ((rand() % (sz - start)) & 0xFFFFFFFF);
Vector<Uint32> check;
check.fill(sz32, zero);
for(Uint32 j = 0; j<sz; j++)
{
bool expect = (j >= start && j<stop);
if(expect)
BitmaskImpl::set(sz32, check.getBase(), j);
}
BitmaskImpl::set(sz32, map.getBase(), start, stop);
if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
{
ndbout_c(" FAIL sz: %d [ %d %d ]", sz, start, stop);
printf("check: ");
for(Uint32 j = 0; j<sz32; j++)
printf("%.8x ", check[j]);
printf("\n");
printf("map : ");
for(Uint32 j = 0; j<sz32; j++)
printf("%.8x ", map[j]);
printf("\n");
abort();
}
map.clear();
check.clear();
Uint32 one = ~(Uint32)0;
map.fill(sz32, one);
check.fill(sz32, one);
for(Uint32 j = 0; j<sz; j++)
{
bool expect = (j >= start && j<stop);
if(expect)
BitmaskImpl::clear(sz32, check.getBase(), j);
}
BitmaskImpl::clear(sz32, map.getBase(), start, stop);
if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
{
ndbout_c(" FAIL sz: %d [ %d %d ]", sz, start, stop);
printf("check: ");
for(Uint32 j = 0; j<sz32; j++)
printf("%.8x ", check[j]);
printf("\n");
printf("map : ");
for(Uint32 j = 0; j<sz32; j++)
printf("%.8x ", map[j]);
printf("\n");
abort();
}
}
#endif
}
template class Vector<Alloc>;
template class Vector<Uint32>;
#endif
/* Bitmask testcase code moved from here to
* storage/ndb/test/ndbapi/testBitfield.cpp
* to get coverage from automated testing
*/
......@@ -11,9 +11,10 @@ Next CMVMI 9000
Next BACKUP 10038
Next DBUTIL 11002
Next DBTUX 12008
Next SUMA 13034
Next SUMA 13036
Next LGMAN 15001
Next TSMAN 16001
Next SUMA 13034
TESTING NODE FAILURE, ARBITRATION
---------------------------------
......
......@@ -4908,6 +4908,21 @@ Suma::release_gci(Signal* signal, Uint32 buck, Uint32 gci)
if(gci >= head.m_max_gci)
{
jam();
if (ERROR_INSERTED(13034))
{
jam();
SET_ERROR_INSERT_VALUE(13035);
return;
}
if (ERROR_INSERTED(13035))
{
CLEAR_ERROR_INSERT_VALUE;
NodeReceiverGroup rg(CMVMI, c_nodes_in_nodegroup_mask);
rg.m_nodes.clear(getOwnNodeId());
signal->theData[0] = 9999;
sendSignal(rg, GSN_NDB_TAMPER, signal, 1, JBA);
return;
}
head.m_page_pos = 0;
head.m_max_gci = gci;
head.m_last_gci = 0;
......@@ -4979,7 +4994,6 @@ Suma::start_resend(Signal* signal, Uint32 buck)
if(min > max)
{
ndbrequire(pos.m_page_pos <= 2);
ndbrequire(pos.m_page_id == bucket->m_buffer_tail);
m_active_buckets.set(buck);
m_gcp_complete_rep_count ++;
......
/* Copyright (C) 2003 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; 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 */
#ifndef ATRT_CLIENT_HPP
#define ATRT_CLIENT_HPP
#include <DbUtil.hpp>
class AtrtClient: public DbUtil {
public:
enum AtrtCommandType {
ATCT_CHANGE_VERSION= 1,
ATCT_RESET_PROC= 2
};
AtrtClient(const char* _user= "root",
const char* _password= "",
const char* _suffix= ".1.atrt");
AtrtClient(MYSQL*);
~AtrtClient();
// Command functions
bool changeVersion(int process_id, const char* process_args);
bool resetProc(int process_id);
// Query functions
bool getConnectString(int cluster_id, SqlResultSet& result);
bool getClusters(SqlResultSet& result);
bool getMgmds(int cluster_id, SqlResultSet& result);
bool getNdbds(int cluster_id, SqlResultSet& result);
private:
int writeCommand(AtrtCommandType _type,
const Properties& args);
bool readCommand(uint command_id,
SqlResultSet& result);
bool doCommand(AtrtCommandType _type,
const Properties& args);
};
#endif
......@@ -19,17 +19,11 @@
#ifndef DBUTIL_HPP
#define DBUTIL_HPP
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <NDBT.hpp>
#include <BaseString.hpp>
#include <Properties.hpp>
#include <Vector.hpp>
#include <mysql.h>
//include "rand.h"
#include <stdlib.h>
#include "BaseString.hpp"
#include "NDBT.hpp"
//#define DEBUG
#define DIE_UNLESS(expr) \
......@@ -52,8 +46,41 @@ if (r) \
DIE_UNLESS(r == 0);\
}
#define DBU_TRUE 1
#define DBU_FALSE 0
class SqlResultSet : public Properties {
public:
// Get row with number
bool get_row(int row_num);
// Load next row
bool next(void);
// Reset iterator
void reset(void);
// Remove current row from resultset
void remove();
SqlResultSet();
~SqlResultSet();
const char* column(const char* col_name);
uint columnAsInt(const char* col_name);
uint insertId();
uint affectedRows();
uint numRows(void);
uint mysqlErrno();
const char* mysqlError();
const char* mysqlSqlstate();
private:
uint get_int(const char* name);
const char* get_string(const char* name);
const Properties* m_curr_row;
uint m_curr_row_num;
};
#define DBU_FAILED 1
#define DBU_OK 0
......@@ -61,11 +88,23 @@ class DbUtil
{
public:
/* Deprecated, see DbUtil(dbname, suffix) */
DbUtil(const char * databaseName);
DbUtil(const char* dbname, const char* suffix = NULL);
DbUtil(MYSQL* mysql);
DbUtil(const char* dbname = "mysql",
const char* user = "root",
const char* pass = "",
const char* suffix = NULL);
~DbUtil();
bool doQuery(const char* query);
bool doQuery(const char* query, SqlResultSet& result);
bool doQuery(const char* query, const Properties& args, SqlResultSet& result);
bool doQuery(BaseString& str);
bool doQuery(BaseString& str, SqlResultSet& result);
bool doQuery(BaseString& str, const Properties& args, SqlResultSet& result);
bool waitConnected(int timeout);
/* Deprecated, see connect() */
void databaseLogin(const char * system,
const char * usr,
......@@ -79,25 +118,35 @@ public:
const char * getPassword(){return m_pass.c_str();};
const char * getHost() {return m_host.c_str();};
const char * getSocket() {return m_socket.c_str();};
const char * getServerType(){return mysql_get_server_info(mysql);};
const char * getServerType(){return mysql_get_server_info(m_mysql);};
const char * getError();
MYSQL * getMysql(){return mysql;};
MYSQL * getMysql(){return m_mysql;};
MYSQL_STMT * STDCALL mysqlSimplePrepare(const char *query);
void databaseLogout();
void mysqlCloseStmHandle(MYSQL_STMT *my_stmt);
int connect();
void disconnect();
int selectDb();
int selectDb(const char *);
int createDb(BaseString&);
int doQuery(BaseString&);
int doQuery(const char *);
int getErrorNumber();
unsigned long selectCountTable(const char * table);
protected:
bool runQuery(const char* query,
const Properties& args,
SqlResultSet& rows);
bool isConnected();
MYSQL * m_mysql;
bool m_free_mysql; /* Don't free mysql* if allocated elsewhere */
private:
bool m_connected;
......@@ -107,15 +156,11 @@ private:
BaseString m_pass; // MySQL User Password
BaseString m_dbname; // Database to use
BaseString m_socket; // MySQL Server Unix Socket
BaseString default_file;
BaseString default_group;
BaseString m_default_file;
BaseString m_default_group;
unsigned int m_port; // MySQL Server port
MYSQL * mysql;
MYSQL_RES * m_result;
MYSQL_ROW m_row;
void setDbName(const char * name){m_dbname.assign(name);};
void setUser(const char * user_name){m_user.assign(user_name);};
void setPassword(const char * password){m_pass.assign(password);};
......
......@@ -52,7 +52,9 @@ testBitfield \
DbCreate DbAsyncGenerator \
testSRBank \
test_event_merge \
testIndexStat
testIndexStat \
testNDBT \
NdbRepStress
EXTRA_PROGRAMS = \
test_event \
......@@ -98,7 +100,10 @@ ndbapi_slow_select_SOURCES = slow_select.cpp
testReadPerf_SOURCES = testReadPerf.cpp
testLcp_SOURCES = testLcp.cpp
testPartitioning_SOURCES = testPartitioning.cpp
testNDBT_SOURCES = testNDBT.cpp
testNDBT_LDADD = $(LDADD) $(top_srcdir)/libmysql_r/libmysqlclient_r.la
testBitfield_SOURCES = testBitfield.cpp
NdbRepStress_SOURCES = acrt/NdbRepStress.cpp
DbCreate_SOURCES = bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp bench/dbPopulate.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
DbAsyncGenerator_SOURCES = bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
testSRBank_SOURCES = testSRBank.cpp
......@@ -115,8 +120,10 @@ include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am
##testIndex_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel
##testSystemRestart_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel
##testTransactions_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel
NdbRepStress_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/test/include -I$(top_srcdir)/include
testBackup_LDADD = $(LDADD) bank/libbank.a
testSRBank_LDADD = bank/libbank.a $(LDADD)
NdbRepStress_LDADD = $(LDADD) $(top_builddir)/libmysql_r/libmysqlclient_r.la
# Don't update the files from bitkeeper
%::SCCS/s.%
......
......@@ -4,6 +4,8 @@
#include <NDBT.hpp>
#include <NdbApi.hpp>
#include <HugoTransactions.hpp>
#include <Bitmask.hpp>
#include <Vector.hpp>
static const char* _dbname = "TEST_DB";
static int g_loops = 7;
......@@ -37,6 +39,7 @@ static int unique_indexes(Ndb*, const NdbDictionary::Table* tab);
static int ordered_indexes(Ndb*, const NdbDictionary::Table* tab);
static int node_restart(Ndb*, const NdbDictionary::Table* tab);
static int system_restart(Ndb*, const NdbDictionary::Table* tab);
static int testBitmask();
int
main(int argc, char** argv){
......@@ -49,6 +52,15 @@ main(int argc, char** argv){
ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
int res = NDBT_FAILED;
/* Run cluster-independent tests */
for (int i=0; i<(10*g_loops); i++)
{
if (NDBT_OK != (res= testBitmask()))
return NDBT_ProgramExit(res);
}
Ndb_cluster_connection con(opt_connect_str);
if(con.connect(12, 5, 1))
{
......@@ -60,7 +72,6 @@ main(int argc, char** argv){
pNdb = new Ndb(&con, _dbname);
pNdb->init();
while (pNdb->waitUntilReady() != 0);
int res = NDBT_FAILED;
NdbDictionary::Dictionary * dict = pNdb->getDictionary();
......@@ -121,14 +132,12 @@ create_random_table(Ndb* pNdb)
do {
NdbDictionary::Table tab;
Uint32 cols = 1 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE - 1));
Uint32 keys = NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY;
Uint32 length = 4090;
Uint32 key_size = NDB_MAX_KEYSIZE_IN_WORDS;
BaseString name;
name.assfmt("TAB_%d", rand() & 65535);
tab.setName(name.c_str());
for(int i = 0; i<cols && length > 2; i++)
for(Uint32 i = 0; i<cols && length > 2; i++)
{
NdbDictionary::Column col;
name.assfmt("COL_%d", i);
......@@ -206,3 +215,394 @@ system_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
{
return 0;
}
/* Note : folowing classes test functionality of storage/ndb/src/common/util/Bitmask.cpp
* and were originally defined there.
* Set BITMASK_DEBUG to 1 to get more test debugging info.
*/
#define BITMASK_DEBUG 0
static
bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
{
Uint32 sz32 = (len + 31) >> 5;
for(Uint32 i = 0; i<len; i++)
{
if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
return false;
}
return true;
}
static
void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
{
printf("b'");
for(unsigned i = 0; i<len; i++)
{
if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
printf("1");
else
printf("0");
if((i & 31) == 31)
printf(" ");
}
}
static int lrand()
{
return rand();
}
static
void rand(Uint32 dst[], Uint32 len)
{
for(Uint32 i = 0; i<len; i++)
BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
}
static
int checkNoTramplingGetSetField(const Uint32 totalTests)
{
const Uint32 numWords= 67;
const Uint32 maxBitsToCopy= (numWords * 32);
Uint32 sourceBuf[numWords];
Uint32 targetBuf[numWords];
ndbout << "Testing : Bitmask NoTrampling\n";
memset(sourceBuf, 0x00, (numWords*4));
for (Uint32 test=0; test<totalTests; test++)
{
/* Always copy at least 1 bit */
Uint32 srcStart= rand() % (maxBitsToCopy -1);
Uint32 length= (rand() % ((maxBitsToCopy -1) - srcStart)) + 1;
if (BITMASK_DEBUG)
ndbout << "Testing start %u, length %u \n"
<< srcStart
<< length;
// Set target to all ones.
memset(targetBuf, 0xff, (numWords*4));
BitmaskImpl::getField(numWords, sourceBuf, srcStart, length, targetBuf);
// Check that there is no trampling
Uint32 firstUntrampledWord= (length + 31)/32;
for (Uint32 word=0; word< numWords; word++)
{
Uint32 targetWord= targetBuf[word];
if (BITMASK_DEBUG)
ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
<< word << targetWord << firstUntrampledWord;
if (! (word < firstUntrampledWord) ?
(targetWord == 0) :
(targetWord == 0xffffffff))
{
ndbout << "Notrampling getField failed for srcStart "
<< srcStart
<< " length " << length
<< " at word " << word << "\n";
ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
<< word << targetWord << firstUntrampledWord;
return -1;
}
}
/* Set target back to all ones. */
memset(targetBuf, 0xff, (numWords*4));
BitmaskImpl::setField(numWords, targetBuf, srcStart, length, sourceBuf);
/* Check we've got all ones, with zeros only where expected */
for (Uint32 word=0; word< numWords; word++)
{
Uint32 targetWord= targetBuf[word];
for (Uint32 bit=0; bit< 32; bit++)
{
Uint32 bitNum= (word << 5) + bit;
bool expectedValue= !((bitNum >= srcStart) &&
(bitNum < (srcStart + length)));
bool actualValue= (((targetWord >> bit) & 1) == 1);
if (BITMASK_DEBUG)
ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
<< bitNum << expectedValue << actualValue;
if (actualValue != expectedValue)
{
ndbout << "Notrampling setField failed for srcStart "
<< srcStart
<< " length " << length
<< " at word " << word << " bit " << bit << "\n";
ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
<< bitNum << expectedValue << actualValue;
return -1;
}
}
}
}
return 0;
}
static
int simple(int pos, int size)
{
ndbout << "Testing : Bitmask simple pos: " << pos << " size: " << size << "\n";
Vector<Uint32> _mask;
Vector<Uint32> _src;
Vector<Uint32> _dst;
Uint32 sz32 = (size + pos + 32) >> 5;
const Uint32 sz = 4 * sz32;
Uint32 zero = 0;
_mask.fill(sz32+1, zero);
_src.fill(sz32+1, zero);
_dst.fill(sz32+1, zero);
Uint32 * src = _src.getBase();
Uint32 * dst = _dst.getBase();
Uint32 * mask = _mask.getBase();
memset(src, 0x0, sz);
memset(dst, 0x0, sz);
memset(mask, 0xFF, sz);
rand(src, size);
BitmaskImpl::setField(sz32, mask, pos, size, src);
BitmaskImpl::getField(sz32, mask, pos, size, dst);
if (BITMASK_DEBUG)
{
printf("src: "); print(src, size+31); printf("\n");
printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
printf("dst: "); print(dst, size+31); printf("\n");
}
return (cmp(src, dst, size+31)?0 : -1);
};
struct Alloc
{
Uint32 pos;
Uint32 size;
Vector<Uint32> data;
};
static
int
testRanges(Uint32 bitmask_size)
{
Vector<Alloc> alloc_list;
bitmask_size = (bitmask_size + 31) & ~31;
Uint32 sz32 = (bitmask_size >> 5);
Vector<Uint32> alloc_mask;
Vector<Uint32> test_mask;
ndbout_c("Testing : Bitmask ranges for bitmask of size %d", bitmask_size);
Uint32 zero = 0;
alloc_mask.fill(sz32, zero);
test_mask.fill(sz32, zero);
/* Loop a number of times, setting and clearing bits in the mask
* and tracking the modifications in a separate structure.
* Check that both structures remain in sync
*/
for(int i = 0; i<5000; i++)
{
Vector<Uint32> tmp;
tmp.fill(sz32, zero);
Uint32 pos = lrand() % (bitmask_size - 1);
Uint32 free = 0;
if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
{
// Bit was allocated
// 1) Look up allocation
// 2) Check data
// 3) free it
size_t j;
Uint32 min, max;
for(j = 0; j<alloc_list.size(); j++)
{
min = alloc_list[j].pos;
max = min + alloc_list[j].size;
if(pos >= min && pos < max)
{
break;
}
}
if (! ((pos >= min) && (pos < max)))
{
printf("Failed with pos %u, min %u, max %u\n",
pos, min, max);
return -1;
}
BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
tmp.getBase());
if(BITMASK_DEBUG)
{
printf("freeing [ %d %d ]", min, max);
printf("- mask: ");
print(tmp.getBase(), max - min);
printf(" save: ");
size_t k;
Alloc& a = alloc_list[j];
for(k = 0; k<a.data.size(); k++)
printf("%.8x ", a.data[k]);
printf("\n");
}
if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
{
return -1;
}
while(min < max)
BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
alloc_list.erase(j);
}
else
{
Vector<Uint32> tmp;
tmp.fill(sz32, zero);
// Bit was free
// 1) Check how much space is avaiable
// 2) Create new allocation of lrandom size
// 3) Fill data with lrandom data
// 4) Update alloc mask
while(pos+free < bitmask_size &&
!BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
free++;
Uint32 sz =
(free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
sz = sz ? sz : 1;
sz = pos + sz == bitmask_size ? sz - 1 : sz;
Alloc a;
a.pos = pos;
a.size = sz;
a.data.fill(((sz+31)>> 5)-1, zero);
if(BITMASK_DEBUG)
printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
for(size_t j = 0; j<sz; j++)
{
BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
if((lrand() % 1000) > 500)
BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
}
if(BITMASK_DEBUG)
{
printf("- mask: ");
print(a.data.getBase(), sz);
printf("\n");
}
BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
a.data.getBase());
alloc_list.push_back(a);
}
}
#define NDB_BM_SUPPORT_RANGE
#ifdef NDB_BM_SUPPORT_RANGE
for(Uint32 i = 0; i<1000; i++)
{
Uint32 sz32 = 10+rand() % 100;
Uint32 zero = 0;
Vector<Uint32> map;
map.fill(sz32, zero);
Uint32 sz = 32 * sz32;
Uint32 start = (rand() % sz);
Uint32 stop = start + ((rand() % (sz - start)) & 0xFFFFFFFF);
Vector<Uint32> check;
check.fill(sz32, zero);
/* Verify range setting method works correctly */
for(Uint32 j = 0; j<sz; j++)
{
bool expect = (j >= start && j<stop);
if(expect)
BitmaskImpl::set(sz32, check.getBase(), j);
}
BitmaskImpl::set_range(sz32, map.getBase(), start, stop);
if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
{
ndbout_c(" FAIL 1 sz: %d [ %d %d ]", sz, start, stop);
printf("check: ");
for(Uint32 j = 0; j<sz32; j++)
printf("%.8x ", check[j]);
printf("\n");
printf("map : ");
for(Uint32 j = 0; j<sz32; j++)
printf("%.8x ", map[j]);
printf("\n");
return -1;
}
map.clear();
check.clear();
/* Verify range clearing method works correctly */
Uint32 one = ~(Uint32)0;
map.fill(sz32, one);
check.fill(sz32, one);
for(Uint32 j = 0; j<sz; j++)
{
bool expect = (j >= start && j<stop);
if(expect)
BitmaskImpl::clear(sz32, check.getBase(), j);
}
BitmaskImpl::clear_range(sz32, map.getBase(), start, stop);
if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
{
ndbout_c(" FAIL 2 sz: %d [ %d %d ]", sz, start, stop);
printf("check: ");
for(Uint32 j = 0; j<sz32; j++)
printf("%.8x ", check[j]);
printf("\n");
printf("map : ");
for(Uint32 j = 0; j<sz32; j++)
printf("%.8x ", map[j]);
printf("\n");
return -1;
}
}
#endif
return 0;
}
static
int
testBitmask()
{
/* Some testcases from storage/ndb/src/common/util/Bitmask.cpp */
int res= 0;
if ((res= checkNoTramplingGetSetField(100 /* totalTests */)) != 0)
return res;
if ((res= simple(rand() % 33, // position
(rand() % 63)+1) // size
) != 0)
return res;
if ((res= testRanges(1+(rand() % 1000) // bitmask size
)) != 0)
return res;
return 0;
}
template class Vector<Alloc>;
template class Vector<Uint32>;
/* Copyright (C) 2003 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; 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 <NDBT.hpp>
#include <NDBT_Test.hpp>
#include <DbUtil.hpp>
#include <AtrtClient.hpp>
int runTestAtrtClient(NDBT_Context* ctx, NDBT_Step* step){
AtrtClient atrt;
SqlResultSet clusters;
if (!atrt.getClusters(clusters))
return NDBT_FAILED;
int i= 0;
while(clusters.next())
{
ndbout << clusters.column("name") << endl;
if (i++ == 1){
ndbout << "removing: " << clusters.column("name") << endl;
clusters.remove();
}
}
clusters.reset();
while(clusters.next())
{
ndbout << clusters.column("name") << endl;
}
return NDBT_OK;
}
int runTestDbUtil(NDBT_Context* ctx, NDBT_Step* step){
DbUtil sql;
{
// Select all rows from mysql.user
SqlResultSet result;
if (!sql.doQuery("SELECT * FROM mysql.user", result))
return NDBT_FAILED;
// result.print();
while(result.next())
{
ndbout << result.column("host") << ", "
<< result.column("uSer") << ", "
<< result.columnAsInt("max_updates") << ", "
<< endl;
}
result.reset();
while(result.next())
{
ndbout << result.column("host") << endl;
}
}
{
// No column name, query should fail
Properties args;
SqlResultSet result;
if (sql.doQuery("SELECT * FROM mysql.user WHERE name=?", args, result))
return NDBT_FAILED;
result.print();
}
{
// Select nonexisiting rows from mysql.user
Properties args;
SqlResultSet result;
args.put("0", "no_such_host");
if (!sql.doQuery("SELECT * FROM mysql.user WHERE host=?", args, result))
return NDBT_FAILED;
ndbout << "no rows" << endl;
result.print();
// Change args to an find one row
args.clear();
args.put("0", "localhost");
if (!sql.doQuery("SELECT host, user FROM mysql.user WHERE host=?",
args, result))
return NDBT_FAILED;
result.print();
}
{
if (!sql.doQuery("CREATE TABLE sql_client_test (a int, b varchar(255))"))
return NDBT_FAILED;
if (!sql.doQuery("INSERT INTO sql_client_test VALUES(1, 'hello'), (2, 'bye')"))
return NDBT_FAILED;
// Select all rows from sql_client_test
SqlResultSet result;
if (!sql.doQuery("SELECT * FROM sql_client_test", result))
return NDBT_FAILED;
// result.print();
while(result.next())
{
}
// Select second row from sql_client_test
Properties args;
args.put("0", 2);
if (!sql.doQuery("SELECT * FROM sql_client_test WHERE a=?", args,result))
return NDBT_FAILED;
result.print();
result.reset();
while(result.next())
{
ndbout << "a: " << result.columnAsInt("a") << endl;
ndbout << "b: " << result.column("b") << endl;
if (result.columnAsInt("a") != 2){
ndbout << "hepp1" << endl;
return NDBT_FAILED;
}
if (strcmp(result.column("b"), "bye")){
ndbout << "hepp2" << endl;
return NDBT_FAILED;
}
}
if (sql.selectCountTable("sql_client_test") != 2)
{
ndbout << "Got wrong count" << endl;
return NDBT_FAILED;
}
if (!sql.doQuery("DROP TABLE sql_client_test"))
return NDBT_FAILED;
}
return NDBT_OK;
}
NDBT_TESTSUITE(testNDBT);
TESTCASE("AtrtClient",
"Test AtrtClient class"){
INITIALIZER(runTestAtrtClient);
}
TESTCASE("DbUtil",
"Test DbUtil class"){
INITIALIZER(runTestDbUtil);
}
NDBT_TESTSUITE_END(testNDBT);
int main(int argc, const char** argv){
ndb_init();
return testNDBT.execute(argc, argv);
}
......@@ -1838,6 +1838,61 @@ runBug31701(NDBT_Context* ctx, NDBT_Step* step)
return NDBT_OK;
}
int
runBug33793(NDBT_Context* ctx, NDBT_Step* step)
{
int result = NDBT_OK;
int loops = ctx->getNumLoops();
NdbRestarter restarter;
if (restarter.getNumDbNodes() < 2){
ctx->stopTest();
return NDBT_OK;
}
// This should really wait for applier to start...10s is likely enough
NdbSleep_SecSleep(10);
while (loops-- && ctx->isTestStopped() == false)
{
int nodeId = restarter.getDbNodeId(rand() % restarter.getNumDbNodes());
int nodecount = 0;
int nodes[255];
printf("nodeid: %u : victims: ", nodeId);
for (int i = 0; i<restarter.getNumDbNodes(); i++)
{
int id = restarter.getDbNodeId(i);
if (id == nodeId)
continue;
if (restarter.getNodeGroup(id) == restarter.getNodeGroup(nodeId))
{
nodes[nodecount++] = id;
printf("%u ", id);
int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
if (restarter.dumpStateOneNode(id, val2, 2))
return NDBT_FAILED;
}
}
printf("\n"); fflush(stdout);
restarter.insertErrorInNode(nodeId, 13034);
if (restarter.waitNodesNoStart(nodes, nodecount))
return NDBT_FAILED;
if (restarter.startNodes(nodes, nodecount))
return NDBT_FAILED;
if (restarter.waitClusterStarted())
return NDBT_FAILED;
}
ctx->stopTest();
return NDBT_OK;
}
NDBT_TESTSUITE(test_event);
TESTCASE("BasicEventOperation",
"Verify that we can listen to Events"
......@@ -1975,6 +2030,12 @@ TESTCASE("Bug31701", ""){
FINALIZER(runDropEvent);
FINALIZER(runDropShadowTable);
}
TESTCASE("Bug33793", ""){
INITIALIZER(runCreateEvent);
STEP(runEventListenerUntilStopped);
STEP(runBug33793);
FINALIZER(runDropEvent);
}
NDBT_TESTSUITE_END(test_event);
int main(int argc, const char** argv){
......
......@@ -1046,3 +1046,7 @@ max-time: 300
cmd: testSystemRestart
args: -n Bug22696 T1
max-time: 300
cmd: test_event
args: -n Bug33793 T1
/* Copyright (C) 2008 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; 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 <AtrtClient.hpp>
#include <NDBT_Output.hpp>
#include <NdbSleep.h>
AtrtClient::AtrtClient(const char* _user,
const char* _password,
const char* _group_suffix)
: DbUtil(_user, _password, _group_suffix)
{
}
AtrtClient::AtrtClient(MYSQL* mysql)
: DbUtil(mysql)
{
}
AtrtClient::~AtrtClient(){
}
int
AtrtClient::writeCommand(AtrtCommandType _type,
const Properties& args){
if (!isConnected())
return false;
BaseString sql;
sql.assfmt("INSERT command ( ");
const char* name;
{
Properties::Iterator iter(&args);
while((name= iter.next())){
sql.appfmt("%s, ", name);
}
}
sql.appfmt(" state, cmd) VALUES (");
{
Properties::Iterator iter(&args);
while((name= iter.next())){
PropertiesType t;
Uint32 val_i;
BaseString val_s;
args.getTypeOf(name, &t);
switch(t) {
case PropertiesType_Uint32:
args.get(name, &val_i);
sql.appfmt("%d, ", val_i);
break;
case PropertiesType_char:
args.get(name, val_s);
sql.appfmt("'%s', ", val_s.c_str());
break;
default:
assert(false);
break;
}
}
}
sql.appfmt("'new', %d)", _type);
if (!doQuery(sql)){
return -1;
}
return mysql_insert_id(m_mysql);
}
bool
AtrtClient::readCommand(uint command_id,
SqlResultSet& result){
Properties args;
args.put("0", command_id);
return runQuery("SELECT * FROM command WHERE id = ?",
args,
result);
}
bool
AtrtClient::doCommand(AtrtCommandType type,
const Properties& args){
int running_timeout= 10;
int total_timeout= 120;
int commandId= writeCommand(type,
args);
if (commandId == -1){
g_err << "Failed to write command" << endl;
return false;
}
while (true){
SqlResultSet result;
if (!readCommand(commandId, result))
{
result.print();
g_err << "Failed to read command "<< commandId << endl;
return false;
}
// Get first row
result.next();
// Check if command has completed
BaseString state(result.column("state"));
if (state == "done") {
return true;
}
if (state == "new"){
if (!running_timeout--){
g_err << "Timeout while waiting for command "
<< commandId << " to start run" << endl;
return false;
}
}
else if (!total_timeout--){
g_err << "Timeout while waiting for result of command "
<< commandId << endl;
return false;
}
NdbSleep_SecSleep(1);
}
return false;
}
bool
AtrtClient::changeVersion(int process_id,
const char* process_args){
Properties args;
args.put("process_id", process_id);
args.put("process_args", process_args);
return doCommand(ATCT_CHANGE_VERSION, args);
}
bool
AtrtClient::resetProc(int process_id){
Properties args;
args.put("process_id", process_id);
return doCommand(ATCT_RESET_PROC, args);
}
bool
AtrtClient::getConnectString(int cluster_id, SqlResultSet& result){
Properties args;
args.put("0", cluster_id);
return doQuery("SELECT value as connectstring " \
"FROM cluster c, process p, host h, options o " \
"WHERE c.id=p.cluster_id AND p.host_id=h.id AND " \
"p.id=o.process_id AND c.id=? AND " \
"o.name='--ndb-connectstring=' AND type='ndb_mgmd'",
args,
result);
}
bool
AtrtClient::getClusters(SqlResultSet& result){
Properties args;
return runQuery("SELECT id, name FROM cluster WHERE name != '.atrt'",
args,
result);
}
bool
AtrtClient::getMgmds(int cluster_id, SqlResultSet& result){
Properties args;
args.put("0", cluster_id);
return runQuery("SELECT * FROM process WHERE cluster_id=? and type='ndb_mgmd'",
args,
result);
}
bool
AtrtClient::getNdbds(int cluster_id, SqlResultSet& result){
Properties args;
args.put("0", cluster_id);
return runQuery("SELECT * FROM process WHERE cluster_id=? and type='ndbd'",
args,
result);
}
/* Copyright (C) 2007 MySQL AB
/* Copyright (C) 2008 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
......@@ -16,43 +16,89 @@
/* DbUtil.cpp: implementation of the database utilities class.*/
#include "DbUtil.hpp"
#include <NdbSleep.h>
/* Constructors */
DbUtil::DbUtil(const char * dbname)
{
m_port = 0;
m_connected = false;
this->setDbName(dbname);
}
/* Constructors */
DbUtil::DbUtil(const char * dbname, const char* suffix)
DbUtil::DbUtil(const char* _dbname,
const char* _user,
const char* _password,
const char* _suffix):
m_connected(false),
m_dbname(_dbname),
m_mysql(NULL),
m_free_mysql(true)
{
this->setDbName(dbname);
m_connected = false;
const char* env= getenv("MYSQL_HOME");
if (env && strlen(env))
{
default_file.assfmt("%s/my.cnf", env);
m_default_file.assfmt("%s/my.cnf", env);
}
if (suffix != NULL){
default_group.assfmt("client%s", suffix);
if (_suffix != NULL){
m_default_group.assfmt("client%s", _suffix);
}
else {
default_group.assign("client.1.master");
m_default_group.assign("client.1.master");
}
ndbout << "default_file: " << m_default_file.c_str() << endl;
ndbout << "default_group: " << m_default_group.c_str() << endl;
m_user.assign(_user);
m_pass.assign(_password);
}
DbUtil::DbUtil(MYSQL* mysql):
m_connected(true),
m_mysql(mysql),
m_free_mysql(false)
{
}
bool
DbUtil::isConnected(){
if (m_connected == true)
{
assert(m_mysql);
return true;
}
return connect() == 0;
}
bool
DbUtil::waitConnected(int timeout) {
timeout*= 10;
while(!isConnected()){
if (timeout-- == 0)
return false;
NdbSleep_MilliSleep(100);
}
return true;
}
ndbout << "default_file: " << default_file.c_str() << endl;
ndbout << "default_group: " << default_group.c_str() << endl;
void
DbUtil::disconnect(){
if (m_mysql != NULL){
if (m_free_mysql)
mysql_close(m_mysql);
m_mysql= NULL;
}
m_connected = false;
}
/* Destructor*/
/* Destructor */
DbUtil::~DbUtil()
{
this->databaseLogout();
disconnect();
}
/* Database Login */
......@@ -62,18 +108,18 @@ DbUtil::databaseLogin(const char* system, const char* usr,
const char* password, unsigned int portIn,
const char* sockIn, bool transactional)
{
if (!(mysql = mysql_init(NULL)))
if (!(m_mysql = mysql_init(NULL)))
{
myerror("DB Login-> mysql_init() failed");
exit(DBU_FAILED);
}
this->setUser(usr);
this->setHost(system);
this->setPassword(password);
this->setPort(portIn);
this->setSocket(sockIn);
setUser(usr);
setHost(system);
setPassword(password);
setPort(portIn);
setSocket(sockIn);
if (!(mysql_real_connect(mysql,
if (!(mysql_real_connect(m_mysql,
m_host.c_str(),
m_user.c_str(),
m_pass.c_str(),
......@@ -82,24 +128,24 @@ DbUtil::databaseLogin(const char* system, const char* usr,
m_socket.c_str(), 0)))
{
myerror("connection failed");
mysql_close(mysql);
mysql_close(m_mysql);
exit(DBU_FAILED);
}
mysql->reconnect = DBU_TRUE;
m_mysql->reconnect = TRUE;
/* set AUTOCOMMIT */
if(!transactional)
mysql_autocommit(mysql, DBU_TRUE);
mysql_autocommit(m_mysql, TRUE);
else
mysql_autocommit(mysql, DBU_FALSE);
mysql_autocommit(m_mysql, FALSE);
#ifdef DEBUG
printf("\n\tConnected to MySQL server version: %s (%lu)\n\n",
mysql_get_server_info(mysql),
(unsigned long) mysql_get_server_version(mysql));
mysql_get_server_info(m_mysql),
(unsigned long) mysql_get_server_version(m_mysql));
#endif
this->selectDb();
selectDb();
}
/* Database Connect */
......@@ -107,15 +153,15 @@ DbUtil::databaseLogin(const char* system, const char* usr,
int
DbUtil::connect()
{
if (!(mysql = mysql_init(NULL)))
if (!(m_mysql = mysql_init(NULL)))
{
myerror("DB connect-> mysql_init() failed");
return DBU_FAILED;
}
/* Load connection parameters file and group */
if (mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, default_file.c_str()) ||
mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, default_group.c_str()))
if (mysql_options(m_mysql, MYSQL_READ_DEFAULT_FILE, m_default_file.c_str()) ||
mysql_options(m_mysql, MYSQL_READ_DEFAULT_GROUP, m_default_group.c_str()))
{
myerror("DB Connect -> mysql_options failed");
return DBU_FAILED;
......@@ -126,14 +172,14 @@ DbUtil::connect()
NOTE! user and password can be stored there as well
*/
if (mysql_real_connect(mysql, NULL, "root","", m_dbname.c_str(),
if (mysql_real_connect(m_mysql, NULL, "root","", m_dbname.c_str(),
0, NULL, 0) == NULL)
{
myerror("connection failed");
mysql_close(mysql);
mysql_close(m_mysql);
return DBU_FAILED;
}
this->selectDb();
selectDb();
m_connected = true;
return DBU_OK;
}
......@@ -144,11 +190,11 @@ DbUtil::connect()
void
DbUtil::databaseLogout()
{
if (mysql){
if (m_mysql){
#ifdef DEBUG
printf("\n\tClosing the MySQL database connection ...\n\n");
#endif
mysql_close(mysql);
mysql_close(m_mysql);
}
}
......@@ -184,13 +230,13 @@ DbUtil::mysqlCloseStmHandle(MYSQL_STMT *my_stmt)
void
DbUtil::printError(const char *msg)
{
if (this->getMysql() && mysql_errno(this->getMysql()))
if (m_mysql && mysql_errno(m_mysql))
{
if (this->getMysql()->server_version)
printf("\n [MySQL-%s]", this->getMysql()->server_version);
if (m_mysql->server_version)
printf("\n [MySQL-%s]", m_mysql->server_version);
else
printf("\n [MySQL]");
printf("[%d] %s\n", this->getErrorNumber(), this->getError());
printf("[%d] %s\n", getErrorNumber(), getError());
}
else if (msg)
printf(" [MySQL] %s\n", msg);
......@@ -201,8 +247,8 @@ DbUtil::printStError(MYSQL_STMT *stmt, const char *msg)
{
if (stmt && mysql_stmt_errno(stmt))
{
if (this->getMysql() && this->getMysql()->server_version)
printf("\n [MySQL-%s]", this->getMysql()->server_version);
if (m_mysql && m_mysql->server_version)
printf("\n [MySQL-%s]", m_mysql->server_version);
else
printf("\n [MySQL]");
......@@ -218,16 +264,16 @@ DbUtil::printStError(MYSQL_STMT *stmt, const char *msg)
int
DbUtil::selectDb()
{
if ((this->getDbName()) != NULL)
if ((getDbName()) != NULL)
{
if(mysql_select_db(this->getMysql(), this->getDbName()))
if(mysql_select_db(m_mysql, this->getDbName()))
{
this->printError("mysql_select_db failed");
printError("mysql_select_db failed");
return DBU_FAILED;
}
return DBU_OK;
}
this->printError("getDbName() == NULL");
printError("getDbName() == NULL");
return DBU_FAILED;
}
......@@ -235,9 +281,9 @@ int
DbUtil::selectDb(const char * m_db)
{
{
if(mysql_select_db(this->getMysql(), m_db))
if(mysql_select_db(m_mysql, m_db))
{
this->printError("mysql_select_db failed");
printError("mysql_select_db failed");
return DBU_FAILED;
}
return DBU_OK;
......@@ -249,43 +295,247 @@ DbUtil::createDb(BaseString& m_db)
{
BaseString stm;
{
if(mysql_select_db(this->getMysql(), m_db.c_str()) == DBU_OK)
if(mysql_select_db(m_mysql, m_db.c_str()) == DBU_OK)
{
stm.assfmt("DROP DATABASE %s", m_db.c_str());
if(this->doQuery(m_db.c_str()) == DBU_FAILED)
if(doQuery(m_db.c_str()) == DBU_FAILED)
return DBU_FAILED;
}
stm.assfmt("CREATE DATABASE %s", m_db.c_str());
if(this->doQuery(m_db.c_str()) == DBU_FAILED)
if(doQuery(m_db.c_str()) == DBU_FAILED)
return DBU_FAILED;
return DBU_OK;
}
}
/* Run Simple Queries */
int
DbUtil::doQuery(BaseString& str)
/* Count Table Rows */
unsigned long
DbUtil::selectCountTable(const char * table)
{
if(mysql_query(this->getMysql(), str.c_str()))
{
this->printError(str.c_str());
return DBU_FAILED;
BaseString query;
SqlResultSet result;
query.assfmt("select count(*) as count from %s", table);
if (!doQuery(query, result)) {
printError("select count(*) failed");
return -1;
}
return DBU_OK;
return result.columnAsInt("count");
}
int
DbUtil::doQuery(const char * stm)
{
if(mysql_query(this->getMysql(), stm))
/* Run Simple Queries */
static bool is_int_type(enum_field_types type){
switch(type){
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_ENUM:
return true;
default:
return false;
}
return false;
}
bool
DbUtil::runQuery(const char* sql,
const Properties& args,
SqlResultSet& rows){
rows.clear();
if (!isConnected())
return false;
g_debug << "runQuery: " << endl
<< " sql: '" << sql << "'" << endl;
MYSQL_STMT *stmt= mysql_stmt_init(m_mysql);
if (mysql_stmt_prepare(stmt, sql, strlen(sql)))
{
this->printError(stm);
return DBU_FAILED;
g_err << "Failed to prepare: " << mysql_error(m_mysql) << endl;
return false;
}
return DBU_OK;
uint params= mysql_stmt_param_count(stmt);
MYSQL_BIND bind_param[params];
bzero(bind_param, sizeof(bind_param));
for(uint i= 0; i < mysql_stmt_param_count(stmt); i++)
{
BaseString name;
name.assfmt("%d", i);
// Parameters are named 0, 1, 2...
if (!args.contains(name.c_str()))
{
g_err << "param " << i << " missing" << endl;
assert(false);
}
PropertiesType t;
Uint32 val_i;
const char* val_s;
args.getTypeOf(name.c_str(), &t);
switch(t) {
case PropertiesType_Uint32:
args.get(name.c_str(), &val_i);
bind_param[i].buffer_type= MYSQL_TYPE_LONG;
bind_param[i].buffer= (char*)&val_i;
g_debug << " param" << name.c_str() << ": " << val_i << endl;
break;
case PropertiesType_char:
args.get(name.c_str(), &val_s);
bind_param[i].buffer_type= MYSQL_TYPE_STRING;
bind_param[i].buffer= (char*)val_s;
bind_param[i].buffer_length= strlen(val_s);
g_debug << " param" << name.c_str() << ": " << val_s << endl;
break;
default:
assert(false);
break;
}
}
if (mysql_stmt_bind_param(stmt, bind_param))
{
g_err << "Failed to bind param: " << mysql_error(m_mysql) << endl;
mysql_stmt_close(stmt);
return false;
}
if (mysql_stmt_execute(stmt))
{
g_err << "Failed to execute: " << mysql_error(m_mysql) << endl;
mysql_stmt_close(stmt);
return false;
}
/*
Update max_length, making it possible to know how big
buffers to allocate
*/
my_bool one= 1;
mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one);
if (mysql_stmt_store_result(stmt))
{
g_err << "Failed to store result: " << mysql_error(m_mysql) << endl;
mysql_stmt_close(stmt);
return false;
}
uint row= 0;
MYSQL_RES* res= mysql_stmt_result_metadata(stmt);
if (res != NULL)
{
MYSQL_FIELD *fields= mysql_fetch_fields(res);
uint num_fields= mysql_num_fields(res);
MYSQL_BIND bind_result[num_fields];
bzero(bind_result, sizeof(bind_result));
for (uint i= 0; i < num_fields; i++)
{
if (is_int_type(fields[i].type)){
bind_result[i].buffer_type= MYSQL_TYPE_LONG;
bind_result[i].buffer= malloc(sizeof(int));
}
else
{
uint max_length= fields[i].max_length + 1;
bind_result[i].buffer_type= MYSQL_TYPE_STRING;
bind_result[i].buffer= malloc(max_length);
bind_result[i].buffer_length= max_length;
}
}
if (mysql_stmt_bind_result(stmt, bind_result)){
g_err << "Failed to bind result: " << mysql_error(m_mysql) << endl;
mysql_stmt_close(stmt);
return false;
}
while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
{
Properties curr(true);
for (uint i= 0; i < num_fields; i++){
if (is_int_type(fields[i].type))
curr.put(fields[i].name, *(int*)bind_result[i].buffer);
else
curr.put(fields[i].name, (char*)bind_result[i].buffer);
}
rows.put("row", row++, &curr);
}
mysql_free_result(res);
for (uint i= 0; i < num_fields; i++)
free(bind_result[i].buffer);
}
// Save stats in result set
rows.put("rows", row);
rows.put("affected_rows", mysql_affected_rows(m_mysql));
rows.put("mysql_errno", mysql_errno(m_mysql));
rows.put("mysql_error", mysql_error(m_mysql));
rows.put("mysql_sqlstate", mysql_sqlstate(m_mysql));
rows.put("insert_id", mysql_insert_id(m_mysql));
mysql_stmt_close(stmt);
return true;
}
bool
DbUtil::doQuery(const char* query){
const Properties args;
SqlResultSet result;
return doQuery(query, args, result);
}
bool
DbUtil::doQuery(const char* query, SqlResultSet& result){
Properties args;
return doQuery(query, args, result);
}
bool
DbUtil::doQuery(const char* query, const Properties& args,
SqlResultSet& result){
if (!runQuery(query, args, result))
return false;
result.get_row(0); // Load first row
return true;
}
bool
DbUtil::doQuery(BaseString& str){
return doQuery(str.c_str());
}
bool
DbUtil::doQuery(BaseString& str, SqlResultSet& result){
return doQuery(str.c_str(), result);
}
bool
DbUtil::doQuery(BaseString& str, const Properties& args,
SqlResultSet& result){
return doQuery(str.c_str(), args, result);
}
/* Return MySQL Error String */
const char *
......@@ -294,7 +544,7 @@ DbUtil::getError()
return mysql_error(this->getMysql());
}
/* Retrun MySQL Error Number */
/* Return MySQL Error Number */
int
DbUtil::getErrorNumber()
......@@ -302,35 +552,125 @@ DbUtil::getErrorNumber()
return mysql_errno(this->getMysql());
}
/* Count Table Rows */
/* DIE */
unsigned long
DbUtil::selectCountTable(const char * table)
void
DbUtil::die(const char *file, int line, const char *expr)
{
unsigned long m_count = 0;
BaseString m_query;
printf("%s:%d: check failed: '%s'\n", file, line, expr);
abort();
}
m_query.assfmt("select count(*) from %s", table);
if (mysql_query(this->getMysql(),m_query.c_str()) ||
!(m_result=mysql_store_result(this->getMysql())))
{
this->printError("selectCountTable\n");
return DBU_FAILED;
/* SqlResultSet */
bool
SqlResultSet::get_row(int row_num){
if(!get("row", row_num, &m_curr_row)){
return false;
}
m_row = mysql_fetch_row(m_result);
m_count = (ulong) strtoull(m_row[0], (char**) 0, 10);
mysql_free_result(m_result);
return true;
}
return m_count;
bool
SqlResultSet::next(void){
return get_row(++m_curr_row_num);
}
/* DIE */
void
DbUtil::die(const char *file, int line, const char *expr)
{
printf("%s:%d: check failed: '%s'\n", file, line, expr);
abort();
// Reset iterator
void SqlResultSet::reset(void){
m_curr_row_num= -1;
m_curr_row= 0;
}
// Remove row from resultset
void SqlResultSet::remove(){
BaseString row_name;
row_name.assfmt("row_%d", m_curr_row_num);
Properties::remove(row_name.c_str());
}
SqlResultSet::SqlResultSet(): m_curr_row(0), m_curr_row_num(-1){
}
SqlResultSet::~SqlResultSet(){
}
const char* SqlResultSet::column(const char* col_name){
const char* value;
if (!m_curr_row){
g_err << "ERROR: SqlResultSet::column("<< col_name << ")" << endl
<< "There is no row loaded, call next() before "
<< "acessing the column values" << endl;
assert(m_curr_row);
}
if (!m_curr_row->get(col_name, &value))
return NULL;
return value;
}
uint SqlResultSet::columnAsInt(const char* col_name){
uint value;
if (!m_curr_row){
g_err << "ERROR: SqlResultSet::columnAsInt("<< col_name << ")" << endl
<< "There is no row loaded, call next() before "
<< "acessing the column values" << endl;
assert(m_curr_row);
}
if (!m_curr_row->get(col_name, &value))
return (uint)-1;
return value;
}
uint SqlResultSet::insertId(){
return get_int("insert_id");
}
uint SqlResultSet::affectedRows(){
return get_int("affected_rows");
}
uint SqlResultSet::numRows(void){
return get_int("rows");
}
uint SqlResultSet::mysqlErrno(void){
return get_int("mysql_errno");
}
const char* SqlResultSet::mysqlError(void){
return get_string("mysql_error");
}
const char* SqlResultSet::mysqlSqlstate(void){
return get_string("mysql_sqlstate");
}
uint SqlResultSet::get_int(const char* name){
uint value;
get(name, &value);
return value;
}
const char* SqlResultSet::get_string(const char* name){
const char* value;
get(name, &value);
return value;
}
/* EOF */
......
......@@ -23,10 +23,10 @@ libNDBT_a_SOURCES = \
HugoAsynchTransactions.cpp UtilTransactions.cpp \
NdbRestarter.cpp NdbRestarts.cpp NDBT_Output.cpp \
NdbBackup.cpp NdbConfig.cpp NdbGrep.cpp NDBT_Table.cpp \
NdbSchemaCon.cpp NdbSchemaOp.cpp getarg.c \
CpcClient.cpp NdbMixRestarter.cpp NDBT_Thread.cpp dbutil.cpp
NdbSchemaCon.cpp NdbSchemaOp.cpp getarg.c AtrtClient.cpp \
CpcClient.cpp NdbMixRestarter.cpp NDBT_Thread.cpp DbUtil.cpp
INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/common/mgmcommon -I$(top_srcdir)/storage/ndb/include/mgmcommon -I$(top_srcdir)/storage/ndb/include/kernel -I$(top_srcdir)/storage/ndb/src/mgmapi
INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/common/mgmcommon -I$(top_srcdir)/storage/ndb/include/mgmcommon -I$(top_srcdir)/storage/ndb/include/kernel -I$(top_srcdir)/storage/ndb/src/mgmapi -I$(top_srcdir)/include
include $(top_srcdir)/storage/ndb/config/common.mk.am
include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment