Commit c50598bd 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-merge
parents 2401f86c 79e8f3e4
...@@ -139,6 +139,7 @@ public: ...@@ -139,6 +139,7 @@ public:
/** /**
* setField - Set bitfield at given position and length (max 32 bits) * setField - Set bitfield at given position and length (max 32 bits)
* Note : length == 0 not supported.
*/ */
static void setField(unsigned size, Uint32 data[], static void setField(unsigned size, Uint32 data[],
unsigned pos, unsigned len, Uint32 val); unsigned pos, unsigned len, Uint32 val);
...@@ -146,6 +147,7 @@ public: ...@@ -146,6 +147,7 @@ public:
/** /**
* getField - Get bitfield at given position and length * getField - Get bitfield at given position and length
* Note : length == 0 not supported.
*/ */
static void getField(unsigned size, const Uint32 data[], static void getField(unsigned size, const Uint32 data[],
unsigned pos, unsigned len, Uint32 dst[]); unsigned pos, unsigned len, Uint32 dst[]);
...@@ -918,6 +920,9 @@ BitmaskImpl::getField(unsigned size, const Uint32 src[], ...@@ -918,6 +920,9 @@ BitmaskImpl::getField(unsigned size, const Uint32 src[],
unsigned pos, unsigned len, Uint32 dst[]) unsigned pos, unsigned len, Uint32 dst[])
{ {
assert(pos + len <= (size << 5)); assert(pos + len <= (size << 5));
assert (len != 0);
if (len == 0)
return;
src += (pos >> 5); src += (pos >> 5);
Uint32 offset = pos & 31; Uint32 offset = pos & 31;
...@@ -937,6 +942,9 @@ BitmaskImpl::setField(unsigned size, Uint32 dst[], ...@@ -937,6 +942,9 @@ BitmaskImpl::setField(unsigned size, Uint32 dst[],
unsigned pos, unsigned len, const Uint32 src[]) unsigned pos, unsigned len, const Uint32 src[])
{ {
assert(pos + len <= (size << 5)); assert(pos + len <= (size << 5));
assert(len != 0);
if (len == 0)
return;
dst += (pos >> 5); dst += (pos >> 5);
Uint32 offset = pos & 31; Uint32 offset = pos & 31;
......
...@@ -317,22 +317,32 @@ TCP_Transporter::doSend() { ...@@ -317,22 +317,32 @@ TCP_Transporter::doSend() {
// Empty the SendBuffers // Empty the SendBuffers
bool sent_any = true;
while (m_sendBuffer.dataSize > 0)
{
const char * const sendPtr = m_sendBuffer.sendPtr; const char * const sendPtr = m_sendBuffer.sendPtr;
const Uint32 sizeToSend = m_sendBuffer.sendDataSize; const Uint32 sizeToSend = m_sendBuffer.sendDataSize;
if (sizeToSend > 0){
const int nBytesSent = send(theSocket, sendPtr, sizeToSend, 0); const int nBytesSent = send(theSocket, sendPtr, sizeToSend, 0);
if (nBytesSent > 0) { if (nBytesSent > 0)
{
sent_any = true;
m_sendBuffer.bytesSent(nBytesSent); m_sendBuffer.bytesSent(nBytesSent);
sendCount ++; sendCount ++;
sendSize += nBytesSent; sendSize += nBytesSent;
if(sendCount == reportFreq){ if(sendCount == reportFreq)
{
reportSendLen(get_callback_obj(), remoteNodeId, sendCount, sendSize); reportSendLen(get_callback_obj(), remoteNodeId, sendCount, sendSize);
sendCount = 0; sendCount = 0;
sendSize = 0; sendSize = 0;
} }
} else { }
else
{
if (nBytesSent < 0 && InetErrno == EAGAIN && sent_any)
break;
// Send failed // Send failed
#if defined DEBUG_TRANSPORTER #if defined DEBUG_TRANSPORTER
g_eventLogger.error("Send Failure(disconnect==%d) to node = %d nBytesSent = %d " g_eventLogger.error("Send Failure(disconnect==%d) to node = %d nBytesSent = %d "
......
...@@ -20,13 +20,38 @@ void ...@@ -20,13 +20,38 @@ void
BitmaskImpl::getFieldImpl(const Uint32 src[], BitmaskImpl::getFieldImpl(const Uint32 src[],
unsigned shiftL, unsigned len, Uint32 dst[]) 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); assert(shiftL < 32);
unsigned shiftR = 32 - shiftL; unsigned shiftR = 32 - shiftL;
unsigned undefined = shiftL ? ~0 : 0; unsigned undefined = shiftL ? ~0 : 0;
/* Merge first word with previously set bits if there's a shift */
* dst = shiftL ? * dst : 0; * 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) while(len >= 32)
{ {
* dst++ |= (* src) << shiftL; * dst++ |= (* src) << shiftL;
...@@ -34,15 +59,21 @@ BitmaskImpl::getFieldImpl(const Uint32 src[], ...@@ -34,15 +59,21 @@ BitmaskImpl::getFieldImpl(const Uint32 src[],
len -= 32; 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; * dst |= ((* src) & ((1 << len) - 1)) << shiftL;
} }
else else
{ {
/* Need to write to two dst words */
* dst++ |= ((* src) << shiftL); * dst++ |= ((* src) << shiftL);
* dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined; * dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined;
} }
}
} }
void void
...@@ -64,370 +95,23 @@ BitmaskImpl::setFieldImpl(Uint32 dst[], ...@@ -64,370 +95,23 @@ BitmaskImpl::setFieldImpl(Uint32 dst[],
len -= 32; len -= 32;
} }
/* Copy last bits */
Uint32 mask = ((1 << len) -1); Uint32 mask = ((1 << len) -1);
* dst = (* dst & ~mask); * dst = (* dst & ~mask);
if(len < shiftR) if(len <= shiftR)
{ {
/* Remaining bits fit in current word */
* dst |= ((* src++) >> shiftL) & mask; * dst |= ((* src++) >> shiftL) & mask;
} }
else else
{ {
/* Remaining bits update 2 words */
* dst |= ((* src++) >> shiftL); * dst |= ((* src++) >> shiftL);
* dst |= ((* src) & ((1 << (len - shiftR)) - 1)) << shiftR ; * 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: "); /* Bitmask testcase code moved from here to
size_t k; * storage/ndb/test/ndbapi/testBitfield.cpp
Alloc& a = alloc_list[j]; * to get coverage from automated testing
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
...@@ -11,7 +11,7 @@ Next CMVMI 9000 ...@@ -11,7 +11,7 @@ Next CMVMI 9000
Next BACKUP 10038 Next BACKUP 10038
Next DBUTIL 11002 Next DBUTIL 11002
Next DBTUX 12008 Next DBTUX 12008
Next SUMA 13034 Next SUMA 13036
TESTING NODE FAILURE, ARBITRATION TESTING NODE FAILURE, ARBITRATION
--------------------------------- ---------------------------------
......
...@@ -619,6 +619,24 @@ Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr) ...@@ -619,6 +619,24 @@ Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr)
if (lcp && lcp_list != RNIL) if (lcp && lcp_list != RNIL)
goto found_lcp_keep; goto found_lcp_keep;
switch(pos.m_get){
case ScanPos::Get_next_tuple:
case ScanPos::Get_next_tuple_fs:
jam();
key.m_page_idx += size;
// fall through
case ScanPos::Get_tuple:
case ScanPos::Get_tuple_fs:
jam();
/**
* We need to refetch page after timeslice
*/
pos.m_get = ScanPos::Get_page;
break;
default:
break;
}
while (true) { while (true) {
switch (pos.m_get) { switch (pos.m_get) {
case ScanPos::Get_next_page: case ScanPos::Get_next_page:
......
...@@ -4908,6 +4908,21 @@ Suma::release_gci(Signal* signal, Uint32 buck, Uint32 gci) ...@@ -4908,6 +4908,21 @@ Suma::release_gci(Signal* signal, Uint32 buck, Uint32 gci)
if(gci >= head.m_max_gci) if(gci >= head.m_max_gci)
{ {
jam(); 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_page_pos = 0;
head.m_max_gci = gci; head.m_max_gci = gci;
head.m_last_gci = 0; head.m_last_gci = 0;
...@@ -4979,7 +4994,6 @@ Suma::start_resend(Signal* signal, Uint32 buck) ...@@ -4979,7 +4994,6 @@ Suma::start_resend(Signal* signal, Uint32 buck)
if(min > max) if(min > max)
{ {
ndbrequire(pos.m_page_pos <= 2);
ndbrequire(pos.m_page_id == bucket->m_buffer_tail); ndbrequire(pos.m_page_id == bucket->m_buffer_tail);
m_active_buckets.set(buck); m_active_buckets.set(buck);
m_gcp_complete_rep_count ++; 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
/* Copyright (C) 2007 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 */
// dbutil.h: interface for the database utilities class.
// Supplies a database to the test application
#ifndef DBUTIL_HPP
#define DBUTIL_HPP
#include <NDBT.hpp>
#include <BaseString.hpp>
#include <Properties.hpp>
#include <Vector.hpp>
#include <mysql.h>
//#define DEBUG
#define DIE_UNLESS(expr) \
((void) ((expr) ? 0 : (Die(__FILE__, __LINE__, #expr), 0)))
#define DIE(expr) \
Die(__FILE__, __LINE__, #expr)
#define myerror(msg) printError(msg)
#define mysterror(stmt, msg) printStError(stmt, msg)
#define CheckStmt(stmt) \
{ \
if ( stmt == 0) \
myerror(NULL); \
DIE_UNLESS(stmt != 0); \
}
#define check_execute(stmt, r) \
{ \
if (r) \
mysterror(stmt, NULL); \
DIE_UNLESS(r == 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
class DbUtil
{
public:
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,
const char * password,
unsigned int portIn,
const char * sockIn,
bool transactional);
const char * getDbName() {return m_dbname.c_str();};
const char * getUser() {return m_user.c_str();};
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(m_mysql);};
const char * getError();
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 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;
BaseString m_host; // Computer to connect to
BaseString m_user; // MySQL User
BaseString m_pass; // MySQL User Password
BaseString m_dbname; // Database to use
BaseString m_socket; // MySQL Server Unix Socket
BaseString m_default_file;
BaseString m_default_group;
unsigned int m_port; // MySQL Server port
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);};
void setHost(const char * system){m_host.assign(system);};
void setPort(unsigned int portIn){m_port=portIn;};
void setSocket(const char * sockIn){m_socket.assign(sockIn);};
void printError(const char *msg);
void printStError(MYSQL_STMT *stmt, const char *msg);
void die(const char *file, int line, const char *expr); // stop program
};
#endif
// dbutil.h: interface for the database utilities class.
//////////////////////////////////////////////////////////////////////
// Supplies a database to the test application
//////////////////////////////////////////////////////////////////////
#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 <mysql.h>
//include "rand.h"
#include <stdlib.h>
//#define DEBUG
#define DIE_UNLESS(expr) \
((void) ((expr) ? 0 : (Die(__FILE__, __LINE__, #expr), 0)))
#define DIE(expr) \
Die(__FILE__, __LINE__, #expr)
#define myerror(msg) PrintError(msg)
#define mysterror(stmt, msg) PrintStError(stmt, msg)
#define CheckStmt(stmt) \
{ \
if ( stmt == 0) \
myerror(NULL); \
DIE_UNLESS(stmt != 0); \
}
#define check_execute(stmt, r) \
{ \
if (r) \
mysterror(stmt, NULL); \
DIE_UNLESS(r == 0);\
}
#define TRUE 1
#define FALSE 0
class dbutil
{
public:
dbutil(const char * databaseName);
~dbutil();
void DatabaseLogin(const char * system,
const char * usr,
const char * password,
unsigned int portIn,
const char * sockIn,
bool transactional);
char * GetDbName(){return dbs;};
char * GetUser(){return user;};
char * GetPassword(){return pass;};
char * GetHost(){return host;};
char * GetSocket(){return socket;};
const char * GetServerType(){return mysql_get_server_info(myDbHandel);};
MYSQL* GetDbHandel(){return myDbHandel;};
MYSQL_STMT *STDCALL MysqlSimplePrepare(const char *query);
int Select_DB();
int Do_Query(char * stm);
const char * GetError();
int GetErrorNumber();
unsigned long SelectCountTable(const char * table);
private:
//Connect variables
char * databaseName; //hold results file name
char host[256]; // Computer to connect to
char user[256]; // MySQL User
char pass[256]; // MySQL User Password
char dbs[256]; // Database to use (TPCB)
unsigned int port; // MySQL Server port
char socket[256]; // MySQL Server Unix Socket
MYSQL *myDbHandel;
void DatabaseLogout();
void SetDbName(const char * name){strcpy((char *)dbs, name);};
void SetUser(const char * userName){strcpy((char *)user, userName);};
void SetPassword(const char * password){strcpy((char *)pass,password);};
void SetHost(const char * system){strcpy((char*)host, system);};
void SetPort(unsigned int portIn){port=portIn;};
void SetSocket(const char * sockIn){strcpy((char *)socket, sockIn);};
void PrintError(const char *msg);
void PrintStError(MYSQL_STMT *stmt, const char *msg);
void Die(const char *file, int line, const char *expr); // stop program
};
#endif
...@@ -52,7 +52,9 @@ testBitfield \ ...@@ -52,7 +52,9 @@ testBitfield \
DbCreate DbAsyncGenerator \ DbCreate DbAsyncGenerator \
testSRBank \ testSRBank \
test_event_merge \ test_event_merge \
testIndexStat testIndexStat \
testNDBT \
NdbRepStress
EXTRA_PROGRAMS = \ EXTRA_PROGRAMS = \
test_event \ test_event \
...@@ -98,7 +100,10 @@ ndbapi_slow_select_SOURCES = slow_select.cpp ...@@ -98,7 +100,10 @@ ndbapi_slow_select_SOURCES = slow_select.cpp
testReadPerf_SOURCES = testReadPerf.cpp testReadPerf_SOURCES = testReadPerf.cpp
testLcp_SOURCES = testLcp.cpp testLcp_SOURCES = testLcp.cpp
testPartitioning_SOURCES = testPartitioning.cpp testPartitioning_SOURCES = testPartitioning.cpp
testNDBT_SOURCES = testNDBT.cpp
testNDBT_LDADD = $(LDADD) $(top_srcdir)/libmysql_r/libmysqlclient_r.la
testBitfield_SOURCES = testBitfield.cpp 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 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 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 testSRBank_SOURCES = testSRBank.cpp
...@@ -115,8 +120,10 @@ include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am ...@@ -115,8 +120,10 @@ include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am
##testIndex_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel ##testIndex_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel
##testSystemRestart_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 ##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 testBackup_LDADD = $(LDADD) bank/libbank.a
testSRBank_LDADD = bank/libbank.a $(LDADD) testSRBank_LDADD = bank/libbank.a $(LDADD)
NdbRepStress_LDADD = $(LDADD) $(top_builddir)/libmysql_r/libmysqlclient_r.la
# Don't update the files from bitkeeper # Don't update the files from bitkeeper
%::SCCS/s.% %::SCCS/s.%
......
/* 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_Test.hpp>
#include <NDBT_ReturnCodes.h>
#include <HugoTransactions.hpp>
#include <UtilTransactions.hpp>
#include <DbUtil.hpp>
#include <mysql.h>
/*
Will include restart testing in future phases
#include <NdbRestarter.hpp>
#include <NdbRestarts.hpp>
*/
/**** TOOL SECTION ****/
static uint
urandom()
{
uint r = (uint)random();
return r;
}
static uint
urandom(uint m)
{
if (m == 0)
return NDBT_OK;
uint r = urandom();
r = r % m;
return r;
}
#define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb()
/*
*/
int
syncSlaveWithMaster()
{
/*
We need to look at the MAX epoch of the
mysql.ndb_binlog_index table so we will
know when the slave has caught up
*/
MYSQL_RES * result;
MYSQL_ROW row;
unsigned int masterEpoch = 0;
unsigned int slaveEpoch = 0;
unsigned int slaveEpochOld = 0;
int maxLoops = 100;
int loopCnt = 0;
//Create a DbUtil object for the master
DbUtil master("mysql","");
//Login to Master
if (!master.connect())
{
return NDBT_FAILED;
}
//Get max epoch from master
if(master.doQuery("SELECT MAX(epoch) FROM mysql.ndb_binlog_index"))
{
return NDBT_FAILED;
}
result = mysql_use_result(master.getMysql());
row = mysql_fetch_row(result);
masterEpoch = atoi(row[0]);
mysql_free_result(result);
/*
Now we will pull current epoch from slave. If not the
same as master, we will continue to retrieve the epoch
and compare until it matches or we reach the max loops
allowed.
*/
//Create a dbutil object for the slave
DbUtil slave("mysql",".slave");
//Login to slave
if (!slave.connect())
{
return NDBT_FAILED;
}
while(slaveEpoch != masterEpoch && loopCnt < maxLoops)
{
if(slave.doQuery("SELECT epoch FROM mysql.ndb_apply_status"))
{
return NDBT_FAILED;
}
result = mysql_use_result(slave.getMysql());
row = mysql_fetch_row(result);
slaveEpoch = atoi(row[0]);
mysql_free_result(result);
if(slaveEpoch != slaveEpochOld)
{
slaveEpochOld = slaveEpoch;
if(loopCnt > 0)
loopCnt--;
sleep(3);
}
else
{
sleep(1);
loopCnt++;
}
}
if(slaveEpoch != masterEpoch)
{
g_err << "Slave not in sync with master!" << endl;
return NDBT_FAILED;
}
return NDBT_OK;
}
int
verifySlaveLoad(BaseString *table)
{
BaseString sqlStm;
BaseString db;
MYSQL_RES * result;
MYSQL_ROW row;
unsigned int masterCount = 0;
unsigned int slaveCount = 0;
db.assign("TEST_DB");
sqlStm.assfmt("SELECT COUNT(*) FROM %s", table);
//First thing to do is sync slave
if(syncSlaveWithMaster())
{
g_err << "Verify Load -> Syncing with slave failed" << endl;
return NDBT_FAILED;
}
//Now that slave is sync we can verify load
DbUtil master(db.c_str()," ");
//Login to Master
if (!master.connect())
{
return NDBT_FAILED;
}
if(master.doQuery(sqlStm.c_str()))
{
return NDBT_FAILED;
}
result = mysql_use_result(master.getMysql());
row = mysql_fetch_row(result);
masterCount = atoi(row[0]);
mysql_free_result(result);
//Create a DB Object for slave
DbUtil slave(db.c_str(),".slave");
//Login to slave
if (!slave.connect())
{
return NDBT_FAILED;
}
if(slave.doQuery(sqlStm.c_str()))
{
return NDBT_FAILED;
}
result = mysql_use_result(slave.getMysql());
row = mysql_fetch_row(result);
slaveCount = atoi(row[0]);
mysql_free_result(result);
if(slaveCount != masterCount)
{
g_err << "Verify Load -> Slave Count != Master Count "
<< endl;
return NDBT_FAILED;
}
return NDBT_OK;
}
int
createTEST_DB(NDBT_Context* ctx, NDBT_Step* step)
{
BaseString cdb;
cdb.assign("TEST_DB");
//Create a dbutil object
DbUtil master("mysql","");
if (master.connect())
{
if (master.createDb(cdb) == NDBT_OK)
{
return NDBT_OK;
}
}
return NDBT_FAILED;
}
int
dropTEST_DB(NDBT_Context* ctx, NDBT_Step* step)
{
//Create an SQL Object
DbUtil master("mysql","");
//Login to Master
if (!master.connect())
{
return NDBT_FAILED;
}
if(master.doQuery("DROP DATABASE TEST_DB") != NDBT_OK)
{
return NDBT_FAILED;
}
if(syncSlaveWithMaster() != NDBT_OK)
{
g_err << "Drop DB -> Syncing with slave failed"
<< endl;
return NDBT_FAILED;
}
return NDBT_OK;
}
int
verifySlave(BaseString& sqlStm, BaseString& db)
{
MYSQL_RES* resource;
MYSQL_ROW row;
float masterSum;
float slaveSum;
//Create SQL Objects
DbUtil master(db.c_str(),"");
DbUtil slave(db.c_str(),".slave");
if(syncSlaveWithMaster() != NDBT_OK)
{
g_err << "Verify Slave rep1 -> Syncing with slave failed"
<< endl;
return NDBT_FAILED;
}
//Login to Master
if (!master.connect())
{
return NDBT_FAILED;
}
if(master.doQuery(sqlStm.c_str()) != NDBT_OK)
{
return NDBT_FAILED;
}
resource = mysql_use_result(master.getMysql());
row = mysql_fetch_row(resource);
masterSum = atoi(row[0]);
mysql_free_result(resource);
//Login to slave
if (!slave.connect())
{
return NDBT_FAILED;
}
if(slave.doQuery(sqlStm.c_str()) != NDBT_OK)
{
return NDBT_FAILED;
}
resource = mysql_use_result(slave.getMysql());
row = mysql_fetch_row(resource);
slaveSum = atoi(row[0]);
mysql_free_result(resource);
if(masterSum != slaveSum)
{
g_err << "VerifySlave -> masterSum != slaveSum..." << endl;
return NDBT_FAILED;
}
return NDBT_OK;
}
/**** Test Section ****/
int
createDB(NDBT_Context* ctx, NDBT_Step* step)
{
BaseString cdb;
cdb.assign("TEST_DB");
//Create a dbutil object
DbUtil master("mysql","");
if (master.connect())
{
if (master.createDb(cdb) == NDBT_OK)
{
return NDBT_OK;
}
}
return NDBT_FAILED;
}
int
createTable_rep1(NDBT_Context* ctx, NDBT_Step* step)
{
BaseString table;
BaseString db;
table.assign("rep1");
db.assign("TEST_DB");
//Ensure slave is up and ready
if(syncSlaveWithMaster() != NDBT_OK)
{
g_err << "Create Table -> Syncing with slave failed"
<< endl;
return NDBT_FAILED;
}
//Create an SQL Object
DbUtil master(db.c_str(),"");
//Login to Master
if (!master.connect())
{
return NDBT_FAILED;
}
if (master.doQuery("CREATE TABLE rep1 (c1 MEDIUMINT NOT NULL AUTO_INCREMENT,"
" c2 FLOAT, c3 CHAR(5), c4 bit(8), c5 FLOAT, c6 INT,"
" c7 INT, PRIMARY KEY (c1))ENGINE=NDB"))
{
return NDBT_FAILED;
}
ctx->setProperty("TABLES",table.c_str());
HugoTransactions hugoTrans(*ctx->getTab());
if (hugoTrans.loadTable(GETNDB(step), ctx->getNumRecords(), 1, true, 0) != NDBT_OK)
{
g_err << "Create Table -> Load failed!" << endl;
return NDBT_FAILED;
}
if(verifySlaveLoad(&table)!= NDBT_OK)
{
g_err << "Create Table -> Failed on verify slave load!"
<< endl;
return NDBT_FAILED;
}
//else everything is okay
return NDBT_OK;
}
int
stressNDB_rep1(NDBT_Context* ctx, NDBT_Step* step)
{
const NdbDictionary::Table * table= ctx->getTab();
HugoTransactions hugoTrans(* table);
while(!ctx->isTestStopped())
{
if (hugoTrans.pkUpdateRecords(GETNDB(step), ctx->getNumRecords(), 1, 30) != 0)
{
g_err << "pkUpdate Failed!" << endl;
return NDBT_FAILED;
}
if (hugoTrans.scanUpdateRecords(GETNDB(step), ctx->getNumRecords(), 1, 30) != 0)
{
g_err << "scanUpdate Failed!" << endl;
return NDBT_FAILED;
}
}
return NDBT_OK;
}
int
stressSQL_rep1(NDBT_Context* ctx, NDBT_Step* step)
{
BaseString sqlStm;
DbUtil master("TEST_DB","");
int loops = ctx->getNumLoops();
uint record = 0;
//Login to Master
if (!master.connect())
{
ctx->stopTest();
return NDBT_FAILED;
}
for (int j= 0; loops == 0 || j < loops; j++)
{
record = urandom(ctx->getNumRecords());
sqlStm.assfmt("UPDATE TEST_DB.rep1 SET c2 = 33.3221 where c1 = %u", record);
if(master.doQuery(sqlStm.c_str()))
{
return NDBT_FAILED;
}
}
ctx->stopTest();
return NDBT_OK;
}
int
verifySlave_rep1(NDBT_Context* ctx, NDBT_Step* step)
{
BaseString sql;
BaseString db;
sql.assign("SELECT SUM(c3) FROM rep1");
db.assign("TEST_DB");
if (verifySlave(sql,db) != NDBT_OK)
return NDBT_FAILED;
return NDBT_OK;
}
/* TOOLS LIST
syncSlaveWithMaster()
{ensures slave is at same epoch as master}
verifySlaveLoad(BaseString *table)
{ensures slave table has same record count as master}
createTEST_DB()
{Creates TEST_DB database on master}
dropTEST_DB()
{Drops TEST_DB database on master}
verifySlave(BaseString& sql, BaseSting& db)
{The SQL statement must sum a column and will verify
that the sum of the column is equal on master & slave}
*/
NDBT_TESTSUITE(NdbRepStress);
TESTCASE("PHASE_I_Stress","Basic Replication Stressing")
{
INITIALIZER(createDB);
INITIALIZER(createTable_rep1);
STEP(stressNDB_rep1);
STEP(stressSQL_rep1);
FINALIZER(verifySlave_rep1);
FINALIZER(dropTEST_DB);
}
NDBT_TESTSUITE_END(NdbRepStress);
int main(int argc, const char** argv){
ndb_init();
NdbRepStress.setCreateAllTables(true);
return NdbRepStress.execute(argc, argv);
}
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <NDBT.hpp> #include <NDBT.hpp>
#include <NdbApi.hpp> #include <NdbApi.hpp>
#include <HugoTransactions.hpp> #include <HugoTransactions.hpp>
#include <Bitmask.hpp>
#include <Vector.hpp>
static const char* _dbname = "TEST_DB"; static const char* _dbname = "TEST_DB";
static int g_loops = 7; static int g_loops = 7;
...@@ -37,6 +39,7 @@ static int unique_indexes(Ndb*, const NdbDictionary::Table* tab); ...@@ -37,6 +39,7 @@ static int unique_indexes(Ndb*, const NdbDictionary::Table* tab);
static int ordered_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 node_restart(Ndb*, const NdbDictionary::Table* tab);
static int system_restart(Ndb*, const NdbDictionary::Table* tab); static int system_restart(Ndb*, const NdbDictionary::Table* tab);
static int testBitmask();
int int
main(int argc, char** argv){ main(int argc, char** argv){
...@@ -49,6 +52,15 @@ main(int argc, char** argv){ ...@@ -49,6 +52,15 @@ main(int argc, char** argv){
ndb_std_get_one_option))) ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS); 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); Ndb_cluster_connection con(opt_connect_str);
if(con.connect(12, 5, 1)) if(con.connect(12, 5, 1))
{ {
...@@ -60,7 +72,6 @@ main(int argc, char** argv){ ...@@ -60,7 +72,6 @@ main(int argc, char** argv){
pNdb = new Ndb(&con, _dbname); pNdb = new Ndb(&con, _dbname);
pNdb->init(); pNdb->init();
while (pNdb->waitUntilReady() != 0); while (pNdb->waitUntilReady() != 0);
int res = NDBT_FAILED;
NdbDictionary::Dictionary * dict = pNdb->getDictionary(); NdbDictionary::Dictionary * dict = pNdb->getDictionary();
...@@ -121,14 +132,12 @@ create_random_table(Ndb* pNdb) ...@@ -121,14 +132,12 @@ create_random_table(Ndb* pNdb)
do { do {
NdbDictionary::Table tab; NdbDictionary::Table tab;
Uint32 cols = 1 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE - 1)); Uint32 cols = 1 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE - 1));
Uint32 keys = NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY;
Uint32 length = 4090; Uint32 length = 4090;
Uint32 key_size = NDB_MAX_KEYSIZE_IN_WORDS;
BaseString name; BaseString name;
name.assfmt("TAB_%d", rand() & 65535); name.assfmt("TAB_%d", rand() & 65535);
tab.setName(name.c_str()); 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; NdbDictionary::Column col;
name.assfmt("COL_%d", i); name.assfmt("COL_%d", i);
...@@ -206,3 +215,394 @@ system_restart(Ndb* pNdb, const NdbDictionary::Table* tab) ...@@ -206,3 +215,394 @@ system_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
{ {
return 0; 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) ...@@ -1838,6 +1838,61 @@ runBug31701(NDBT_Context* ctx, NDBT_Step* step)
return NDBT_OK; 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); NDBT_TESTSUITE(test_event);
TESTCASE("BasicEventOperation", TESTCASE("BasicEventOperation",
"Verify that we can listen to Events" "Verify that we can listen to Events"
...@@ -1975,6 +2030,12 @@ TESTCASE("Bug31701", ""){ ...@@ -1975,6 +2030,12 @@ TESTCASE("Bug31701", ""){
FINALIZER(runDropEvent); FINALIZER(runDropEvent);
FINALIZER(runDropShadowTable); FINALIZER(runDropShadowTable);
} }
TESTCASE("Bug33793", ""){
INITIALIZER(runCreateEvent);
STEP(runEventListenerUntilStopped);
STEP(runBug33793);
FINALIZER(runDropEvent);
}
NDBT_TESTSUITE_END(test_event); NDBT_TESTSUITE_END(test_event);
int main(int argc, const char** argv){ int main(int argc, const char** argv){
......
...@@ -1046,3 +1046,7 @@ max-time: 300 ...@@ -1046,3 +1046,7 @@ max-time: 300
cmd: testSystemRestart cmd: testSystemRestart
args: -n Bug22696 T1 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) 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 */
/* DbUtil.cpp: implementation of the database utilities class.*/
#include "DbUtil.hpp"
#include <NdbSleep.h>
/* Constructors */
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)
{
const char* env= getenv("MYSQL_HOME");
if (env && strlen(env))
{
m_default_file.assfmt("%s/my.cnf", env);
}
if (_suffix != NULL){
m_default_group.assfmt("client%s", _suffix);
}
else {
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;
}
void
DbUtil::disconnect(){
if (m_mysql != NULL){
if (m_free_mysql)
mysql_close(m_mysql);
m_mysql= NULL;
}
m_connected = false;
}
/* Destructor */
DbUtil::~DbUtil()
{
disconnect();
}
/* Database Login */
void
DbUtil::databaseLogin(const char* system, const char* usr,
const char* password, unsigned int portIn,
const char* sockIn, bool transactional)
{
if (!(m_mysql = mysql_init(NULL)))
{
myerror("DB Login-> mysql_init() failed");
exit(DBU_FAILED);
}
setUser(usr);
setHost(system);
setPassword(password);
setPort(portIn);
setSocket(sockIn);
if (!(mysql_real_connect(m_mysql,
m_host.c_str(),
m_user.c_str(),
m_pass.c_str(),
"test",
m_port,
m_socket.c_str(), 0)))
{
myerror("connection failed");
mysql_close(m_mysql);
exit(DBU_FAILED);
}
m_mysql->reconnect = TRUE;
/* set AUTOCOMMIT */
if(!transactional)
mysql_autocommit(m_mysql, TRUE);
else
mysql_autocommit(m_mysql, FALSE);
#ifdef DEBUG
printf("\n\tConnected to MySQL server version: %s (%lu)\n\n",
mysql_get_server_info(m_mysql),
(unsigned long) mysql_get_server_version(m_mysql));
#endif
selectDb();
}
/* Database Connect */
int
DbUtil::connect()
{
if (!(m_mysql = mysql_init(NULL)))
{
myerror("DB connect-> mysql_init() failed");
return DBU_FAILED;
}
/* Load connection parameters file and group */
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;
}
/*
Connect, read settings from my.cnf
NOTE! user and password can be stored there as well
*/
if (mysql_real_connect(m_mysql, NULL, "root","", m_dbname.c_str(),
0, NULL, 0) == NULL)
{
myerror("connection failed");
mysql_close(m_mysql);
return DBU_FAILED;
}
selectDb();
m_connected = true;
return DBU_OK;
}
/* Database Logout */
void
DbUtil::databaseLogout()
{
if (m_mysql){
#ifdef DEBUG
printf("\n\tClosing the MySQL database connection ...\n\n");
#endif
mysql_close(m_mysql);
}
}
/* Prepare MySQL Statements Cont */
MYSQL_STMT *STDCALL
DbUtil::mysqlSimplePrepare(const char *query)
{
#ifdef DEBUG
printf("Inside DbUtil::mysqlSimplePrepare\n");
#endif
int m_res = DBU_OK;
MYSQL_STMT *my_stmt= mysql_stmt_init(this->getMysql());
if (my_stmt && (m_res = mysql_stmt_prepare(my_stmt, query, strlen(query)))){
this->printStError(my_stmt,"Prepare Statement Failed");
mysql_stmt_close(my_stmt);
exit(DBU_FAILED);
}
return my_stmt;
}
/* Close MySQL Statements Handle */
void
DbUtil::mysqlCloseStmHandle(MYSQL_STMT *my_stmt)
{
mysql_stmt_close(my_stmt);
}
/* Error Printing */
void
DbUtil::printError(const char *msg)
{
if (m_mysql && mysql_errno(m_mysql))
{
if (m_mysql->server_version)
printf("\n [MySQL-%s]", m_mysql->server_version);
else
printf("\n [MySQL]");
printf("[%d] %s\n", getErrorNumber(), getError());
}
else if (msg)
printf(" [MySQL] %s\n", msg);
}
void
DbUtil::printStError(MYSQL_STMT *stmt, const char *msg)
{
if (stmt && mysql_stmt_errno(stmt))
{
if (m_mysql && m_mysql->server_version)
printf("\n [MySQL-%s]", m_mysql->server_version);
else
printf("\n [MySQL]");
printf("[%d] %s\n", mysql_stmt_errno(stmt),
mysql_stmt_error(stmt));
}
else if (msg)
printf("[MySQL] %s\n", msg);
}
/* Select which database to use */
int
DbUtil::selectDb()
{
if ((getDbName()) != NULL)
{
if(mysql_select_db(m_mysql, this->getDbName()))
{
printError("mysql_select_db failed");
return DBU_FAILED;
}
return DBU_OK;
}
printError("getDbName() == NULL");
return DBU_FAILED;
}
int
DbUtil::selectDb(const char * m_db)
{
{
if(mysql_select_db(m_mysql, m_db))
{
printError("mysql_select_db failed");
return DBU_FAILED;
}
return DBU_OK;
}
}
int
DbUtil::createDb(BaseString& m_db)
{
BaseString stm;
{
if(mysql_select_db(m_mysql, m_db.c_str()) == DBU_OK)
{
stm.assfmt("DROP DATABASE %s", m_db.c_str());
if(doQuery(m_db.c_str()) == DBU_FAILED)
return DBU_FAILED;
}
stm.assfmt("CREATE DATABASE %s", m_db.c_str());
if(doQuery(m_db.c_str()) == DBU_FAILED)
return DBU_FAILED;
return DBU_OK;
}
}
/* Count Table Rows */
unsigned long
DbUtil::selectCountTable(const char * table)
{
BaseString query;
SqlResultSet result;
query.assfmt("select count(*) as count from %s", table);
if (!doQuery(query, result)) {
printError("select count(*) failed");
return -1;
}
return result.columnAsInt("count");
}
/* 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)))
{
g_err << "Failed to prepare: " << mysql_error(m_mysql) << endl;
return false;
}
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 *
DbUtil::getError()
{
return mysql_error(this->getMysql());
}
/* Return MySQL Error Number */
int
DbUtil::getErrorNumber()
{
return mysql_errno(this->getMysql());
}
/* DIE */
void
DbUtil::die(const char *file, int line, const char *expr)
{
printf("%s:%d: check failed: '%s'\n", file, line, expr);
abort();
}
/* SqlResultSet */
bool
SqlResultSet::get_row(int row_num){
if(!get("row", row_num, &m_curr_row)){
return false;
}
return true;
}
bool
SqlResultSet::next(void){
return get_row(++m_curr_row_num);
}
// 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 = \ ...@@ -23,10 +23,10 @@ libNDBT_a_SOURCES = \
HugoAsynchTransactions.cpp UtilTransactions.cpp \ HugoAsynchTransactions.cpp UtilTransactions.cpp \
NdbRestarter.cpp NdbRestarts.cpp NDBT_Output.cpp \ NdbRestarter.cpp NdbRestarts.cpp NDBT_Output.cpp \
NdbBackup.cpp NdbConfig.cpp NdbGrep.cpp NDBT_Table.cpp \ NdbBackup.cpp NdbConfig.cpp NdbGrep.cpp NDBT_Table.cpp \
NdbSchemaCon.cpp NdbSchemaOp.cpp getarg.c \ NdbSchemaCon.cpp NdbSchemaOp.cpp getarg.c AtrtClient.cpp \
CpcClient.cpp NdbMixRestarter.cpp NDBT_Thread.cpp dbutil.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/common.mk.am
include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am
......
// dbutil.cpp: implementation of the database utilities class.
//
//////////////////////////////////////////////////////////////////////
#include "dbutil.hpp"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
dbutil::dbutil(const char * dbname)
{
memset(host,' ',sizeof(host));
memset(user,' ',sizeof(pass));
memset(dbs,' ',sizeof(dbs));
port = 0;
memset(socket,' ',sizeof(socket));
this->SetDbName(dbname);
}
dbutil::~dbutil()
{
this->DatabaseLogout();
}
//////////////////////////////////////////////////////////////////////
// Database Login
//////////////////////////////////////////////////////////////////////
void dbutil::DatabaseLogin(const char* system,
const char* usr,
const char* password,
unsigned int portIn,
const char* sockIn,
bool transactional
){
if (!(myDbHandel = mysql_init(NULL))){
myerror("mysql_init() failed");
exit(1);
}
this->SetUser(usr);
this->SetHost(system);
this->SetPassword(password);
this->SetPort(portIn);
this->SetSocket(sockIn);
if (!(mysql_real_connect(myDbHandel, host, user, pass, "test", port, socket, 0))){
myerror("connection failed");
mysql_close(myDbHandel);
fprintf(stdout, "\n Check the connection options using --help or -?\n");
exit(1);
}
myDbHandel->reconnect= 1;
/* set AUTOCOMMIT */
if(!transactional){
mysql_autocommit(myDbHandel, TRUE);
}
else{
mysql_autocommit(myDbHandel, FALSE);
}
fprintf(stdout, "\n\tConnected to MySQL server version: %s (%lu)\n\n",
mysql_get_server_info(myDbHandel),
(unsigned long) mysql_get_server_version(myDbHandel));
}
//////////////////////////////////////////////////////////////////////
// Database Logout
//////////////////////////////////////////////////////////////////////
void dbutil::DatabaseLogout(){
if (myDbHandel){
fprintf(stdout, "\n\tClosing the MySQL database connection ...\n\n");
mysql_close(myDbHandel);
}
}
//////////////////////////////////////////////////////////////////////
// Prepare MySQL Statements Cont
//////////////////////////////////////////////////////////////////////
MYSQL_STMT *STDCALL dbutil::MysqlSimplePrepare(const char *query){
#ifdef DEBUG
printf("Inside dbutil::MysqlSimplePrepare\n");
#endif
int result = 0;
MYSQL_STMT *my_stmt= mysql_stmt_init(this->GetDbHandel());
if (my_stmt && (result = mysql_stmt_prepare(my_stmt, query, strlen(query)))){
printf("res = %s\n",mysql_stmt_error(my_stmt));
mysql_stmt_close(my_stmt);
return 0;
}
return my_stmt;
}
//////////////////////////////////////////////////////////////////////
// Error Printing
//////////////////////////////////////////////////////////////////////
void dbutil::PrintError(const char *msg){
if (this->GetDbHandel()
&& mysql_errno(this->GetDbHandel())){
if (this->GetDbHandel()->server_version){
fprintf(stdout, "\n [MySQL-%s]",
this->GetDbHandel()->server_version);
}
else
fprintf(stdout, "\n [MySQL]");
fprintf(stdout, "[%d] %s\n",
mysql_errno(this->GetDbHandel()),
mysql_error(this->GetDbHandel()));
}
else if (msg)
fprintf(stderr, " [MySQL] %s\n", msg);
}
void dbutil::PrintStError(MYSQL_STMT *stmt, const char *msg)
{
if (stmt && mysql_stmt_errno(stmt))
{
if (this->GetDbHandel()
&& this->GetDbHandel()->server_version)
fprintf(stdout, "\n [MySQL-%s]",
this->GetDbHandel()->server_version);
else
fprintf(stdout, "\n [MySQL]");
fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt),
mysql_stmt_error(stmt));
}
else if (msg)
fprintf(stderr, " [MySQL] %s\n", msg);
}
/////////////////////////////////////////////////////
int dbutil::Select_DB()
{
return mysql_select_db(this->GetDbHandel(),
this->GetDbName());
}
////////////////////////////////////////////////////
int dbutil::Do_Query(char * stm)
{
return mysql_query(this->GetDbHandel(), stm);
}
////////////////////////////////////////////////////
const char * dbutil::GetError()
{
return mysql_error(this->GetDbHandel());
}
////////////////////////////////////////////////////
int dbutil::GetErrorNumber()
{
return mysql_errno(this->GetDbHandel());
}
////////////////////////////////////////////////////
unsigned long dbutil::SelectCountTable(const char * table)
{
unsigned long count = 0;
MYSQL_RES *result;
char query[1024];
MYSQL_ROW row;
sprintf(query,"select count(*) from `%s`", table);
if (mysql_query(this->GetDbHandel(),query) || !(result=mysql_store_result(this->GetDbHandel())))
{
printf("error\n");
return 1;
}
row= mysql_fetch_row(result);
count= (ulong) strtoull(row[0], (char**) 0, 10);
mysql_free_result(result);
return count;
}
void dbutil::Die(const char *file, int line, const char *expr){
fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr);
abort();
}
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