polardbxengine/storage/ndb/test/ndbapi/testUpgrade.cpp

2285 lines
58 KiB
C++

/*
Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
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, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <NDBT.hpp>
#include <NDBT_Test.hpp>
#include <HugoTransactions.hpp>
#include <UtilTransactions.hpp>
#include <NdbRestarter.hpp>
#include <AtrtClient.hpp>
#include <Bitmask.hpp>
#include <NdbBackup.hpp>
#include <ndb_version.h>
#include <random.h>
#include <NdbMutex.h>
#include <NdbEnv.h>
#include <signaldata/DumpStateOrd.hpp>
static Vector<BaseString> table_list;
static Uint32 preVersion = 0;
static Uint32 postVersion = 0;
struct NodeInfo
{
int nodeId;
int processId;
int nodeGroup;
};
static
const char* getBaseDir()
{
/* Atrt basedir exposed via env var MYSQL_HOME */
const char* envHome = NdbEnv_GetEnv("MYSQL_HOME", NULL, 0);
if (envHome == NULL)
{
ndbout_c("testUpgrade getBaseDir() MYSQL_HOME not set");
return "./";
}
else
{
return envHome;
}
}
int CMT_createTableHook(Ndb* ndb,
NdbDictionary::Table& table,
int when,
void* arg)
{
if (when == 0)
{
Uint32 num = ((Uint32*) arg)[0];
Uint32 fragCount = ((Uint32*) arg)[1];
/* Substitute a unique name */
char buf[100];
BaseString::snprintf(buf, sizeof(buf),
"%s_%u",
table.getName(),
num);
table.setName(buf);
if (fragCount > 0)
{
table.setFragmentCount(fragCount);
table.setPartitionBalance(
NdbDictionary::Object::PartitionBalance_Specific);
}
ndbout << "Creating " << buf
<< " with fragment count " << fragCount
<< endl;
}
return 0;
}
Uint32
determineMaxFragCount(NDBT_Context* ctx, NDBT_Step* step)
{
Ndb* pNdb = GETNDB(step);
NdbDictionary::Dictionary* dict = pNdb->getDictionary();
/* Find max # frags we can create... */
ndbout << "Determining max fragment count on this cluster" << endl;
Uint32 fc = (ctx->getTab()->getFragmentCount() * 2);
ndbout << "Start point " << fc << endl;
bool up = true;
do
{
ndbout << "Trying " << fc << " ...";
NdbDictionary::HashMap hm;
bool ok = (dict->getDefaultHashMap(hm, fc) == 0);
ndbout << "a" << endl;
if (!ok)
{
if (dict->initDefaultHashMap(hm, fc) == 0)
{
ndbout << "b" << endl;
ok = (dict->createHashMap(hm) == 0);
}
ndbout << "c" << endl;
}
if (ok)
{
Uint32 args[2];
args[0] = 0;
args[1] = fc;
if (NDBT_Tables::createTable(pNdb,
ctx->getTab()->getName(),
false,
false,
CMT_createTableHook,
&args) != 0)
{
ok = false;
}
else
{
/* Worked, drop it... */
char buf[100];
BaseString::snprintf(buf, sizeof(buf),
"%s_%u",
ctx->getTab()->getName(),
0);
ndbout << "Dropping " << buf << endl;
pNdb->getDictionary()->dropTable(buf);
}
}
if (ok)
{
ndbout << "ok" << endl;
if (up)
{
fc*= 2;
}
else
{
break;
}
}
else
{
ndbout << "failed" << endl;
if (up)
{
up = false;
}
fc--;
}
} while (true);
ndbout << "Max frag count : " << fc << endl;
return fc;
}
static const Uint32 defaultManyTableCount = 70;
int
createManyTables(NDBT_Context* ctx, NDBT_Step* step)
{
Ndb* pNdb = GETNDB(step);
Uint32 tableCount = ctx->getProperty("ManyTableCount", defaultManyTableCount);
Uint32 fragmentCount = ctx->getProperty("FragmentCount", Uint32(0));
/* fragmentCount
* 0 = default
* 1..n = as requested
* ~Uint32(0) = max possible
*/
if (fragmentCount == ~Uint32(0))
{
fragmentCount = determineMaxFragCount(ctx, step);
}
for (Uint32 tn = 1; tn < tableCount; tn++)
{
Uint32 args[2];
args[0] = tn;
args[1] = fragmentCount;
if (NDBT_Tables::createTable(pNdb,
ctx->getTab()->getName(),
false,
false,
CMT_createTableHook,
&args) != 0)
{
return NDBT_FAILED;
}
}
return NDBT_OK;
}
int dropManyTables(NDBT_Context* ctx, NDBT_Step* step)
{
Ndb* pNdb = GETNDB(step);
Uint32 tableCount = ctx->getProperty("ManyTableCount", defaultManyTableCount);
char buf[100];
for (Uint32 tn = 0; tn < tableCount; tn++)
{
BaseString::snprintf(buf, sizeof(buf),
"%s_%u",
ctx->getTab()->getName(),
tn);
ndbout << "Dropping " << buf << endl;
pNdb->getDictionary()->dropTable(buf);
}
return NDBT_OK;
}
static
int
createEvent(Ndb *pNdb,
const NdbDictionary::Table &tab,
bool merge_events = true,
bool report = true)
{
char eventName[1024];
sprintf(eventName,"%s_EVENT",tab.getName());
NdbDictionary::Dictionary *myDict = pNdb->getDictionary();
if (!myDict) {
g_err << "Dictionary not found "
<< pNdb->getNdbError().code << " "
<< pNdb->getNdbError().message << endl;
return NDBT_FAILED;
}
myDict->dropEvent(eventName);
NdbDictionary::Event myEvent(eventName);
myEvent.setTable(tab.getName());
myEvent.addTableEvent(NdbDictionary::Event::TE_ALL);
for(int a = 0; a < tab.getNoOfColumns(); a++){
myEvent.addEventColumn(a);
}
myEvent.mergeEvents(merge_events);
if (report)
myEvent.setReport(NdbDictionary::Event::ER_SUBSCRIBE);
int res = myDict->createEvent(myEvent); // Add event to database
if (res == 0)
myEvent.print();
else if (myDict->getNdbError().classification ==
NdbError::SchemaObjectExists)
{
g_info << "Event creation failed event exists\n";
res = myDict->dropEvent(eventName);
if (res) {
g_err << "Failed to drop event: "
<< myDict->getNdbError().code << " : "
<< myDict->getNdbError().message << endl;
return NDBT_FAILED;
}
// try again
res = myDict->createEvent(myEvent); // Add event to database
if (res) {
g_err << "Failed to create event (1): "
<< myDict->getNdbError().code << " : "
<< myDict->getNdbError().message << endl;
return NDBT_FAILED;
}
}
else
{
g_err << "Failed to create event (2): "
<< myDict->getNdbError().code << " : "
<< myDict->getNdbError().message << endl;
return NDBT_FAILED;
}
return NDBT_OK;
}
static
int
dropEvent(Ndb *pNdb, const NdbDictionary::Table &tab)
{
char eventName[1024];
sprintf(eventName,"%s_EVENT",tab.getName());
NdbDictionary::Dictionary *myDict = pNdb->getDictionary();
if (!myDict) {
g_err << "Dictionary not found "
<< pNdb->getNdbError().code << " "
<< pNdb->getNdbError().message << endl;
return NDBT_FAILED;
}
if (myDict->dropEvent(eventName)) {
g_err << "Failed to drop event: "
<< myDict->getNdbError().code << " : "
<< myDict->getNdbError().message << endl;
return NDBT_FAILED;
}
return NDBT_OK;
}
static NdbMutex* createDropEvent_mutex = 0;
static
int
createDropEvent(NDBT_Context* ctx, NDBT_Step* step, bool wait = true)
{
if (!wait)
{
if (NdbMutex_Trylock(createDropEvent_mutex) != 0)
{
g_err << "Skipping createDropEvent since already running in other process" << endl;
return NDBT_OK;
}
}
else if (NdbMutex_Lock(createDropEvent_mutex) != 0)
{
g_err << "Error while locking createDropEvent_mutex" << endl;
return NDBT_FAILED;
}
Ndb* pNdb = GETNDB(step);
NdbDictionary::Dictionary *myDict = pNdb->getDictionary();
int res = NDBT_OK;
if (ctx->getProperty("NoDDL", Uint32(0)) == 0)
{
for (unsigned i = 0; i<table_list.size(); i++)
{
const NdbDictionary::Table* tab = myDict->getTable(table_list[i].c_str());
if (tab == 0)
{
continue;
}
if ((res = createEvent(pNdb, *tab) != NDBT_OK))
{
goto done;
}
if ((res = dropEvent(pNdb, *tab)) != NDBT_OK)
{
goto done;
}
}
}
done:
if (NdbMutex_Unlock(createDropEvent_mutex) != 0)
{
g_err << "Error while unlocking createDropEvent_mutex" << endl;
return NDBT_FAILED;
}
return res;
}
/* An enum for expressing how many of the multiple nodes
* of a given type an action should be applied to
*/
enum NodeSet
{
All = 0,
NotAll = 1, /* less than All, or None if there's only 1 */
None = 2
};
uint getNodeCount(NodeSet set, uint numNodes)
{
switch(set)
{
case All:
return numNodes;
case NotAll:
{
if (numNodes < 2)
return 0;
if (numNodes == 2)
return 1;
uint range = numNodes - 2;
/* At least 1, at most numNodes - 1 */
return (1 + (rand() % (range + 1)));
}
case None:
{
return 0;
}
default:
g_err << "Unknown set type : " << set << endl;
abort();
return 0;
}
}
/**
Test that one node at a time can be upgraded
*/
int runUpgrade_NR1(NDBT_Context* ctx, NDBT_Step* step){
AtrtClient atrt;
NodeSet mgmdNodeSet = (NodeSet) ctx->getProperty("MgmdNodeSet", Uint32(0));
NodeSet ndbdNodeSet = (NodeSet) ctx->getProperty("NdbdNodeSet", Uint32(0));
SqlResultSet clusters;
if (!atrt.getClusters(clusters))
return NDBT_FAILED;
while (clusters.next())
{
uint clusterId= clusters.columnAsInt("id");
SqlResultSet tmp_result;
if (!atrt.getConnectString(clusterId, tmp_result))
return NDBT_FAILED;
NdbRestarter restarter(tmp_result.column("connectstring"));
restarter.setReconnect(true); // Restarting mgmd
g_err << "Cluster '" << clusters.column("name")
<< "@" << tmp_result.column("connectstring") << "'" << endl;
if (restarter.waitClusterStarted())
return NDBT_FAILED;
// Restart ndb_mgmd(s)
SqlResultSet mgmds;
if (!atrt.getMgmds(clusterId, mgmds))
return NDBT_FAILED;
uint mgmdCount = mgmds.numRows();
uint mgmd_start_count = mgmdCount;
uint restartCount = getNodeCount(mgmdNodeSet, mgmdCount);
while (mgmds.next() && mgmdCount --)
{
ndbout << "Restart mgmd" << mgmds.columnAsInt("node_id") << endl;
if (!atrt.stopProcess(mgmds.columnAsInt("id")) ||
!atrt.switchConfig(mgmds.columnAsInt("id"),"--initial"))
return NDBT_FAILED;
}
mgmds.reset();
while (mgmds.next() && mgmd_start_count --)
{
ndbout << "Restart mgmd" << mgmds.columnAsInt("node_id") << endl;
if (!atrt.startProcess(mgmds.columnAsInt("id")))
return NDBT_FAILED;
}
// Restart ndbd(s)
SqlResultSet ndbds;
if (!atrt.getNdbds(clusterId, ndbds))
return NDBT_FAILED;
uint ndbdCount = ndbds.numRows();
restartCount = getNodeCount(ndbdNodeSet, ndbdCount);
ndbout << "Restarting "
<< restartCount << " of " << ndbdCount
<< " ndbds" << endl;
while(ndbds.next() && restartCount --)
{
int nodeId = ndbds.columnAsInt("node_id");
int processId = ndbds.columnAsInt("id");
ndbout << "Restart node " << nodeId << endl;
if (!atrt.changeVersion(processId, ""))
return NDBT_FAILED;
if (restarter.waitNodesNoStart(&nodeId, 1))
return NDBT_FAILED;
if (restarter.startNodes(&nodeId, 1))
return NDBT_FAILED;
if (restarter.waitNodesStarted(&nodeId, 1))
return NDBT_FAILED;
if (createDropEvent(ctx, step))
return NDBT_FAILED;
}
}
ctx->stopTest();
return NDBT_OK;
}
static
int
runBug48416(NDBT_Context* ctx, NDBT_Step* step)
{
Ndb* pNdb = GETNDB(step);
return NDBT_Tables::createTable(pNdb, "I1");
}
static
int
runUpgrade_Half(NDBT_Context* ctx, NDBT_Step* step)
{
// Assuming 2 replicas
AtrtClient atrt;
const bool waitNode = ctx->getProperty("WaitNode", Uint32(0)) != 0;
const bool event = ctx->getProperty("CreateDropEvent", Uint32(0)) != 0;
const char * args = "";
if (ctx->getProperty("KeepFS", Uint32(0)) != 0)
{
args = "--initial=0";
}
NodeSet mgmdNodeSet = (NodeSet) ctx->getProperty("MgmdNodeSet", Uint32(0));
NodeSet ndbdNodeSet = (NodeSet) ctx->getProperty("NdbdNodeSet", Uint32(0));
SqlResultSet clusters;
if (!atrt.getClusters(clusters))
return NDBT_FAILED;
while (clusters.next())
{
uint clusterId= clusters.columnAsInt("id");
SqlResultSet tmp_result;
if (!atrt.getConnectString(clusterId, tmp_result))
return NDBT_FAILED;
NdbRestarter restarter(tmp_result.column("connectstring"));
restarter.setReconnect(true); // Restarting mgmd
g_err << "Cluster '" << clusters.column("name")
<< "@" << tmp_result.column("connectstring") << "'" << endl;
if(restarter.waitClusterStarted())
return NDBT_FAILED;
// Restart ndb_mgmd(s)
SqlResultSet mgmds;
if (!atrt.getMgmds(clusterId, mgmds))
return NDBT_FAILED;
uint mgmdCount = mgmds.numRows();
uint restartCount = getNodeCount(mgmdNodeSet, mgmdCount);
ndbout << "Restarting "
<< restartCount << " of " << mgmdCount
<< " mgmds" << endl;
while (mgmds.next() && restartCount --)
{
ndbout << "Restart mgmd" << mgmds.columnAsInt("node_id") << endl;
if (!atrt.changeVersion(mgmds.columnAsInt("id"), ""))
return NDBT_FAILED;
if(restarter.waitConnected())
return NDBT_FAILED;
}
NdbSleep_SecSleep(5); // TODO, handle arbitration
// Restart one ndbd in each node group
SqlResultSet ndbds;
if (!atrt.getNdbds(clusterId, ndbds))
return NDBT_FAILED;
Vector<NodeInfo> nodes;
while (ndbds.next())
{
struct NodeInfo n;
n.nodeId = ndbds.columnAsInt("node_id");
n.processId = ndbds.columnAsInt("id");
n.nodeGroup = restarter.getNodeGroup(n.nodeId);
nodes.push_back(n);
}
uint ndbdCount = ndbds.numRows();
restartCount = getNodeCount(ndbdNodeSet, ndbdCount);
ndbout << "Restarting "
<< restartCount << " of " << ndbdCount
<< " ndbds" << endl;
int nodesarray[256];
int cnt= 0;
Bitmask<4> seen_groups;
Bitmask<4> restarted_nodes;
for (Uint32 i = 0; (i<nodes.size() && restartCount); i++)
{
int nodeId = nodes[i].nodeId;
int processId = nodes[i].processId;
int nodeGroup= nodes[i].nodeGroup;
if (seen_groups.get(nodeGroup))
{
// One node in this node group already down
continue;
}
seen_groups.set(nodeGroup);
restarted_nodes.set(nodeId);
ndbout << "Restart node " << nodeId << endl;
if (!atrt.changeVersion(processId, args))
return NDBT_FAILED;
if (waitNode)
{
restarter.waitNodesNoStart(&nodeId, 1);
}
nodesarray[cnt++]= nodeId;
restartCount--;
}
if (!waitNode)
{
if (restarter.waitNodesNoStart(nodesarray, cnt))
return NDBT_FAILED;
}
ndbout << "Starting and wait for started..." << endl;
if (restarter.startAll())
return NDBT_FAILED;
if (restarter.waitClusterStarted())
return NDBT_FAILED;
CHK_NDB_READY(GETNDB(step));
if (event && createDropEvent(ctx, step))
{
return NDBT_FAILED;
}
ndbout << "Half started" << endl;
if (ctx->getProperty("HalfStartedHold", (Uint32)0) != 0)
{
while (ctx->getProperty("HalfStartedHold", (Uint32)0) != 0)
{
ndbout << "Half started holding..." << endl;
ctx->setProperty("HalfStartedDone", (Uint32)1);
NdbSleep_SecSleep(30);
}
ndbout << "Got half started continue..." << endl;
}
// Restart the remaining nodes
cnt= 0;
for (Uint32 i = 0; (i<nodes.size() && restartCount); i++)
{
int nodeId = nodes[i].nodeId;
int processId = nodes[i].processId;
if (restarted_nodes.get(nodeId))
continue;
ndbout << "Restart node " << nodeId << endl;
if (!atrt.changeVersion(processId, args))
return NDBT_FAILED;
if (waitNode)
{
restarter.waitNodesNoStart(&nodeId, 1);
}
nodesarray[cnt++]= nodeId;
restartCount --;
}
if (!waitNode)
{
if (restarter.waitNodesNoStart(nodesarray, cnt))
return NDBT_FAILED;
}
ndbout << "Starting and wait for started..." << endl;
if (restarter.startAll())
return NDBT_FAILED;
if (restarter.waitClusterStarted())
return NDBT_FAILED;
CHK_NDB_READY(GETNDB(step));
if (event && createDropEvent(ctx, step))
{
return NDBT_FAILED;
}
}
return NDBT_OK;
}
/**
Test that one node in each nodegroup can be upgraded simultaneously
- using method1
*/
int runUpgrade_NR2(NDBT_Context* ctx, NDBT_Step* step)
{
// Assuming 2 replicas
ctx->setProperty("WaitNode", 1);
ctx->setProperty("CreateDropEvent", 1);
int res = runUpgrade_Half(ctx, step);
ctx->stopTest();
return res;
}
/**
Test that one node in each nodegroup can be upgrade simultaneously
- using method2, ie. don't wait for "nostart" before stopping
next node
*/
int runUpgrade_NR3(NDBT_Context* ctx, NDBT_Step* step){
// Assuming 2 replicas
ctx->setProperty("CreateDropEvent", 1);
int res = runUpgrade_Half(ctx, step);
ctx->stopTest();
return res;
}
/**
Test that we can upgrade the Ndbds on their own
*/
int runUpgrade_NdbdOnly(NDBT_Context* ctx, NDBT_Step* step)
{
ctx->setProperty("MgmdNodeSet", (Uint32) NodeSet(None));
int res = runUpgrade_Half(ctx, step);
ctx->stopTest();
return res;
}
/**
Test that we can upgrade the Ndbds first, then
the MGMDs
*/
int runUpgrade_NdbdFirst(NDBT_Context* ctx, NDBT_Step* step)
{
ctx->setProperty("MgmdNodeSet", (Uint32) NodeSet(None));
int res = runUpgrade_Half(ctx, step);
if (res == NDBT_OK)
{
ctx->setProperty("MgmdNodeSet", (Uint32) NodeSet(All));
ctx->setProperty("NdbdNodeSet", (Uint32) NodeSet(None));
res = runUpgrade_Half(ctx, step);
}
ctx->stopTest();
return res;
}
/**
Upgrade some of the MGMDs
*/
int runUpgrade_NotAllMGMD(NDBT_Context* ctx, NDBT_Step* step)
{
NdbRestarter restarter;
int minMgmVer = 0;
int maxMgmVer = 0;
int myVer = NDB_VERSION;
if (restarter.getNodeTypeVersionRange(NDB_MGM_NODE_TYPE_MGM,
minMgmVer,
maxMgmVer) == -1)
{
g_err << "runUpgrade_NotAllMGMD: getNodeTypeVersionRange call failed" << endl;
}
g_err << "runUpgrade_NotAllMGMD: My version " << myVer
<< " Min mgm version " << minMgmVer
<< " Max mgm version " << maxMgmVer << endl;
ctx->setProperty("MgmdNodeSet", (Uint32) NodeSet(NotAll));
ctx->setProperty("NdbdNodeSet", (Uint32) NodeSet(None));
int res = runUpgrade_Half(ctx, step);
ctx->stopTest();
return res;
}
int runCheckStarted(NDBT_Context* ctx, NDBT_Step* step){
// Check cluster is started
NdbRestarter restarter;
if(restarter.waitClusterStarted() != 0){
g_err << "All nodes was not started " << endl;
return NDBT_FAILED;
}
// Check atrtclient is started
AtrtClient atrt;
if(!atrt.waitConnected()){
g_err << "atrt server was not started " << endl;
return NDBT_FAILED;
}
// Make sure atrt assigns nodeid != -1
SqlResultSet procs;
if (!atrt.doQuery("SELECT * FROM process where type <> \'mysql\'", procs))
return NDBT_FAILED;
while (procs.next())
{
if (procs.columnAsInt("node_id") == (unsigned)-1){
ndbout << "Found one process with node_id -1, "
<< "use --fix-nodeid=1 to atrt to fix this" << endl;
return NDBT_FAILED;
}
}
return NDBT_OK;
}
int
runCreateIndexT1(NDBT_Context* ctx, NDBT_Step* step)
{
Ndb* pNdb = GETNDB(step);
NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
const NdbDictionary::Table* pTab = pDict->getTable("T1");
if (pTab == 0)
{
g_err << "getTable(T1) error: " << pDict->getNdbError() << endl;
return NDBT_FAILED;
}
NdbDictionary::Index ind;
ind.setName("T1X1");
ind.setTable("T1");
ind.setType(NdbDictionary::Index::OrderedIndex);
ind.setLogging(false);
ind.addColumn("KOL2");
ind.addColumn("KOL3");
ind.addColumn("KOL4");
if (pDict->createIndex(ind, *pTab) != 0)
{
g_err << "createIndex(T1X1) error: " << pDict->getNdbError() << endl;
return NDBT_FAILED;
}
return NDBT_OK;
}
int
runCreateAllTables(NDBT_Context* ctx, NDBT_Step* step)
{
Uint32 useRangeScanT1 = ctx->getProperty("UseRangeScanT1", (Uint32)0);
ndbout_c("createAllTables");
if (NDBT_Tables::createAllTables(GETNDB(step), false, true))
return NDBT_FAILED;
for (int i = 0; i<NDBT_Tables::getNumTables(); i++)
table_list.push_back(BaseString(NDBT_Tables::getTable(i)->getName()));
if (useRangeScanT1)
if (runCreateIndexT1(ctx, step) != NDBT_OK)
return NDBT_FAILED;
return NDBT_OK;
}
int
runCreateOneTable(NDBT_Context* ctx, NDBT_Step* step)
{
// Table is already created...
// so we just add it to table_list
table_list.push_back(BaseString(ctx->getTab()->getName()));
return NDBT_OK;
}
int runGetTableList(NDBT_Context* ctx, NDBT_Step* step)
{
table_list.clear();
ndbout << "Looking for tables ... ";
for (int i = 0; i<NDBT_Tables::getNumTables(); i++)
{
const NdbDictionary::Table* tab =
GETNDB(step)->getDictionary()
->getTable(NDBT_Tables::getTable(i)
->getName());
if (tab != NULL)
{
ndbout << tab->getName() << " ";
table_list.push_back(BaseString(tab->getName()));
}
}
ndbout << endl;
return NDBT_OK;
}
int
runLoadAll(NDBT_Context* ctx, NDBT_Step* step)
{
Ndb* pNdb = GETNDB(step);
NdbDictionary::Dictionary * pDict = pNdb->getDictionary();
int records = ctx->getNumRecords();
int result = NDBT_OK;
for (unsigned i = 0; i<table_list.size(); i++)
{
const NdbDictionary::Table* tab = pDict->getTable(table_list[i].c_str());
HugoTransactions trans(* tab);
trans.loadTable(pNdb, records);
trans.scanUpdateRecords(pNdb, records);
}
return result;
}
int
runClearAll(NDBT_Context* ctx, NDBT_Step* step)
{
Ndb* pNdb = GETNDB(step);
NdbDictionary::Dictionary * pDict = pNdb->getDictionary();
int records = ctx->getNumRecords();
int result = NDBT_OK;
for (unsigned i = 0; i<table_list.size(); i++)
{
const NdbDictionary::Table* tab = pDict->getTable(table_list[i].c_str());
if (tab)
{
HugoTransactions trans(* tab);
trans.clearTable(pNdb, records);
}
}
return result;
}
int
runBasic(NDBT_Context* ctx, NDBT_Step* step)
{
Uint32 useRangeScanT1 = ctx->getProperty("UseRangeScanT1", (uint32)0);
Ndb* pNdb = GETNDB(step);
NdbDictionary::Dictionary * pDict = pNdb->getDictionary();
int records = ctx->getNumRecords();
int result = NDBT_OK;
int l = 0;
while (!ctx->isTestStopped())
{
for (unsigned i = 0; i<table_list.size(); i++)
{
const NdbDictionary::Table* tab = pDict->getTable(table_list[i].c_str());
HugoTransactions trans(* tab);
switch(l % 4){
case 0:
trans.loadTable(pNdb, records);
trans.scanUpdateRecords(pNdb, records);
trans.pkUpdateRecords(pNdb, records);
trans.pkReadUnlockRecords(pNdb, records);
break;
case 1:
trans.scanUpdateRecords(pNdb, records);
// TODO make pkInterpretedUpdateRecords work on any table
// (or check if it does)
if (strcmp(tab->getName(), "T1") == 0)
trans.pkInterpretedUpdateRecords(pNdb, records);
if (strcmp(tab->getName(), "T1") == 0 &&
useRangeScanT1)
{
const NdbDictionary::Index* pInd = pDict->getIndex("T1X1", "T1");
if (pInd == 0)
{
g_err << "getIndex(T1X1) error: " << pDict->getNdbError() << endl;
return NDBT_FAILED;
}
// bug#13834481 - bound values do not matter
const Uint32 lo = 0x11110000;
const Uint32 hi = 0xaaaa0000;
HugoTransactions::HugoBound bound_arr[6];
int bound_cnt = 0;
for (int j = 0; j <= 1; j++) {
int n = rand() % 4;
for (int i = 0; i < n; i++) {
HugoTransactions::HugoBound& b = bound_arr[bound_cnt++];
b.attr = i;
b.type = (j == 0 ? 0 : 2); // LE/GE
b.value = (j == 0 ? &lo : &hi);
}
}
g_info << "range scan T1 with " << bound_cnt << " bounds" << endl;
if (trans.scanReadRecords(pNdb, pInd, records, 0, 0,
NdbOperation::LM_Read, 0, bound_cnt, bound_arr) != 0)
{
const NdbError& err = trans.getNdbError();
/*
* bug#13834481 symptoms include timeouts and error 1231.
* Check for any non-temporary error.
*/
if (err.status == NdbError::TemporaryError)
{
g_info << "range scan T1 temporary error: " << err << endl;
}
if (err.status != NdbError::TemporaryError)
{
g_err << "range scan T1 permanent error: " << err << endl;
return NDBT_FAILED;
}
}
}
trans.clearTable(pNdb, records/2);
trans.loadTable(pNdb, records/2);
break;
case 2:
trans.clearTable(pNdb, records/2);
trans.loadTable(pNdb, records/2);
trans.clearTable(pNdb, records/2);
break;
case 3:
if (createDropEvent(ctx, step, false))
{
return NDBT_FAILED;
}
break;
}
}
l++;
}
return result;
}
#define CHK2(b, e) \
if (!(b)) { \
g_err << "ERR: " << #b << " failed at line " << __LINE__ \
<< ": " << e << endl; \
result = NDBT_FAILED; \
break; \
}
static int
runBug14702377(NDBT_Context* ctx, NDBT_Step* step)
{
Ndb* pNdb = GETNDB(step);
NdbDictionary::Dictionary * pDict = pNdb->getDictionary();
int records = ctx->getNumRecords();
int result = NDBT_OK;
while (ctx->getProperty("HalfStartedDone", (Uint32)0) == 0)
{
ndbout << "Wait for half started..." << endl;
NdbSleep_SecSleep(15);
}
ndbout << "Got half started" << endl;
while (1)
{
require(table_list.size() == 1);
const char* tabname = table_list[0].c_str();
const NdbDictionary::Table* tab = 0;
CHK2((tab = pDict->getTable(tabname)) != 0,
tabname << ": " << pDict->getNdbError());
const int ncol = tab->getNoOfColumns();
{
HugoTransactions trans(*tab);
CHK2(trans.loadTable(pNdb, records) == 0, trans.getNdbError());
}
for (int r = 0; r < records; r++)
{
// with 1000 records will surely hit bug case
const int lm = myRandom48(4); // 2
const int nval = myRandom48(ncol + 1); // most
const bool exist = myRandom48(2); // false
NdbTransaction* pTx = 0;
NdbOperation* pOp = 0;
CHK2((pTx = pNdb->startTransaction()) != 0,
pNdb->getNdbError());
CHK2((pOp = pTx->getNdbOperation(tab)) != 0,
pTx->getNdbError());
CHK2((pOp->readTuple((NdbOperation::LockMode)lm)) == 0,
pOp->getNdbError());
for (int id = 0; id <= 0; id++)
{
const NdbDictionary::Column* c = tab->getColumn(id);
require(c != 0 && c->getPrimaryKey() &&
c->getType() == NdbDictionary::Column::Unsigned);
Uint32 val = myRandom48(records);
if (!exist)
val = 0xaaaa0000 + myRandom48(0xffff + 1);
const char* valp = (const char*)&val;
CHK2(pOp->equal(id, valp) == 0, pOp->getNdbError());
}
CHK2(result == NDBT_OK, "failed");
for (int id = 0; id < nval; id++)
{
const NdbDictionary::Column* c = tab->getColumn(id);
require(c != 0 && (id == 0 || !c->getPrimaryKey()));
CHK2(pOp->getValue(id) != 0, pOp->getNdbError());
}
CHK2(result == NDBT_OK, "failed");
char info1[200];
sprintf(info1, "lm=%d nval=%d exist=%d",
lm, nval, exist);
g_info << "PK read T1 exec: " << info1 << endl;
Uint64 t1 = NdbTick_CurrentMillisecond();
int ret = pTx->execute(NdbTransaction::NoCommit);
Uint64 t2 = NdbTick_CurrentMillisecond();
int msec = (int)(t2-t1);
const NdbError& txerr = pTx->getNdbError();
const NdbError& operr = pOp->getNdbError();
char info2[300];
sprintf(info2, "%s msec=%d ret=%d txerr=%d operr=%d",
info1, msec, ret, txerr.code, operr.code);
g_info << "PK read T1 done: " << info2 << endl;
if (ret == 0 && txerr.code == 0 && operr.code == 0)
{
CHK2(exist, "row should not be found: " << info2);
}
else
if (ret == 0 && txerr.code == 626 && operr.code == 626)
{
CHK2(!exist, "row should be found: " << info2);
}
else
if (txerr.status == NdbError::TemporaryError)
{
g_err << "PK read T1 temporary error (tx): " << info2 << endl;
NdbSleep_MilliSleep(50);
}
else
if (operr.status == NdbError::TemporaryError)
{
g_err << "PK read T1 temporary error (op): " << info2 << endl;
NdbSleep_MilliSleep(50);
}
else
{
// gets 4012 before bugfix
CHK2(false, "unexpected error: " << info2);
}
pNdb->closeTransaction(pTx);
pTx = 0;
}
break;
}
g_err << "Clear half started hold..." << endl;
ctx->setProperty("HalfStartedHold", (Uint32)0);
return result;
}
int
rollingRestart(NDBT_Context* ctx, NDBT_Step* step)
{
// Assuming 2 replicas
AtrtClient atrt;
SqlResultSet clusters;
if (!atrt.getClusters(clusters))
return NDBT_FAILED;
while (clusters.next())
{
uint clusterId= clusters.columnAsInt("id");
SqlResultSet tmp_result;
if (!atrt.getConnectString(clusterId, tmp_result))
return NDBT_FAILED;
NdbRestarter restarter(tmp_result.column("connectstring"));
if (restarter.rollingRestart())
return NDBT_FAILED;
}
return NDBT_OK;
}
int runUpgrade_Traffic(NDBT_Context* ctx, NDBT_Step* step){
// Assuming 2 replicas
ndbout_c("upgrading");
int res = runUpgrade_Half(ctx, step);
if (res == NDBT_OK)
{
ndbout_c("rolling restarting");
res = rollingRestart(ctx, step);
}
ctx->stopTest();
return res;
}
int
startPostUpgradeChecks(NDBT_Context* ctx, NDBT_Step* step)
{
/**
* This will restart *self* in new version
*/
BaseString extraArgs;
if (ctx->getProperty("RestartNoDDL", Uint32(0)))
{
/* Ask post-upgrade steps not to perform DDL
* (e.g. for 6.3->7.0 upgrade)
*/
extraArgs.append(" --noddl ");
}
/**
* mysql-getopt works so that passing "-n X -n Y" is ok
* and is interpreted as "-n Y"
*
* so we restart ourselves with testcase-name and "--post-upgrade" appended
* e.g if testcase is "testUpgrade -n X"
* this will restart it as "testUpgrade -n X -n X--post-upgrade"
*/
BaseString tc;
tc.assfmt("-n %s--post-upgrade %s",
ctx->getCase()->getName(),
extraArgs.c_str());
ndbout << "About to restart self with extra arg: " << tc.c_str() << endl;
AtrtClient atrt;
int process_id = atrt.getOwnProcessId();
if (process_id == -1)
{
g_err << "Failed to find own process id" << endl;
return NDBT_FAILED;
}
if (!atrt.changeVersion(process_id, tc.c_str()))
return NDBT_FAILED;
// Will not be reached...
return NDBT_OK;
}
int
startPostUpgradeChecksApiFirst(NDBT_Context* ctx, NDBT_Step* step)
{
/* If Api is upgraded before all NDBDs then it may not
* be possible to use DDL from the upgraded API
* The upgraded Api will decide, but we pass NoDDL
* in
*/
ctx->setProperty("RestartNoDDL", 1);
return startPostUpgradeChecks(ctx, step);
}
int
runPostUpgradeChecks(NDBT_Context* ctx, NDBT_Step* step)
{
/**
* Table will be dropped/recreated
* automatically by NDBT...
* so when we enter here, this is already tested
*/
NdbBackup backup;
ndbout << "Starting backup..." << flush;
if (backup.start() != 0)
{
ndbout << "Failed" << endl;
return NDBT_FAILED;
}
ndbout << "done" << endl;
if ((ctx->getProperty("NoDDL", Uint32(0)) == 0) &&
(ctx->getProperty("KeepFS", Uint32(0)) != 0))
{
/**
* Bug48227
* Upgrade with FS 6.3->7.0, followed by table
* create, followed by Sys restart resulted in
* table loss.
*/
Ndb* pNdb = GETNDB(step);
NdbDictionary::Dictionary *pDict = pNdb->getDictionary();
{
NdbDictionary::Dictionary::List l;
pDict->listObjects(l);
for (Uint32 i = 0; i<l.count; i++)
ndbout_c("found %u : %s", l.elements[i].id, l.elements[i].name);
}
pDict->dropTable("I3");
if (NDBT_Tables::createTable(pNdb, "I3"))
{
ndbout_c("Failed to create table!");
ndbout << pDict->getNdbError() << endl;
return NDBT_FAILED;
}
{
NdbDictionary::Dictionary::List l;
pDict->listObjects(l);
for (Uint32 i = 0; i<l.count; i++)
ndbout_c("found %u : %s", l.elements[i].id, l.elements[i].name);
}
NdbRestarter res;
if (res.restartAll() != 0)
{
ndbout_c("restartAll() failed");
return NDBT_FAILED;
}
if (res.waitClusterStarted() != 0)
{
ndbout_c("waitClusterStarted() failed");
return NDBT_FAILED;
}
CHK_NDB_READY(pNdb);
if (pDict->getTable("I3") == 0)
{
ndbout_c("Table disappered");
return NDBT_FAILED;
}
}
return NDBT_OK;
}
int
runWait(NDBT_Context* ctx, NDBT_Step* step)
{
Uint32 waitSeconds = ctx->getProperty("WaitSeconds", Uint32(30));
while (waitSeconds &&
!ctx->isTestStopped())
{
NdbSleep_MilliSleep(1000);
waitSeconds --;
}
ctx->stopTest();
return NDBT_OK;
}
bool versionsSpanBoundary(int verA, int verB, int incBoundaryVer)
{
int minPeerVer = MIN(verA, verB);
int maxPeerVer = MAX(verA, verB);
return ( (minPeerVer < incBoundaryVer) &&
(maxPeerVer >= incBoundaryVer) );
}
#define SchemaTransVersion NDB_MAKE_VERSION(6,4,0)
int runPostUpgradeDecideDDL(NDBT_Context* ctx, NDBT_Step* step)
{
/* We are running post-upgrade, now examine the versions
* of connected nodes and update the 'NoDDL' variable
* accordingly
*/
/* DDL should be ok as long as
* 1) All data nodes have the same version
* 2) There is not some version specific exception
*/
bool useDDL = true;
Ndb* pNdb = GETNDB(step);
NdbRestarter restarter;
int minNdbVer = 0;
int maxNdbVer = 0;
int myVer = NDB_VERSION;
if (restarter.getNodeTypeVersionRange(NDB_MGM_NODE_TYPE_NDB,
minNdbVer,
maxNdbVer) == -1)
{
g_err << "getNodeTypeVersionRange call failed" << endl;
return NDBT_FAILED;
}
if (minNdbVer != maxNdbVer)
{
useDDL = false;
ndbout << "Ndbd nodes have mixed versions, DDL not supported" << endl;
}
if (versionsSpanBoundary(myVer, minNdbVer, SchemaTransVersion))
{
useDDL = false;
ndbout << "Api and Ndbd versions span schema-trans boundary, DDL not supported" << endl;
}
ctx->setProperty("NoDDL", useDDL?0:1);
if (useDDL)
{
ndbout << "Dropping and recreating tables..." << endl;
for (int i=0; i < NDBT_Tables::getNumTables(); i++)
{
/* Drop table (ignoring rc if it doesn't exist etc...) */
pNdb->getDictionary()->dropTable(NDBT_Tables::getTable(i)->getName());
int ret= NDBT_Tables::createTable(pNdb,
NDBT_Tables::getTable(i)->getName(),
false, // temp
false); // exists ok
if(ret)
{
NdbError err = pNdb->getDictionary()->getNdbError();
g_err << "Failed to create table "
<< NDBT_Tables::getTable(i)->getName()
<< " error : "
<< err
<< endl;
/* Check for allowed exceptions during upgrade */
if (err.code == 794)
{
/* Schema feature requires data node upgrade */
if (minNdbVer >= myVer)
{
g_err << "Error 794 received, but data nodes are upgraded" << endl;
// TODO : Dump versions here
return NDBT_FAILED;
}
g_err << "Create table failure due to old version NDBDs, continuing" << endl;
}
}
}
ndbout << "Done" << endl;
}
return NDBT_OK;
}
static
int
runUpgrade_SR(NDBT_Context* ctx, NDBT_Step* step)
{
/* System restart upgrade.
* Stop all data nodes
* Change versions
* Restart em together.
*/
AtrtClient atrt;
NodeSet mgmdNodeSet = All;
const char * args = "";
bool skipMgmds = (ctx->getProperty("SkipMgmds", Uint32(0)) != 0);
SqlResultSet clusters;
if (!atrt.getClusters(clusters))
return NDBT_FAILED;
while (clusters.next())
{
uint clusterId= clusters.columnAsInt("id");
SqlResultSet tmp_result;
if (!atrt.getConnectString(clusterId, tmp_result))
return NDBT_FAILED;
NdbRestarter restarter(tmp_result.column("connectstring"));
restarter.setReconnect(true); // Restarting mgmd
g_err << "Cluster '" << clusters.column("name")
<< "@" << tmp_result.column("connectstring") << "'" << endl;
if(restarter.waitClusterStarted())
return NDBT_FAILED;
/* Now restart to nostart state, prior to SR */
g_err << "Restarting all data nodes-nostart" << endl;
if (restarter.restartAll2(NdbRestarter::NRRF_NOSTART) != 0)
{
g_err << "Failed to restart all" << endl;
return NDBT_FAILED;
}
ndbout << "Waiting for no-start state" << endl;
if (restarter.waitClusterNoStart() != 0)
{
g_err << "Failed waiting for NoStart state" << endl;
return NDBT_FAILED;
}
// Restart ndb_mgmd(s)
SqlResultSet mgmds;
if (!atrt.getMgmds(clusterId, mgmds))
return NDBT_FAILED;
uint mgmdCount = mgmds.numRows();
uint restartCount = getNodeCount(mgmdNodeSet, mgmdCount);
if (!skipMgmds)
{
ndbout << "Restarting "
<< restartCount << " of " << mgmdCount
<< " mgmds" << endl;
while (mgmds.next() && restartCount --)
{
ndbout << "Restart mgmd" << mgmds.columnAsInt("node_id") << endl;
if (!atrt.changeVersion(mgmds.columnAsInt("id"), ""))
return NDBT_FAILED;
if(restarter.waitConnected())
return NDBT_FAILED;
}
NdbSleep_SecSleep(5); // TODO, handle arbitration
}
else
{
ndbout << "Skipping MGMD upgrade" << endl;
}
// Restart all ndbds
SqlResultSet ndbds;
if (!atrt.getNdbds(clusterId, ndbds))
return NDBT_FAILED;
uint ndbdCount = ndbds.numRows();
restartCount = ndbdCount;
ndbout << "Upgrading "
<< restartCount << " of " << ndbdCount
<< " ndbds" << endl;
while (ndbds.next())
{
uint nodeId = ndbds.columnAsInt("node_id");
uint processId = ndbds.columnAsInt("id");
ndbout << "Upgrading node " << nodeId << endl;
if (!atrt.changeVersion(processId, args))
return NDBT_FAILED;
}
ndbout << "Waiting for no-start state" << endl;
if (restarter.waitClusterNoStart() != 0)
{
g_err << "Failed waiting for NoStart state" << endl;
return NDBT_FAILED;
}
ndbout << "Starting cluster (SR)" << endl;
if (restarter.restartAll2(0) != 0)
{
g_err << "Error restarting all nodes" << endl;
return NDBT_FAILED;
}
ndbout << "Waiting for cluster to start" << endl;
if (restarter.waitClusterStarted() != 0)
{
g_err << "Failed waiting for Cluster start" << endl;
return NDBT_FAILED;
}
ndbout << "Cluster started." << endl;
}
return NDBT_OK;
}
static
int
runStartBlockLcp(NDBT_Context* ctx, NDBT_Step* step)
{
NdbRestarter restarter;
restarter.setReconnect(true);
while ((ctx->getProperty("HalfStartedDone", (Uint32)0) == 0) &&
!ctx->isTestStopped())
{
ndbout << "runStartBlockLcp: waiting for half nodes to be restarted..." << endl;
NdbSleep_MilliSleep(5000);
}
if (ctx->isTestStopped())
{
return NDBT_FAILED;
}
ndbout << "Half of the nodes restarted, beginning slow LCPs for remainder..." << endl;
/* Trigger LCPs which will be slow to complete,
* testing more complex LCP takeover protocols
* especially when the last 'old' data node
* (likely to be DIH Master) fails.
* */
do
{
int dumpCode[] = { 7099 };
while (restarter.dumpStateAllNodes(dumpCode, 1) != 0) {};
/* Stall fragment completions */
while (restarter.insertErrorInAllNodes(5073) != 0) {};
/* Allow restarts to continue... */
ctx->setProperty("HalfStartedHold", Uint32(0));
/**
* Only stall for 20s to avoid default LCP frag
* watchdog timeouts
*/
NdbSleep_MilliSleep(20000);
ndbout << "Unblocking LCP..." << endl;
while (restarter.insertErrorInAllNodes(0) != 0)
{};
NdbSleep_MilliSleep(5000);
} while (!ctx->isTestStopped());
return NDBT_OK;
}
static
int
runUpgradeAndFail(NDBT_Context* ctx, NDBT_Step* step)
{
AtrtClient atrt;
SqlResultSet clusters;
if (!atrt.getClusters(clusters))
return NDBT_FAILED;
// Get the first cluster
clusters.next();
uint clusterId= clusters.columnAsInt("id");
SqlResultSet tmp_result;
if (!atrt.getConnectString(clusterId, tmp_result))
return NDBT_FAILED;
NdbRestarter restarter(tmp_result.column("connectstring"));
restarter.setReconnect(true); // Restarting mgmd
ndbout << "Cluster '" << clusters.column("name")
<< "@" << tmp_result.column("connectstring") << "'" << endl;
if (restarter.waitClusterStarted())
return NDBT_FAILED;
// Restart ndb_mgmd(s)
SqlResultSet mgmds;
if (!atrt.getMgmds(clusterId, mgmds))
return NDBT_FAILED;
uint mgmdCount = mgmds.numRows();
uint restartCount = mgmdCount;
ndbout << "Restarting "
<< restartCount << " of " << mgmdCount
<< " mgmds" << endl;
while (mgmds.next() && restartCount --)
{
ndbout << "Restart mgmd " << mgmds.columnAsInt("node_id") << endl;
if (!atrt.changeVersion(mgmds.columnAsInt("id"), ""))
return NDBT_FAILED;
if (restarter.waitConnected())
return NDBT_FAILED;
ndbout << "Connected to mgmd"<< endl;
}
ndbout << "Waiting for started"<< endl;
if (restarter.waitClusterStarted())
return NDBT_FAILED;
ndbout << "Started"<< endl;
// Restart one ndbd
SqlResultSet ndbds;
if (!atrt.getNdbds(clusterId, ndbds))
return NDBT_FAILED;
//Get the node id of first node
ndbds.next();
int nodeId = ndbds.columnAsInt("node_id");
int processId = ndbds.columnAsInt("id");
ndbout << "Restart node " << nodeId << endl;
if (!atrt.changeVersion(processId, "--initial=0"))
{
g_err << "Unable to change version of data node" << endl;
return NDBT_FAILED;
}
if (restarter.waitNodesNoStart(&nodeId, 1))
{
g_err << "The newer version of the node never came up" << endl;
return NDBT_FAILED;
}
ndbout << "Node changed version and in NOSTART state" << endl;
ndbout << "Arranging for start failure to cause return to NOSTART" << endl;
/* We need the node to go to NO START after crash. */
int restartDump[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
if (restarter.dumpStateOneNode(nodeId, restartDump, 2))
return NDBT_FAILED;
/* 1007 forces the node to crash instead of failing with
* NDBD_EXIT_UPGRADE_INITIAL_REQUIRED */
restarter.insertErrorInNode(nodeId, 1007);
int origConnectCount = restarter.getNodeConnectCount(nodeId);
ndbout << "Starting node" << endl;
/* Now start it, should fail */
restarter.startAll();
ndbout << "Waiting for node to return to NOSTART state" << endl;
int newConnectCount = origConnectCount;
while (newConnectCount == origConnectCount)
{
/* Wait for the node to go to no start */
if (restarter.waitNodesNoStart(&nodeId, 1))
{
g_err << "Node never crashed" << nodeId << endl;
return NDBT_FAILED;
}
newConnectCount = restarter.getNodeConnectCount(nodeId);
}
ndbout << "Node reconnected and returned to NOSTART state "
<< "due to start failure"
<< endl;
return NDBT_OK;
}
static
int
runShowVersion(NDBT_Context* ctx, NDBT_Step* step)
{
const bool postUpgrade =
(ctx->getProperty("PostUpgrade", Uint32(0))) != 0;
ndbout_c("*******************************");
ndbout_c("%s version",
(postUpgrade?"Post":"Pre"));
ndbout_c(" Mysql version : %u.%u.%u%s",
MYSQL_VERSION_MAJOR,
MYSQL_VERSION_MINOR,
MYSQL_VERSION_PATCH,
MYSQL_VERSION_EXTRA);
ndbout_c(" Ndb version : %u.%u.%u %s",
NDB_VERSION_MAJOR,
NDB_VERSION_MINOR,
NDB_VERSION_BUILD,
NDB_VERSION_STATUS);
ndbout_c("*******************************");
if (!postUpgrade)
{
ndbout_c(" Note that this test may fail if Post version does"
" not implement ShowVersions, this is not a bug");
}
return NDBT_OK;
}
static const char* preVersionFileName = "preVersion.txt";
static const char* postVersionFileName = "postVersion.txt";
static BaseString
getFileName(bool post)
{
/* Path is 1 level *above* basedir, treated as 'run' directory */
BaseString nameBuff;
nameBuff.assfmt("%s/../%s",
getBaseDir(),
(post?
postVersionFileName:
preVersionFileName));
return nameBuff;
}
static int
runRecordVersion(NDBT_Context* ctx, NDBT_Step* step)
{
const bool postUpgrade =
(ctx->getProperty("PostUpgrade", Uint32(0))) != 0;
BaseString fileNameBuf = getFileName(postUpgrade);
const char* fileName = fileNameBuf.c_str();
ndbout_c("Writing version info to %s", fileName);
FILE* versionFile = fopen(fileName, "w");
if (!versionFile)
{
ndbout_c("Error opening file %s",
fileName);
return NDBT_FAILED;
}
fprintf(versionFile,
"%u.%u.%u\n",
NDB_VERSION_MAJOR,
NDB_VERSION_MINOR,
NDB_VERSION_BUILD);
fclose(versionFile);
return NDBT_OK;
}
static
bool
readVersionFile(const char* fileName,
Uint32& version)
{
bool ok = true;
version = 0;
ndbout_c("Reading version info from %s", fileName);
FILE* versionFile = fopen(fileName, "r");
if (versionFile != NULL)
{
unsigned int major = 0;
unsigned int minor = 0;
unsigned int build = 0;
int res = fscanf(versionFile,
"%u.%u.%u",
&major,
&minor,
&build);
if (res == 3)
{
version = NDB_MAKE_VERSION(major, minor, build);
}
else
{
ndbout_c("Version file %s read failed res = %d",
fileName,
res);
ok = false;
}
fclose(versionFile);
}
return ok;
}
/**
* runReadVersions
*
* Read, print and store version info captured by previous test
* run including runRecordVersion on both versions
*
* This can allow version specific conditions to be included
* in tests.
*/
static int
runReadVersions(NDBT_Context* ctx, NDBT_Step* step)
{
preVersion = postVersion = 0;
const bool preVersionReadOk =
readVersionFile(getFileName(false).c_str(),
preVersion);
const bool postVersionReadOk =
readVersionFile(getFileName(true).c_str(),
postVersion);
ndbout_c("runReadVersions");
ndbout_c(" PreVersion %s : %u.%u.%u",
(preVersionReadOk?"read":"not found"),
ndbGetMajor(preVersion),
ndbGetMinor(preVersion),
ndbGetBuild(preVersion));
ndbout_c(" PostVersion %s : %u.%u.%u",
(postVersionReadOk?"read":"not found"),
ndbGetMajor(postVersion),
ndbGetMinor(postVersion),
ndbGetBuild(postVersion));
return NDBT_OK;
}
/**
* runSkipIfCannotKeepFS
*
* Check whether we can perform an upgrade while keeping the
* FS with the versions being tested.
* If not, skip
*/
static int
runSkipIfCannotKeepFS(NDBT_Context* ctx, NDBT_Step* step)
{
if (preVersion == 0 || postVersion == 0)
{
ndbout_c("Missing version info to determine whether to skip, running.");
return NDBT_OK;
}
const Uint32 problemBoundary = NDB_MAKE_VERSION(7,6,3); // NDBD_LOCAL_SYSFILE_VERSION
if (versionsSpanBoundary(preVersion, postVersion, problemBoundary))
{
ndbout_c("Cannot run with these versions as they do not support "
"non initial upgrades.");
return NDBT_SKIPPED;
}
return NDBT_OK;
}
/**
* runSkipIfPostCanKeepFS
*
* Will skip unless the post version cannot handle a
* 'keepFS' upgrade.
*/
static int
runSkipIfPostCanKeepFS(NDBT_Context* ctx, NDBT_Step* step)
{
if (preVersion == 0 ||
postVersion == 0)
{
ndbout_c("Not running as specific version info missing");
return NDBT_SKIPPED;
}
const bool upgrade = (postVersion > preVersion);
if (!upgrade)
{
/* Only support upgrade test, downgrade is not handled cleanly attm */
ndbout_c("Not running as not an upgrade");
return NDBT_SKIPPED;
}
const Uint32 problemBoundary = NDB_MAKE_VERSION(7,6,3); // NDBD_LOCAL_SYSFILE_VERSION
if (!versionsSpanBoundary(preVersion, postVersion, problemBoundary))
{
ndbout_c("Not running as versions involved are not relevant for this test");
return NDBT_SKIPPED;
}
return NDBT_OK;
}
NDBT_TESTSUITE(testUpgrade);
TESTCASE("ShowVersions",
"Upgrade API, showing actual versions run")
{
INITIALIZER(runCheckStarted);
STEP(runShowVersion);
STEP(runRecordVersion);
VERIFIER(startPostUpgradeChecks);
}
POSTUPGRADE("ShowVersions")
{
TC_PROPERTY("PostUpgrade", Uint32(1));
INITIALIZER(runCheckStarted);
STEP(runShowVersion);
STEP(runRecordVersion);
};
TESTCASE("Upgrade_NR1",
"Test that one node at a time can be upgraded"){
INITIALIZER(runCheckStarted);
INITIALIZER(runReadVersions);
INITIALIZER(runBug48416);
STEP(runUpgrade_NR1);
VERIFIER(startPostUpgradeChecks);
}
POSTUPGRADE("Upgrade_NR1")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeChecks);
}
TESTCASE("Upgrade_NR2",
"Test that one node in each nodegroup can be upgradde simultaneously"){
INITIALIZER(runCheckStarted);
STEP(runUpgrade_NR2);
VERIFIER(startPostUpgradeChecks);
}
POSTUPGRADE("Upgrade_NR2")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeChecks);
}
TESTCASE("Upgrade_NR3",
"Test that one node in each nodegroup can be upgradde simultaneously"){
INITIALIZER(runCheckStarted);
STEP(runUpgrade_NR3);
VERIFIER(startPostUpgradeChecks);
}
POSTUPGRADE("Upgrade_NR3")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeChecks);
}
TESTCASE("Upgrade_FS",
"Test that one node in each nodegroup can be upgrade simultaneously")
{
TC_PROPERTY("KeepFS", 1);
INITIALIZER(runCheckStarted);
INITIALIZER(runReadVersions);
INITIALIZER(runSkipIfCannotKeepFS);
INITIALIZER(runCreateAllTables);
INITIALIZER(runLoadAll);
STEP(runUpgrade_Traffic);
VERIFIER(startPostUpgradeChecks);
}
POSTUPGRADE("Upgrade_FS")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeChecks);
}
TESTCASE("Upgrade_Traffic",
"Test upgrade with traffic, all tables and restart --initial")
{
TC_PROPERTY("UseRangeScanT1", (Uint32)1);
INITIALIZER(runCheckStarted);
INITIALIZER(runCreateAllTables);
STEP(runUpgrade_Traffic);
STEP(runBasic);
VERIFIER(startPostUpgradeChecks);
}
POSTUPGRADE("Upgrade_Traffic")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeChecks);
}
TESTCASE("Upgrade_Traffic_FS",
"Test upgrade with traffic, all tables and restart using FS")
{
TC_PROPERTY("UseRangeScanT1", (Uint32)1);
TC_PROPERTY("KeepFS", 1);
INITIALIZER(runCheckStarted);
INITIALIZER(runReadVersions);
INITIALIZER(runSkipIfCannotKeepFS);
INITIALIZER(runCreateAllTables);
STEP(runUpgrade_Traffic);
STEP(runBasic);
VERIFIER(startPostUpgradeChecks);
}
POSTUPGRADE("Upgrade_Traffic_FS")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeChecks);
}
TESTCASE("Upgrade_Traffic_one",
"Test upgrade with traffic, *one* table and restart --initial")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runCreateOneTable);
STEP(runUpgrade_Traffic);
STEP(runBasic);
VERIFIER(startPostUpgradeChecks);
}
POSTUPGRADE("Upgrade_Traffic_one")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeChecks);
}
TESTCASE("Upgrade_Traffic_FS_one",
"Test upgrade with traffic, all tables and restart using FS")
{
TC_PROPERTY("KeepFS", 1);
INITIALIZER(runCheckStarted);
INITIALIZER(runReadVersions);
INITIALIZER(runSkipIfCannotKeepFS);
INITIALIZER(runCreateOneTable);
STEP(runUpgrade_Traffic);
STEP(runBasic);
VERIFIER(startPostUpgradeChecks);
}
POSTUPGRADE("Upgrade_Traffic_FS_one")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeChecks);
}
TESTCASE("Upgrade_Api_Only",
"Test that upgrading the Api node only works")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runCreateAllTables);
VERIFIER(startPostUpgradeChecksApiFirst);
}
POSTUPGRADE("Upgrade_Api_Only")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeDecideDDL);
INITIALIZER(runGetTableList);
TC_PROPERTY("WaitSeconds", 30);
STEP(runBasic);
STEP(runPostUpgradeChecks);
STEP(runWait);
FINALIZER(runClearAll);
}
TESTCASE("Upgrade_Api_Before_NR1",
"Test that upgrading the Api node before the kernel works")
{
/* Api, then MGMD(s), then NDBDs */
INITIALIZER(runCheckStarted);
INITIALIZER(runCreateAllTables);
VERIFIER(startPostUpgradeChecksApiFirst);
}
POSTUPGRADE("Upgrade_Api_Before_NR1")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeDecideDDL);
INITIALIZER(runGetTableList);
STEP(runBasic);
STEP(runUpgrade_NR1); /* Upgrade kernel nodes using NR1 */
FINALIZER(runPostUpgradeChecks);
FINALIZER(runClearAll);
}
TESTCASE("Upgrade_Api_NDBD_MGMD",
"Test that updating in reverse order works")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runCreateAllTables);
VERIFIER(startPostUpgradeChecksApiFirst);
}
POSTUPGRADE("Upgrade_Api_NDBD_MGMD")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeDecideDDL);
INITIALIZER(runGetTableList);
STEP(runBasic);
STEP(runUpgrade_NdbdFirst);
FINALIZER(runPostUpgradeChecks);
FINALIZER(runClearAll);
}
TESTCASE("Upgrade_Mixed_MGMD_API_NDBD",
"Test that upgrading MGMD/API partially before data nodes works")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runCreateAllTables);
STEP(runUpgrade_NotAllMGMD); /* Upgrade an MGMD */
STEP(runBasic);
VERIFIER(startPostUpgradeChecksApiFirst); /* Upgrade Api */
}
POSTUPGRADE("Upgrade_Mixed_MGMD_API_NDBD")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeDecideDDL);
INITIALIZER(runGetTableList);
INITIALIZER(runClearAll); /* Clear rows from old-ver basic run */
STEP(runBasic);
STEP(runUpgrade_NdbdFirst); /* Upgrade all Ndbds, then MGMDs finally */
FINALIZER(runPostUpgradeChecks);
FINALIZER(runClearAll);
}
TESTCASE("Bug14702377",
"Dirty PK read of non-existent tuple 6.3->7.x hangs"){
TC_PROPERTY("HalfStartedHold", (Uint32)1);
INITIALIZER(runCheckStarted);
INITIALIZER(runCreateOneTable);
STEP(runUpgrade_Half);
STEP(runBug14702377);
}
POSTUPGRADE("Bug14702377")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeChecks);
}
TESTCASE("Upgrade_SR_ManyTablesMaxFrag",
"Check that number of tables has no impact")
{
TC_PROPERTY("SkipMgmds", Uint32(1)); /* For 7.0.14... */
TC_PROPERTY("FragmentCount", ~Uint32(0));
INITIALIZER(runCheckStarted);
INITIALIZER(runReadVersions);
INITIALIZER(runSkipIfCannotKeepFS);
INITIALIZER(createManyTables);
STEP(runUpgrade_SR);
VERIFIER(startPostUpgradeChecks);
}
POSTUPGRADE("Upgrade_SR_ManyTablesMaxFrag")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runPostUpgradeChecks);
INITIALIZER(dropManyTables);
}
TESTCASE("Upgrade_NR3_LCP_InProgress",
"Check that half-cluster upgrade with LCP in progress is ok")
{
TC_PROPERTY("HalfStartedHold", Uint32(1)); /* Stop half way through */
INITIALIZER(runCheckStarted);
STEP(runStartBlockLcp);
STEP(runUpgrade_NR3);
/* No need for postUpgrade, and cannot rely on it existing for
* downgrades...
* Better solution needed for downgrades where postUpgrade is
* useful, e.g. RunIfPresentElseIgnore...
*/
//VERIFIER(startPostUpgradeChecks);
}
//POSTUPGRADE("Upgrade_NR3_LCP_InProgress")
//{
// INITIALIZER(runCheckStarted);
// INITIALIZER(runPostUpgradeChecks);
//}
TESTCASE("Upgrade_Newer_LCP_FS_Fail",
"Try upgrading a data node from any lower version to 7.6.4 and fail."
"7.6.4 has a newer LCP file system and requires a upgrade with initial."
"(Bug#27308632)")
{
INITIALIZER(runCheckStarted);
INITIALIZER(runReadVersions);
INITIALIZER(runSkipIfPostCanKeepFS);
STEP(runUpgradeAndFail);
// No postupgradecheck required as the upgrade is expected to fail
}
NDBT_TESTSUITE_END(testUpgrade)
int main(int argc, const char** argv){
ndb_init();
NDBT_TESTSUITE_INSTANCE(testUpgrade);
testUpgrade.setCreateAllTables(true);
if (0)
{
static char env[100];
strcpy(env, "API_SIGNAL_LOG=-"); // stdout
putenv(env);
}
createDropEvent_mutex = NdbMutex_Create();
int ret = testUpgrade.execute(argc, argv);
NdbMutex_Destroy(createDropEvent_mutex);
return ret;
}
template class Vector<NodeInfo>;