Commit 5f183053 authored by unknown's avatar unknown

Merge whalegate.ndb.mysql.com:/home/tomas/mysql-5.0

into  whalegate.ndb.mysql.com:/home/tomas/mysql-5.0-ndb-merge


sql/ha_ndbcluster.cc:
  Auto merged
parents 5c836d24 cc0750ac
DROP TABLE IF EXISTS t1;
CREATE TABLE `test` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`t` VARCHAR( 10 ) NOT NULL
) ENGINE = ndbcluster;
GRANT USAGE ON *.* TO user1@localhost IDENTIFIED BY 'pass';
DROP TABLE `test`.`test`;
drop user user1@localhost;
...@@ -405,3 +405,22 @@ a b ...@@ -405,3 +405,22 @@ a b
1 1 1 1
10 10 10 10
drop table t2; drop table t2;
create table t1 (id int primary key) engine ndb;
insert into t1 values (1), (2), (3);
create table t2 (id int primary key) engine ndb;
insert into t2 select id from t1;
create trigger kaboom after delete on t1
for each row begin
delete from t2 where id=old.id;
end|
select * from t1 order by id;
id
1
2
3
delete from t1 where id in (1,2);
select * from t2 order by id;
id
3
drop trigger kaboom;
drop table t1;
-- source include/have_ndb.inc
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE `test` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`t` VARCHAR( 10 ) NOT NULL
) ENGINE = ndbcluster;
# Add user1@localhost with a specific password
# and connect as that user
GRANT USAGE ON *.* TO user1@localhost IDENTIFIED BY 'pass';
connect (user1,localhost,user1,pass,*NO-ONE*);
# Run the query 100 times
disable_query_log;
disable_result_log;
let $i= 100;
while ($i)
{
select count(*) from information_schema.tables union all select count(*) from information_schema.tables union all select count(*) from information_schema.tables;
dec $i;
}
enable_query_log;
enable_result_log;
disconnect user1;
# Switch back to the default connection and cleanup
connection default;
DROP TABLE `test`.`test`;
drop user user1@localhost;
...@@ -291,3 +291,25 @@ insert into t2 values (1,1), (10,10); ...@@ -291,3 +291,25 @@ insert into t2 values (1,1), (10,10);
select * from t2 use index (ab) where a in(1,10) order by a; select * from t2 use index (ab) where a in(1,10) order by a;
drop table t2; drop table t2;
#bug#30337
create table t1 (id int primary key) engine ndb;
insert into t1 values (1), (2), (3);
create table t2 (id int primary key) engine ndb;
insert into t2 select id from t1;
delimiter |;
create trigger kaboom after delete on t1
for each row begin
delete from t2 where id=old.id;
end|
delimiter ;|
select * from t1 order by id;
delete from t1 where id in (1,2);
select * from t2 order by id;
drop trigger kaboom;
drop table t1;
...@@ -6,7 +6,7 @@ Next DBTUP 4014 ...@@ -6,7 +6,7 @@ Next DBTUP 4014
Next DBLQH 5043 Next DBLQH 5043
Next DBDICT 6007 Next DBDICT 6007
Next DBDIH 7183 Next DBDIH 7183
Next DBTC 8039 Next DBTC 8052
Next CMVMI 9000 Next CMVMI 9000
Next BACKUP 10022 Next BACKUP 10022
Next DBUTIL 11002 Next DBUTIL 11002
...@@ -296,6 +296,10 @@ ABORT OF TCKEYREQ ...@@ -296,6 +296,10 @@ ABORT OF TCKEYREQ
8038 : Simulate API disconnect just after SCAN_TAB_REQ 8038 : Simulate API disconnect just after SCAN_TAB_REQ
8039 : Simulate failure of TransactionBufferMemory allocation for OI lookup
8051 : Simulate failure of allocation for saveINDXKEYINFO
CMVMI CMVMI
----- -----
......
...@@ -1497,12 +1497,12 @@ private: ...@@ -1497,12 +1497,12 @@ private:
void clearCommitAckMarker(ApiConnectRecord * const regApiPtr, void clearCommitAckMarker(ApiConnectRecord * const regApiPtr,
TcConnectRecord * const regTcPtr); TcConnectRecord * const regTcPtr);
// Trigger and index handling // Trigger and index handling
bool saveINDXKEYINFO(Signal* signal, int saveINDXKEYINFO(Signal* signal,
TcIndexOperation* indexOp, TcIndexOperation* indexOp,
const Uint32 *src, const Uint32 *src,
Uint32 len); Uint32 len);
bool receivedAllINDXKEYINFO(TcIndexOperation* indexOp); bool receivedAllINDXKEYINFO(TcIndexOperation* indexOp);
bool saveINDXATTRINFO(Signal* signal, int saveINDXATTRINFO(Signal* signal,
TcIndexOperation* indexOp, TcIndexOperation* indexOp,
const Uint32 *src, const Uint32 *src,
Uint32 len); Uint32 len);
......
...@@ -1789,9 +1789,18 @@ start_failure: ...@@ -1789,9 +1789,18 @@ start_failure:
}//switch }//switch
} }
static
inline
bool
compare_transid(Uint32* val0, Uint32* val1)
{
Uint32 tmp0 = val0[0] ^ val1[0];
Uint32 tmp1 = val0[1] ^ val1[1];
return (tmp0 | tmp1) == 0;
}
void Dbtc::execKEYINFO(Signal* signal) void Dbtc::execKEYINFO(Signal* signal)
{ {
UintR compare_transid1, compare_transid2;
jamEntry(); jamEntry();
apiConnectptr.i = signal->theData[0]; apiConnectptr.i = signal->theData[0];
tmaxData = 20; tmaxData = 20;
...@@ -1801,10 +1810,8 @@ void Dbtc::execKEYINFO(Signal* signal) ...@@ -1801,10 +1810,8 @@ void Dbtc::execKEYINFO(Signal* signal)
}//if }//if
ptrAss(apiConnectptr, apiConnectRecord); ptrAss(apiConnectptr, apiConnectRecord);
ttransid_ptr = 1; ttransid_ptr = 1;
compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[1]; if (compare_transid(apiConnectptr.p->transid, signal->theData+1) == false)
compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[2]; {
compare_transid1 = compare_transid1 | compare_transid2;
if (compare_transid1 != 0) {
TCKEY_abort(signal, 19); TCKEY_abort(signal, 19);
return; return;
}//if }//if
...@@ -2105,7 +2112,6 @@ void Dbtc::saveAttrbuf(Signal* signal) ...@@ -2105,7 +2112,6 @@ void Dbtc::saveAttrbuf(Signal* signal)
void Dbtc::execATTRINFO(Signal* signal) void Dbtc::execATTRINFO(Signal* signal)
{ {
UintR compare_transid1, compare_transid2;
UintR Tdata1 = signal->theData[0]; UintR Tdata1 = signal->theData[0];
UintR Tlength = signal->length(); UintR Tlength = signal->length();
UintR TapiConnectFilesize = capiConnectFilesize; UintR TapiConnectFilesize = capiConnectFilesize;
...@@ -2120,17 +2126,13 @@ void Dbtc::execATTRINFO(Signal* signal) ...@@ -2120,17 +2126,13 @@ void Dbtc::execATTRINFO(Signal* signal)
return; return;
}//if }//if
UintR Tdata2 = signal->theData[1];
UintR Tdata3 = signal->theData[2];
ApiConnectRecord * const regApiPtr = &localApiConnectRecord[Tdata1]; ApiConnectRecord * const regApiPtr = &localApiConnectRecord[Tdata1];
compare_transid1 = regApiPtr->transid[0] ^ Tdata2;
compare_transid2 = regApiPtr->transid[1] ^ Tdata3;
apiConnectptr.p = regApiPtr; apiConnectptr.p = regApiPtr;
compare_transid1 = compare_transid1 | compare_transid2;
if (compare_transid1 != 0) { if (compare_transid(regApiPtr->transid, signal->theData+1) == false)
{
DEBUG("Drop ATTRINFO, wrong transid, lenght="<<Tlength DEBUG("Drop ATTRINFO, wrong transid, lenght="<<Tlength
<< " transid("<<hex<<Tdata2<<", "<<Tdata3); << " transid("<<hex<<signal->theData[1]<<", "<<signal->theData[2]);
TCKEY_abort(signal, 19); TCKEY_abort(signal, 19);
return; return;
}//if }//if
...@@ -5456,11 +5458,32 @@ void Dbtc::execTC_COMMITREQ(Signal* signal) ...@@ -5456,11 +5458,32 @@ void Dbtc::execTC_COMMITREQ(Signal* signal)
} }
}//Dbtc::execTC_COMMITREQ() }//Dbtc::execTC_COMMITREQ()
/**
* TCROLLBACKREQ
*
* Format is:
*
* thedata[0] = apiconnectptr
* thedata[1] = transid[0]
* thedata[2] = transid[1]
* OPTIONAL thedata[3] = flags
*
* Flags:
* 0x1 = potentiallyBad data from API (try not to assert)
*/
void Dbtc::execTCROLLBACKREQ(Signal* signal) void Dbtc::execTCROLLBACKREQ(Signal* signal)
{ {
bool potentiallyBad= false;
UintR compare_transid1, compare_transid2; UintR compare_transid1, compare_transid2;
jamEntry(); jamEntry();
if(unlikely((signal->getLength() >= 4) && (signal->theData[3] & 0x1)))
{
ndbout_c("Trying to roll back potentially bad txn\n");
potentiallyBad= true;
}
apiConnectptr.i = signal->theData[0]; apiConnectptr.i = signal->theData[0];
if (apiConnectptr.i >= capiConnectFilesize) { if (apiConnectptr.i >= capiConnectFilesize) {
goto TC_ROLL_warning; goto TC_ROLL_warning;
...@@ -5547,12 +5570,14 @@ void Dbtc::execTCROLLBACKREQ(Signal* signal) ...@@ -5547,12 +5570,14 @@ void Dbtc::execTCROLLBACKREQ(Signal* signal)
TC_ROLL_warning: TC_ROLL_warning:
jam(); jam();
warningHandlerLab(signal, __LINE__); if(likely(potentiallyBad==false))
warningHandlerLab(signal, __LINE__);
return; return;
TC_ROLL_system_error: TC_ROLL_system_error:
jam(); jam();
systemErrorLab(signal, __LINE__); if(likely(potentiallyBad==false))
systemErrorLab(signal, __LINE__);
return; return;
}//Dbtc::execTCROLLBACKREQ() }//Dbtc::execTCROLLBACKREQ()
...@@ -11559,6 +11584,7 @@ void Dbtc::execTCINDXREQ(Signal* signal) ...@@ -11559,6 +11584,7 @@ void Dbtc::execTCINDXREQ(Signal* signal)
// This is a newly started transaction, clean-up // This is a newly started transaction, clean-up
releaseAllSeizedIndexOperations(regApiPtr); releaseAllSeizedIndexOperations(regApiPtr);
regApiPtr->apiConnectstate = CS_STARTED;
regApiPtr->transid[0] = tcIndxReq->transId1; regApiPtr->transid[0] = tcIndxReq->transId1;
regApiPtr->transid[1] = tcIndxReq->transId2; regApiPtr->transid[1] = tcIndxReq->transId2;
}//if }//if
...@@ -11599,20 +11625,29 @@ void Dbtc::execTCINDXREQ(Signal* signal) ...@@ -11599,20 +11625,29 @@ void Dbtc::execTCINDXREQ(Signal* signal)
Uint32 includedIndexLength = MIN(indexLength, indexBufSize); Uint32 includedIndexLength = MIN(indexLength, indexBufSize);
indexOp->expectedAttrInfo = attrLength; indexOp->expectedAttrInfo = attrLength;
Uint32 includedAttrLength = MIN(attrLength, attrBufSize); Uint32 includedAttrLength = MIN(attrLength, attrBufSize);
if (saveINDXKEYINFO(signal,
indexOp, int ret;
dataPtr, if ((ret = saveINDXKEYINFO(signal,
includedIndexLength)) { indexOp,
dataPtr,
includedIndexLength)) == 0)
{
jam(); jam();
// We have received all we need // We have received all we need
readIndexTable(signal, regApiPtr, indexOp); readIndexTable(signal, regApiPtr, indexOp);
return; return;
} }
else if (ret == -1)
{
jam();
return;
}
dataPtr += includedIndexLength; dataPtr += includedIndexLength;
if (saveINDXATTRINFO(signal, if (saveINDXATTRINFO(signal,
indexOp, indexOp,
dataPtr, dataPtr,
includedAttrLength)) { includedAttrLength) == 0) {
jam(); jam();
// We have received all we need // We have received all we need
readIndexTable(signal, regApiPtr, indexOp); readIndexTable(signal, regApiPtr, indexOp);
...@@ -11715,13 +11750,25 @@ void Dbtc::execINDXKEYINFO(Signal* signal) ...@@ -11715,13 +11750,25 @@ void Dbtc::execINDXKEYINFO(Signal* signal)
TcIndexOperationPtr indexOpPtr; TcIndexOperationPtr indexOpPtr;
TcIndexOperation* indexOp; TcIndexOperation* indexOp;
if (compare_transid(regApiPtr->transid, indxKeyInfo->transId) == false)
{
TCKEY_abort(signal, 19);
return;
}
if (regApiPtr->apiConnectstate == CS_ABORTING)
{
jam();
return;
}
if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL) if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL)
{ {
indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i); indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
if (saveINDXKEYINFO(signal, if (saveINDXKEYINFO(signal,
indexOp, indexOp,
src, src,
keyInfoLength)) { keyInfoLength) == 0) {
jam(); jam();
// We have received all we need // We have received all we need
readIndexTable(signal, regApiPtr, indexOp); readIndexTable(signal, regApiPtr, indexOp);
...@@ -11748,17 +11795,31 @@ void Dbtc::execINDXATTRINFO(Signal* signal) ...@@ -11748,17 +11795,31 @@ void Dbtc::execINDXATTRINFO(Signal* signal)
TcIndexOperationPtr indexOpPtr; TcIndexOperationPtr indexOpPtr;
TcIndexOperation* indexOp; TcIndexOperation* indexOp;
if (compare_transid(regApiPtr->transid, indxAttrInfo->transId) == false)
{
TCKEY_abort(signal, 19);
return;
}
if (regApiPtr->apiConnectstate == CS_ABORTING)
{
jam();
return;
}
if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL) if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL)
{ {
indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i); indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
if (saveINDXATTRINFO(signal, if (saveINDXATTRINFO(signal,
indexOp, indexOp,
src, src,
attrInfoLength)) { attrInfoLength) == 0) {
jam(); jam();
// We have received all we need // We have received all we need
readIndexTable(signal, regApiPtr, indexOp); readIndexTable(signal, regApiPtr, indexOp);
return;
} }
return;
} }
} }
...@@ -11766,12 +11827,13 @@ void Dbtc::execINDXATTRINFO(Signal* signal) ...@@ -11766,12 +11827,13 @@ void Dbtc::execINDXATTRINFO(Signal* signal)
* Save signal INDXKEYINFO * Save signal INDXKEYINFO
* Return true if we have received all needed data * Return true if we have received all needed data
*/ */
bool Dbtc::saveINDXKEYINFO(Signal* signal, int
TcIndexOperation* indexOp, Dbtc::saveINDXKEYINFO(Signal* signal,
const Uint32 *src, TcIndexOperation* indexOp,
Uint32 len) const Uint32 *src,
Uint32 len)
{ {
if (!indexOp->keyInfo.append(src, len)) { if (ERROR_INSERTED(8039) || !indexOp->keyInfo.append(src, len)) {
jam(); jam();
// Failed to seize keyInfo, abort transaction // Failed to seize keyInfo, abort transaction
#ifdef VM_TRACE #ifdef VM_TRACE
...@@ -11781,15 +11843,17 @@ bool Dbtc::saveINDXKEYINFO(Signal* signal, ...@@ -11781,15 +11843,17 @@ bool Dbtc::saveINDXKEYINFO(Signal* signal,
apiConnectptr.i = indexOp->connectionIndex; apiConnectptr.i = indexOp->connectionIndex;
ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
releaseIndexOperation(apiConnectptr.p, indexOp); releaseIndexOperation(apiConnectptr.p, indexOp);
terrorCode = 4000; terrorCode = 289;
if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo))
apiConnectptr.p->m_exec_flag= 1;
abortErrorLab(signal); abortErrorLab(signal);
return false; return -1;
} }
if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) { if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) {
jam(); jam();
return true; return 0;
} }
return false; return 1;
} }
bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp) bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp)
...@@ -11801,12 +11865,13 @@ bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp) ...@@ -11801,12 +11865,13 @@ bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp)
* Save signal INDXATTRINFO * Save signal INDXATTRINFO
* Return true if we have received all needed data * Return true if we have received all needed data
*/ */
bool Dbtc::saveINDXATTRINFO(Signal* signal, int
TcIndexOperation* indexOp, Dbtc::saveINDXATTRINFO(Signal* signal,
const Uint32 *src, TcIndexOperation* indexOp,
Uint32 len) const Uint32 *src,
Uint32 len)
{ {
if (!indexOp->attrInfo.append(src, len)) { if (ERROR_INSERTED(8051) || !indexOp->attrInfo.append(src, len)) {
jam(); jam();
#ifdef VM_TRACE #ifdef VM_TRACE
ndbout_c("Dbtc::saveINDXATTRINFO: Failed to seize attrInfo\n"); ndbout_c("Dbtc::saveINDXATTRINFO: Failed to seize attrInfo\n");
...@@ -11814,15 +11879,17 @@ bool Dbtc::saveINDXATTRINFO(Signal* signal, ...@@ -11814,15 +11879,17 @@ bool Dbtc::saveINDXATTRINFO(Signal* signal,
apiConnectptr.i = indexOp->connectionIndex; apiConnectptr.i = indexOp->connectionIndex;
ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
releaseIndexOperation(apiConnectptr.p, indexOp); releaseIndexOperation(apiConnectptr.p, indexOp);
terrorCode = 4000; terrorCode = 289;
if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo))
apiConnectptr.p->m_exec_flag= 1;
abortErrorLab(signal); abortErrorLab(signal);
return false; return -1;
} }
if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) { if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) {
jam(); jam();
return true; return 0;
} }
return false; return 1;
} }
bool Dbtc::receivedAllINDXATTRINFO(TcIndexOperation* indexOp) bool Dbtc::receivedAllINDXATTRINFO(TcIndexOperation* indexOp)
...@@ -12006,6 +12073,9 @@ void Dbtc::execTCKEYREF(Signal* signal) ...@@ -12006,6 +12073,9 @@ void Dbtc::execTCKEYREF(Signal* signal)
tcIndxRef->transId[0] = tcKeyRef->transId[0]; tcIndxRef->transId[0] = tcKeyRef->transId[0];
tcIndxRef->transId[1] = tcKeyRef->transId[1]; tcIndxRef->transId[1] = tcKeyRef->transId[1];
tcIndxRef->errorCode = tcKeyRef->errorCode; tcIndxRef->errorCode = tcKeyRef->errorCode;
releaseIndexOperation(regApiPtr, indexOp);
sendSignal(regApiPtr->ndbapiBlockref, sendSignal(regApiPtr->ndbapiBlockref,
GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB);
return; return;
...@@ -12538,7 +12608,18 @@ void Dbtc::executeIndexOperation(Signal* signal, ...@@ -12538,7 +12608,18 @@ void Dbtc::executeIndexOperation(Signal* signal,
bool Dbtc::seizeIndexOperation(ApiConnectRecord* regApiPtr, bool Dbtc::seizeIndexOperation(ApiConnectRecord* regApiPtr,
TcIndexOperationPtr& indexOpPtr) TcIndexOperationPtr& indexOpPtr)
{ {
return regApiPtr->theSeizedIndexOperations.seize(indexOpPtr); if (regApiPtr->theSeizedIndexOperations.seize(indexOpPtr))
{
ndbassert(indexOpPtr.p->expectedKeyInfo == 0);
ndbassert(indexOpPtr.p->keyInfo.getSize() == 0);
ndbassert(indexOpPtr.p->expectedAttrInfo == 0);
ndbassert(indexOpPtr.p->attrInfo.getSize() == 0);
ndbassert(indexOpPtr.p->expectedTransIdAI == 0);
ndbassert(indexOpPtr.p->transIdAI.getSize() == 0);
return true;
}
return false;
} }
void Dbtc::releaseIndexOperation(ApiConnectRecord* regApiPtr, void Dbtc::releaseIndexOperation(ApiConnectRecord* regApiPtr,
......
...@@ -892,7 +892,12 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count) ...@@ -892,7 +892,12 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count)
while (n < count) { while (n < count) {
NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable); NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
if (tOp == NULL || if (tOp == NULL ||
tOp->committedRead() == -1 || /*
* This was committedRead() before. However lock on main
* table tuple does not fully protect blob parts since DBTUP
* commits each tuple separately.
*/
tOp->readTuple() == -1 ||
setPartKeyValue(tOp, part + n) == -1 || setPartKeyValue(tOp, part + n) == -1 ||
tOp->getValue((Uint32)3, buf) == NULL) { tOp->getValue((Uint32)3, buf) == NULL) {
setErrorCode(tOp); setErrorCode(tOp);
......
...@@ -481,12 +481,27 @@ NdbTransaction::executeNoBlobs(ExecType aTypeOfExec, ...@@ -481,12 +481,27 @@ NdbTransaction::executeNoBlobs(ExecType aTypeOfExec,
while (1) { while (1) {
int noOfComp = tNdb->sendPollNdb(3 * timeout, 1, forceSend); int noOfComp = tNdb->sendPollNdb(3 * timeout, 1, forceSend);
if (noOfComp == 0) { if (noOfComp == 0) {
/** /*
* This timeout situation can occur if NDB crashes. * Just for fun, this is only one of two places where
* we could hit this error... It's quite possible we
* hit it in Ndbif.cpp in Ndb::check_send_timeout()
*
* We behave rather similarly in both places.
* Hitting this is certainly a bug though...
*/ */
ndbout << "This timeout should never occur, execute(..)" << endl; g_eventLogger.error("WARNING: Timeout in executeNoBlobs() waiting for "
theError.code = 4012; "response from NDB data nodes. This should NEVER "
setOperationErrorCodeAbort(4012); // Error code for "Cluster Failure" "occur. You have likely hit a NDB Bug. Please "
"file a bug.");
DBUG_PRINT("error",("This timeout should never occure, execute()"));
g_eventLogger.error("Forcibly trying to rollback txn (%p"
") to try to clean up data node resources.",
this);
executeNoBlobs(NdbTransaction::Rollback);
theError.code = 4012;
theError.status= NdbError::PermanentError;
theError.classification= NdbError::TimeoutExpired;
setOperationErrorCodeAbort(4012); // ndbd timeout
DBUG_RETURN(-1); DBUG_RETURN(-1);
}//if }//if
...@@ -550,7 +565,12 @@ NdbTransaction::executeAsynchPrepare( ExecType aTypeOfExec, ...@@ -550,7 +565,12 @@ NdbTransaction::executeAsynchPrepare( ExecType aTypeOfExec,
*/ */
if (theError.code != 0) if (theError.code != 0)
DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code)); DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code));
theError.code = 0; /**
* for timeout (4012) we want sendROLLBACK to behave differently.
* Else, normal behaviour of reset errcode
*/
if (theError.code != 4012)
theError.code = 0;
NdbScanOperation* tcOp = m_theFirstScanOperation; NdbScanOperation* tcOp = m_theFirstScanOperation;
if (tcOp != 0){ if (tcOp != 0){
// Execute any cursor operations // Execute any cursor operations
...@@ -873,6 +893,12 @@ NdbTransaction::sendROLLBACK() // Send a TCROLLBACKREQ signal; ...@@ -873,6 +893,12 @@ NdbTransaction::sendROLLBACK() // Send a TCROLLBACKREQ signal;
tSignal.setData(theTCConPtr, 1); tSignal.setData(theTCConPtr, 1);
tSignal.setData(tTransId1, 2); tSignal.setData(tTransId1, 2);
tSignal.setData(tTransId2, 3); tSignal.setData(tTransId2, 3);
if(theError.code == 4012)
{
g_eventLogger.error("Sending TCROLLBACKREQ with Bad flag");
tSignal.setLength(tSignal.getLength() + 1); // + flags
tSignal.setData(0x1, 4); // potentially bad data
}
tReturnCode = tp->sendSignal(&tSignal,theDBnode); tReturnCode = tp->sendSignal(&tSignal,theDBnode);
if (tReturnCode != -1) { if (tReturnCode != -1) {
theSendStatus = sendTC_ROLLBACK; theSendStatus = sendTC_ROLLBACK;
......
...@@ -173,6 +173,8 @@ ErrorBundle ErrorCodes[] = { ...@@ -173,6 +173,8 @@ ErrorBundle ErrorCodes[] = {
{ 4022, TR, "Out of Send Buffer space in NDB API" }, { 4022, TR, "Out of Send Buffer space in NDB API" },
{ 4032, TR, "Out of Send Buffer space in NDB API" }, { 4032, TR, "Out of Send Buffer space in NDB API" },
{ 288, TR, "Out of index operations in transaction coordinator (increase MaxNoOfConcurrentIndexOperations)" }, { 288, TR, "Out of index operations in transaction coordinator (increase MaxNoOfConcurrentIndexOperations)" },
{ 289, TR, "Out of transaction buffer memory in TC (increase TransactionBufferMemory)" },
/** /**
* InsufficientSpace * InsufficientSpace
*/ */
......
...@@ -1297,6 +1297,102 @@ runBug25059(NDBT_Context* ctx, NDBT_Step* step) ...@@ -1297,6 +1297,102 @@ runBug25059(NDBT_Context* ctx, NDBT_Step* step)
return res; return res;
} }
int tcSaveINDX_test(NDBT_Context* ctx, NDBT_Step* step, int inject_err)
{
int result= NDBT_OK;
Ndb* pNdb = GETNDB(step);
NdbDictionary::Dictionary * dict = pNdb->getDictionary();
const NdbDictionary::Index * idx = dict->getIndex(pkIdxName, *ctx->getTab());
HugoOperations ops(*ctx->getTab(), idx);
g_err << "Using INDEX: " << pkIdxName << endl;
NdbRestarter restarter;
int loops = ctx->getNumLoops();
const int rows = ctx->getNumRecords();
const int batchsize = ctx->getProperty("BatchSize", 1);
for(int bs=1; bs < loops; bs++)
{
int c= 0;
while (c++ < loops)
{
g_err << "BS " << bs << " LOOP #" << c << endl;
g_err << "inserting error on op#" << c << endl;
CHECK(ops.startTransaction(pNdb) == 0);
for(int i=1;i<=c;i++)
{
if(i==c)
{
if(restarter.insertErrorInAllNodes(inject_err)!=0)
{
g_err << "**** FAILED to insert error" << endl;
result= NDBT_FAILED;
break;
}
}
CHECK(ops.indexReadRecords(pNdb, pkIdxName, i,false,1) == 0);
if(i%bs==0 || i==c)
{
if(i<c)
{
if(ops.execute_NoCommit(pNdb, AO_IgnoreError)!=NDBT_OK)
{
g_err << "**** executeNoCommit should have succeeded" << endl;
result= NDBT_FAILED;
}
}
else
{
if(ops.execute_NoCommit(pNdb, AO_IgnoreError)!=289)
{
g_err << "**** executeNoCommit should have failed with 289"
<< endl;
result= NDBT_FAILED;
}
g_err << "NdbError.code= " <<
ops.getTransaction()->getNdbError().code << endl;
break;
}
}
}
CHECK(ops.closeTransaction(pNdb) == 0);
if(restarter.insertErrorInAllNodes(0) != 0)
{
g_err << "**** Failed to error insert(0)" << endl;
return NDBT_FAILED;
}
CHECK(ops.startTransaction(pNdb) == 0);
if (ops.indexReadRecords(pNdb, pkIdxName,0,0,rows) != 0){
g_err << "**** Index read failed" << endl;
return NDBT_FAILED;
}
CHECK(ops.closeTransaction(pNdb) == 0);
}
}
return result;
}
int
runBug28804(NDBT_Context* ctx, NDBT_Step* step)
{
return tcSaveINDX_test(ctx, step, 8039);
}
int
runBug28804_ATTRINFO(NDBT_Context* ctx, NDBT_Step* step)
{
return tcSaveINDX_test(ctx, step, 8051);
}
NDBT_TESTSUITE(testIndex); NDBT_TESTSUITE(testIndex);
TESTCASE("CreateAll", TESTCASE("CreateAll",
"Test that we can create all various indexes on each table\n" "Test that we can create all various indexes on each table\n"
...@@ -1628,6 +1724,27 @@ TESTCASE("Bug25059", ...@@ -1628,6 +1724,27 @@ TESTCASE("Bug25059",
STEP(runBug25059); STEP(runBug25059);
FINALIZER(createPkIndex_Drop); FINALIZER(createPkIndex_Drop);
} }
TESTCASE("Bug28804",
"Test behaviour on out of TransactionBufferMemory for index lookup"){
TC_PROPERTY("LoggedIndexes", (unsigned)0);
INITIALIZER(runClearTable);
INITIALIZER(createPkIndex);
INITIALIZER(runLoadTable);
STEP(runBug28804);
FINALIZER(createPkIndex_Drop);
FINALIZER(runClearTable);
}
TESTCASE("Bug28804_ATTRINFO",
"Test behaviour on out of TransactionBufferMemory for index lookup"
" in saveINDXATTRINFO"){
TC_PROPERTY("LoggedIndexes", (unsigned)0);
INITIALIZER(runClearTable);
INITIALIZER(createPkIndex);
INITIALIZER(runLoadTable);
STEP(runBug28804_ATTRINFO);
FINALIZER(createPkIndex_Drop);
FINALIZER(runClearTable);
}
NDBT_TESTSUITE_END(testIndex); NDBT_TESTSUITE_END(testIndex);
int main(int argc, const char** argv){ int main(int argc, const char** argv){
......
...@@ -779,3 +779,11 @@ cmd: DbAsyncGenerator ...@@ -779,3 +779,11 @@ cmd: DbAsyncGenerator
args: -time 60 -p 1 -proc 25 args: -time 60 -p 1 -proc 25
type: bench type: bench
max-time: 180
cmd: testIndex
args: -n Bug28804 T1 T3
max-time: 180
cmd: testIndex
args: -n Bug28804_ATTRINFO T1 T3
...@@ -1758,9 +1758,15 @@ int ha_ndbcluster::unique_index_read(const byte *key, ...@@ -1758,9 +1758,15 @@ int ha_ndbcluster::unique_index_read(const byte *key,
if (execute_no_commit_ie(this,trans,false) != 0) if (execute_no_commit_ie(this,trans,false) != 0)
{ {
table->status= STATUS_NOT_FOUND; int err= ndb_err(trans);
DBUG_RETURN(ndb_err(trans)); if(err==HA_ERR_KEY_NOT_FOUND)
table->status= STATUS_NOT_FOUND;
else
table->status= STATUS_GARBAGE;
DBUG_RETURN(err);
} }
// The value have now been fetched from NDB // The value have now been fetched from NDB
unpack_record(buf); unpack_record(buf);
table->status= 0; table->status= 0;
...@@ -3310,6 +3316,8 @@ int ha_ndbcluster::info(uint flag) ...@@ -3310,6 +3316,8 @@ int ha_ndbcluster::info(uint flag)
DBUG_PRINT("info", ("HA_STATUS_AUTO")); DBUG_PRINT("info", ("HA_STATUS_AUTO"));
if (m_table && table->found_next_number_field) if (m_table && table->found_next_number_field)
{ {
if ((my_errno= check_ndb_connection()))
DBUG_RETURN(my_errno);
Ndb *ndb= get_ndb(); Ndb *ndb= get_ndb();
Uint64 auto_increment_value64; Uint64 auto_increment_value64;
...@@ -6462,7 +6470,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, ...@@ -6462,7 +6470,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
if (uses_blob_value(m_retrieve_all_fields) || if (uses_blob_value(m_retrieve_all_fields) ||
(cur_index_type == UNIQUE_INDEX && (cur_index_type == UNIQUE_INDEX &&
has_null_in_unique_index(active_index) && has_null_in_unique_index(active_index) &&
null_value_index_search(ranges, ranges+range_count, buffer))) null_value_index_search(ranges, ranges+range_count, buffer))
|| m_delete_cannot_batch || m_update_cannot_batch)
{ {
m_disable_multi_read= TRUE; m_disable_multi_read= TRUE;
DBUG_RETURN(handler::read_multi_range_first(found_range_p, DBUG_RETURN(handler::read_multi_range_first(found_range_p,
......
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