ndb - bug#21755

  redo checkSchemaState to handle bug (plus prepare to handle other DD related bugs in the area)
parent 4810b84c
...@@ -2659,25 +2659,63 @@ checkSchemaStatus(Uint32 tableType, Uint32 pass) ...@@ -2659,25 +2659,63 @@ checkSchemaStatus(Uint32 tableType, Uint32 pass)
case DictTabInfo::IndexTrigger: case DictTabInfo::IndexTrigger:
return false; return false;
case DictTabInfo::LogfileGroup: case DictTabInfo::LogfileGroup:
return pass == 0; return pass == 0 || pass == 9 || pass == 10;
case DictTabInfo::Tablespace: case DictTabInfo::Tablespace:
return pass == 1; return pass == 1 || pass == 8 || pass == 11;
case DictTabInfo::Datafile: case DictTabInfo::Datafile:
case DictTabInfo::Undofile: case DictTabInfo::Undofile:
return pass == 2; return pass == 2 || pass == 7 || pass == 12;
case DictTabInfo::SystemTable: case DictTabInfo::SystemTable:
case DictTabInfo::UserTable: case DictTabInfo::UserTable:
return pass == 3; return /* pass == 3 || pass == 6 || */ pass == 13;
case DictTabInfo::UniqueHashIndex: case DictTabInfo::UniqueHashIndex:
case DictTabInfo::HashIndex: case DictTabInfo::HashIndex:
case DictTabInfo::UniqueOrderedIndex: case DictTabInfo::UniqueOrderedIndex:
case DictTabInfo::OrderedIndex: case DictTabInfo::OrderedIndex:
return pass == 4; return /* pass == 4 || pass == 5 || */ pass == 14;
} }
return false; 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) void Dbdict::checkSchemaStatus(Signal* signal)
{ {
XSchemaFile * newxsf = &c_schemaFile[c_schemaRecord.schemaPage != 0]; XSchemaFile * newxsf = &c_schemaFile[c_schemaRecord.schemaPage != 0];
...@@ -2692,287 +2730,132 @@ void Dbdict::checkSchemaStatus(Signal* signal) ...@@ -2692,287 +2730,132 @@ void Dbdict::checkSchemaStatus(Signal* signal)
Uint32 tableId = c_restartRecord.activeTable; Uint32 tableId = c_restartRecord.activeTable;
SchemaFile::TableEntry *newEntry = getTableEntry(newxsf, tableId); SchemaFile::TableEntry *newEntry = getTableEntry(newxsf, tableId);
SchemaFile::TableEntry *oldEntry = getTableEntry(oldxsf, tableId); SchemaFile::TableEntry *oldEntry = getTableEntry(oldxsf, tableId);
SchemaFile::TableState schemaState = SchemaFile::TableState newSchemaState =
(SchemaFile::TableState)newEntry->m_tableState; (SchemaFile::TableState)newEntry->m_tableState;
SchemaFile::TableState oldSchemaState = SchemaFile::TableState oldSchemaState =
(SchemaFile::TableState)oldEntry->m_tableState; (SchemaFile::TableState)oldEntry->m_tableState;
if (c_restartRecord.activeTable >= c_tableRecordPool.getSize()) { if (c_restartRecord.activeTable >= c_tableRecordPool.getSize()) {
jam(); jam();
ndbrequire(schemaState == SchemaFile::INIT); ndbrequire(newSchemaState == SchemaFile::INIT);
ndbrequire(oldSchemaState == SchemaFile::INIT); ndbrequire(oldSchemaState == SchemaFile::INIT);
continue; continue;
}//if }//if
if(!::checkSchemaStatus(oldEntry->m_tableType, c_restartRecord.m_pass)) //#define PRINT_SCHEMA_RESTART
continue; #ifdef PRINT_SCHEMA_RESTART
char buf[100];
if(!::checkSchemaStatus(newEntry->m_tableType, c_restartRecord.m_pass)) snprintf(buf, sizeof(buf), "checkSchemaStatus: pass: %d table: %d",
continue; c_restartRecord.m_pass, tableId);
#endif
switch(schemaState){ if (c_restartRecord.m_pass <= CREATE_OLD_PASS)
case SchemaFile::INIT:{ {
jam(); if (!::checkSchemaStatus(oldEntry->m_tableType, c_restartRecord.m_pass))
bool ok = false; continue;
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;
case SchemaFile::TEMPORARY_TABLE_COMMITTED: switch(oldSchemaState){
// Temporary table is never written to disk, so just set to INIT. case SchemaFile::INIT: jam();
jam(); case SchemaFile::DROP_TABLE_COMMITTED: jam();
ok = true; case SchemaFile::ADD_STARTED: jam();
newEntry->m_tableState = SchemaFile::INIT; case SchemaFile::DROP_TABLE_STARTED: jam();
break; case SchemaFile::TEMPORARY_TABLE_COMMITTED: jam();
}//switch continue;
ndbrequire(ok); case SchemaFile::TABLE_ADD_COMMITTED: jam();
break; case SchemaFile::ALTER_TABLE_COMMITTED: jam();
}
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:
jam(); jam();
ok = true; #ifdef PRINT_SCHEMA_RESTART
//------------------------------------------------------------------ ndbout_c("%s -> restartCreateTab", buf);
// Add Table was started but not completed. Will be dropped in all ndbout << *newEntry << " " << *oldEntry << endl;
// nodes. Update schema information (restore table version). #endif
//------------------------------------------------------------------ restartCreateTab(signal, tableId, oldEntry, oldEntry, true);
newEntry->m_tableState = SchemaFile::INIT; return;
restartDropTab(signal, tableId);
return;
case SchemaFile::TEMPORARY_TABLE_COMMITTED:
jam();
ok = true;
newEntry->m_tableState = SchemaFile::INIT;
break;
} }
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; if (c_restartRecord.m_pass <= DROP_OLD_PASS)
} else { {
//------------------------------------------------------------------ if (!::checkSchemaStatus(oldEntry->m_tableType, c_restartRecord.m_pass))
// Must be a new version of the table if anything differs. Both table continue;
// version and global checkpoint must be different.
// This should not happen for the master node. This can happen after switch(oldSchemaState){
// drop table followed by add table or after change table. case SchemaFile::INIT: jam();
// Not supported in this version. case SchemaFile::DROP_TABLE_COMMITTED: jam();
//------------------------------------------------------------------ case SchemaFile::TEMPORARY_TABLE_COMMITTED: jam();
ndbrequire(c_masterNodeId != getOwnNodeId()); continue;
ndbrequire(newEntry->m_tableVersion != oldEntry->m_tableVersion); case SchemaFile::ADD_STARTED: jam();
jam(); case SchemaFile::DROP_TABLE_STARTED: jam();
#ifdef PRINT_SCHEMA_RESTART
restartCreateTab(signal, tableId, oldEntry, newEntry, false); ndbout_c("%s -> restartDropTab", buf);
return; ndbout << *newEntry << " " << *oldEntry << endl;
}//if #endif
case SchemaFile::TEMPORARY_TABLE_COMMITTED: restartDropTab(signal, tableId, oldEntry, newEntry);
jam(); return;
ok = true; case SchemaFile::TABLE_ADD_COMMITTED: jam();
// For NR, we must re-create the table. case SchemaFile::ALTER_TABLE_COMMITTED: jam();
// For SR, we do nothing as the table was never saved to disk. if (! (* oldEntry == * newEntry))
if(!c_systemRestart)
{ {
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; return;
} }
break; continue;
}
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;
} }
ndbrequire(ok);
break;
} }
case SchemaFile::ALTER_TABLE_COMMITTED: {
jam(); if (c_restartRecord.m_pass <= CREATE_NEW_PASS)
bool ok = false; {
switch(oldSchemaState) { if (!::checkSchemaStatus(newEntry->m_tableType, c_restartRecord.m_pass))
case SchemaFile::INIT: continue;
jam();
case SchemaFile::ADD_STARTED: switch(newSchemaState){
jam(); case SchemaFile::INIT: jam();
case SchemaFile::DROP_TABLE_STARTED: case SchemaFile::DROP_TABLE_COMMITTED: jam();
jam(); case SchemaFile::TEMPORARY_TABLE_COMMITTED: jam();
case SchemaFile::DROP_TABLE_COMMITTED: * oldEntry = * newEntry;
jam(); continue;
case SchemaFile::TEMPORARY_TABLE_COMMITTED: case SchemaFile::ADD_STARTED: jam();
jam(); case SchemaFile::DROP_TABLE_STARTED: jam();
ok = true; ndbrequire(false);
if(!c_systemRestart) 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; return;
} }
break; else if (! (* oldEntry == *newEntry))
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)
{ {
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; return;
} else { }
newEntry->m_tableState = SchemaFile::INIT; * oldEntry = * newEntry;
} continue;
break;
} }
ndbrequire(ok);
break;
}
} }
} }
c_restartRecord.m_pass++; c_restartRecord.m_pass++;
c_restartRecord.activeTable= 0; c_restartRecord.activeTable= 0;
if(c_restartRecord.m_pass <= 4) if(c_restartRecord.m_pass <= LAST_PASS)
{ {
checkSchemaStatus(signal); checkSchemaStatus(signal);
} }
...@@ -3299,7 +3182,33 @@ Dbdict::releaseCreateTableOp(Signal* signal, CreateTableRecordPtr createTabPtr) ...@@ -3299,7 +3182,33 @@ Dbdict::releaseCreateTableOp(Signal* signal, CreateTableRecordPtr createTabPtr)
} }
void 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; const Uint32 key = ++c_opRecordSequence;
...@@ -3333,6 +3242,7 @@ Dbdict::restartDropTab_complete(Signal* signal, ...@@ -3333,6 +3242,7 @@ Dbdict::restartDropTab_complete(Signal* signal,
//@todo check error //@todo check error
releaseTableObject(c_restartRecord.activeTable);
c_opDropTable.release(dropTabPtr); c_opDropTable.release(dropTabPtr);
c_restartRecord.activeTable++; c_restartRecord.activeTable++;
......
...@@ -2551,7 +2551,9 @@ private: ...@@ -2551,7 +2551,9 @@ private:
void restartCreateTab_dihComplete(Signal* signal, Uint32 callback, Uint32); void restartCreateTab_dihComplete(Signal* signal, Uint32 callback, Uint32);
void restartCreateTab_activateComplete(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 restartDropTab_complete(Signal*, Uint32 callback, Uint32);
void restart_checkSchemaStatusComplete(Signal*, Uint32 callback, Uint32); void restart_checkSchemaStatusComplete(Signal*, Uint32 callback, Uint32);
......
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