summaryrefslogtreecommitdiff
path: root/storage/ndb/test/ndbapi/testBackup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/test/ndbapi/testBackup.cpp')
-rw-r--r--storage/ndb/test/ndbapi/testBackup.cpp559
1 files changed, 559 insertions, 0 deletions
diff --git a/storage/ndb/test/ndbapi/testBackup.cpp b/storage/ndb/test/ndbapi/testBackup.cpp
new file mode 100644
index 00000000000..810ec3260fd
--- /dev/null
+++ b/storage/ndb/test/ndbapi/testBackup.cpp
@@ -0,0 +1,559 @@
+/* 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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 <HugoTransactions.hpp>
+#include <UtilTransactions.hpp>
+#include <NdbBackup.hpp>
+
+
+#define CHECK(b) if (!(b)) { \
+ g_err << "ERR: "<< step->getName() \
+ << " failed on line " << __LINE__ << endl; \
+ result = NDBT_FAILED; \
+ continue; }
+
+
+int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
+
+ int records = ctx->getNumRecords();
+ HugoTransactions hugoTrans(*ctx->getTab());
+ if (hugoTrans.loadTable(GETNDB(step), records) != 0){
+ return NDBT_FAILED;
+ }
+ return NDBT_OK;
+}
+
+bool testMaster = true;
+bool testSlave = false;
+
+int setMaster(NDBT_Context* ctx, NDBT_Step* step){
+ testMaster = true;
+ testSlave = false;
+ return NDBT_OK;
+}
+int setMasterAsSlave(NDBT_Context* ctx, NDBT_Step* step){
+ testMaster = true;
+ testSlave = true;
+ return NDBT_OK;
+}
+int setSlave(NDBT_Context* ctx, NDBT_Step* step){
+ testMaster = false;
+ testSlave = true;
+ return NDBT_OK;
+}
+
+int runAbort(NDBT_Context* ctx, NDBT_Step* step){
+ NdbBackup backup(GETNDB(step)->getNodeId()+1);
+
+ NdbRestarter restarter;
+
+ if (restarter.getNumDbNodes() < 2){
+ ctx->stopTest();
+ return NDBT_OK;
+ }
+
+ if(restarter.waitClusterStarted(60) != 0){
+ g_err << "Cluster failed to start" << endl;
+ return NDBT_FAILED;
+ }
+
+ if (testMaster) {
+ if (testSlave) {
+ if (backup.NFMasterAsSlave(restarter) != NDBT_OK){
+ return NDBT_FAILED;
+ }
+ } else {
+ if (backup.NFMaster(restarter) != NDBT_OK){
+ return NDBT_FAILED;
+ }
+ }
+ } else {
+ if (backup.NFSlave(restarter) != NDBT_OK){
+ return NDBT_FAILED;
+ }
+ }
+
+ return NDBT_OK;
+}
+
+int runFail(NDBT_Context* ctx, NDBT_Step* step){
+ NdbBackup backup(GETNDB(step)->getNodeId()+1);
+
+ NdbRestarter restarter;
+
+ if (restarter.getNumDbNodes() < 2){
+ ctx->stopTest();
+ return NDBT_OK;
+ }
+
+ if(restarter.waitClusterStarted(60) != 0){
+ g_err << "Cluster failed to start" << endl;
+ return NDBT_FAILED;
+ }
+
+ if (testMaster) {
+ if (testSlave) {
+ if (backup.FailMasterAsSlave(restarter) != NDBT_OK){
+ return NDBT_FAILED;
+ }
+ } else {
+ if (backup.FailMaster(restarter) != NDBT_OK){
+ return NDBT_FAILED;
+ }
+ }
+ } else {
+ if (backup.FailSlave(restarter) != NDBT_OK){
+ return NDBT_FAILED;
+ }
+ }
+
+ return NDBT_OK;
+}
+
+int runBackupOne(NDBT_Context* ctx, NDBT_Step* step){
+ NdbBackup backup(GETNDB(step)->getNodeId()+1);
+ unsigned backupId = 0;
+
+ if (backup.start(backupId) == -1){
+ return NDBT_FAILED;
+ }
+ ndbout << "Started backup " << backupId << endl;
+ ctx->setProperty("BackupId", backupId);
+
+ return NDBT_OK;
+}
+
+int
+runBackupLoop(NDBT_Context* ctx, NDBT_Step* step){
+ NdbBackup backup(GETNDB(step)->getNodeId()+1);
+ unsigned backupId = 0;
+
+ int loops = ctx->getNumLoops();
+ while(!ctx->isTestStopped() && loops--)
+ {
+ if (backup.start(backupId) == -1)
+ {
+ sleep(1);
+ loops++;
+ }
+ else
+ {
+ sleep(3);
+ }
+ }
+
+ ctx->stopTest();
+ return NDBT_OK;
+}
+
+int
+runDDL(NDBT_Context* ctx, NDBT_Step* step){
+ Ndb* pNdb= GETNDB(step);
+ NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
+
+ const int tables = NDBT_Tables::getNumTables();
+ while(!ctx->isTestStopped())
+ {
+ const int tab_no = rand() % (tables);
+ NdbDictionary::Table tab = *NDBT_Tables::getTable(tab_no);
+ BaseString name= tab.getName();
+ name.appfmt("-%d", step->getStepNo());
+ tab.setName(name.c_str());
+ if(pDict->createTable(tab) == 0)
+ {
+ HugoTransactions hugoTrans(* pDict->getTable(name.c_str()));
+ if (hugoTrans.loadTable(pNdb, 10000) != 0){
+ return NDBT_FAILED;
+ }
+
+ while(pDict->dropTable(tab.getName()) != 0 &&
+ pDict->getNdbError().code != 4009)
+ g_err << pDict->getNdbError() << endl;
+
+ sleep(1);
+
+ }
+ }
+ return NDBT_OK;
+}
+
+
+int runDropTablesRestart(NDBT_Context* ctx, NDBT_Step* step){
+ NdbRestarter restarter;
+
+ Ndb* pNdb = GETNDB(step);
+
+ const NdbDictionary::Table *tab = ctx->getTab();
+ pNdb->getDictionary()->dropTable(tab->getName());
+
+ if (restarter.restartAll(false) != 0)
+ return NDBT_FAILED;
+
+ if (restarter.waitClusterStarted() != 0)
+ return NDBT_FAILED;
+
+ return NDBT_OK;
+}
+
+int runRestoreOne(NDBT_Context* ctx, NDBT_Step* step){
+ NdbBackup backup(GETNDB(step)->getNodeId()+1);
+ unsigned backupId = ctx->getProperty("BackupId");
+
+ ndbout << "Restoring backup " << backupId << endl;
+
+ if (backup.restore(backupId) == -1){
+ return NDBT_FAILED;
+ }
+
+ return NDBT_OK;
+}
+
+int runVerifyOne(NDBT_Context* ctx, NDBT_Step* step){
+ int records = ctx->getNumRecords();
+ Ndb* pNdb = GETNDB(step);
+ int result = NDBT_OK;
+ int count = 0;
+
+ const NdbDictionary::Table* tab =
+ GETNDB(step)->getDictionary()->getTable(ctx->getTab()->getName());
+ if(tab == 0)
+ return NDBT_FAILED;
+
+ UtilTransactions utilTrans(* tab);
+ HugoTransactions hugoTrans(* tab);
+
+ do{
+
+ // Check that there are as many records as we expected
+ CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
+
+ g_err << "count = " << count;
+ g_err << " records = " << records;
+ g_err << endl;
+
+ CHECK(count == records);
+
+ // Read and verify every record
+ CHECK(hugoTrans.pkReadRecords(pNdb, records) == 0);
+
+ } while (false);
+
+ return result;
+}
+
+int runClearTable(NDBT_Context* ctx, NDBT_Step* step){
+ int records = ctx->getNumRecords();
+
+ UtilTransactions utilTrans(*ctx->getTab());
+ if (utilTrans.clearTable2(GETNDB(step), records) != 0){
+ return NDBT_FAILED;
+ }
+ return NDBT_OK;
+}
+
+int runDropTable(NDBT_Context* ctx, NDBT_Step* step){
+ GETNDB(step)->getDictionary()->dropTable(ctx->getTab()->getName());
+ return NDBT_OK;
+}
+
+#include "bank/Bank.hpp"
+
+int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){
+ Bank bank(ctx->m_cluster_connection);
+ int overWriteExisting = true;
+ if (bank.createAndLoadBank(overWriteExisting, 10) != NDBT_OK)
+ return NDBT_FAILED;
+ return NDBT_OK;
+}
+
+int runBankTimer(NDBT_Context* ctx, NDBT_Step* step){
+ Bank bank(ctx->m_cluster_connection);
+ int wait = 30; // Max seconds between each "day"
+ int yield = 1; // Loops before bank returns
+
+ while (ctx->isTestStopped() == false) {
+ bank.performIncreaseTime(wait, yield);
+ }
+ return NDBT_OK;
+}
+
+int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){
+ Bank bank(ctx->m_cluster_connection);
+ int wait = 10; // Max ms between each transaction
+ int yield = 100; // Loops before bank returns
+
+ while (ctx->isTestStopped() == false) {
+ bank.performTransactions(wait, yield);
+ }
+ return NDBT_OK;
+}
+
+int runBankGL(NDBT_Context* ctx, NDBT_Step* step){
+ Bank bank(ctx->m_cluster_connection);
+ int yield = 20; // Loops before bank returns
+ int result = NDBT_OK;
+
+ while (ctx->isTestStopped() == false) {
+ if (bank.performMakeGLs(yield) != NDBT_OK){
+ ndbout << "bank.performMakeGLs FAILED" << endl;
+ result = NDBT_FAILED;
+ }
+ }
+ return NDBT_OK;
+}
+
+int runBankSum(NDBT_Context* ctx, NDBT_Step* step){
+ Bank bank(ctx->m_cluster_connection);
+ int wait = 2000; // Max ms between each sum of accounts
+ int yield = 1; // Loops before bank returns
+ int result = NDBT_OK;
+
+ while (ctx->isTestStopped() == false) {
+ if (bank.performSumAccounts(wait, yield) != NDBT_OK){
+ ndbout << "bank.performSumAccounts FAILED" << endl;
+ result = NDBT_FAILED;
+ }
+ }
+ return result ;
+}
+
+int runDropBank(NDBT_Context* ctx, NDBT_Step* step){
+ Bank bank(ctx->m_cluster_connection);
+ if (bank.dropBank() != NDBT_OK)
+ return NDBT_FAILED;
+ return NDBT_OK;
+}
+
+int runBackupBank(NDBT_Context* ctx, NDBT_Step* step){
+ int loops = ctx->getNumLoops();
+ int l = 0;
+ int maxSleep = 30; // Max seconds between each backup
+ Ndb* pNdb = GETNDB(step);
+ NdbBackup backup(GETNDB(step)->getNodeId()+1);
+ unsigned minBackupId = ~0;
+ unsigned maxBackupId = 0;
+ unsigned backupId = 0;
+ int result = NDBT_OK;
+
+ while (l < loops && result != NDBT_FAILED){
+
+ if (pNdb->waitUntilReady() != 0){
+ result = NDBT_FAILED;
+ continue;
+ }
+
+ // Sleep for a while
+ NdbSleep_SecSleep(maxSleep);
+
+ // Perform backup
+ if (backup.start(backupId) != 0){
+ ndbout << "backup.start failed" << endl;
+ result = NDBT_FAILED;
+ continue;
+ }
+ ndbout << "Started backup " << backupId << endl;
+
+ // Remember min and max backupid
+ if (backupId < minBackupId)
+ minBackupId = backupId;
+
+ if (backupId > maxBackupId)
+ maxBackupId = backupId;
+
+ ndbout << " maxBackupId = " << maxBackupId
+ << ", minBackupId = " << minBackupId << endl;
+ ctx->setProperty("MinBackupId", minBackupId);
+ ctx->setProperty("MaxBackupId", maxBackupId);
+
+ l++;
+ }
+
+ ctx->stopTest();
+
+ return result;
+}
+
+int runRestoreBankAndVerify(NDBT_Context* ctx, NDBT_Step* step){
+ NdbRestarter restarter;
+ NdbBackup backup(GETNDB(step)->getNodeId()+1);
+ unsigned minBackupId = ctx->getProperty("MinBackupId");
+ unsigned maxBackupId = ctx->getProperty("MaxBackupId");
+ unsigned backupId = minBackupId;
+ int result = NDBT_OK;
+ int errSumAccounts = 0;
+ int errValidateGL = 0;
+
+ ndbout << " maxBackupId = " << maxBackupId << endl;
+ ndbout << " minBackupId = " << minBackupId << endl;
+
+ while (backupId <= maxBackupId){
+
+ // TEMPORARY FIX
+ // To erase all tables from cache(s)
+ // To be removed, maybe replaced by ndb.invalidate();
+ runDropTable(ctx,step);
+ {
+ Bank bank(ctx->m_cluster_connection);
+
+ if (bank.dropBank() != NDBT_OK){
+ result = NDBT_FAILED;
+ break;
+ }
+ }
+ // END TEMPORARY FIX
+
+ ndbout << "Performing restart" << endl;
+ if (restarter.restartAll(false) != 0)
+ return NDBT_FAILED;
+
+ if (restarter.waitClusterStarted() != 0)
+ return NDBT_FAILED;
+
+ ndbout << "Restoring backup " << backupId << endl;
+ if (backup.restore(backupId) == -1){
+ return NDBT_FAILED;
+ }
+ ndbout << "Backup " << backupId << " restored" << endl;
+
+ // Let bank verify
+ Bank bank(ctx->m_cluster_connection);
+
+ int wait = 0;
+ int yield = 1;
+ if (bank.performSumAccounts(wait, yield) != 0){
+ ndbout << "bank.performSumAccounts FAILED" << endl;
+ ndbout << " backupId = " << backupId << endl << endl;
+ result = NDBT_FAILED;
+ errSumAccounts++;
+ }
+
+ if (bank.performValidateAllGLs() != 0){
+ ndbout << "bank.performValidateAllGLs FAILED" << endl;
+ ndbout << " backupId = " << backupId << endl << endl;
+ result = NDBT_FAILED;
+ errValidateGL++;
+ }
+
+ backupId++;
+ }
+
+ if (result != NDBT_OK){
+ ndbout << "Verification of backup failed" << endl
+ << " errValidateGL="<<errValidateGL<<endl
+ << " errSumAccounts="<<errSumAccounts<<endl << endl;
+ }
+
+ return result;
+}
+
+NDBT_TESTSUITE(testBackup);
+TESTCASE("BackupOne",
+ "Test that backup and restore works on one table \n"
+ "1. Load table\n"
+ "2. Backup\n"
+ "3. Drop tables and restart \n"
+ "4. Restore\n"
+ "5. Verify count and content of table\n"){
+ INITIALIZER(runLoadTable);
+ INITIALIZER(runBackupOne);
+ INITIALIZER(runDropTablesRestart);
+ INITIALIZER(runRestoreOne);
+ VERIFIER(runVerifyOne);
+ FINALIZER(runClearTable);
+}
+TESTCASE("BackupDDL",
+ "Test that backup and restore works on with DDL ongoing\n"
+ "1. Backups and DDL (create,drop,table.index)"){
+ INITIALIZER(runLoadTable);
+ STEP(runBackupLoop);
+ STEP(runDDL);
+ STEP(runDDL);
+ FINALIZER(runClearTable);
+}
+TESTCASE("BackupBank",
+ "Test that backup and restore works during transaction load\n"
+ " by backing up the bank"
+ "1. Create bank\n"
+ "2a. Start bank and let it run\n"
+ "2b. Perform loop number of backups of the bank\n"
+ " when backups are finished tell bank to close\n"
+ "3. Restart ndb -i and reload each backup\n"
+ " let bank verify that the backup is consistent\n"
+ "4. Drop bank\n"){
+ INITIALIZER(runCreateBank);
+ STEP(runBankTimer);
+ STEP(runBankTransactions);
+ STEP(runBankTransactions);
+ STEP(runBankTransactions);
+ STEP(runBankTransactions);
+ STEP(runBankTransactions);
+ STEP(runBankTransactions);
+ STEP(runBankTransactions);
+ STEP(runBankTransactions);
+ STEP(runBankTransactions);
+ STEP(runBankTransactions);
+ STEP(runBankGL);
+ // TODO STEP(runBankSum);
+ STEP(runBackupBank);
+ VERIFIER(runRestoreBankAndVerify);
+ // FINALIZER(runDropBank);
+}
+TESTCASE("NFMaster",
+ "Test that backup behaves during node failiure\n"){
+ INITIALIZER(setMaster);
+ STEP(runAbort);
+
+}
+TESTCASE("NFMasterAsSlave",
+ "Test that backup behaves during node failiure\n"){
+ INITIALIZER(setMasterAsSlave);
+ STEP(runAbort);
+
+}
+TESTCASE("NFSlave",
+ "Test that backup behaves during node failiure\n"){
+ INITIALIZER(setSlave);
+ STEP(runAbort);
+
+}
+TESTCASE("FailMaster",
+ "Test that backup behaves during node failiure\n"){
+ INITIALIZER(setMaster);
+ STEP(runFail);
+
+}
+TESTCASE("FailMasterAsSlave",
+ "Test that backup behaves during node failiure\n"){
+ INITIALIZER(setMasterAsSlave);
+ STEP(runFail);
+
+}
+TESTCASE("FailSlave",
+ "Test that backup behaves during node failiure\n"){
+ INITIALIZER(setSlave);
+ STEP(runFail);
+
+}
+NDBT_TESTSUITE_END(testBackup);
+
+int main(int argc, const char** argv){
+ ndb_init();
+ return testBackup.execute(argc, argv);
+}
+
+