Commit f7115f12 authored by jonas@perch.ndb.mysql.com's avatar jonas@perch.ndb.mysql.com

Merge perch.ndb.mysql.com:/home/jonas/src/51-telco-gca

into  perch.ndb.mysql.com:/home/jonas/src/mysql-5.1-new-ndb
parents 527158ba 6a35ddde
......@@ -2659,25 +2659,63 @@ checkSchemaStatus(Uint32 tableType, Uint32 pass)
case DictTabInfo::IndexTrigger:
return false;
case DictTabInfo::LogfileGroup:
return pass == 0;
return pass == 0 || pass == 9 || pass == 10;
case DictTabInfo::Tablespace:
return pass == 1;
return pass == 1 || pass == 8 || pass == 11;
case DictTabInfo::Datafile:
case DictTabInfo::Undofile:
return pass == 2;
return pass == 2 || pass == 7 || pass == 12;
case DictTabInfo::SystemTable:
case DictTabInfo::UserTable:
return pass == 3;
return /* pass == 3 || pass == 6 || */ pass == 13;
case DictTabInfo::UniqueHashIndex:
case DictTabInfo::HashIndex:
case DictTabInfo::UniqueOrderedIndex:
case DictTabInfo::OrderedIndex:
return pass == 4;
return /* pass == 4 || pass == 5 || */ pass == 14;
}
return false;
}
static const Uint32 CREATE_OLD_PASS = 4;
static const Uint32 DROP_OLD_PASS = 9;
static const Uint32 CREATE_NEW_PASS = 14;
static const Uint32 LAST_PASS = 14;
NdbOut&
operator<<(NdbOut& out, const SchemaFile::TableEntry entry)
{
out << "[";
out << " state: " << entry.m_tableState;
out << " version: " << hex << entry.m_tableVersion << dec;
out << " type: " << entry.m_tableType;
out << " words: " << entry.m_info_words;
out << " gcp: " << entry.m_gcp;
out << " ]";
return out;
}
/**
* Pass 0 Create old LogfileGroup
* Pass 1 Create old Tablespace
* Pass 2 Create old Datafile/Undofile
* Pass 3 Create old Table // NOT DONE DUE TO DIH
* Pass 4 Create old Index // NOT DONE DUE TO DIH
* Pass 5 Drop old Index // NOT DONE DUE TO DIH
* Pass 6 Drop old Table // NOT DONE DUE TO DIH
* Pass 7 Drop old Datafile/Undofile
* Pass 8 Drop old Tablespace
* Pass 9 Drop old Logfilegroup
* Pass 10 Create new LogfileGroup
* Pass 11 Create new Tablespace
* Pass 12 Create new Datafile/Undofile
* Pass 13 Create new Table
* Pass 14 Create new Index
*/
void Dbdict::checkSchemaStatus(Signal* signal)
{
XSchemaFile * newxsf = &c_schemaFile[c_schemaRecord.schemaPage != 0];
......@@ -2692,287 +2730,132 @@ void Dbdict::checkSchemaStatus(Signal* signal)
Uint32 tableId = c_restartRecord.activeTable;
SchemaFile::TableEntry *newEntry = getTableEntry(newxsf, tableId);
SchemaFile::TableEntry *oldEntry = getTableEntry(oldxsf, tableId);
SchemaFile::TableState schemaState =
SchemaFile::TableState newSchemaState =
(SchemaFile::TableState)newEntry->m_tableState;
SchemaFile::TableState oldSchemaState =
(SchemaFile::TableState)oldEntry->m_tableState;
if (c_restartRecord.activeTable >= c_tableRecordPool.getSize()) {
jam();
ndbrequire(schemaState == SchemaFile::INIT);
ndbrequire(newSchemaState == SchemaFile::INIT);
ndbrequire(oldSchemaState == SchemaFile::INIT);
continue;
}//if
if(!::checkSchemaStatus(oldEntry->m_tableType, c_restartRecord.m_pass))
continue;
if(!::checkSchemaStatus(newEntry->m_tableType, c_restartRecord.m_pass))
continue;
//#define PRINT_SCHEMA_RESTART
#ifdef PRINT_SCHEMA_RESTART
char buf[100];
snprintf(buf, sizeof(buf), "checkSchemaStatus: pass: %d table: %d",
c_restartRecord.m_pass, tableId);
#endif
switch(schemaState){
case SchemaFile::INIT:{
jam();
bool ok = false;
switch(oldSchemaState) {
case SchemaFile::INIT:
jam();
case SchemaFile::DROP_TABLE_COMMITTED:
jam();
ok = true;
jam();
break;
case SchemaFile::ADD_STARTED:
jam();
case SchemaFile::TABLE_ADD_COMMITTED:
jam();
case SchemaFile::DROP_TABLE_STARTED:
jam();
case SchemaFile::ALTER_TABLE_COMMITTED:
jam();
ok = true;
jam();
newEntry->m_tableState = SchemaFile::INIT;
restartDropTab(signal, tableId);
return;
if (c_restartRecord.m_pass <= CREATE_OLD_PASS)
{
if (!::checkSchemaStatus(oldEntry->m_tableType, c_restartRecord.m_pass))
continue;
case SchemaFile::TEMPORARY_TABLE_COMMITTED:
// Temporary table is never written to disk, so just set to INIT.
jam();
ok = true;
newEntry->m_tableState = SchemaFile::INIT;
break;
}//switch
ndbrequire(ok);
break;
}
case SchemaFile::ADD_STARTED:{
jam();
bool ok = false;
switch(oldSchemaState) {
case SchemaFile::INIT:
jam();
case SchemaFile::DROP_TABLE_COMMITTED:
jam();
ok = true;
break;
case SchemaFile::ADD_STARTED:
jam();
case SchemaFile::DROP_TABLE_STARTED:
jam();
case SchemaFile::TABLE_ADD_COMMITTED:
jam();
case SchemaFile::ALTER_TABLE_COMMITTED:
switch(oldSchemaState){
case SchemaFile::INIT: jam();
case SchemaFile::DROP_TABLE_COMMITTED: jam();
case SchemaFile::ADD_STARTED: jam();
case SchemaFile::DROP_TABLE_STARTED: jam();
case SchemaFile::TEMPORARY_TABLE_COMMITTED: jam();
continue;
case SchemaFile::TABLE_ADD_COMMITTED: jam();
case SchemaFile::ALTER_TABLE_COMMITTED: jam();
jam();
ok = true;
//------------------------------------------------------------------
// Add Table was started but not completed. Will be dropped in all
// nodes. Update schema information (restore table version).
//------------------------------------------------------------------
newEntry->m_tableState = SchemaFile::INIT;
restartDropTab(signal, tableId);
return;
case SchemaFile::TEMPORARY_TABLE_COMMITTED:
jam();
ok = true;
newEntry->m_tableState = SchemaFile::INIT;
break;
#ifdef PRINT_SCHEMA_RESTART
ndbout_c("%s -> restartCreateTab", buf);
ndbout << *newEntry << " " << *oldEntry << endl;
#endif
restartCreateTab(signal, tableId, oldEntry, oldEntry, true);
return;
}
ndbrequire(ok);
break;
}
case SchemaFile::TABLE_ADD_COMMITTED:{
jam();
bool ok = false;
switch(oldSchemaState) {
case SchemaFile::INIT:
jam();
case SchemaFile::ADD_STARTED:
jam();
case SchemaFile::DROP_TABLE_STARTED:
jam();
case SchemaFile::DROP_TABLE_COMMITTED:
jam();
ok = true;
//------------------------------------------------------------------
// Table was added in the master node but not in our node. We can
// retrieve the table definition from the master.
//------------------------------------------------------------------
restartCreateTab(signal, tableId, oldEntry, newEntry, false);
return;
break;
case SchemaFile::TABLE_ADD_COMMITTED:
jam();
case SchemaFile::ALTER_TABLE_COMMITTED:
jam();
ok = true;
//------------------------------------------------------------------
// Table was added in both our node and the master node. We can
// retrieve the table definition from our own disk.
//------------------------------------------------------------------
if(newEntry->m_tableVersion == oldEntry->m_tableVersion)
{
jam();
ndbrequire(newEntry->m_gcp == oldEntry->m_gcp);
ndbrequire(newEntry->m_tableType == oldEntry->m_tableType);
Uint32 type= oldEntry->m_tableType;
// On NR get index from master because index state is not on file
const bool file = c_systemRestart || !DictTabInfo::isIndex(type);
newEntry->m_info_words= oldEntry->m_info_words;
restartCreateTab(signal, tableId, oldEntry, newEntry, file);
return;
} else {
//------------------------------------------------------------------
// Must be a new version of the table if anything differs. Both table
// version and global checkpoint must be different.
// This should not happen for the master node. This can happen after
// drop table followed by add table or after change table.
// Not supported in this version.
//------------------------------------------------------------------
ndbrequire(c_masterNodeId != getOwnNodeId());
ndbrequire(newEntry->m_tableVersion != oldEntry->m_tableVersion);
jam();
restartCreateTab(signal, tableId, oldEntry, newEntry, false);
return;
}//if
case SchemaFile::TEMPORARY_TABLE_COMMITTED:
jam();
ok = true;
// For NR, we must re-create the table.
// For SR, we do nothing as the table was never saved to disk.
if(!c_systemRestart)
if (c_restartRecord.m_pass <= DROP_OLD_PASS)
{
if (!::checkSchemaStatus(oldEntry->m_tableType, c_restartRecord.m_pass))
continue;
switch(oldSchemaState){
case SchemaFile::INIT: jam();
case SchemaFile::DROP_TABLE_COMMITTED: jam();
case SchemaFile::TEMPORARY_TABLE_COMMITTED: jam();
continue;
case SchemaFile::ADD_STARTED: jam();
case SchemaFile::DROP_TABLE_STARTED: jam();
#ifdef PRINT_SCHEMA_RESTART
ndbout_c("%s -> restartDropTab", buf);
ndbout << *newEntry << " " << *oldEntry << endl;
#endif
restartDropTab(signal, tableId, oldEntry, newEntry);
return;
case SchemaFile::TABLE_ADD_COMMITTED: jam();
case SchemaFile::ALTER_TABLE_COMMITTED: jam();
if (! (* oldEntry == * newEntry))
{
restartCreateTab(signal, tableId, oldEntry, newEntry, false);
#ifdef PRINT_SCHEMA_RESTART
ndbout_c("%s -> restartDropTab", buf);
ndbout << *newEntry << " " << *oldEntry << endl;
#endif
restartDropTab(signal, tableId, oldEntry, newEntry);
return;
}
break;
}
ndbrequire(ok);
break;
}
case SchemaFile::DROP_TABLE_STARTED:
jam();
case SchemaFile::DROP_TABLE_COMMITTED:{
jam();
bool ok = false;
switch(oldSchemaState){
case SchemaFile::INIT:
jam();
case SchemaFile::DROP_TABLE_COMMITTED:
jam();
ok = true;
break;
case SchemaFile::ADD_STARTED:
jam();
case SchemaFile::TABLE_ADD_COMMITTED:
jam();
case SchemaFile::DROP_TABLE_STARTED:
jam();
case SchemaFile::ALTER_TABLE_COMMITTED:
jam();
newEntry->m_tableState = SchemaFile::INIT;
restartDropTab(signal, tableId);
return;
case SchemaFile::TEMPORARY_TABLE_COMMITTED:
jam();
ok = true;
newEntry->m_tableState = SchemaFile::INIT;
break;
continue;
}
ndbrequire(ok);
break;
}
case SchemaFile::ALTER_TABLE_COMMITTED: {
jam();
bool ok = false;
switch(oldSchemaState) {
case SchemaFile::INIT:
jam();
case SchemaFile::ADD_STARTED:
jam();
case SchemaFile::DROP_TABLE_STARTED:
jam();
case SchemaFile::DROP_TABLE_COMMITTED:
jam();
case SchemaFile::TEMPORARY_TABLE_COMMITTED:
jam();
ok = true;
if(!c_systemRestart)
if (c_restartRecord.m_pass <= CREATE_NEW_PASS)
{
if (!::checkSchemaStatus(newEntry->m_tableType, c_restartRecord.m_pass))
continue;
switch(newSchemaState){
case SchemaFile::INIT: jam();
case SchemaFile::DROP_TABLE_COMMITTED: jam();
case SchemaFile::TEMPORARY_TABLE_COMMITTED: jam();
* oldEntry = * newEntry;
continue;
case SchemaFile::ADD_STARTED: jam();
case SchemaFile::DROP_TABLE_STARTED: jam();
ndbrequire(false);
return;
case SchemaFile::TABLE_ADD_COMMITTED: jam();
case SchemaFile::ALTER_TABLE_COMMITTED: jam();
if (DictTabInfo::isIndex(newEntry->m_tableType) ||
DictTabInfo::isTable(newEntry->m_tableType))
{
restartCreateTab(signal, tableId, oldEntry, newEntry, false);
bool file = * oldEntry == *newEntry &&
(!DictTabInfo::isIndex(newEntry->m_tableType) || c_systemRestart);
#ifdef PRINT_SCHEMA_RESTART
ndbout_c("%s -> restartCreateTab (file: %d)", buf, file);
ndbout << *newEntry << " " << *oldEntry << endl;
#endif
restartCreateTab(signal, tableId, newEntry, newEntry, file);
* oldEntry = * newEntry;
return;
}
break;
case SchemaFile::TABLE_ADD_COMMITTED:
jam();
ok = true;
//------------------------------------------------------------------
// Table was altered in the master node but not in our node. We can
// retrieve the altered table definition from the master.
//------------------------------------------------------------------
restartCreateTab(signal, tableId, oldEntry, newEntry, false);
return;
break;
case SchemaFile::ALTER_TABLE_COMMITTED:
jam();
ok = true;
//------------------------------------------------------------------
// Table was altered in both our node and the master node. We can
// retrieve the table definition from our own disk.
//------------------------------------------------------------------
// On NR get index from master because index state is not on file
Uint32 type= oldEntry->m_tableType;
const bool file = (* newEntry == * oldEntry) &&
(c_systemRestart || !DictTabInfo::isIndex(type));
newEntry->m_info_words= oldEntry->m_info_words;
restartCreateTab(signal, tableId, oldEntry, newEntry, file);
return;
}
ndbrequire(ok);
break;
}
case SchemaFile::TEMPORARY_TABLE_COMMITTED: {
jam();
bool ok = false;
switch(oldSchemaState){
case SchemaFile::INIT:
jam();
case SchemaFile::DROP_TABLE_COMMITTED:
jam();
case SchemaFile::ADD_STARTED:
jam();
case SchemaFile::TABLE_ADD_COMMITTED:
jam();
case SchemaFile::DROP_TABLE_STARTED:
jam();
case SchemaFile::ALTER_TABLE_COMMITTED:
jam();
case SchemaFile::TEMPORARY_TABLE_COMMITTED:
jam();
ok = true;
if(!c_systemRestart)
else if (! (* oldEntry == *newEntry))
{
restartCreateTab(signal, tableId, oldEntry, newEntry, false);
#ifdef PRINT_SCHEMA_RESTART
ndbout_c("%s -> restartCreateTab", buf);
ndbout << *newEntry << " " << *oldEntry << endl;
#endif
restartCreateTab(signal, tableId, oldEntry, newEntry, false);
* oldEntry = * newEntry;
return;
} else {
newEntry->m_tableState = SchemaFile::INIT;
}
break;
}
* oldEntry = * newEntry;
continue;
}
ndbrequire(ok);
break;
}
}
}
c_restartRecord.m_pass++;
c_restartRecord.activeTable= 0;
if(c_restartRecord.m_pass <= 4)
if(c_restartRecord.m_pass <= LAST_PASS)
{
checkSchemaStatus(signal);
}
......@@ -3299,7 +3182,33 @@ Dbdict::releaseCreateTableOp(Signal* signal, CreateTableRecordPtr createTabPtr)
}
void
Dbdict::restartDropTab(Signal* signal, Uint32 tableId){
Dbdict::restartDropTab(Signal* signal, Uint32 tableId,
const SchemaFile::TableEntry * old_entry,
const SchemaFile::TableEntry * new_entry)
{
switch(old_entry->m_tableType){
case DictTabInfo::UndefTableType:
case DictTabInfo::HashIndexTrigger:
case DictTabInfo::SubscriptionTrigger:
case DictTabInfo::ReadOnlyConstraint:
case DictTabInfo::IndexTrigger:
ndbrequire(false);
case DictTabInfo::SystemTable:
case DictTabInfo::UserTable:
case DictTabInfo::UniqueHashIndex:
case DictTabInfo::HashIndex:
case DictTabInfo::UniqueOrderedIndex:
case DictTabInfo::OrderedIndex:
break;
case DictTabInfo::Tablespace:
case DictTabInfo::LogfileGroup:
case DictTabInfo::Datafile:
case DictTabInfo::Undofile:
warningEvent("Dont drop object: %d", tableId);
c_restartRecord.activeTable++;
checkSchemaStatus(signal);
return;
}
const Uint32 key = ++c_opRecordSequence;
......@@ -3333,6 +3242,7 @@ Dbdict::restartDropTab_complete(Signal* signal,
//@todo check error
releaseTableObject(c_restartRecord.activeTable);
c_opDropTable.release(dropTabPtr);
c_restartRecord.activeTable++;
......
......@@ -2560,7 +2560,9 @@ private:
void restartCreateTab_dihComplete(Signal* signal, Uint32 callback, Uint32);
void restartCreateTab_activateComplete(Signal*, Uint32 callback, Uint32);
void restartDropTab(Signal* signal, Uint32 tableId);
void restartDropTab(Signal* signal, Uint32 tableId,
const SchemaFile::TableEntry *,
const SchemaFile::TableEntry *);
void restartDropTab_complete(Signal*, Uint32 callback, Uint32);
void restart_checkSchemaStatusComplete(Signal*, Uint32 callback, Uint32);
......
......@@ -217,6 +217,8 @@ Ndbfs::execFSOPENREQ(Signal* signal)
releaseSections(signal);
}
file->reportTo(&theFromThreads);
if (getenv("NDB_TRACE_OPEN"))
ndbout_c("open(%s)", file->theFileName.c_str());
Request* request = theRequestPool->get();
request->action = Request::open;
......
/* 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 NDBT_MIX_RESTARTER_HPP
#define NDBT_MIX_RESTARTER_HPP
#include <mgmapi.h>
#include <Vector.hpp>
#include <BaseString.hpp>
#include "NdbRestarter.hpp"
#include "NDBT_Test.hpp"
#define NMR_SR "SR"
#define NMR_SR_THREADS "SR_ThreadCount"
#define NMR_SR_THREADS_STOPPED "SR_ThreadsStoppedCount"
#define NMR_SR_VALIDATE_THREADS "SR_ValidateThreadCount"
#define NMR_SR_VALIDATE_THREADS_DONE "SR_ValidateThreadsDoneCount"
class NdbMixRestarter : public NdbRestarter
{
public:
enum RestartTypeMask
{
RTM_RestartCluster = 0x01,
RTM_RestartNode = 0x02,
RTM_RestartNodeInitial = 0x04,
RTM_StopNode = 0x08,
RTM_StopNodeInitial = 0x10,
RTM_StartNode = 0x20,
RTM_COUNT = 6,
RTM_ALL = 0xFF,
RTM_SR = RTM_RestartCluster,
RTM_NR = 0x2 | 0x4 | 0x8 | 0x10 | 0x20
};
enum SR_State {
SR_RUNNING = 0,
SR_STOPPING = 1,
SR_STOPPED = 2,
SR_VALIDATING = 3
};
NdbMixRestarter(const char* _addr = 0);
~NdbMixRestarter();
void setRestartTypeMask(Uint32 mask);
int runUntilStopped(NDBT_Context* ctx, NDBT_Step* step, Uint32 freq);
int runPeriod(NDBT_Context* ctx, NDBT_Step* step, Uint32 time, Uint32 freq);
int init(NDBT_Context* ctx, NDBT_Step* step);
int dostep(NDBT_Context* ctx, NDBT_Step* step);
int finish(NDBT_Context* ctx, NDBT_Step* step);
private:
Uint32 m_mask;
Vector<ndb_mgm_node_state> m_nodes;
int restart_cluster(NDBT_Context* ctx, NDBT_Step* step, bool abort = true);
};
#endif
......@@ -23,6 +23,7 @@
#include <../../include/kernel/ndb_limits.h>
#include <random.h>
#include <NdbAutoPtr.hpp>
#include <NdbMixRestarter.hpp>
#define CHECK(b) if (!(b)) { \
g_err << "ERR: "<< step->getName() \
......@@ -2110,6 +2111,448 @@ runDictOps(NDBT_Context* ctx, NDBT_Step* step)
return result;
}
int
runBug21755(NDBT_Context* ctx, NDBT_Step* step)
{
char buf[256];
NdbRestarter res;
NdbDictionary::Table pTab0 = * ctx->getTab();
NdbDictionary::Table pTab1 = pTab0;
if (res.getNumDbNodes() < 2)
return NDBT_OK;
Ndb* pNdb = GETNDB(step);
NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
if (pDic->createTable(pTab0))
{
ndbout << pDic->getNdbError() << endl;
return NDBT_FAILED;
}
NdbDictionary::Index idx0;
BaseString::snprintf(buf, sizeof(buf), "%s-idx", pTab0.getName());
idx0.setName(buf);
idx0.setType(NdbDictionary::Index::OrderedIndex);
idx0.setTable(pTab0.getName());
idx0.setStoredIndex(false);
for (Uint32 i = 0; i<pTab0.getNoOfColumns(); i++)
{
const NdbDictionary::Column * col = pTab0.getColumn(i);
if(col->getPrimaryKey()){
idx0.addIndexColumn(col->getName());
}
}
if (pDic->createIndex(idx0))
{
ndbout << pDic->getNdbError() << endl;
return NDBT_FAILED;
}
BaseString::snprintf(buf, sizeof(buf), "%s-2", pTab1.getName());
pTab1.setName(buf);
if (pDic->createTable(pTab1))
{
ndbout << pDic->getNdbError() << endl;
return NDBT_FAILED;
}
{
HugoTransactions t0 (*pDic->getTable(pTab0.getName()));
t0.loadTable(pNdb, 1000);
}
{
HugoTransactions t1 (*pDic->getTable(pTab1.getName()));
t1.loadTable(pNdb, 1000);
}
int node = res.getRandomNotMasterNodeId(rand());
res.restartOneDbNode(node, false, true, true);
if (pDic->dropTable(pTab1.getName()))
{
ndbout << pDic->getNdbError() << endl;
return NDBT_FAILED;
}
BaseString::snprintf(buf, sizeof(buf), "%s-idx2", pTab0.getName());
idx0.setName(buf);
if (pDic->createIndex(idx0))
{
ndbout << pDic->getNdbError() << endl;
return NDBT_FAILED;
}
res.waitNodesNoStart(&node, 1);
res.startNodes(&node, 1);
if (res.waitClusterStarted())
{
return NDBT_FAILED;
}
if (pDic->dropTable(pTab0.getName()))
{
ndbout << pDic->getNdbError() << endl;
return NDBT_FAILED;
}
return NDBT_OK;
}
struct RandSchemaOp
{
struct Obj
{
BaseString m_name;
Uint32 m_type;
struct Obj* m_parent;
Vector<Obj*> m_dependant;
};
Vector<Obj*> m_objects;
int schema_op(Ndb*);
int validate(Ndb*);
int cleanup(Ndb*);
Obj* get_obj(Uint32 mask);
int create_table(Ndb*);
int create_index(Ndb*, Obj*);
int drop_obj(Ndb*, Obj*);
void remove_obj(Obj*);
};
template class Vector<RandSchemaOp::Obj*>;
int
RandSchemaOp::schema_op(Ndb* ndb)
{
struct Obj* obj = 0;
Uint32 type = 0;
loop:
switch((rand() >> 16) & 3){
case 0:
return create_table(ndb);
case 1:
if ((obj = get_obj(1 << NdbDictionary::Object::UserTable)) == 0)
goto loop;
return create_index(ndb, obj);
case 2:
type = (1 << NdbDictionary::Object::UserTable);
goto drop_object;
case 3:
type =
(1 << NdbDictionary::Object::UniqueHashIndex) |
(1 << NdbDictionary::Object::OrderedIndex);
goto drop_object;
default:
goto loop;
}
drop_object:
if ((obj = get_obj(type)) == 0)
goto loop;
return drop_obj(ndb, obj);
}
RandSchemaOp::Obj*
RandSchemaOp::get_obj(Uint32 mask)
{
Vector<Obj*> tmp;
for (Uint32 i = 0; i<m_objects.size(); i++)
{
if ((1 << m_objects[i]->m_type) & mask)
tmp.push_back(m_objects[i]);
}
if (tmp.size())
{
return tmp[rand()%tmp.size()];
}
return 0;
}
int
RandSchemaOp::create_table(Ndb* ndb)
{
int numTables = NDBT_Tables::getNumTables();
int num = myRandom48(numTables);
NdbDictionary::Table pTab = * NDBT_Tables::getTable(num);
NdbDictionary::Dictionary* pDict = ndb->getDictionary();
if (pDict->getTable(pTab.getName()))
{
char buf[100];
BaseString::snprintf(buf, sizeof(buf), "%s-%d",
pTab.getName(), rand());
pTab.setName(buf);
if (pDict->createTable(pTab))
return NDBT_FAILED;
}
else
{
if (NDBT_Tables::createTable(ndb, pTab.getName()))
{
return NDBT_FAILED;
}
}
ndbout_c("create table %s", pTab.getName());
const NdbDictionary::Table* tab2 = pDict->getTable(pTab.getName());
HugoTransactions trans(*tab2);
trans.loadTable(ndb, 1000);
Obj *obj = new Obj;
obj->m_name.assign(pTab.getName());
obj->m_type = NdbDictionary::Object::UserTable;
obj->m_parent = 0;
m_objects.push_back(obj);
return NDBT_OK;
}
int
RandSchemaOp::create_index(Ndb* ndb, Obj* tab)
{
NdbDictionary::Dictionary* pDict = ndb->getDictionary();
const NdbDictionary::Table * pTab = pDict->getTable(tab->m_name.c_str());
if (pTab == 0)
{
return NDBT_FAILED;
}
bool ordered = (rand() >> 16) & 1;
bool stored = (rand() >> 16) & 1;
Uint32 type = ordered ?
NdbDictionary::Index::OrderedIndex :
NdbDictionary::Index::UniqueHashIndex;
char buf[255];
BaseString::snprintf(buf, sizeof(buf), "%s-%s",
pTab->getName(),
ordered ? "OI" : "UI");
if (pDict->getIndex(buf, pTab->getName()))
{
// Index exists...let it be ok
return NDBT_OK;
}
ndbout_c("create index %s", buf);
NdbDictionary::Index idx0;
idx0.setName(buf);
idx0.setType((NdbDictionary::Index::Type)type);
idx0.setTable(pTab->getName());
idx0.setStoredIndex(ordered ? false : stored);
for (Uint32 i = 0; i<pTab->getNoOfColumns(); i++)
{
if (pTab->getColumn(i)->getPrimaryKey())
idx0.addColumn(pTab->getColumn(i)->getName());
}
if (pDict->createIndex(idx0))
{
ndbout << pDict->getNdbError() << endl;
return NDBT_FAILED;
}
Obj *obj = new Obj;
obj->m_name.assign(buf);
obj->m_type = type;
obj->m_parent = tab;
m_objects.push_back(obj);
tab->m_dependant.push_back(obj);
return NDBT_OK;
}
int
RandSchemaOp::drop_obj(Ndb* ndb, Obj* obj)
{
NdbDictionary::Dictionary* pDict = ndb->getDictionary();
if (obj->m_type == NdbDictionary::Object::UserTable)
{
ndbout_c("drop table %s", obj->m_name.c_str());
/**
* Drop of table automatically drops all indexes
*/
if (pDict->dropTable(obj->m_name.c_str()))
{
return NDBT_FAILED;
}
while(obj->m_dependant.size())
{
remove_obj(obj->m_dependant[0]);
}
remove_obj(obj);
}
else if (obj->m_type == NdbDictionary::Object::UniqueHashIndex ||
obj->m_type == NdbDictionary::Object::OrderedIndex)
{
ndbout_c("drop index %s", obj->m_name.c_str());
if (pDict->dropIndex(obj->m_name.c_str(),
obj->m_parent->m_name.c_str()))
{
return NDBT_FAILED;
}
remove_obj(obj);
}
return NDBT_OK;
}
void
RandSchemaOp::remove_obj(Obj* obj)
{
Uint32 i;
if (obj->m_parent)
{
bool found = false;
for (i = 0; i<obj->m_parent->m_dependant.size(); i++)
{
if (obj->m_parent->m_dependant[i] == obj)
{
found = true;
obj->m_parent->m_dependant.erase(i);
break;
}
}
assert(found);
}
{
bool found = false;
for (i = 0; i<m_objects.size(); i++)
{
if (m_objects[i] == obj)
{
found = true;
m_objects.erase(i);
break;
}
}
assert(found);
}
delete obj;
}
int
RandSchemaOp::validate(Ndb* ndb)
{
NdbDictionary::Dictionary* pDict = ndb->getDictionary();
for (Uint32 i = 0; i<m_objects.size(); i++)
{
if (m_objects[i]->m_type == NdbDictionary::Object::UserTable)
{
const NdbDictionary::Table* tab2 =
pDict->getTable(m_objects[i]->m_name.c_str());
HugoTransactions trans(*tab2);
trans.scanUpdateRecords(ndb, 1000);
trans.clearTable(ndb);
trans.loadTable(ndb, 1000);
}
}
return NDBT_OK;
}
/*
SystemTable = 1, ///< System table
UserTable = 2, ///< User table (may be temporary)
UniqueHashIndex = 3, ///< Unique un-ordered hash index
OrderedIndex = 6, ///< Non-unique ordered index
HashIndexTrigger = 7, ///< Index maintenance, internal
IndexTrigger = 8, ///< Index maintenance, internal
SubscriptionTrigger = 9,///< Backup or replication, internal
ReadOnlyConstraint = 10,///< Trigger, internal
Tablespace = 20, ///< Tablespace
LogfileGroup = 21, ///< Logfile group
Datafile = 22, ///< Datafile
Undofile = 23 ///< Undofile
*/
int
RandSchemaOp::cleanup(Ndb* ndb)
{
Int32 i;
for (i = m_objects.size() - 1; i >= 0; i--)
{
switch(m_objects[i]->m_type){
case NdbDictionary::Object::UniqueHashIndex:
case NdbDictionary::Object::OrderedIndex:
if (drop_obj(ndb, m_objects[i]))
return NDBT_FAILED;
break;
default:
break;
}
}
for (i = m_objects.size() - 1; i >= 0; i--)
{
switch(m_objects[i]->m_type){
case NdbDictionary::Object::UserTable:
if (drop_obj(ndb, m_objects[i]))
return NDBT_FAILED;
break;
default:
break;
}
}
assert(m_objects.size() == 0);
return NDBT_OK;
}
int
runDictRestart(NDBT_Context* ctx, NDBT_Step* step)
{
Ndb* pNdb = GETNDB(step);
int loops = ctx->getNumLoops();
NdbMixRestarter res;
RandSchemaOp dict;
if (res.getNumDbNodes() < 2)
return NDBT_OK;
if (res.init(ctx, step))
return NDBT_FAILED;
for (Uint32 i = 0; i<loops; i++)
{
for (Uint32 j = 0; j<10; j++)
if (dict.schema_op(pNdb))
return NDBT_FAILED;
if (res.dostep(ctx, step))
return NDBT_FAILED;
if (dict.validate(pNdb))
return NDBT_FAILED;
}
if (res.finish(ctx, step))
return NDBT_FAILED;
if (dict.validate(pNdb))
return NDBT_FAILED;
if (dict.cleanup(pNdb))
return NDBT_FAILED;
return NDBT_OK;
}
NDBT_TESTSUITE(testDict);
TESTCASE("CreateAndDrop",
"Try to create and drop the table loop number of times\n"){
......@@ -2256,7 +2699,14 @@ TESTCASE("Restart_NR2",
STEP(runRestarts);
STEP(runDictOps);
}
TESTCASE("Bug21755",
""){
INITIALIZER(runBug21755);
}
TESTCASE("DictRestart",
""){
INITIALIZER(runDictRestart);
}
NDBT_TESTSUITE_END(testDict);
int main(int argc, const char** argv){
......
......@@ -20,9 +20,16 @@
#include <NdbBackup.hpp>
#include "bank/Bank.hpp"
#include <NdbMixRestarter.hpp>
bool disk = false;
#define CHECK(b) if (!(b)) { \
g_err << "ERR: "<< step->getName() \
<< " failed on line " << __LINE__ << endl; \
result = NDBT_FAILED; \
continue; }
int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){
Bank bank(ctx->m_cluster_connection);
int overWriteExisting = true;
......@@ -37,21 +44,25 @@ int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){
* SR 1 - shutdown in progress
* SR 2 - restart in progress
*/
int runBankTimer(NDBT_Context* ctx, NDBT_Step* step){
int
runBankTimer(NDBT_Context* ctx, NDBT_Step* step){
int wait = 5; // Max seconds between each "day"
int yield = 1; // Loops before bank returns
ctx->incProperty("ThreadCount");
ctx->incProperty(NMR_SR_THREADS);
while (!ctx->isTestStopped())
{
Bank bank(ctx->m_cluster_connection);
while(!ctx->isTestStopped() && ctx->getProperty("SR") <= 1)
while(!ctx->isTestStopped() &&
ctx->getProperty(NMR_SR) <= NdbMixRestarter::SR_STOPPING)
{
if(bank.performIncreaseTime(wait, yield) == NDBT_FAILED)
break;
}
ndbout_c("runBankTimer is stopped");
ctx->incProperty("ThreadStopped");
if(ctx->getPropertyWait("SR", (Uint32)0))
ctx->incProperty(NMR_SR_THREADS_STOPPED);
if(ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_RUNNING))
break;
}
return NDBT_OK;
......@@ -61,17 +72,18 @@ int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){
int wait = 0; // Max ms between each transaction
int yield = 1; // Loops before bank returns
ctx->incProperty("ThreadCount");
ctx->incProperty(NMR_SR_THREADS);
while (!ctx->isTestStopped())
{
Bank bank(ctx->m_cluster_connection);
while(!ctx->isTestStopped() && ctx->getProperty("SR") <= 1)
while(!ctx->isTestStopped() &&
ctx->getProperty(NMR_SR) <= NdbMixRestarter::SR_STOPPING)
if(bank.performTransactions(0, 1) == NDBT_FAILED)
break;
ndbout_c("runBankTransactions is stopped");
ctx->incProperty("ThreadStopped");
if(ctx->getPropertyWait("SR", (Uint32)0))
ctx->incProperty(NMR_SR_THREADS_STOPPED);
if(ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_RUNNING))
break;
}
return NDBT_OK;
......@@ -80,278 +92,108 @@ int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){
int runBankGL(NDBT_Context* ctx, NDBT_Step* step){
int yield = 1; // Loops before bank returns
int result = NDBT_OK;
ctx->incProperty("ThreadCount");
ctx->incProperty(NMR_SR_THREADS);
while (ctx->isTestStopped() == false)
{
Bank bank(ctx->m_cluster_connection);
while(!ctx->isTestStopped() && ctx->getProperty("SR") <= 1)
while(!ctx->isTestStopped() &&
ctx->getProperty(NMR_SR) <= NdbMixRestarter::SR_STOPPING)
if (bank.performMakeGLs(yield) != NDBT_OK)
{
if(ctx->getProperty("SR") != 0)
if(ctx->getProperty(NMR_SR) != NdbMixRestarter::SR_RUNNING)
break;
ndbout << "bank.performMakeGLs FAILED" << endl;
abort();
return NDBT_FAILED;
}
ndbout_c("runBankGL is stopped");
ctx->incProperty("ThreadStopped");
if(ctx->getPropertyWait("SR", (Uint32)0))
ctx->incProperty(NMR_SR_THREADS_STOPPED);
if(ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_RUNNING))
break;
}
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 ;
}
#define CHECK(b) if (!(b)) { \
g_err << "ERR: "<< step->getName() \
<< " failed on line " << __LINE__ << endl; \
result = NDBT_FAILED; \
continue; }
static
int
restart_cluster(NDBT_Context* ctx, NDBT_Step* step, NdbRestarter& restarter)
int
runBankSrValidator(NDBT_Context* ctx, NDBT_Step* step)
{
bool abort = true;
int timeout = 180;
int result = NDBT_OK;
do
ctx->incProperty(NMR_SR_VALIDATE_THREADS);
while(!ctx->isTestStopped())
{
ndbout << " -- Shutting down " << endl;
ctx->setProperty("SR", 1);
CHECK(restarter.restartAll(false, true, abort) == 0);
ctx->setProperty("SR", 2);
CHECK(restarter.waitClusterNoStart(timeout) == 0);
if (ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_VALIDATING))
break;
Uint32 cnt = ctx->getProperty("ThreadCount");
Uint32 curr= ctx->getProperty("ThreadStopped");
while(curr != cnt && !ctx->isTestStopped())
int wait = 0;
int yield = 1;
Bank bank(ctx->m_cluster_connection);
if (bank.performSumAccounts(wait, yield) != 0)
{
ndbout_c("%d %d", curr, cnt);
NdbSleep_MilliSleep(100);
curr= ctx->getProperty("ThreadStopped");
ndbout << "bank.performSumAccounts FAILED" << endl;
abort();
return NDBT_FAILED;
}
ctx->setProperty("ThreadStopped", (Uint32)0);
CHECK(restarter.startAll() == 0);
CHECK(restarter.waitClusterStarted(timeout) == 0);
ndbout << " -- Validating starts " << endl;
if (bank.performValidateAllGLs() != 0)
{
int wait = 0;
int yield = 1;
Bank bank(ctx->m_cluster_connection);
if (bank.performSumAccounts(wait, yield) != 0)
{
ndbout << "bank.performSumAccounts FAILED" << endl;
return NDBT_FAILED;
}
if (bank.performValidateAllGLs() != 0)
{
ndbout << "bank.performValidateAllGLs FAILED" << endl;
return NDBT_FAILED;
}
ndbout << "bank.performValidateAllGLs FAILED" << endl;
abort();
return NDBT_FAILED;
}
ndbout << " -- Validating complete " << endl;
} while(0);
ctx->setProperty("SR", (Uint32)0);
ctx->broadcast();
return result;
}
static
ndb_mgm_node_state*
select_node_to_stop(Vector<ndb_mgm_node_state>& nodes)
{
Uint32 i, j;
Vector<ndb_mgm_node_state*> alive_nodes;
for(i = 0; i<nodes.size(); i++)
{
ndb_mgm_node_state* node = &nodes[i];
if (node->node_status == NDB_MGM_NODE_STATUS_STARTED)
alive_nodes.push_back(node);
}
Vector<ndb_mgm_node_state*> victims;
// Remove those with one in node group
for(i = 0; i<alive_nodes.size(); i++)
{
int group = alive_nodes[i]->node_group;
for(j = 0; j<alive_nodes.size(); j++)
{
if (i != j && alive_nodes[j]->node_group == group)
{
victims.push_back(alive_nodes[i]);
break;
}
}
}
if (victims.size())
{
int victim = rand() % victims.size();
return victims[victim];
}
else
{
return 0;
ctx->incProperty(NMR_SR_VALIDATE_THREADS_DONE);
if (ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_RUNNING))
break;
}
return NDBT_OK;
}
static
ndb_mgm_node_state*
select_node_to_start(Vector<ndb_mgm_node_state>& nodes)
{
Uint32 i, j;
Vector<ndb_mgm_node_state*> victims;
for(i = 0; i<nodes.size(); i++)
{
ndb_mgm_node_state* node = &nodes[i];
if (node->node_status == NDB_MGM_NODE_STATUS_NOT_STARTED)
victims.push_back(node);
}
#if 0
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;
if (victims.size())
{
int victim = rand() % victims.size();
return victims[victim];
}
else
while (ctx->isTestStopped() == false)
{
return 0;
if (bank.performSumAccounts(wait, yield) != NDBT_OK){
ndbout << "bank.performSumAccounts FAILED" << endl;
result = NDBT_FAILED;
}
}
return result ;
}
#endif
enum Action {
AA_RestartCluster = 0x1,
AA_RestartNode = 0x2,
AA_StopNode = 0x4,
AA_StartNode = 0x8,
AA_COUNT = 4
};
int
runMixRestart(NDBT_Context* ctx, NDBT_Step* step)
{
int result = NDBT_OK;
NdbMixRestarter res;
int runtime = ctx->getNumLoops();
int sleeptime = ctx->getNumRecords();
NdbRestarter restarter;
int timeout = 180;
Uint32 type = ctx->getProperty("Type", ~(Uint32)0);
restarter.waitClusterStarted();
Vector<ndb_mgm_node_state> nodes;
nodes = restarter.ndbNodes;
#if 0
for (Uint32 i = 0; i<restarter.ndbNodes.size(); i++)
nodes.push_back(restarter.ndbNodes[i]);
#endif
Uint32 mask = ctx->getProperty("Type", ~(Uint32)0);
res.setRestartTypeMask(mask);
Uint32 now;
const Uint32 stop = time(0)+ runtime;
while(!ctx->isTestStopped() && ((now= time(0)) < stop) && result == NDBT_OK)
if (res.runPeriod(ctx, step, runtime, sleeptime))
{
ndbout << " -- Sleep " << sleeptime << "s " << endl;
int cnt = sleeptime;
while (cnt-- && !ctx->isTestStopped())
NdbSleep_SecSleep(1);
if (ctx->isTestStopped())
return NDBT_FAILED;
ndb_mgm_node_state* node = 0;
int action;
loop:
while(((action = (1 << (rand() % AA_COUNT))) & type) == 0);
switch(action){
case AA_RestartCluster:
if (restart_cluster(ctx, step, restarter))
return NDBT_FAILED;
for (Uint32 i = 0; i<nodes.size(); i++)
nodes[i].node_status = NDB_MGM_NODE_STATUS_STARTED;
break;
case AA_RestartNode:
case AA_StopNode:
{
if ((node = select_node_to_stop(nodes)) == 0)
goto loop;
if (action == AA_RestartNode)
g_err << "Restarting " << node->node_id << endl;
else
g_err << "Stopping " << node->node_id << endl;
if (restarter.restartOneDbNode(node->node_id, false, true, true))
return NDBT_FAILED;
if (restarter.waitNodesNoStart(&node->node_id, 1))
return NDBT_FAILED;
node->node_status = NDB_MGM_NODE_STATUS_NOT_STARTED;
if (action == AA_StopNode)
break;
else
goto start;
}
case AA_StartNode:
if ((node = select_node_to_start(nodes)) == 0)
goto loop;
start:
g_err << "Starting " << node->node_id << endl;
if (restarter.startNodes(&node->node_id, 1))
return NDBT_FAILED;
if (restarter.waitNodesStarted(&node->node_id, 1))
return NDBT_FAILED;
node->node_status = NDB_MGM_NODE_STATUS_STARTED;
break;
}
}
Vector<int> not_started;
{
ndb_mgm_node_state* node = 0;
while((node = select_node_to_start(nodes)))
{
not_started.push_back(node->node_id);
node->node_status = NDB_MGM_NODE_STATUS_STARTED;
}
}
if (not_started.size())
{
g_err << "Starting stopped nodes " << endl;
if (restarter.startNodes(not_started.getBase(), not_started.size()))
return NDBT_FAILED;
if (restarter.waitClusterStarted())
return NDBT_FAILED;
abort();
return NDBT_FAILED;
}
ctx->stopTest();
return NDBT_OK;
}
int runDropBank(NDBT_Context* ctx, NDBT_Step* step){
int
runDropBank(NDBT_Context* ctx, NDBT_Step* step){
Bank bank(ctx->m_cluster_connection);
if (bank.dropBank() != NDBT_OK)
return NDBT_FAILED;
......@@ -367,7 +209,7 @@ TESTCASE("SR",
"3. Restart ndb and verify consistency\n"
"4. Drop bank\n")
{
TC_PROPERTY("Type", AA_RestartCluster);
TC_PROPERTY("Type", NdbMixRestarter::RTM_SR);
INITIALIZER(runCreateBank);
STEP(runBankTimer);
STEP(runBankTransactions);
......@@ -381,6 +223,7 @@ TESTCASE("SR",
STEP(runBankTransactions);
STEP(runBankTransactions);
STEP(runBankGL);
STEP(runBankSrValidator);
STEP(runMixRestart);
}
TESTCASE("NR",
......@@ -390,7 +233,7 @@ TESTCASE("NR",
"3. Restart ndb and verify consistency\n"
"4. Drop bank\n")
{
TC_PROPERTY("Type", AA_RestartNode | AA_StopNode | AA_StartNode);
TC_PROPERTY("Type", NdbMixRestarter::RTM_NR);
INITIALIZER(runCreateBank);
STEP(runBankTimer);
STEP(runBankTransactions);
......@@ -414,7 +257,7 @@ TESTCASE("Mix",
"3. Restart ndb and verify consistency\n"
"4. Drop bank\n")
{
TC_PROPERTY("Type", ~0);
TC_PROPERTY("Type", NdbMixRestarter::RTM_ALL);
INITIALIZER(runCreateBank);
STEP(runBankTimer);
STEP(runBankTransactions);
......@@ -429,6 +272,7 @@ TESTCASE("Mix",
STEP(runBankTransactions);
STEP(runBankGL);
STEP(runMixRestart);
STEP(runBankSrValidator);
FINALIZER(runDropBank);
}
NDBT_TESTSUITE_END(testSRBank);
......
......@@ -599,6 +599,14 @@ max-time: 1500
cmd: testDict
args: -n Restart_NR2 T1 I3
max-time: 500
cmd: testDict
args: -n Bug21755 T1
max-time: 1500
cmd: testDict
args: -l 25 -n DictRestart T1
#
# TEST NDBAPI
#
......
......@@ -24,7 +24,7 @@ libNDBT_a_SOURCES = \
NdbRestarter.cpp NdbRestarts.cpp NDBT_Output.cpp \
NdbBackup.cpp NdbConfig.cpp NdbGrep.cpp NDBT_Table.cpp \
NdbSchemaCon.cpp NdbSchemaOp.cpp getarg.c \
CpcClient.cpp
CpcClient.cpp NdbMixRestarter.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
......
......@@ -146,8 +146,10 @@ void NDBT_Context::setProperty(const char* _name, Uint32 _val){
NdbMutex_Lock(propertyMutexPtr);
const bool b = props.put(_name, _val, true);
assert(b == true);
NdbCondition_Broadcast(propertyCondPtr);
NdbMutex_Unlock(propertyMutexPtr);
}
void
NDBT_Context::decProperty(const char * name){
NdbMutex_Lock(propertyMutexPtr);
......@@ -159,6 +161,7 @@ NDBT_Context::decProperty(const char * name){
NdbCondition_Broadcast(propertyCondPtr);
NdbMutex_Unlock(propertyMutexPtr);
}
void
NDBT_Context::incProperty(const char * name){
NdbMutex_Lock(propertyMutexPtr);
......@@ -173,6 +176,7 @@ void NDBT_Context::setProperty(const char* _name, const char* _val){
NdbMutex_Lock(propertyMutexPtr);
const bool b = props.put(_name, _val);
assert(b == true);
NdbCondition_Broadcast(propertyCondPtr);
NdbMutex_Unlock(propertyMutexPtr);
}
......
/* 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 "NdbMixRestarter.hpp"
NdbMixRestarter::NdbMixRestarter(const char* _addr) :
NdbRestarter(_addr),
m_mask(~(Uint32)0)
{
}
NdbMixRestarter::~NdbMixRestarter()
{
}
#define CHECK(b) if (!(b)) { \
ndbout << "ERR: "<< step->getName() \
<< " failed on line " << __LINE__ << endl; \
result = NDBT_FAILED; \
continue; }
int
NdbMixRestarter::restart_cluster(NDBT_Context* ctx,
NDBT_Step* step,
bool stopabort)
{
int timeout = 180;
int result = NDBT_OK;
do
{
ctx->setProperty(NMR_SR_THREADS_STOPPED, (Uint32)0);
ctx->setProperty(NMR_SR_VALIDATE_THREADS_DONE, (Uint32)0);
ndbout << " -- Shutting down " << endl;
ctx->setProperty(NMR_SR, NdbMixRestarter::SR_STOPPING);
CHECK(restartAll(false, true, stopabort) == 0);
ctx->setProperty(NMR_SR, NdbMixRestarter::SR_STOPPED);
CHECK(waitClusterNoStart(timeout) == 0);
Uint32 cnt = ctx->getProperty(NMR_SR_THREADS);
Uint32 curr= ctx->getProperty(NMR_SR_THREADS_STOPPED);
while(curr != cnt && !ctx->isTestStopped())
{
if (curr > cnt)
{
ndbout_c("stopping: curr: %d cnt: %d", curr, cnt);
abort();
}
NdbSleep_MilliSleep(100);
curr= ctx->getProperty(NMR_SR_THREADS_STOPPED);
}
CHECK(ctx->isTestStopped() == false);
CHECK(startAll() == 0);
CHECK(waitClusterStarted(timeout) == 0);
cnt = ctx->getProperty(NMR_SR_VALIDATE_THREADS);
if (cnt)
{
ndbout << " -- Validating starts " << endl;
ctx->setProperty(NMR_SR_VALIDATE_THREADS_DONE, (Uint32)0);
ctx->setProperty(NMR_SR, NdbMixRestarter::SR_VALIDATING);
curr = ctx->getProperty(NMR_SR_VALIDATE_THREADS_DONE);
while (curr != cnt && !ctx->isTestStopped())
{
if (curr > cnt)
{
ndbout_c("validating: curr: %d cnt: %d", curr, cnt);
abort();
}
NdbSleep_MilliSleep(100);
curr = ctx->getProperty(NMR_SR_VALIDATE_THREADS_DONE);
}
ndbout << " -- Validating complete " << endl;
}
CHECK(ctx->isTestStopped() == false);
ctx->setProperty(NMR_SR, NdbMixRestarter::SR_RUNNING);
} while(0);
return result;
}
static
ndb_mgm_node_state*
select_node_to_stop(Vector<ndb_mgm_node_state>& nodes)
{
Uint32 i, j;
Vector<ndb_mgm_node_state*> alive_nodes;
for(i = 0; i<nodes.size(); i++)
{
ndb_mgm_node_state* node = &nodes[i];
if (node->node_status == NDB_MGM_NODE_STATUS_STARTED)
alive_nodes.push_back(node);
}
Vector<ndb_mgm_node_state*> victims;
// Remove those with one in node group
for(i = 0; i<alive_nodes.size(); i++)
{
int group = alive_nodes[i]->node_group;
for(j = 0; j<alive_nodes.size(); j++)
{
if (i != j && alive_nodes[j]->node_group == group)
{
victims.push_back(alive_nodes[i]);
break;
}
}
}
if (victims.size())
{
int victim = rand() % victims.size();
return victims[victim];
}
else
{
return 0;
}
}
static
ndb_mgm_node_state*
select_node_to_start(Vector<ndb_mgm_node_state>& nodes)
{
Uint32 i;
Vector<ndb_mgm_node_state*> victims;
for(i = 0; i<nodes.size(); i++)
{
ndb_mgm_node_state* node = &nodes[i];
if (node->node_status == NDB_MGM_NODE_STATUS_NOT_STARTED)
victims.push_back(node);
}
if (victims.size())
{
int victim = rand() % victims.size();
return victims[victim];
}
else
{
return 0;
}
}
void
NdbMixRestarter::setRestartTypeMask(Uint32 mask)
{
m_mask = mask;
}
int
NdbMixRestarter::runUntilStopped(NDBT_Context* ctx,
NDBT_Step* step,
Uint32 freq)
{
if (init(ctx, step))
return NDBT_FAILED;
while (!ctx->isTestStopped())
{
if (dostep(ctx, step))
return NDBT_FAILED;
NdbSleep_SecSleep(freq);
}
if (!finish(ctx, step))
return NDBT_FAILED;
return NDBT_OK;
}
int
NdbMixRestarter::runPeriod(NDBT_Context* ctx,
NDBT_Step* step,
Uint32 period, Uint32 freq)
{
if (init(ctx, step))
return NDBT_FAILED;
Uint32 stop = time(0) + period;
while (!ctx->isTestStopped() && (time(0) < stop))
{
if (dostep(ctx, step))
{
return NDBT_FAILED;
}
NdbSleep_SecSleep(freq);
}
if (finish(ctx, step))
{
return NDBT_FAILED;
}
ctx->stopTest();
return NDBT_OK;
}
int
NdbMixRestarter::init(NDBT_Context* ctx, NDBT_Step* step)
{
waitClusterStarted();
m_nodes = ndbNodes;
return 0;
}
int
NdbMixRestarter::dostep(NDBT_Context* ctx, NDBT_Step* step)
{
ndb_mgm_node_state* node = 0;
int action;
loop:
while(((action = (1 << (rand() % RTM_COUNT))) & m_mask) == 0);
switch(action){
case RTM_RestartCluster:
if (restart_cluster(ctx, step))
return NDBT_FAILED;
for (Uint32 i = 0; i<m_nodes.size(); i++)
m_nodes[i].node_status = NDB_MGM_NODE_STATUS_STARTED;
break;
case RTM_RestartNode:
case RTM_RestartNodeInitial:
case RTM_StopNode:
case RTM_StopNodeInitial:
{
if ((node = select_node_to_stop(m_nodes)) == 0)
goto loop;
if (action == RTM_RestartNode || action == RTM_RestartNodeInitial)
ndbout << "Restarting " << node->node_id;
else
ndbout << "Stopping " << node->node_id;
bool initial =
action == RTM_RestartNodeInitial || action == RTM_StopNodeInitial;
if (initial)
ndbout << " inital";
ndbout << endl;
if (restartOneDbNode(node->node_id, initial, true, true))
return NDBT_FAILED;
if (waitNodesNoStart(&node->node_id, 1))
return NDBT_FAILED;
node->node_status = NDB_MGM_NODE_STATUS_NOT_STARTED;
if (action == RTM_StopNode || action == RTM_StopNodeInitial)
break;
else
goto start;
}
case RTM_StartNode:
if ((node = select_node_to_start(m_nodes)) == 0)
goto loop;
start:
ndbout << "Starting " << node->node_id << endl;
if (startNodes(&node->node_id, 1))
return NDBT_FAILED;
if (waitNodesStarted(&node->node_id, 1))
return NDBT_FAILED;
node->node_status = NDB_MGM_NODE_STATUS_STARTED;
break;
}
return NDBT_OK;
}
int
NdbMixRestarter::finish(NDBT_Context* ctx, NDBT_Step* step)
{
Vector<int> not_started;
{
ndb_mgm_node_state* node = 0;
while((node = select_node_to_start(m_nodes)))
{
not_started.push_back(node->node_id);
node->node_status = NDB_MGM_NODE_STATUS_STARTED;
}
}
if (not_started.size())
{
ndbout << "Starting stopped nodes " << endl;
if (startNodes(not_started.getBase(), not_started.size()))
return NDBT_FAILED;
if (waitClusterStarted())
return NDBT_FAILED;
}
return NDBT_OK;
}
template class Vector<ndb_mgm_node_state*>;
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