#At file:///home/msvensson/mysql/6.3-wl4531/
2729 Magnus Svensson 2008-10-30
WL#4531 Test program to check that mysqld can recover from total cluster failure
added:
storage/ndb/test/ndbapi/testReconnect.cpp
modified:
storage/ndb/test/include/DbUtil.hpp
storage/ndb/test/ndbapi/Makefile.am
storage/ndb/test/src/DbUtil.cpp
=== modified file 'storage/ndb/test/include/DbUtil.hpp'
--- a/storage/ndb/test/include/DbUtil.hpp 2008-03-03 15:10:42 +0000
+++ b/storage/ndb/test/include/DbUtil.hpp 2008-10-30 15:15:48 +0000
@@ -97,10 +97,12 @@ public:
bool doQuery(const char* query);
bool doQuery(const char* query, SqlResultSet& result);
bool doQuery(const char* query, const Properties& args, SqlResultSet& result);
+ bool doQuery(const char* query, const Properties& args);
bool doQuery(BaseString& str);
bool doQuery(BaseString& str, SqlResultSet& result);
bool doQuery(BaseString& str, const Properties& args, SqlResultSet& result);
+ bool doQuery(BaseString& str, const Properties& args);
bool waitConnected(int timeout);
@@ -131,9 +133,13 @@ public:
bool selectDb(const char *);
bool createDb(BaseString&);
int getErrorNumber();
+ const char* last_error() const { return m_last_error.c_str(); }
+ int last_errno() const { return m_last_errno; }
unsigned long selectCountTable(const char * table);
+ void silent() { m_silent= true; };
+
protected:
bool runQuery(const char* query,
@@ -159,6 +165,14 @@ private:
unsigned int m_port; // MySQL Server port
+ int m_last_errno;
+ BaseString m_last_error;
+
+ bool m_silent;
+
+ void report_error(const char* message, MYSQL* mysql);
+ void clear_error(void) { m_last_errno= 0; m_last_error.clear(); }
+
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);};
=== modified file 'storage/ndb/test/ndbapi/Makefile.am'
--- a/storage/ndb/test/ndbapi/Makefile.am 2008-09-30 08:18:41 +0000
+++ b/storage/ndb/test/ndbapi/Makefile.am 2008-10-30 15:15:48 +0000
@@ -57,6 +57,7 @@ testIndexStat \
ndbapi_50compat0 \
ndbapi_50compat1 \
testNDBT \
+testReconnect \
NdbRepStress \
msa
@@ -108,6 +109,8 @@ testLcp_SOURCES = testLcp.cpp
testPartitioning_SOURCES = testPartitioning.cpp
testNDBT_SOURCES = testNDBT.cpp
testNDBT_LDADD = $(LDADD) $(top_srcdir)/libmysql_r/libmysqlclient_r.la
+testReconnect_SOURCES = testReconnect.cpp
+testReconnect_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
=== added file 'storage/ndb/test/ndbapi/testReconnect.cpp'
--- a/storage/ndb/test/ndbapi/testReconnect.cpp 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/ndbapi/testReconnect.cpp 2008-10-30 15:15:48 +0000
@@ -0,0 +1,204 @@
+/* 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>
+
+#include <NdbRestarts.hpp>
+
+
+int runCreateTable(NDBT_Context* ctx, NDBT_Step* step){
+ DbUtil sql("test");
+
+ if (!sql.doQuery("CREATE TABLE reconnect ("
+ "pk bigint, "
+ "thread int, "
+ "b varchar(32) NOT NULL, "
+ "PRIMARY KEY(pk, thread)"
+ ") engine = NDB;"))
+ return NDBT_FAILED;
+ return NDBT_OK;
+}
+
+int runDropTable(NDBT_Context* ctx, NDBT_Step* step){
+ DbUtil sql("test");
+
+ if (!sql.doQuery("DROP TABLE IF EXISTS reconnect"))
+ return NDBT_FAILED;
+ return NDBT_OK;
+}
+
+
+int runSQLQueries(NDBT_Context* ctx, NDBT_Step* step,
+ const char* query)
+{
+ int result = -1;
+ DbUtil sql("test");
+
+ unsigned failed = 0;
+ unsigned i = 0;
+ unsigned shutdown_counter= 0;
+ while (result == -1)
+ {
+ Properties args;
+ args.put("0", i);
+ if (!sql.doQuery(query, args))
+ {
+ switch(sql.last_errno()){
+ case 2006: // MySQL server has gone away(ie. crash)
+ g_err << "Fatal error: " << sql.last_error() << endl;
+ g_err.print("query: %s", query);
+ result = NDBT_FAILED;
+ break;
+ default:
+ // Ignore
+ failed++;
+ break;
+ }
+ }
+ else
+ g_info << query << endl;
+ sql.silent(); // Late, to catch any SQL syntax errors
+ i++;
+
+ if (ctx->isTestStopped())
+ {
+ // When the test is stopped we run additional queries
+ // that all should work
+
+ if (shutdown_counter == 0)
+ {
+ shutdown_counter = i;
+ }
+ else
+ {
+ unsigned extra_loops= i - shutdown_counter;
+
+ if (extra_loops < 10)
+ {
+ // Check that last query suceeded
+ if (sql.last_errno() != 0)
+ {
+ g_err << "Fatal error during shutdown queries: "
+ << sql.last_error() << endl;
+ g_err.print("query: %s", query);
+ result = NDBT_FAILED;
+ }
+ }
+ else
+ {
+ // We are done, signal sucess
+ result= NDBT_OK;
+ }
+ }
+ }
+
+ }
+ ctx->stopTest();
+ g_info << i - failed << " queries completed and "
+ << failed << " failed" << endl;
+ return result;
+}
+
+
+int runINSERT(NDBT_Context* ctx, NDBT_Step* step){
+ BaseString query;
+ query.assfmt("INSERT INTO reconnect "
+ "(pk, thread, b) VALUES (?, %d, 'data%d')",
+ step->getStepNo(), step->getStepNo());
+ return runSQLQueries(ctx, step, query.c_str());
+
+}
+
+
+int runSELECT(NDBT_Context* ctx, NDBT_Step* step){
+ return runSQLQueries(ctx, step, "SELECT * FROM reconnect");
+}
+
+
+int runDELETE(NDBT_Context* ctx, NDBT_Step* step){
+ BaseString query;
+ query.assfmt("DELETE from reconnect WHERE thread=%d LIMIT 10",
+ step->getStepNo());
+ return runSQLQueries(ctx, step, query.c_str());
+}
+
+
+int runRestartCluster(NDBT_Context* ctx, NDBT_Step* step){
+ int result = NDBT_OK;
+ int loops = ctx->getNumLoops();
+ NdbRestarts restarts;
+ int i = 0;
+ int timeout = 240;
+
+ while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){
+
+ ndbout << "Loop " << i << "/"<< loops <<" started" << endl;
+
+ if(restarts.executeRestart("RestartAllNodesAbort", timeout) != 0){
+ g_err << "Failed to restart all nodes with abort" << endl;
+ result = NDBT_FAILED;
+ break;
+ }
+
+ NdbSleep_SecSleep(10);
+ i++;
+ }
+ ctx->stopTest();
+ return result;
+}
+
+
+NDBT_TESTSUITE(testSQL);
+TESTCASE("InsertAndRestart",
+ "Run INSERTs while cluster restart"){
+ INITIALIZER(runDropTable);
+ INITIALIZER(runCreateTable);
+ STEP(runINSERT);
+ STEP(runRestartCluster);
+}
+TESTCASE("SelectAndRestart",
+ "Run SELECTs while cluster restart"){
+ INITIALIZER(runDropTable);
+ INITIALIZER(runCreateTable);
+ STEP(runSELECT);
+ STEP(runRestartCluster);
+}
+TESTCASE("DeleteAndRestart",
+ "Run DELETEs while cluster restart"){
+ INITIALIZER(runDropTable);
+ INITIALIZER(runCreateTable);
+ STEP(runDELETE);
+ STEP(runRestartCluster);
+}
+TESTCASE("AllAndRestart",
+ "Run all kind of statements while cluster restart"){
+ INITIALIZER(runDropTable);
+ INITIALIZER(runCreateTable);
+ STEPS(runSELECT, 5);
+ STEPS(runINSERT, 25);
+ STEPS(runDELETE, 2);
+ STEP(runRestartCluster);
+}
+
+NDBT_TESTSUITE_END(testSQL);
+
+int main(int argc, const char** argv){
+ ndb_init();
+ return testSQL.execute(argc, argv);
+}
+
=== modified file 'storage/ndb/test/src/DbUtil.cpp'
--- a/storage/ndb/test/src/DbUtil.cpp 2008-04-09 09:42:01 +0000
+++ b/storage/ndb/test/src/DbUtil.cpp 2008-10-30 15:15:48 +0000
@@ -28,7 +28,8 @@ DbUtil::DbUtil(const char* _dbname,
m_connected(false),
m_user("root"),
m_pass(""),
- m_dbname(_dbname)
+ m_dbname(_dbname),
+ m_silent(false)
{
const char* env= getenv("MYSQL_HOME");
if (env && strlen(env))
@@ -335,9 +336,10 @@ DbUtil::selectCountTable(const char * ta
bool
DbUtil::runQuery(const char* sql,
- const Properties& args,
- SqlResultSet& rows){
+ const Properties& args,
+ SqlResultSet& rows){
+ clear_error();
rows.clear();
if (!isConnected())
return false;
@@ -350,7 +352,7 @@ DbUtil::runQuery(const char* sql,
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;
+ report_error("Failed to prepare: ", m_mysql);
return false;
}
@@ -393,14 +395,14 @@ DbUtil::runQuery(const char* sql,
}
if (mysql_stmt_bind_param(stmt, bind_param))
{
- g_err << "Failed to bind param: " << mysql_error(m_mysql) << endl;
+ report_error("Failed to bind param: ", m_mysql);
mysql_stmt_close(stmt);
return false;
}
if (mysql_stmt_execute(stmt))
{
- g_err << "Failed to execute: " << mysql_error(m_mysql) << endl;
+ report_error("Failed to execute: ", m_mysql);
mysql_stmt_close(stmt);
return false;
}
@@ -414,7 +416,7 @@ DbUtil::runQuery(const char* sql,
if (mysql_stmt_store_result(stmt))
{
- g_err << "Failed to store result: " << mysql_error(m_mysql) << endl;
+ report_error("Failed to store result: ", m_mysql);
mysql_stmt_close(stmt);
return false;
}
@@ -452,7 +454,7 @@ DbUtil::runQuery(const char* sql,
}
if (mysql_stmt_bind_result(stmt, bind_result)){
- g_err << "Failed to bind result: " << mysql_error(m_mysql) << endl;
+ report_error("Failed to bind result: ", m_mysql);
mysql_stmt_close(stmt);
return false;
}
@@ -525,6 +527,12 @@ DbUtil::doQuery(const char* query, const
return true;
}
+bool
+DbUtil::doQuery(const char* query, const Properties& args){
+ SqlResultSet result;
+ return doQuery(query, args, result);
+}
+
bool
DbUtil::doQuery(BaseString& str){
@@ -545,6 +553,12 @@ DbUtil::doQuery(BaseString& str, const P
}
+bool
+DbUtil::doQuery(BaseString& str, const Properties& args){
+ return doQuery(str.c_str(), args);
+}
+
+
/* Return MySQL Error String */
const char *
@@ -561,6 +575,17 @@ DbUtil::getErrorNumber()
return mysql_errno(this->getMysql());
}
+void
+DbUtil::report_error(const char* message, MYSQL* mysql)
+{
+ m_last_errno= mysql_errno(mysql);
+ m_last_error.assfmt("%d: %s", m_last_errno, mysql_error(mysql));
+
+ if (!m_silent)
+ g_err << message << m_last_error << endl;
+}
+
+
/* DIE */
void
| Thread |
|---|
| • bzr commit into mysql-5.1 branch (msvensson:2729) WL#4531 | Magnus Svensson | 30 Oct |