diff options
Diffstat (limited to 'ndb')
66 files changed, 1136 insertions, 858 deletions
diff --git a/ndb/include/kernel/LogLevel.hpp b/ndb/include/kernel/LogLevel.hpp index 52c2f70cda8..be0627c98a8 100644 --- a/ndb/include/kernel/LogLevel.hpp +++ b/ndb/include/kernel/LogLevel.hpp @@ -64,7 +64,7 @@ public: /** * No of categories */ -#define _LOGLEVEL_CATEGORIES (CFG_MAX_LOGLEVEL - CFG_MIN_LOGLEVEL + 1); +#define _LOGLEVEL_CATEGORIES (CFG_MAX_LOGLEVEL - CFG_MIN_LOGLEVEL + 1) static const Uint32 LOGLEVEL_CATEGORIES = _LOGLEVEL_CATEGORIES; void clear(); diff --git a/ndb/include/kernel/signaldata/TcContinueB.hpp b/ndb/include/kernel/signaldata/TcContinueB.hpp index 7a093b457e8..85213791b2a 100644 --- a/ndb/include/kernel/signaldata/TcContinueB.hpp +++ b/ndb/include/kernel/signaldata/TcContinueB.hpp @@ -42,7 +42,9 @@ private: ZWAIT_ABORT_ALL = 14, ZCHECK_SCAN_ACTIVE_FAILED_LQH = 15, CHECK_WAIT_DROP_TAB_FAILED_LQH = 16, - TRIGGER_PENDING = 17 + TRIGGER_PENDING = 17, + + DelayTCKEYCONF = 18 }; }; diff --git a/ndb/include/kernel/signaldata/TcKeyConf.hpp b/ndb/include/kernel/signaldata/TcKeyConf.hpp index 27ff344f793..277872b990b 100644 --- a/ndb/include/kernel/signaldata/TcKeyConf.hpp +++ b/ndb/include/kernel/signaldata/TcKeyConf.hpp @@ -47,7 +47,8 @@ public: */ STATIC_CONST( StaticLength = 5 ); STATIC_CONST( OperationLength = 2 ); - + STATIC_CONST( SimpleReadBit = (((Uint32)1) << 31) ); + private: /** diff --git a/ndb/include/kernel/signaldata/TuxBound.hpp b/ndb/include/kernel/signaldata/TuxBound.hpp index 1f256150573..87ce3c3c098 100644 --- a/ndb/include/kernel/signaldata/TuxBound.hpp +++ b/ndb/include/kernel/signaldata/TuxBound.hpp @@ -48,7 +48,6 @@ private: Uint32 tuxScanPtrI; /* * Number of words of bound info included after fixed signal data. - * Starts with 5 unused words (word 0 is length used by LQH). */ Uint32 boundAiLength; }; diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index 44307c3e73c..d3a320123a3 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -122,7 +122,10 @@ extern "C" { /* Service errors - Single User Mode */ NDB_MGM_COULD_NOT_ENTER_SINGLE_USER_MODE = 4001, - NDB_MGM_COULD_NOT_EXIT_SINGLE_USER_MODE = 4002 + NDB_MGM_COULD_NOT_EXIT_SINGLE_USER_MODE = 4002, + + /* Usage errors */ + NDB_MGM_USAGE_ERROR = 5001 }; struct Ndb_Mgm_Error_Msg { @@ -158,7 +161,11 @@ extern "C" { { NDB_MGM_COULD_NOT_ENTER_SINGLE_USER_MODE, "Could not enter single user mode" }, { NDB_MGM_COULD_NOT_EXIT_SINGLE_USER_MODE, - "Could not exit single user mode" } + "Could not exit single user mode" }, + + /* Usage errors */ + { NDB_MGM_USAGE_ERROR, + "Usage error" } }; const int ndb_mgm_noOfErrorMsgs = diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index 550d0c0931a..134a48e1d6d 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -1612,7 +1612,6 @@ private: char prefixName[NDB_MAX_INTERNAL_TABLE_LENGTH]; char * prefixEnd; - //Table* theTable; // The table object class NdbImpl * theImpl; class NdbDictionaryImpl* theDictionary; class NdbGlobalEventBufferHandle* theGlobalEventBufferHandle; @@ -1698,10 +1697,13 @@ private: NdbApiSignal* theCommitAckSignal; + +#ifdef POORMANSPURIFY int cfreeSignals; int cnewSignals; int cgetSignals; int creleaseSignals; +#endif static void executeMessage(void*, NdbApiSignal *, struct LinearSectionPtr ptr[3]); diff --git a/ndb/include/ndbapi/NdbConnection.hpp b/ndb/include/ndbapi/NdbConnection.hpp index d23a2e7cc0d..92b940e96f7 100644 --- a/ndb/include/ndbapi/NdbConnection.hpp +++ b/ndb/include/ndbapi/NdbConnection.hpp @@ -526,9 +526,8 @@ private: int sendCOMMIT(); // Send a TC_COMMITREQ signal; void setGCI(int GCI); // Set the global checkpoint identity - int OpCompleteFailure(); // Operation Completed with success - int OpCompleteSuccess(); // Operation Completed with success - + int OpCompleteFailure(Uint8 abortoption); + int OpCompleteSuccess(); void CompletedOperations(); // Move active ops to list of completed void OpSent(); // Operation Sent with success @@ -649,6 +648,18 @@ private: Uint32 theNodeSequence; // The sequence no of the db node bool theReleaseOnClose; + /** + * handle transaction spanning + * multiple TC/db nodes + * + * 1) Bitmask with used nodes + * 2) Bitmask with nodes failed during op + */ + Uint32 m_db_nodes[2]; + Uint32 m_failed_db_nodes[2]; + + int report_node_failure(Uint32 id); + // Scan operations bool m_waitForReply; NdbIndexScanOperation* m_theFirstScanOperation; diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp index a854cb58665..66b3fc9d43b 100644 --- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp +++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp @@ -56,27 +56,11 @@ public: } /** - * @name Define Range Scan - * - * A range scan is a scan on an ordered index. The operation is on - * the index table but tuples are returned from the primary table. - * The index contains all tuples where at least one index key has not - * null value. - * - * A range scan is currently opened via a normal open scan method. - * Bounds can be defined for each index key. After setting bounds, - * usual scan methods can be used (get value, interpreter, take over). - * These operate on the primary table. - * - * @{ - */ - - /** * Type of ordered index key bound. The values (0-4) will not change * and can be used explicitly (e.g. they could be computed). */ enum BoundType { - BoundLE = 0, ///< lower bound, + BoundLE = 0, ///< lower bound BoundLT = 1, ///< lower bound, strict BoundGE = 2, ///< upper bound BoundGT = 3, ///< upper bound, strict @@ -86,20 +70,28 @@ public: /** * Define bound on index key in range scan. * - * Each index key can have lower and/or upper bound, or can be set - * equal to a value. The bounds can be defined in any order but - * a duplicate definition is an error. + * Each index key can have lower and/or upper bound. Setting the key + * equal to a value defines both upper and lower bounds. The bounds + * can be defined in any order. Conflicting definitions is an error. + * + * For equality, it is better to use BoundEQ instead of the equivalent + * pair of BoundLE and BoundGE. This is especially true when table + * distribution key is an initial part of the index key. * - * The bounds must specify a single range i.e. they are on an initial - * sequence of index keys and the condition is equality for all but - * (at most) the last key which has a lower and/or upper bound. + * The sets of lower and upper bounds must be on initial sequences of + * index keys. All but possibly the last bound must be non-strict. + * So "a >= 2 and b > 3" is ok but "a > 2 and b >= 3" is not. + * + * The scan may currently return tuples for which the bounds are not + * satisfied. For example, "a <= 2 and b <= 3" scans the index up to + * (a=2, b=3) but also returns any (a=1, b=4). * * NULL is treated like a normal value which is less than any not-NULL - * value and equal to another NULL value. To search for NULL use + * value and equal to another NULL value. To compare against NULL use * setBound with null pointer (0). * - * An index stores also all-NULL keys (this may become optional). - * Doing index scan with empty bound set returns all table tuples. + * An index stores also all-NULL keys. Doing index scan with empty + * bound set returns all table tuples. * * @param attrName Attribute name, alternatively: * @param anAttrId Index column id (starting from 0) @@ -117,8 +109,6 @@ public: */ int setBound(Uint32 anAttrId, int type, const void* aValue, Uint32 len = 0); - /** @} *********************************************************************/ - /** * Reset bounds and put operation in list that will be * sent on next execute diff --git a/ndb/include/ndbapi/NdbOperation.hpp b/ndb/include/ndbapi/NdbOperation.hpp index d35fea0e995..8e0294e41e6 100644 --- a/ndb/include/ndbapi/NdbOperation.hpp +++ b/ndb/include/ndbapi/NdbOperation.hpp @@ -787,11 +787,6 @@ protected: int receiveTCKEYREF(NdbApiSignal*); - - int receiveTRANSID_AI(const Uint32* aDataPtr, Uint32 aDataLength); - int receiveREAD_CONF(const Uint32* aDataPtr, Uint32 aDataLength); - - int checkMagicNumber(bool b = true); // Verify correct object int checkState_TransId(NdbApiSignal* aSignal); @@ -815,8 +810,6 @@ protected: int branch_col_null(Uint32 type, Uint32 col, Uint32 Label); // Handle ATTRINFO signals - int receiveREAD_AI(Uint32* aDataPtr, Uint32 aLength); - int insertATTRINFO(Uint32 aData); int insertATTRINFOloop(const Uint32* aDataPtr, Uint32 aLength); diff --git a/ndb/include/ndbapi/NdbReceiver.hpp b/ndb/include/ndbapi/NdbReceiver.hpp index b7f73bb618d..6f577380728 100644 --- a/ndb/include/ndbapi/NdbReceiver.hpp +++ b/ndb/include/ndbapi/NdbReceiver.hpp @@ -19,6 +19,7 @@ #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL // Not part of public interface #include <ndb_types.h> +#include <ndb_global.h> class Ndb; class NdbReceiver @@ -59,6 +60,7 @@ public: inline void next(NdbReceiver* next) { m_next = next;} inline NdbReceiver* next() { return m_next; } + void setErrorCode(int); private: Uint32 theMagicNumber; Ndb* m_ndb; @@ -127,7 +129,8 @@ int NdbReceiver::execTCOPCONF(Uint32 len){ Uint32 tmp = m_received_result_length; m_expected_result_length = len; - return (tmp == len ? 1 : 0); + assert(!(tmp && !len)); + return ((bool)len ^ (bool)tmp ? 0 : 1); } inline diff --git a/ndb/include/util/version.h b/ndb/include/util/version.h index a82ae4b8b52..5459e44b818 100644 --- a/ndb/include/util/version.h +++ b/ndb/include/util/version.h @@ -30,7 +30,7 @@ extern "C" { Uint32 makeVersion(Uint32 major, Uint32 minor, Uint32 build); - char* getVersionString(Uint32 version, char * status); + const char* getVersionString(Uint32 version, const char * status); void ndbPrintVersion(); Uint32 ndbGetOwnVersion(); diff --git a/ndb/src/common/debugger/signaldata/SignalNames.cpp b/ndb/src/common/debugger/signaldata/SignalNames.cpp index 9d4d5bdf6f5..9228e305677 100644 --- a/ndb/src/common/debugger/signaldata/SignalNames.cpp +++ b/ndb/src/common/debugger/signaldata/SignalNames.cpp @@ -446,6 +446,8 @@ const GsnName SignalNames [] = { ,{ GSN_STOP_REQ, "STOP_REQ" } ,{ GSN_STOP_REF, "STOP_REF" } + ,{ GSN_API_VERSION_REQ, "API_VERSION_REQ" } + ,{ GSN_API_VERSION_CONF, "API_VERSION_CONF" } ,{ GSN_ABORT_ALL_REQ, "ABORT_ALL_REQ" } ,{ GSN_ABORT_ALL_REF, "ABORT_ALL_REF" } diff --git a/ndb/src/common/debugger/signaldata/TcKeyConf.cpp b/ndb/src/common/debugger/signaldata/TcKeyConf.cpp index 727e097a464..652c2b8a557 100644 --- a/ndb/src/common/debugger/signaldata/TcKeyConf.cpp +++ b/ndb/src/common/debugger/signaldata/TcKeyConf.cpp @@ -22,38 +22,48 @@ printTCKEYCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receive if (receiverBlockNo == API_PACKED) { - fprintf(output, "Signal data: "); - Uint32 i = 0; - while (i < len) - fprintf(output, "H\'%.8x ", theData[i++]); - fprintf(output,"\n"); + return false; + Uint32 Theader = * theData++; + Uint32 TpacketLen = (Theader & 0x1F) + 3; + Uint32 TrecBlockNo = Theader >> 16; + + do { + fprintf(output, "Block: %d %d %d\n", TrecBlockNo, len, TpacketLen); + printTCKEYCONF(output, theData, TpacketLen, TrecBlockNo); + assert(len >= (1 + TpacketLen)); + len -= (1 + TpacketLen); + theData += TpacketLen; + } while(len); + return true; } else { const TcKeyConf * const sig = (TcKeyConf *) theData; - fprintf(output, "Signal data: "); Uint32 i = 0; Uint32 confInfo = sig->confInfo; Uint32 noOfOp = TcKeyConf::getNoOfOperations(confInfo); if (noOfOp > 10) noOfOp = 10; - while (i < len) - fprintf(output, "H\'%.8x ", theData[i++]); - fprintf(output,"\n"); - fprintf(output, "apiConnectPtr: H'%.8x, gci: %u, transId:(H'%.8x, H'%.8x)\n", + fprintf(output, " apiConnectPtr: H'%.8x, gci: %u, transId:(H'%.8x, H'%.8x)\n", sig->apiConnectPtr, sig->gci, sig->transId1, sig->transId2); - fprintf(output, "noOfOperations: %u, commitFlag: %s, markerFlag: %s\n", + fprintf(output, " noOfOperations: %u, commitFlag: %s, markerFlag: %s\n", noOfOp, (TcKeyConf::getCommitFlag(confInfo) == 0)?"false":"true", (TcKeyConf::getMarkerFlag(confInfo) == 0)?"false":"true"); fprintf(output, "Operations:\n"); for(i = 0; i < noOfOp; i++) { - fprintf(output, - "apiOperationPtr: H'%.8x, attrInfoLen: %u\n", - sig->operations[i].apiOperationPtr, - sig->operations[i].attrInfoLen); + if(sig->operations[i].attrInfoLen > TcKeyConf::SimpleReadBit) + fprintf(output, + " apiOperationPtr: H'%.8x, simplereadnode: %u\n", + sig->operations[i].apiOperationPtr, + sig->operations[i].attrInfoLen & (~TcKeyConf::SimpleReadBit)); + else + fprintf(output, + " apiOperationPtr: H'%.8x, attrInfoLen: %u\n", + sig->operations[i].apiOperationPtr, + sig->operations[i].attrInfoLen); } } - + return true; } diff --git a/ndb/src/common/util/version.c b/ndb/src/common/util/version.c index b8408c7f201..e2515b243b1 100644 --- a/ndb/src/common/util/version.c +++ b/ndb/src/common/util/version.c @@ -35,7 +35,7 @@ Uint32 makeVersion(Uint32 major, Uint32 minor, Uint32 build) { } -char * getVersionString(Uint32 version, char * status) { +const char * getVersionString(Uint32 version, const char * status) { char buff[100]; if (status && status[0] != 0) snprintf(buff, sizeof(buff), diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt index 43532a973f9..70f11c33cd7 100644 --- a/ndb/src/kernel/blocks/ERROR_codes.txt +++ b/ndb/src/kernel/blocks/ERROR_codes.txt @@ -3,7 +3,7 @@ Next NDBCNTR 1000 Next NDBFS 2000 Next DBACC 3001 Next DBTUP 4007 -Next DBLQH 5040 +Next DBLQH 5042 Next DBDICT 6006 Next DBDIH 7174 Next DBTC 8035 @@ -193,6 +193,8 @@ Delay execution of ABORTREQ signal 2 seconds to generate time-out. 5038: Drop LQHKEYREQ + set 5039 5039: Drop ABORT + set 5003 +8048: Make TC not choose own node for simple/dirty read +5041: Crash is receiving simple read from other TC on different node ERROR CODES FOR TESTING TIME-OUT HANDLING IN DBTC ------------------------------------------------- diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp index b4531af7cd6..d6987f3e478 100644 --- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp +++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp @@ -234,10 +234,6 @@ #define ZNODE_UP 0 #define ZNODE_DOWN 1 /* ------------------------------------------------------------------------- */ -/* OPERATION TYPES */ -/* ------------------------------------------------------------------------- */ -#define ZSIMPLE_READ 1 -/* ------------------------------------------------------------------------- */ /* START PHASES */ /* ------------------------------------------------------------------------- */ #define ZLAST_START_PHASE 255 @@ -2437,6 +2433,7 @@ private: void abortStateHandlerLab(Signal* signal); void writeAttrinfoLab(Signal* signal); void scanAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length); + void abort_scan(Signal* signal, Uint32 scan_ptr_i, Uint32 errcode); void localAbortStateHandlerLab(Signal* signal); void logLqhkeyreqLab(Signal* signal); void lqhAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length); diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index c5e2bd900e9..e6a689eb8d7 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -2824,9 +2824,11 @@ void Dblqh::execKEYINFO(Signal* signal) return; }//if jam(); - abort(); terrorCode = errorCode; - abortErrorLab(signal); + if(state == TcConnectionrec::WAIT_TUPKEYINFO) + abortErrorLab(signal); + else + abort_scan(signal, regTcPtr->tcScanRec, errorCode); return; }//if if(state == TcConnectionrec::WAIT_TUPKEYINFO) @@ -3299,12 +3301,15 @@ void Dblqh::execLQHKEYREQ(Signal* signal) regTcPtr->dirtyOp = LqhKeyReq::getDirtyFlag(Treqinfo); regTcPtr->opExec = LqhKeyReq::getInterpretedFlag(Treqinfo); regTcPtr->opSimple = LqhKeyReq::getSimpleFlag(Treqinfo); - regTcPtr->simpleRead = ((Treqinfo >> 18) & 15); regTcPtr->operation = LqhKeyReq::getOperation(Treqinfo); + regTcPtr->simpleRead = regTcPtr->operation == ZREAD && regTcPtr->opSimple; regTcPtr->seqNoReplica = LqhKeyReq::getSeqNoReplica(Treqinfo); UintR TreclenAiLqhkey = LqhKeyReq::getAIInLqhKeyReq(Treqinfo); regTcPtr->apiVersionNo = 0; + CRASH_INSERTION2(5041, regTcPtr->simpleRead && + refToNode(signal->senderBlockRef()) != cownNodeid); + regTcPtr->reclenAiLqhkey = TreclenAiLqhkey; regTcPtr->currReclenAi = TreclenAiLqhkey; UintR TitcKeyLen = LqhKeyReq::getKeyLen(Treqinfo); @@ -3431,7 +3436,7 @@ void Dblqh::execLQHKEYREQ(Signal* signal) if ((tfragDistKey != TdistKey) && (regTcPtr->seqNoReplica == 0) && (regTcPtr->dirtyOp == ZFALSE) && - (regTcPtr->simpleRead != ZSIMPLE_READ)) { + (regTcPtr->simpleRead == ZFALSE)) { /* ---------------------------------------------------------------------- * WE HAVE DIFFERENT OPINION THAN THE DIH THAT STARTED THE TRANSACTION. * THE REASON COULD BE THAT THIS IS AN OLD DISTRIBUTION WHICH IS NO LONGER @@ -3439,7 +3444,7 @@ void Dblqh::execLQHKEYREQ(Signal* signal) * ONE IS ADDED TO THE DISTRIBUTION KEY EVERY TIME WE ADD A NEW REPLICA. * FAILED REPLICAS DO NOT AFFECT THE DISTRIBUTION KEY. THIS MEANS THAT THE * MAXIMUM DEVIATION CAN BE ONE BETWEEN THOSE TWO VALUES. - * ---------------------------------------------------------------------- */ + * --------------------------------------------------------------------- */ Int32 tmp = TdistKey - tfragDistKey; tmp = (tmp < 0 ? - tmp : tmp); if ((tmp <= 1) || (tfragDistKey == 0)) { @@ -3879,7 +3884,7 @@ void Dblqh::tupkeyConfLab(Signal* signal) /* ---- GET OPERATION TYPE AND CHECK WHAT KIND OF OPERATION IS REQUESTED ---- */ const TupKeyConf * const tupKeyConf = (TupKeyConf *)&signal->theData[0]; TcConnectionrec * const regTcPtr = tcConnectptr.p; - if (regTcPtr->simpleRead == ZSIMPLE_READ) { + if (regTcPtr->simpleRead) { jam(); /* ---------------------------------------------------------------------- * THE OPERATION IS A SIMPLE READ. WE WILL IMMEDIATELY COMMIT THE OPERATION. @@ -5467,6 +5472,8 @@ void Dblqh::commitContinueAfterBlockedLab(Signal* signal) TcConnectionrec * const regTcPtr = tcConnectptr.p; Fragrecord * const regFragptr = fragptr.p; Uint32 operation = regTcPtr->operation; + Uint32 simpleRead = regTcPtr->simpleRead; + Uint32 dirtyOp = regTcPtr->dirtyOp; if (regTcPtr->activeCreat == ZFALSE) { if ((cCommitBlocked == true) && (regFragptr->fragActiveStatus == ZTRUE)) { @@ -5504,13 +5511,18 @@ void Dblqh::commitContinueAfterBlockedLab(Signal* signal) tupCommitReq->hashValue = regTcPtr->hashValue; EXECUTE_DIRECT(tup, GSN_TUP_COMMITREQ, signal, TupCommitReq::SignalLength); - }//if - Uint32 acc = refToBlock(regTcPtr->tcAccBlockref); - signal->theData[0] = regTcPtr->accConnectrec; - EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1); - Uint32 simpleRead = regTcPtr->simpleRead; + Uint32 acc = refToBlock(regTcPtr->tcAccBlockref); + signal->theData[0] = regTcPtr->accConnectrec; + EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1); + } else { + if(!dirtyOp){ + Uint32 acc = refToBlock(regTcPtr->tcAccBlockref); + signal->theData[0] = regTcPtr->accConnectrec; + EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1); + } + } jamEntry(); - if (simpleRead == ZSIMPLE_READ) { + if (simpleRead) { jam(); /* ------------------------------------------------------------------------- */ /*THE OPERATION WAS A SIMPLE READ THUS THE COMMIT PHASE IS ONLY NEEDED TO */ @@ -5523,7 +5535,6 @@ void Dblqh::commitContinueAfterBlockedLab(Signal* signal) return; }//if }//if - Uint32 dirtyOp = regTcPtr->dirtyOp; Uint32 seqNoReplica = regTcPtr->seqNoReplica; if (regTcPtr->gci > regFragptr->newestGci) { jam(); @@ -6092,7 +6103,7 @@ void Dblqh::abortStateHandlerLab(Signal* signal) /* ------------------------------------------------------------------------- */ return; }//if - if (regTcPtr->simpleRead == ZSIMPLE_READ) { + if (regTcPtr->simpleRead) { jam(); /* ------------------------------------------------------------------------- */ /*A SIMPLE READ IS CURRENTLY RELEASING THE LOCKS OR WAITING FOR ACCESS TO */ @@ -6378,7 +6389,7 @@ void Dblqh::continueAbortLab(Signal* signal) void Dblqh::continueAfterLogAbortWriteLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; - if (regTcPtr->simpleRead == ZSIMPLE_READ) { + if (regTcPtr->simpleRead) { jam(); TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend(); @@ -7593,23 +7604,29 @@ void Dblqh::scanAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length) }//if return; }//if - terrorCode = ZGET_ATTRINBUF_ERROR; + abort_scan(signal, scanptr.i, ZGET_ATTRINBUF_ERROR); +} + +void Dblqh::abort_scan(Signal* signal, Uint32 scan_ptr_i, Uint32 errcode){ + jam(); + scanptr.i = scan_ptr_i; + c_scanRecordPool.getPtr(scanptr); finishScanrec(signal); releaseScanrec(signal); tcConnectptr.p->transactionState = TcConnectionrec::IDLE; tcConnectptr.p->abortState = TcConnectionrec::ABORT_ACTIVE; - + ScanFragRef * ref = (ScanFragRef*)&signal->theData[0]; ref->senderData = tcConnectptr.p->clientConnectrec; ref->transId1 = tcConnectptr.p->transid[0]; ref->transId2 = tcConnectptr.p->transid[1]; - ref->errorCode = terrorCode; + ref->errorCode = errcode; sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGREF, signal, ScanFragRef::SignalLength, JBB); deleteTransidHash(signal); releaseOprec(signal); releaseTcrec(signal, tcConnectptr); -}//Dblqh::scanAttrinfoLab() +} /*---------------------------------------------------------------------*/ /* Send this 'I am alive' signal to TC when it is received from ACC */ @@ -7683,7 +7700,6 @@ void Dblqh::accScanConfScanLab(Signal* signal) Uint32 boundAiLength = tcConnectptr.p->primKeyLen - 4; if (scanptr.p->rangeScan) { jam(); - // bound info length is in first of the 5 header words TuxBoundInfo* const req = (TuxBoundInfo*)signal->getDataPtrSend(); req->errorCode = RNIL; req->tuxScanPtrI = scanptr.p->scanAccPtr; diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp index 09a7708783e..a209df24c44 100644 --- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp +++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp @@ -1459,7 +1459,7 @@ private: void releaseAttrinfo(); void releaseGcp(Signal* signal); void releaseKeys(); - void releaseSimpleRead(Signal* signal); + void releaseSimpleRead(Signal*, ApiConnectRecordPtr, TcConnectRecord*); void releaseDirtyWrite(Signal* signal); void releaseTcCon(); void releaseTcConnectFail(Signal* signal); diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 890b6599d0a..3276e4e5bce 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -274,6 +274,12 @@ void Dbtc::execCONTINUEB(Signal* signal) transPtr.p->triggerPending = false; executeTriggers(signal, &transPtr); return; + case TcContinueB::DelayTCKEYCONF: + jam(); + apiConnectptr.i = Tdata0; + ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); + sendtckeyconf(signal, Tdata1); + return; default: ndbrequire(false); }//switch @@ -2290,6 +2296,7 @@ void Dbtc::initApiConnectRec(Signal* signal, regApiPtr->m_exec_flag = 0; regApiPtr->returncode = 0; regApiPtr->returnsignal = RS_TCKEYCONF; + ndbassert(regApiPtr->firstTcConnect == RNIL); regApiPtr->firstTcConnect = RNIL; regApiPtr->lastTcConnect = RNIL; regApiPtr->globalcheckpointid = 0; @@ -2484,18 +2491,30 @@ void Dbtc::execTCKEYREQ(Signal* signal) } break; case CS_STARTED: - //------------------------------------------------------------------------ - // Transaction is started already. Check that the operation is on the same - // transaction. - //------------------------------------------------------------------------ - compare_transid1 = regApiPtr->transid[0] ^ tcKeyReq->transId1; - compare_transid2 = regApiPtr->transid[1] ^ tcKeyReq->transId2; - jam(); - compare_transid1 = compare_transid1 | compare_transid2; - if (compare_transid1 != 0) { - TCKEY_abort(signal, 1); - return; - }//if + if(TstartFlag == 1 && regApiPtr->firstTcConnect == RNIL) + { + /** + * If last operation in last transaction was a simple/dirty read + * it does not have to be committed or rollbacked hence, + * the state will be CS_STARTED + */ + jam(); + initApiConnectRec(signal, regApiPtr); + regApiPtr->m_exec_flag = TexecFlag; + } else { + //---------------------------------------------------------------------- + // Transaction is started already. + // Check that the operation is on the same transaction. + //----------------------------------------------------------------------- + compare_transid1 = regApiPtr->transid[0] ^ tcKeyReq->transId1; + compare_transid2 = regApiPtr->transid[1] ^ tcKeyReq->transId2; + jam(); + compare_transid1 = compare_transid1 | compare_transid2; + if (compare_transid1 != 0) { + TCKEY_abort(signal, 1); + return; + }//if + } break; case CS_ABORTING: if (regApiPtr->abortState == AS_IDLE) { @@ -2644,7 +2663,7 @@ void Dbtc::execTCKEYREQ(Signal* signal) regCachePtr->schemaVersion = TtableSchemaVersion; regTcPtr->operation = TOperationType; - // Uint8 TSimpleFlag = tcKeyReq->getSimpleFlag(Treqinfo); + Uint8 TSimpleFlag = tcKeyReq->getSimpleFlag(Treqinfo); Uint8 TDirtyFlag = tcKeyReq->getDirtyFlag(Treqinfo); Uint8 TInterpretedFlag = tcKeyReq->getInterpretedFlag(Treqinfo); Uint8 TDistrGroupFlag = tcKeyReq->getDistributionGroupFlag(Treqinfo); @@ -2652,11 +2671,9 @@ void Dbtc::execTCKEYREQ(Signal* signal) Uint8 TDistrKeyFlag = tcKeyReq->getDistributionKeyFlag(Treqinfo); Uint8 TexecuteFlag = TexecFlag; - //RONM_TEST Disable simple reads temporarily - regCachePtr->opSimple = 0; - // regCachePtr->opSimple = TSimpleFlag; - regTcPtr->dirtyOp = TDirtyFlag; + regCachePtr->opSimple = TSimpleFlag; regCachePtr->opExec = TInterpretedFlag; + regTcPtr->dirtyOp = TDirtyFlag; regCachePtr->distributionGroupIndicator = TDistrGroupFlag; regCachePtr->distributionGroupType = TDistrGroupTypeFlag; @@ -2757,7 +2774,6 @@ void Dbtc::execTCKEYREQ(Signal* signal) } } - UintR Tattrlength = regCachePtr->attrlength; UintR TwriteCount = c_counters.cwriteCount; UintR Toperationsize = coperationsize; /* -------------------------------------------------------------------- @@ -2766,13 +2782,13 @@ void Dbtc::execTCKEYREQ(Signal* signal) * TEMP TABLES DON'T PARTICIPATE. * -------------------------------------------------------------------- */ if (localTabptr.p->storedTable) { - coperationsize = ((Toperationsize + Tattrlength) + TkeyLength) + 17; + coperationsize = ((Toperationsize + TattrLen) + TkeyLength) + 17; } c_counters.cwriteCount = TwriteCount + 1; switch (TOperationType) { case ZUPDATE: jam(); - if (Tattrlength == 0) { + if (TattrLen == 0) { //TCKEY_abort(signal, 5); //return; }//if @@ -2818,7 +2834,6 @@ void Dbtc::execTCKEYREQ(Signal* signal) if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { jam(); // Trigger execution at commit - regApiPtr->apiConnectstate = CS_REC_COMMITTING; } else { jam(); @@ -2938,12 +2953,13 @@ void Dbtc::tckeyreq050Lab(Signal* signal) regTcPtr->tcNodedata[3] = Tdata6; Uint8 Toperation = regTcPtr->operation; + Uint8 Tdirty = regTcPtr->dirtyOp; tnoOfBackup = tnodeinfo & 3; tnoOfStandby = (tnodeinfo >> 8) & 3; regCachePtr->distributionKey = (tnodeinfo >> 16) & 255; if (Toperation == ZREAD) { - if (regCachePtr->opSimple == 1) { + if (Tdirty == 1) { jam(); /*-------------------------------------------------------------*/ /* A SIMPLE READ CAN SELECT ANY OF THE PRIMARY AND */ @@ -2953,23 +2969,28 @@ void Dbtc::tckeyreq050Lab(Signal* signal) /*-------------------------------------------------------------*/ arrGuard(tnoOfBackup, 4); UintR Tindex; + UintR TownNode = cownNodeid; for (Tindex = 1; Tindex <= tnoOfBackup; Tindex++) { UintR Tnode = regTcPtr->tcNodedata[Tindex]; - UintR TownNode = cownNodeid; jam(); if (Tnode == TownNode) { jam(); regTcPtr->tcNodedata[0] = Tnode; }//if }//for - if (regCachePtr->attrlength == 0) { - /*-------------------------------------------------------------*/ - // A simple read which does not read anything is a strange - // creature and we abort rather than continue. - /*-------------------------------------------------------------*/ - TCKEY_abort(signal, 12); - return; - }//if + if(ERROR_INSERTED(8048) || ERROR_INSERTED(8049)) + { + for (Tindex = 0; Tindex <= tnoOfBackup; Tindex++) + { + UintR Tnode = regTcPtr->tcNodedata[Tindex]; + jam(); + if (Tnode != TownNode) { + jam(); + regTcPtr->tcNodedata[0] = Tnode; + ndbout_c("Choosing %d", Tnode); + }//if + }//for + } }//if jam(); regTcPtr->lastReplicaNo = 0; @@ -3279,7 +3300,7 @@ void Dbtc::packLqhkeyreq040Lab(Signal* signal, releaseAttrinfo(); if (Tboth) { jam(); - releaseSimpleRead(signal); + releaseSimpleRead(signal, apiConnectptr, tcConnectptr.p); return; }//if regTcPtr->tcConnectstate = OS_OPERATING; @@ -3341,8 +3362,21 @@ void Dbtc::releaseAttrinfo() /* ========================================================================= */ /* ------- RELEASE ALL RECORDS CONNECTED TO A SIMPLE OPERATION ------- */ /* ========================================================================= */ -void Dbtc::releaseSimpleRead(Signal* signal) -{ +void Dbtc::releaseSimpleRead(Signal* signal, + ApiConnectRecordPtr regApiPtr, + TcConnectRecord* regTcPtr) +{ + Uint32 Ttckeyrec = regApiPtr.p->tckeyrec; + Uint32 TclientData = regTcPtr->clientData; + Uint32 Tnode = regTcPtr->tcNodedata[0]; + Uint32 Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec; + Uint32 TsimpleReadCount = c_counters.csimpleReadCount; + ConnectionState state = regApiPtr.p->apiConnectstate; + + regApiPtr.p->tcSendArray[Ttckeyrec] = TclientData; + regApiPtr.p->tcSendArray[Ttckeyrec + 1] = TcKeyConf::SimpleReadBit | Tnode; + regApiPtr.p->tckeyrec = Ttckeyrec + 2; + unlinkReadyTcCon(signal); releaseTcCon(); @@ -3350,31 +3384,27 @@ void Dbtc::releaseSimpleRead(Signal* signal) * No LQHKEYCONF in Simple/Dirty read * Therefore decrese no LQHKEYCONF(REF) we are waiting for */ - ApiConnectRecord * const regApiPtr = apiConnectptr.p; - UintR TsimpleReadCount = c_counters.csimpleReadCount; - UintR Tlqhkeyreqrec = regApiPtr->lqhkeyreqrec; - c_counters.csimpleReadCount = TsimpleReadCount + 1; - regApiPtr->lqhkeyreqrec = Tlqhkeyreqrec - 1; - - /** - * If start committing and no operation in lists - * simply return - */ - if (regApiPtr->apiConnectstate == CS_START_COMMITTING && - regApiPtr->firstTcConnect == RNIL) { + regApiPtr.p->lqhkeyreqrec = --Tlqhkeyreqrec; + + if(Tlqhkeyreqrec == 0) + { + /** + * Special case of lqhKeyConf_checkTransactionState: + * - commit with zero operations: handle only for simple read + */ + sendtckeyconf(signal, state == CS_START_COMMITTING); + regApiPtr.p->apiConnectstate = + (state == CS_START_COMMITTING ? CS_CONNECTED : state); + setApiConTimer(regApiPtr.i, 0, __LINE__); - jam(); - setApiConTimer(apiConnectptr.i, 0, __LINE__); - regApiPtr->apiConnectstate = CS_CONNECTED; return; - }//if - + } + /** - * Else Emulate LQHKEYCONF + * Emulate LQHKEYCONF */ - lqhKeyConf_checkTransactionState(signal, regApiPtr); - + lqhKeyConf_checkTransactionState(signal, regApiPtr.p); }//Dbtc::releaseSimpleRead() /* ------------------------------------------------------------------------- */ @@ -3810,6 +3840,15 @@ Dbtc::lqhKeyConf_checkTransactionState(Signal * signal, void Dbtc::sendtckeyconf(Signal* signal, UintR TcommitFlag) { + if(ERROR_INSERTED(8049)){ + CLEAR_ERROR_INSERT_VALUE; + signal->theData[0] = TcContinueB::DelayTCKEYCONF; + signal->theData[1] = apiConnectptr.i; + signal->theData[2] = TcommitFlag; + sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 3000, 3); + return; + } + HostRecordPtr localHostptr; ApiConnectRecord * const regApiPtr = apiConnectptr.p; const UintR TopWords = (UintR)regApiPtr->tckeyrec; @@ -5068,27 +5107,15 @@ void Dbtc::execLQHKEYREF(Signal* signal) *---------------------------------------------------------------------*/ regApiPtr->lqhkeyreqrec--; if (regApiPtr->lqhkeyconfrec == regApiPtr->lqhkeyreqrec) { - if ((regApiPtr->lqhkeyconfrec == 0) && - (regApiPtr->apiConnectstate == CS_START_COMMITTING)) { - - if(abort == TcKeyReq::IgnoreError){ + if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { + if(regApiPtr->lqhkeyconfrec) { jam(); - regApiPtr->returnsignal = RS_NO_RETURN; - abort010Lab(signal); - return; + diverify010Lab(signal); + } else { + jam(); + sendtckeyconf(signal, 1); + regApiPtr->apiConnectstate = CS_CONNECTED; } - - /*---------------------------------------------------------------- - * Not a single operation was successful. - * This we report as an aborted transaction - * to avoid performing a commit of zero operations. - *----------------------------------------------------------------*/ - TCKEY_abort(signal, 54); - return; - }//if - if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { - jam(); - diverify010Lab(signal); return; } else if (regApiPtr->tckeyrec > 0 || regApiPtr->m_exec_flag) { jam(); @@ -8490,6 +8517,10 @@ void Dbtc::execSCAN_TABREQ(Signal* signal) if (transP->apiConnectstate == CS_ABORTING && transP->abortState == AS_IDLE) { jam(); + } else if(transP->apiConnectstate == CS_STARTED && + transP->firstTcConnect == RNIL){ + jam(); + // left over from simple/dirty read } else { jam(); errCode = ZSTATE_ERROR; @@ -9639,6 +9670,7 @@ void Dbtc::initApiConnect(Signal* signal) apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref apiConnectptr.p->commitAckMarker = RNIL; apiConnectptr.p->firstTcConnect = RNIL; + apiConnectptr.p->lastTcConnect = RNIL; apiConnectptr.p->triggerPending = false; apiConnectptr.p->isIndexOp = false; apiConnectptr.p->accumulatingIndexOp = RNIL; @@ -9665,6 +9697,7 @@ void Dbtc::initApiConnect(Signal* signal) apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref apiConnectptr.p->commitAckMarker = RNIL; apiConnectptr.p->firstTcConnect = RNIL; + apiConnectptr.p->lastTcConnect = RNIL; apiConnectptr.p->triggerPending = false; apiConnectptr.p->isIndexOp = false; apiConnectptr.p->accumulatingIndexOp = RNIL; @@ -9691,6 +9724,7 @@ void Dbtc::initApiConnect(Signal* signal) apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref apiConnectptr.p->commitAckMarker = RNIL; apiConnectptr.p->firstTcConnect = RNIL; + apiConnectptr.p->lastTcConnect = RNIL; apiConnectptr.p->triggerPending = false; apiConnectptr.p->isIndexOp = false; apiConnectptr.p->accumulatingIndexOp = RNIL; @@ -11045,9 +11079,11 @@ void Dbtc::execTCINDXREQ(Signal* signal) // Seize index operation TcIndexOperationPtr indexOpPtr; if ((startFlag == 1) && - ((regApiPtr->apiConnectstate == CS_CONNECTED) || - ((regApiPtr->apiConnectstate == CS_ABORTING) && - (regApiPtr->abortState == AS_IDLE)))) { + (regApiPtr->apiConnectstate == CS_CONNECTED || + (regApiPtr->apiConnectstate == CS_STARTED && + regApiPtr->firstTcConnect == RNIL)) || + (regApiPtr->apiConnectstate == CS_ABORTING && + regApiPtr->abortState == AS_IDLE)) { jam(); // This is a newly started transaction, clean-up releaseAllSeizedIndexOperations(regApiPtr); @@ -11702,7 +11738,7 @@ void Dbtc::readIndexTable(Signal* signal, tcKeyLength += MIN(keyLength, keyBufSize); tcKeyReq->tableSchemaVersion = indexOp->tcIndxReq.indexSchemaVersion; TcKeyReq::setOperationType(tcKeyRequestInfo, - opType == ZREAD ? opType : ZREAD_EX); + opType == ZREAD ? ZREAD : ZREAD_EX); TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 1); // Allways send one AttrInfo TcKeyReq::setExecutingTrigger(tcKeyRequestInfo, 0); BlockReference originalReceiver = regApiPtr->ndbapiBlockref; @@ -11727,6 +11763,9 @@ void Dbtc::readIndexTable(Signal* signal, AttributeHeader::init(dataPtr, indexData->primaryKeyPos, 0); tcKeyLength++; tcKeyReq->requestInfo = tcKeyRequestInfo; + + ndbassert(TcKeyReq::getDirtyFlag(tcKeyRequestInfo) == 0); + ndbassert(TcKeyReq::getSimpleFlag(tcKeyRequestInfo) == 0); EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, tcKeyLength); /** @@ -11878,6 +11917,9 @@ void Dbtc::executeIndexOperation(Signal* signal, TcKeyReq::setExecutingTrigger(tcKeyRequestInfo, 0); tcKeyReq->requestInfo = tcKeyRequestInfo; + ndbassert(TcKeyReq::getDirtyFlag(tcKeyRequestInfo) == 0); + ndbassert(TcKeyReq::getSimpleFlag(tcKeyRequestInfo) == 0); + /** * Decrease lqhkeyreqrec to compensate for addition * during read of index table diff --git a/ndb/src/kernel/blocks/dbtup/DbtupLCP.cpp b/ndb/src/kernel/blocks/dbtup/DbtupLCP.cpp index f8f2b9bdbd2..370ef4c4ba5 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupLCP.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupLCP.cpp @@ -265,7 +265,8 @@ void Dbtup::lcpSaveCopyListLab(Signal* signal, CheckpointInfoPtr ciPtr) // We ensure that we have actually allocated the tuple header and // also found it. Otherwise we will fill the undo log with garbage. /* ---------------------------------------------------------------- */ - if (regOpPtr.p->optype == ZUPDATE) { + if (regOpPtr.p->optype == ZUPDATE || + (regOpPtr.p->optype == ZINSERT && regOpPtr.p->deleteInsertFlag)) { ljam(); if (regOpPtr.p->realPageIdC != RNIL) { /* ---------------------------------------------------------------- */ diff --git a/ndb/src/kernel/blocks/dbtux/Dbtux.hpp b/ndb/src/kernel/blocks/dbtux/Dbtux.hpp index 8dca52cec04..ad748d2636f 100644 --- a/ndb/src/kernel/blocks/dbtux/Dbtux.hpp +++ b/ndb/src/kernel/blocks/dbtux/Dbtux.hpp @@ -172,12 +172,21 @@ private: * Physical tuple address in TUP. Provides fast access to table tuple * or index node. Valid within the db node and across timeslices. * Not valid between db nodes or across restarts. + * + * To avoid wasting an Uint16 the pageid is split in two. */ struct TupLoc { - Uint32 m_pageId; // page i-value + private: + Uint16 m_pageId1; // page i-value (big-endian) + Uint16 m_pageId2; Uint16 m_pageOffset; // page offset in words + public: TupLoc(); TupLoc(Uint32 pageId, Uint16 pageOffset); + Uint32 getPageId() const; + void setPageId(Uint32 pageId); + Uint32 getPageOffset() const; + void setPageOffset(Uint32 pageOffset); bool operator==(const TupLoc& loc) const; bool operator!=(const TupLoc& loc) const; }; @@ -224,18 +233,13 @@ private: * work entry part 5 * * There are 3 links to other nodes: left child, right child, parent. - * These are in TupLoc format but the pageIds and pageOffsets are - * stored in separate arrays (saves 1 word). - * * Occupancy (number of entries) is at least 1 except temporarily when - * a node is about to be removed. If occupancy is 1, only max entry - * is present but both min and max prefixes are set. + * a node is about to be removed. */ struct TreeNode; friend struct TreeNode; struct TreeNode { - Uint32 m_linkPI[3]; // link to 0-left child 1-right child 2-parent - Uint16 m_linkPO[3]; // page offsets for above real page ids + TupLoc m_link[3]; // link to 0-left child 1-right child 2-parent unsigned m_side : 2; // we are 0-left child 1-right child 2-root int m_balance : 2; // balance -1, 0, +1 unsigned pad1 : 4; @@ -246,8 +250,8 @@ private: static const unsigned NodeHeadSize = sizeof(TreeNode) >> 2; /* - * Tree nodes are not always accessed fully, for cache reasons. There - * are 3 access sizes. + * Tree node "access size" was for an early version with signal + * interface to TUP. It is now used only to compute sizes. */ enum AccSize { AccNone = 0, @@ -280,7 +284,7 @@ private: * m_occup), and whether the position is at an existing entry or * before one (if any). Position m_occup points past the node and is * also represented by position 0 of next node. Includes direction - * and copy of entry used by scan. + * used by scan. */ struct TreePos; friend struct TreePos; @@ -288,8 +292,7 @@ private: TupLoc m_loc; // physical node address Uint16 m_pos; // position 0 to m_occup Uint8 m_match; // at an existing entry - Uint8 m_dir; // from link (0-2) or within node (3) - TreeEnt m_ent; // copy of current entry + Uint8 m_dir; // see scanNext() TreePos(); }; @@ -370,6 +373,10 @@ private: * a separate lock wait flag. It may be for current entry or it may * be for an entry we were moved away from. In any case nothing * happens with current entry before lock wait flag is cleared. + * + * An unfinished scan is always linked to some tree node, and has + * current position and direction (see comments at scanNext). There + * is also a copy of latest entry found. */ struct ScanOp; friend struct ScanOp; @@ -408,7 +415,7 @@ private: ScanBound* m_bound[2]; // pointers to above 2 Uint16 m_boundCnt[2]; // number of bounds in each TreePos m_scanPos; // position - TreeEnt m_lastEnt; // last entry returned + TreeEnt m_scanEnt; // latest entry found Uint32 m_nodeScan; // next scan at node (single-linked) union { Uint32 nextPool; @@ -515,7 +522,6 @@ private: Frag& m_frag; // fragment using the node TupLoc m_loc; // physical node address TreeNode* m_node; // pointer to node storage - AccSize m_acc; // accessed size NodeHandle(Frag& frag); NodeHandle(const NodeHandle& node); NodeHandle& operator=(const NodeHandle& node); @@ -576,9 +582,8 @@ private: * DbtuxNode.cpp */ int allocNode(Signal* signal, NodeHandle& node); - void accessNode(Signal* signal, NodeHandle& node, AccSize acc); - void selectNode(Signal* signal, NodeHandle& node, TupLoc loc, AccSize acc); - void insertNode(Signal* signal, NodeHandle& node, AccSize acc); + void selectNode(Signal* signal, NodeHandle& node, TupLoc loc); + void insertNode(Signal* signal, NodeHandle& node); void deleteNode(Signal* signal, NodeHandle& node); void setNodePref(Signal* signal, NodeHandle& node); // node operations @@ -805,22 +810,52 @@ Dbtux::ConstData::operator=(Data data) inline Dbtux::TupLoc::TupLoc() : - m_pageId(RNIL), + m_pageId1(RNIL >> 16), + m_pageId2(RNIL & 0xFFFF), m_pageOffset(0) { } inline Dbtux::TupLoc::TupLoc(Uint32 pageId, Uint16 pageOffset) : - m_pageId(pageId), + m_pageId1(pageId >> 16), + m_pageId2(pageId & 0xFFFF), m_pageOffset(pageOffset) { } +inline Uint32 +Dbtux::TupLoc::getPageId() const +{ + return (m_pageId1 << 16) | m_pageId2; +} + +inline void +Dbtux::TupLoc::setPageId(Uint32 pageId) +{ + m_pageId1 = (pageId >> 16); + m_pageId2 = (pageId & 0xFFFF); +} + +inline Uint32 +Dbtux::TupLoc::getPageOffset() const +{ + return (Uint32)m_pageOffset; +} + +inline void +Dbtux::TupLoc::setPageOffset(Uint32 pageOffset) +{ + m_pageOffset = (Uint16)pageOffset; +} + inline bool Dbtux::TupLoc::operator==(const TupLoc& loc) const { - return m_pageId == loc.m_pageId && m_pageOffset == loc.m_pageOffset; + return + m_pageId1 == loc.m_pageId1 && + m_pageId2 == loc.m_pageId2 && + m_pageOffset == loc.m_pageOffset; } inline bool @@ -851,13 +886,13 @@ Dbtux::TreeEnt::eq(const TreeEnt ent) const inline int Dbtux::TreeEnt::cmp(const TreeEnt ent) const { - if (m_tupLoc.m_pageId < ent.m_tupLoc.m_pageId) + if (m_tupLoc.getPageId() < ent.m_tupLoc.getPageId()) return -1; - if (m_tupLoc.m_pageId > ent.m_tupLoc.m_pageId) + if (m_tupLoc.getPageId() > ent.m_tupLoc.getPageId()) return +1; - if (m_tupLoc.m_pageOffset < ent.m_tupLoc.m_pageOffset) + if (m_tupLoc.getPageOffset() < ent.m_tupLoc.getPageOffset()) return -1; - if (m_tupLoc.m_pageOffset > ent.m_tupLoc.m_pageOffset) + if (m_tupLoc.getPageOffset() > ent.m_tupLoc.getPageOffset()) return +1; if (m_tupVersion < ent.m_tupVersion) return -1; @@ -880,12 +915,9 @@ Dbtux::TreeNode::TreeNode() : m_occup(0), m_nodeScan(RNIL) { - m_linkPI[0] = NullTupLoc.m_pageId; - m_linkPO[0] = NullTupLoc.m_pageOffset; - m_linkPI[1] = NullTupLoc.m_pageId; - m_linkPO[1] = NullTupLoc.m_pageOffset; - m_linkPI[2] = NullTupLoc.m_pageId; - m_linkPO[2] = NullTupLoc.m_pageOffset; + m_link[0] = NullTupLoc; + m_link[1] = NullTupLoc; + m_link[2] = NullTupLoc; } // Dbtux::TreeHead @@ -913,7 +945,6 @@ Dbtux::TreeHead::getSize(AccSize acc) const case AccFull: return m_nodeSize; } - abort(); return 0; } @@ -938,8 +969,7 @@ Dbtux::TreePos::TreePos() : m_loc(), m_pos(ZNIL), m_match(false), - m_dir(255), - m_ent() + m_dir(255) { } @@ -980,7 +1010,7 @@ Dbtux::ScanOp::ScanOp(ScanBoundPool& scanBoundPool) : m_boundMin(scanBoundPool), m_boundMax(scanBoundPool), m_scanPos(), - m_lastEnt(), + m_scanEnt(), m_nodeScan(RNIL) { m_bound[0] = &m_boundMin; @@ -1054,8 +1084,7 @@ inline Dbtux::NodeHandle::NodeHandle(Frag& frag) : m_frag(frag), m_loc(), - m_node(0), - m_acc(AccNone) + m_node(0) { } @@ -1063,8 +1092,7 @@ inline Dbtux::NodeHandle::NodeHandle(const NodeHandle& node) : m_frag(node.m_frag), m_loc(node.m_loc), - m_node(node.m_node), - m_acc(node.m_acc) + m_node(node.m_node) { } @@ -1074,7 +1102,6 @@ Dbtux::NodeHandle::operator=(const NodeHandle& node) ndbassert(&m_frag == &node.m_frag); m_loc = node.m_loc; m_node = node.m_node; - m_acc = node.m_acc; return *this; } @@ -1088,13 +1115,13 @@ inline Dbtux::TupLoc Dbtux::NodeHandle::getLink(unsigned i) { ndbrequire(i <= 2); - return TupLoc(m_node->m_linkPI[i], m_node->m_linkPO[i]); + return m_node->m_link[i]; } inline unsigned Dbtux::NodeHandle::getChilds() { - return (getLink(0) != NullTupLoc) + (getLink(1) != NullTupLoc); + return (m_node->m_link[0] != NullTupLoc) + (m_node->m_link[1] != NullTupLoc); } inline unsigned @@ -1125,8 +1152,7 @@ inline void Dbtux::NodeHandle::setLink(unsigned i, TupLoc loc) { ndbrequire(i <= 2); - m_node->m_linkPI[i] = loc.m_pageId; - m_node->m_linkPO[i] = loc.m_pageOffset; + m_node->m_link[i] = loc; } inline void @@ -1161,7 +1187,6 @@ inline Dbtux::Data Dbtux::NodeHandle::getPref() { TreeHead& tree = m_frag.m_tree; - ndbrequire(m_acc >= AccPref); return tree.getPref(m_node); } @@ -1172,11 +1197,6 @@ Dbtux::NodeHandle::getEnt(unsigned pos) TreeEnt* entList = tree.getEntList(m_node); const unsigned occup = m_node->m_occup; ndbrequire(pos < occup); - if (pos == 0 || pos == occup - 1) { - ndbrequire(m_acc >= AccPref) - } else { - ndbrequire(m_acc == AccFull) - } return entList[(1 + pos) % occup]; } @@ -1224,7 +1244,7 @@ Dbtux::getTupAddr(const Frag& frag, TreeEnt ent) const Uint32 tableFragPtrI = frag.m_tupTableFragPtrI[ent.m_fragBit]; const TupLoc tupLoc = ent.m_tupLoc; Uint32 tupAddr = NullTupAddr; - c_tup->tuxGetTupAddr(tableFragPtrI, tupLoc.m_pageId, tupLoc.m_pageOffset, tupAddr); + c_tup->tuxGetTupAddr(tableFragPtrI, tupLoc.getPageId(), tupLoc.getPageOffset(), tupAddr); jamEntry(); return tupAddr; } diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp index 549720cc17c..ddab77b97b5 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp @@ -87,21 +87,23 @@ Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, ConstData searchKey, Cons /* * Scan bound vs node prefix or entry. * - * Compare lower or upper bound and index attribute data. The attribute - * data may be partial in which case CmpUnknown may be returned. - * Returns -1 if the boundary is to the left of the compared key and +1 - * if the boundary is to the right of the compared key. + * Compare lower or upper bound and index entry data. The entry data + * may be partial in which case CmpUnknown may be returned. Otherwise + * returns -1 if the bound is to the left of the entry and +1 if the + * bound is to the right of the entry. * - * To get this behaviour we treat equality a little bit special. If the - * boundary is a lower bound then the boundary is to the left of all - * equal keys and if it is an upper bound then the boundary is to the - * right of all equal keys. + * The routine is similar to cmpSearchKey, but 0 is never returned. + * Suppose all attributes compare equal. Recall that all bounds except + * possibly the last one are non-strict. Use the given bound direction + * (0-lower 1-upper) and strictness of last bound to return -1 or +1. * - * When searching for the first key we are using the lower bound to try - * to find the first key that is to the right of the boundary. Then we - * start scanning from this tuple (including the tuple itself) until we - * find the first key which is to the right of the boundary. Then we - * stop and do not include that key in the scan result. + * Following example illustrates this. We are at (a=2, b=3). + * + * dir bounds strict return + * 0 a >= 2 and b >= 3 no -1 + * 0 a >= 2 and b > 3 yes +1 + * 1 a <= 2 and b <= 3 no +1 + * 1 a <= 2 and b < 3 yes -1 */ int Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigned boundCount, ConstData entryData, unsigned maxlen) @@ -111,12 +113,7 @@ Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigne ndbrequire(dir <= 1); // number of words of data left unsigned len2 = maxlen; - /* - * No boundary means full scan, low boundary is to the right of all - * keys. Thus we should always return -1. For upper bound we are to - * the right of all keys, thus we should always return +1. We achieve - * this behaviour by initializing type to 4. - */ + // in case of no bounds, init last type to something non-strict unsigned type = 4; while (boundCount != 0) { if (len2 <= AttributeHeaderSize) { @@ -124,7 +121,7 @@ Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigne return NdbSqlUtil::CmpUnknown; } len2 -= AttributeHeaderSize; - // get and skip bound type + // get and skip bound type (it is used after the loop) type = boundInfo[0]; boundInfo += 1; if (! boundInfo.ah().isNULL()) { @@ -166,30 +163,7 @@ Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigne entryData += AttributeHeaderSize + entryData.ah().getDataSize(); boundCount -= 1; } - if (dir == 0) { - jam(); - /* - * Looking for the lower bound. If strict lower bound then the - * boundary is to the right of the compared key and otherwise (equal - * included in range) then the boundary is to the left of the key. - */ - if (type == 1) { - jam(); - return +1; - } - return -1; - } else { - jam(); - /* - * Looking for the upper bound. If strict upper bound then the - * boundary is to the left of all equal keys and otherwise (equal - * included in the range) then the boundary is to the right of all - * equal keys. - */ - if (type == 3) { - jam(); - return -1; - } - return +1; - } + // all attributes were equal + const int strict = (type & 0x1); + return (dir == 0 ? (strict == 0 ? -1 : +1) : (strict == 0 ? +1 : -1)); } diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp index 8d31d2c6a55..63c7f5d34a1 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp @@ -122,7 +122,7 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupLoc loc, PrintPar& } TreeHead& tree = frag.m_tree; NodeHandle node(frag); - selectNode(signal, node, loc, AccFull); + selectNode(signal, node, loc); out << par.m_path << " " << node << endl; // check children PrintPar cpar[2]; @@ -256,8 +256,8 @@ operator<<(NdbOut& out, const Dbtux::TupLoc& loc) if (loc == Dbtux::NullTupLoc) { out << "null"; } else { - out << dec << loc.m_pageId; - out << "." << dec << loc.m_pageOffset; + out << dec << loc.getPageId(); + out << "." << dec << loc.getPageOffset(); } return out; } @@ -274,13 +274,10 @@ operator<<(NdbOut& out, const Dbtux::TreeEnt& ent) NdbOut& operator<<(NdbOut& out, const Dbtux::TreeNode& node) { - Dbtux::TupLoc link0(node.m_linkPI[0], node.m_linkPO[0]); - Dbtux::TupLoc link1(node.m_linkPI[1], node.m_linkPO[1]); - Dbtux::TupLoc link2(node.m_linkPI[2], node.m_linkPO[2]); out << "[TreeNode " << hex << &node; - out << " [left " << link0 << "]"; - out << " [right " << link1 << "]"; - out << " [up " << link2 << "]"; + out << " [left " << node.m_link[0] << "]"; + out << " [right " << node.m_link[1] << "]"; + out << " [up " << node.m_link[2] << "]"; out << " [side " << dec << node.m_side << "]"; out << " [occup " << dec << node.m_occup << "]"; out << " [balance " << dec << (int)node.m_balance << "]"; @@ -313,7 +310,6 @@ operator<<(NdbOut& out, const Dbtux::TreePos& pos) out << " [pos " << dec << pos.m_pos << "]"; out << " [match " << dec << pos.m_match << "]"; out << " [dir " << dec << pos.m_dir << "]"; - out << " [ent " << pos.m_ent << "]"; out << "]"; return out; } @@ -350,6 +346,7 @@ operator<<(NdbOut& out, const Dbtux::ScanOp& scan) out << " [lockMode " << dec << scan.m_lockMode << "]"; out << " [keyInfo " << dec << scan.m_keyInfo << "]"; out << " [pos " << scan.m_scanPos << "]"; + out << " [ent " << scan.m_scanEnt << "]"; for (unsigned i = 0; i <= 1; i++) { out << " [bound " << dec << i; Dbtux::ScanBound& bound = *scan.m_bound[i]; @@ -410,27 +407,21 @@ operator<<(NdbOut& out, const Dbtux::NodeHandle& node) const Dbtux::TreeHead& tree = frag.m_tree; out << "[NodeHandle " << hex << &node; out << " [loc " << node.m_loc << "]"; - out << " [acc " << dec << node.m_acc << "]"; out << " [node " << *node.m_node << "]"; - if (node.m_acc >= Dbtux::AccPref) { - const Uint32* data; - out << " [pref"; - data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize; - for (unsigned j = 0; j < tree.m_prefSize; j++) - out << " " << hex << data[j]; - out << "]"; - out << " [entList"; - unsigned numpos = node.m_node->m_occup; - if (node.m_acc < Dbtux::AccFull && numpos > 2) { - numpos = 2; - out << "(" << dec << numpos << ")"; - } - data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize + tree.m_prefSize; - const Dbtux::TreeEnt* entList = (const Dbtux::TreeEnt*)data; - for (unsigned pos = 0; pos < numpos; pos++) - out << " " << entList[pos]; - out << "]"; - } + const Uint32* data; + out << " [pref"; + data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize; + for (unsigned j = 0; j < tree.m_prefSize; j++) + out << " " << hex << data[j]; + out << "]"; + out << " [entList"; + unsigned numpos = node.m_node->m_occup; + data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize + tree.m_prefSize; + const Dbtux::TreeEnt* entList = (const Dbtux::TreeEnt*)data; + // print entries in logical order + for (unsigned pos = 1; pos <= numpos; pos++) + out << " " << entList[pos % numpos]; + out << "]"; out << "]"; return out; } diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp index 39cd8e25184..ded02696a89 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp @@ -245,7 +245,7 @@ Dbtux::readKeyAttrs(const Frag& frag, TreeEnt ent, unsigned start, Data keyData) const Uint32 numAttrs = frag.m_numAttrs - start; // skip to start position in keyAttrs only keyAttrs += start; - int ret = c_tup->tuxReadAttrs(tableFragPtrI, tupLoc.m_pageId, tupLoc.m_pageOffset, tupVersion, keyAttrs, numAttrs, keyData); + int ret = c_tup->tuxReadAttrs(tableFragPtrI, tupLoc.getPageId(), tupLoc.getPageOffset(), tupVersion, keyAttrs, numAttrs, keyData); jamEntry(); // TODO handle error ndbrequire(ret > 0); @@ -256,7 +256,7 @@ Dbtux::readTablePk(const Frag& frag, TreeEnt ent, Data pkData, unsigned& pkSize) { const Uint32 tableFragPtrI = frag.m_tupTableFragPtrI[ent.m_fragBit]; const TupLoc tupLoc = ent.m_tupLoc; - int ret = c_tup->tuxReadPk(tableFragPtrI, tupLoc.m_pageId, tupLoc.m_pageOffset, pkData); + int ret = c_tup->tuxReadPk(tableFragPtrI, tupLoc.getPageId(), tupLoc.getPageOffset(), pkData); jamEntry(); // TODO handle error ndbrequire(ret > 0); diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp index 24b030bf8ec..565e64f9aeb 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp @@ -120,7 +120,7 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal) searchToAdd(signal, frag, c_searchKey, ent, treePos); #ifdef VM_TRACE if (debugFlags & DebugMaint) { - debugOut << treePos << endl; + debugOut << treePos << (treePos.m_match ? " - error" : "") << endl; } #endif if (treePos.m_match) { @@ -154,7 +154,7 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal) searchToRemove(signal, frag, c_searchKey, ent, treePos); #ifdef VM_TRACE if (debugFlags & DebugMaint) { - debugOut << treePos << endl; + debugOut << treePos << (! treePos.m_match ? " - error" : "") << endl; } #endif if (! treePos.m_match) { diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp index 3c0af3ca79d..e0b7fec19cf 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp @@ -235,6 +235,20 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal) tree.m_minOccup = tree.m_maxOccup - maxSlack; // root node does not exist (also set by ctor) tree.m_root = NullTupLoc; +#ifdef VM_TRACE + if (debugFlags & DebugMeta) { + if (fragOpPtr.p->m_fragNo == 0) { + debugOut << "Index id=" << indexPtr.i; + debugOut << " nodeSize=" << tree.m_nodeSize; + debugOut << " headSize=" << NodeHeadSize; + debugOut << " prefSize=" << tree.m_prefSize; + debugOut << " entrySize=" << TreeEntSize; + debugOut << " minOccup=" << tree.m_minOccup; + debugOut << " maxOccup=" << tree.m_maxOccup; + debugOut << endl; + } + } +#endif // fragment is defined c_fragOpPool.release(fragOpPtr); } diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp index a1bfa2179bb..f155917caf5 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp @@ -24,8 +24,8 @@ int Dbtux::allocNode(Signal* signal, NodeHandle& node) { Frag& frag = node.m_frag; - Uint32 pageId = NullTupLoc.m_pageId; - Uint32 pageOffset = NullTupLoc.m_pageOffset; + Uint32 pageId = NullTupLoc.getPageId(); + Uint32 pageOffset = NullTupLoc.getPageOffset(); Uint32* node32 = 0; int errorCode = c_tup->tuxAllocNode(signal, frag.m_tupIndexFragPtrI, pageId, pageOffset, node32); jamEntry(); @@ -33,55 +33,39 @@ Dbtux::allocNode(Signal* signal, NodeHandle& node) jam(); node.m_loc = TupLoc(pageId, pageOffset); node.m_node = reinterpret_cast<TreeNode*>(node32); - node.m_acc = AccNone; ndbrequire(node.m_loc != NullTupLoc && node.m_node != 0); } return errorCode; } /* - * Access more of the node. - */ -void -Dbtux::accessNode(Signal* signal, NodeHandle& node, AccSize acc) -{ - ndbrequire(node.m_loc != NullTupLoc && node.m_node != 0); - if (node.m_acc >= acc) - return; - // XXX could do prefetch - node.m_acc = acc; -} - -/* * Set handle to point to existing node. */ void -Dbtux::selectNode(Signal* signal, NodeHandle& node, TupLoc loc, AccSize acc) +Dbtux::selectNode(Signal* signal, NodeHandle& node, TupLoc loc) { Frag& frag = node.m_frag; ndbrequire(loc != NullTupLoc); - Uint32 pageId = loc.m_pageId; - Uint32 pageOffset = loc.m_pageOffset; + Uint32 pageId = loc.getPageId(); + Uint32 pageOffset = loc.getPageOffset(); Uint32* node32 = 0; c_tup->tuxGetNode(frag.m_tupIndexFragPtrI, pageId, pageOffset, node32); jamEntry(); node.m_loc = loc; node.m_node = reinterpret_cast<TreeNode*>(node32); - node.m_acc = AccNone; ndbrequire(node.m_loc != NullTupLoc && node.m_node != 0); - accessNode(signal, node, acc); } /* * Set handle to point to new node. Uses the pre-allocated node. */ void -Dbtux::insertNode(Signal* signal, NodeHandle& node, AccSize acc) +Dbtux::insertNode(Signal* signal, NodeHandle& node) { Frag& frag = node.m_frag; TupLoc loc = frag.m_freeLoc; frag.m_freeLoc = NullTupLoc; - selectNode(signal, node, loc, acc); + selectNode(signal, node, loc); new (node.m_node) TreeNode(); #ifdef VM_TRACE TreeHead& tree = frag.m_tree; @@ -100,8 +84,8 @@ Dbtux::deleteNode(Signal* signal, NodeHandle& node) Frag& frag = node.m_frag; ndbrequire(node.getOccup() == 0); TupLoc loc = node.m_loc; - Uint32 pageId = loc.m_pageId; - Uint32 pageOffset = loc.m_pageOffset; + Uint32 pageId = loc.getPageId(); + Uint32 pageOffset = loc.getPageOffset(); Uint32* node32 = reinterpret_cast<Uint32*>(node.m_node); c_tup->tuxFreeNode(signal, frag.m_tupIndexFragPtrI, pageId, pageOffset, node32); jamEntry(); diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp index 7414691ab78..585d2dbe58a 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp @@ -108,15 +108,23 @@ Dbtux::execACC_SCANREQ(Signal* signal) /* * Receive bounds for scan in single direct call. The bounds can arrive * in any order. Attribute ids are those of index table. + * + * Replace EQ by equivalent LE + GE. Check for conflicting bounds. + * Check that sets of lower and upper bounds are on initial sequences of + * keys and that all but possibly last bound is non-strict. + * + * Finally save the sets of lower and upper bounds (i.e. start key and + * end key). Full bound type (< 4) is included but only the strict bit + * is used since lower and upper have now been separated. */ void Dbtux::execTUX_BOUND_INFO(Signal* signal) { jamEntry(); struct BoundInfo { + int type; unsigned offset; unsigned size; - int type; }; TuxBoundInfo* const sig = (TuxBoundInfo*)signal->getDataPtrSend(); const TuxBoundInfo reqCopy = *(const TuxBoundInfo*)sig; @@ -124,18 +132,11 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal) // get records ScanOp& scan = *c_scanOpPool.getPtr(req->tuxScanPtrI); Index& index = *c_indexPool.getPtr(scan.m_indexId); - // collect bound info for each index attribute - BoundInfo boundInfo[MaxIndexAttributes][2]; + // collect lower and upper bounds + BoundInfo boundInfo[2][MaxIndexAttributes]; // largest attrId seen plus one - Uint32 maxAttrId = 0; - // skip 5 words + Uint32 maxAttrId[2] = { 0, 0 }; unsigned offset = 0; - if (req->boundAiLength < offset) { - jam(); - scan.m_state = ScanOp::Invalid; - sig->errorCode = TuxBoundInfo::InvalidAttrInfo; - return; - } const Uint32* const data = (Uint32*)sig + TuxBoundInfo::SignalLength; // walk through entries while (offset + 2 <= req->boundAiLength) { @@ -156,32 +157,35 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal) sig->errorCode = TuxBoundInfo::InvalidAttrInfo; return; } - while (maxAttrId <= attrId) { - BoundInfo* b = boundInfo[maxAttrId++]; - b[0].type = b[1].type = -1; - } - BoundInfo* b = boundInfo[attrId]; - if (type == 0 || type == 1 || type == 4) { - if (b[0].type != -1) { - jam(); - scan.m_state = ScanOp::Invalid; - sig->errorCode = TuxBoundInfo::InvalidBounds; - return; + for (unsigned j = 0; j <= 1; j++) { + // check if lower/upper bit matches + const unsigned luBit = (j << 1); + if ((type & 0x2) != luBit && type != 4) + continue; + // EQ -> LE, GE + const unsigned type2 = (type & 0x1) | luBit; + // fill in any gap + while (maxAttrId[j] <= attrId) { + BoundInfo& b = boundInfo[j][maxAttrId[j]++]; + b.type = -1; } - b[0].offset = offset; - b[0].size = 2 + dataSize; - b[0].type = type; - } - if (type == 2 || type == 3 || type == 4) { - if (b[1].type != -1) { - jam(); - scan.m_state = ScanOp::Invalid; - sig->errorCode = TuxBoundInfo::InvalidBounds; - return; + BoundInfo& b = boundInfo[j][attrId]; + if (b.type != -1) { + // compare with previous bound + if (b.type != type2 || + b.size != 2 + dataSize || + memcmp(&data[b.offset + 2], &data[offset + 2], dataSize << 2) != 0) { + jam(); + scan.m_state = ScanOp::Invalid; + sig->errorCode = TuxBoundInfo::InvalidBounds; + return; + } + } else { + // enter new bound + b.type = type2; + b.offset = offset; + b.size = 2 + dataSize; } - b[1].offset = offset; - b[1].size = 2 + dataSize; - b[1].type = type; } // jump to next offset += 2 + dataSize; @@ -192,34 +196,27 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal) sig->errorCode = TuxBoundInfo::InvalidAttrInfo; return; } - // save the bounds in index attribute id order - scan.m_boundCnt[0] = 0; - scan.m_boundCnt[1] = 0; - for (unsigned i = 0; i < maxAttrId; i++) { - jam(); - const BoundInfo* b = boundInfo[i]; - // current limitation - check all but last is equality - if (i + 1 < maxAttrId) { - if (b[0].type != 4 || b[1].type != 4) { + for (unsigned j = 0; j <= 1; j++) { + // save lower/upper bound in index attribute id order + for (unsigned i = 0; i < maxAttrId[j]; i++) { + jam(); + const BoundInfo& b = boundInfo[j][i]; + // check for gap or strict bound before last + if (b.type == -1 || (i + 1 < maxAttrId[j] && (b.type & 0x1))) { jam(); scan.m_state = ScanOp::Invalid; sig->errorCode = TuxBoundInfo::InvalidBounds; return; } - } - for (unsigned j = 0; j <= 1; j++) { - if (b[j].type != -1) { + bool ok = scan.m_bound[j]->append(&data[b.offset], b.size); + if (! ok) { jam(); - bool ok = scan.m_bound[j]->append(&data[b[j].offset], b[j].size); - if (! ok) { - jam(); - scan.m_state = ScanOp::Invalid; - sig->errorCode = TuxBoundInfo::OutOfBuffers; - return; - } - scan.m_boundCnt[j]++; + scan.m_state = ScanOp::Invalid; + sig->errorCode = TuxBoundInfo::OutOfBuffers; + return; } } + scan.m_boundCnt[j] = maxAttrId[j]; } // no error sig->errorCode = 0; @@ -278,7 +275,7 @@ Dbtux::execNEXT_SCANREQ(Signal* signal) jam(); const TupLoc loc = scan.m_scanPos.m_loc; NodeHandle node(frag); - selectNode(signal, node, loc, AccHead); + selectNode(signal, node, loc); unlinkScan(node, scanPtr); scan.m_scanPos.m_loc = NullTupLoc; } @@ -353,7 +350,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal) if (scan.m_lockwait) { jam(); // LQH asks if we are waiting for lock and we tell it to ask again - const TreeEnt ent = scan.m_scanPos.m_ent; + const TreeEnt ent = scan.m_scanEnt; NextScanConf* const conf = (NextScanConf*)signal->getDataPtrSend(); conf->scanPtr = scan.m_userPtr; conf->accOperationPtr = RNIL; // no tuple returned @@ -388,7 +385,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal) ndbrequire(scan.m_accLockOp == RNIL); if (! scan.m_readCommitted) { jam(); - const TreeEnt ent = scan.m_scanPos.m_ent; + const TreeEnt ent = scan.m_scanEnt; // read tuple key readTablePk(frag, ent, pkData, pkSize); // get read lock or exclusive lock @@ -476,7 +473,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal) // we have lock or do not need one jam(); // read keys if not already done (uses signal) - const TreeEnt ent = scan.m_scanPos.m_ent; + const TreeEnt ent = scan.m_scanEnt; if (scan.m_keyInfo) { jam(); if (pkSize == 0) { @@ -539,8 +536,6 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal) total += length; } } - // remember last entry returned - scan.m_lastEnt = ent; // next time look for next entry scan.m_state = ScanOp::Next; return; @@ -715,20 +710,21 @@ Dbtux::scanFirst(Signal* signal, ScanOpPtr scanPtr) scan.m_state = ScanOp::Next; // link the scan to node found NodeHandle node(frag); - selectNode(signal, node, treePos.m_loc, AccFull); + selectNode(signal, node, treePos.m_loc); linkScan(node, scanPtr); } /* * Move to next entry. The scan is already linked to some node. When * we leave, if any entry was found, it will be linked to a possibly - * different node. The scan has a direction, one of: + * different node. The scan has a position, and a direction which tells + * from where we came to this position. This is one of: * - * 0 - coming up from left child - * 1 - coming up from right child (proceed to parent immediately) - * 2 - coming up from root (the scan ends) - * 3 - left to right within node - * 4 - coming down from parent to left or right child + * 0 - up from left child (scan this node next) + * 1 - up from right child (proceed to parent) + * 2 - up from root (the scan ends) + * 3 - left to right within node (at end proceed to right child) + * 4 - down from parent (proceed to left child) */ void Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) @@ -771,10 +767,12 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) TreePos pos = scan.m_scanPos; // get and remember original node NodeHandle origNode(frag); - selectNode(signal, origNode, pos.m_loc, AccHead); + selectNode(signal, origNode, pos.m_loc); ndbrequire(islinkScan(origNode, scanPtr)); // current node in loop NodeHandle node = origNode; + // copy of entry found + TreeEnt ent; while (true) { jam(); if (pos.m_dir == 2) { @@ -786,7 +784,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) } if (node.m_loc != pos.m_loc) { jam(); - selectNode(signal, node, pos.m_loc, AccHead); + selectNode(signal, node, pos.m_loc); } if (pos.m_dir == 4) { // coming down from parent proceed to left child @@ -802,7 +800,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) pos.m_dir = 0; } if (pos.m_dir == 0) { - // coming from left child scan current node + // coming up from left child scan current node jam(); pos.m_pos = 0; pos.m_match = false; @@ -813,8 +811,6 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) jam(); unsigned occup = node.getOccup(); ndbrequire(occup >= 1); - // access full node - accessNode(signal, node, AccFull); // advance position if (! pos.m_match) pos.m_match = true; @@ -822,10 +818,10 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) pos.m_pos++; if (pos.m_pos < occup) { jam(); - pos.m_ent = node.getEnt(pos.m_pos); + ent = node.getEnt(pos.m_pos); pos.m_dir = 3; // unchanged // read and compare all attributes - readKeyAttrs(frag, pos.m_ent, 0, c_entryKey); + readKeyAttrs(frag, ent, 0, c_entryKey); int ret = cmpScanBound(frag, 1, c_dataBuffer, scan.m_boundCnt[1], c_entryKey); ndbrequire(ret != NdbSqlUtil::CmpUnknown); if (ret < 0) { @@ -836,7 +832,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) break; } // can we see it - if (! scanVisible(signal, scanPtr, pos.m_ent)) { + if (! scanVisible(signal, scanPtr, ent)) { jam(); continue; } @@ -856,7 +852,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) pos.m_dir = 1; } if (pos.m_dir == 1) { - // coming from right child proceed to parent + // coming up from right child proceed to parent jam(); pos.m_loc = node.getLink(2); pos.m_dir = node.getSide(); @@ -874,6 +870,8 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) unlinkScan(origNode, scanPtr); linkScan(node, scanPtr); } + // copy found entry + scan.m_scanEnt = ent; } else if (scan.m_state == ScanOp::Last) { jam(); ndbrequire(pos.m_loc == NullTupLoc); @@ -891,7 +889,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) /* * Check if an entry is visible to the scan. * - * There is a special check to never return same tuple twice in a row. + * There is a special check to never accept same tuple twice in a row. * This is faster than asking TUP. It also fixes some special cases * which are not analyzed or handled yet. */ @@ -906,8 +904,8 @@ Dbtux::scanVisible(Signal* signal, ScanOpPtr scanPtr, TreeEnt ent) Uint32 tupAddr = getTupAddr(frag, ent); Uint32 tupVersion = ent.m_tupVersion; // check for same tuple twice in row - if (scan.m_lastEnt.m_tupLoc == ent.m_tupLoc && - scan.m_lastEnt.m_fragBit == fragBit) { + if (scan.m_scanEnt.m_tupLoc == ent.m_tupLoc && + scan.m_scanEnt.m_fragBit == fragBit) { jam(); return false; } diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp index bffbb8f5594..1e20d3e3718 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp @@ -31,10 +31,11 @@ Dbtux::searchToAdd(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt sear const unsigned numAttrs = frag.m_numAttrs; NodeHandle currNode(frag); currNode.m_loc = tree.m_root; + // assume success + treePos.m_match = false; if (currNode.m_loc == NullTupLoc) { // empty tree jam(); - treePos.m_match = false; return; } NodeHandle glbNode(frag); // potential g.l.b of final node @@ -45,7 +46,7 @@ Dbtux::searchToAdd(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt sear NodeHandle bottomNode(frag); while (true) { jam(); - selectNode(signal, currNode, currNode.m_loc, AccPref); + selectNode(signal, currNode, currNode.m_loc); int ret; // compare prefix unsigned start = 0; @@ -93,16 +94,22 @@ Dbtux::searchToAdd(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt sear jam(); treePos.m_loc = currNode.m_loc; treePos.m_pos = 0; + // failed treePos.m_match = true; return; } break; } - // access rest of current node - accessNode(signal, currNode, AccFull); - for (unsigned j = 0, occup = currNode.getOccup(); j < occup; j++) { + // anticipate + treePos.m_loc = currNode.m_loc; + // binary search + int lo = -1; + int hi = currNode.getOccup(); + int ret; + while (1) { jam(); - int ret; + // hi - lo > 1 implies lo < j < hi + int j = (hi + lo) / 2; // read and compare attributes unsigned start = 0; readKeyAttrs(frag, currNode.getEnt(j), start, c_entryKey); @@ -113,25 +120,38 @@ Dbtux::searchToAdd(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt sear // keys are equal, compare entry values ret = searchEnt.cmp(currNode.getEnt(j)); } - if (ret <= 0) { - jam(); - treePos.m_loc = currNode.m_loc; + if (ret < 0) + hi = j; + else if (ret > 0) + lo = j; + else { treePos.m_pos = j; - treePos.m_match = (ret == 0); + // failed + treePos.m_match = true; return; } + if (hi - lo == 1) + break; } - if (! bottomNode.isNull()) { + if (ret < 0) { jam(); - // backwards compatible for now - treePos.m_loc = bottomNode.m_loc; - treePos.m_pos = 0; - treePos.m_match = false; + treePos.m_pos = hi; return; } - treePos.m_loc = currNode.m_loc; - treePos.m_pos = currNode.getOccup(); - treePos.m_match = false; + if (hi < currNode.getOccup()) { + jam(); + treePos.m_pos = hi; + return; + } + if (bottomNode.isNull()) { + jam(); + treePos.m_pos = hi; + return; + } + jam(); + // backwards compatible for now + treePos.m_loc = bottomNode.m_loc; + treePos.m_pos = 0; } /* @@ -150,16 +170,19 @@ Dbtux::searchToRemove(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt s const unsigned numAttrs = frag.m_numAttrs; NodeHandle currNode(frag); currNode.m_loc = tree.m_root; + // assume success + treePos.m_match = true; if (currNode.m_loc == NullTupLoc) { // empty tree jam(); + // failed treePos.m_match = false; return; } NodeHandle glbNode(frag); // potential g.l.b of final node while (true) { jam(); - selectNode(signal, currNode, currNode.m_loc, AccPref); + selectNode(signal, currNode, currNode.m_loc); int ret; // compare prefix unsigned start = 0; @@ -206,27 +229,24 @@ Dbtux::searchToRemove(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt s jam(); treePos.m_loc = currNode.m_loc; treePos.m_pos = 0; - treePos.m_match = true; return; } break; } - // access rest of current node - accessNode(signal, currNode, AccFull); + // anticipate + treePos.m_loc = currNode.m_loc; // pos 0 was handled above for (unsigned j = 1, occup = currNode.getOccup(); j < occup; j++) { jam(); // compare only the entry if (searchEnt.eq(currNode.getEnt(j))) { jam(); - treePos.m_loc = currNode.m_loc; treePos.m_pos = j; - treePos.m_match = true; return; } } - treePos.m_loc = currNode.m_loc; treePos.m_pos = currNode.getOccup(); + // failed treePos.m_match = false; } @@ -251,7 +271,7 @@ Dbtux::searchToScan(Signal* signal, Frag& frag, ConstData boundInfo, unsigned bo NodeHandle bottomNode(frag); while (true) { jam(); - selectNode(signal, currNode, currNode.m_loc, AccPref); + selectNode(signal, currNode, currNode.m_loc); int ret; // compare prefix ret = cmpScanBound(frag, 0, boundInfo, boundCount, currNode.getPref(), tree.m_prefSize); @@ -300,8 +320,6 @@ Dbtux::searchToScan(Signal* signal, Frag& frag, ConstData boundInfo, unsigned bo } break; } - // access rest of current node - accessNode(signal, currNode, AccFull); for (unsigned j = 0, occup = currNode.getOccup(); j < occup; j++) { jam(); int ret; diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp index 3baa62998db..84d26976e05 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp @@ -29,14 +29,13 @@ Dbtux::treeAdd(Signal* signal, Frag& frag, TreePos treePos, TreeEnt ent) // check for empty tree if (treePos.m_loc == NullTupLoc) { jam(); - insertNode(signal, node, AccPref); + insertNode(signal, node); nodePushUp(signal, node, 0, ent); node.setSide(2); tree.m_root = node.m_loc; return; } - // access full node - selectNode(signal, node, treePos.m_loc, AccFull); + selectNode(signal, node, treePos.m_loc); // check if it is bounding node if (pos != 0 && pos != node.getOccup()) { jam(); @@ -59,11 +58,9 @@ Dbtux::treeAdd(Signal* signal, Frag& frag, TreePos treePos, TreeEnt ent) // find glb node while (childLoc != NullTupLoc) { jam(); - selectNode(signal, node, childLoc, AccHead); + selectNode(signal, node, childLoc); childLoc = node.getLink(1); } - // access full node again - accessNode(signal, node, AccFull); pos = node.getOccup(); } // fall thru to next case @@ -79,7 +76,7 @@ Dbtux::treeAdd(Signal* signal, Frag& frag, TreePos treePos, TreeEnt ent) } // add a new node NodeHandle childNode(frag); - insertNode(signal, childNode, AccPref); + insertNode(signal, childNode); nodePushUp(signal, childNode, 0, ent); // connect parent and child node.setLink(i, childNode.m_loc); @@ -105,7 +102,7 @@ Dbtux::treeAdd(Signal* signal, Frag& frag, TreePos treePos, TreeEnt ent) // height of longer subtree increased jam(); NodeHandle childNode(frag); - selectNode(signal, childNode, node.getLink(i), AccHead); + selectNode(signal, childNode, node.getLink(i)); int b2 = childNode.getBalance(); if (b2 == b) { jam(); @@ -129,7 +126,7 @@ Dbtux::treeAdd(Signal* signal, Frag& frag, TreePos treePos, TreeEnt ent) break; } i = node.getSide(); - selectNode(signal, node, parentLoc, AccHead); + selectNode(signal, node, parentLoc); } } @@ -142,8 +139,7 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) TreeHead& tree = frag.m_tree; unsigned pos = treePos.m_pos; NodeHandle node(frag); - // access full node - selectNode(signal, node, treePos.m_loc, AccFull); + selectNode(signal, node, treePos.m_loc); TreeEnt ent; // check interior node first if (node.getChilds() == 2) { @@ -161,11 +157,9 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) TupLoc childLoc = node.getLink(0); while (childLoc != NullTupLoc) { jam(); - selectNode(signal, node, childLoc, AccHead); + selectNode(signal, node, childLoc); childLoc = node.getLink(1); } - // access full node again - accessNode(signal, node, AccFull); // use glb max as new parent min ent = node.getEnt(node.getOccup() - 1); nodePopUp(signal, parentNode, pos, ent); @@ -183,7 +177,7 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) TupLoc childLoc = node.getLink(i); if (childLoc != NullTupLoc) { // move to child - selectNode(signal, node, childLoc, AccFull); + selectNode(signal, node, childLoc); // balance of half-leaf parent requires child to be leaf break; } @@ -196,7 +190,7 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) // move all that fits into parent if (parentLoc != NullTupLoc) { jam(); - selectNode(signal, parentNode, node.getLink(2), AccFull); + selectNode(signal, parentNode, node.getLink(2)); nodeSlide(signal, parentNode, node, i); // fall thru to next case } @@ -222,7 +216,7 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) // move entries from the other child TupLoc childLoc = node.getLink(1 - i); NodeHandle childNode(frag); - selectNode(signal, childNode, childLoc, AccFull); + selectNode(signal, childNode, childLoc); nodeSlide(signal, node, childNode, 1 - i); if (childNode.getOccup() == 0) { jam(); @@ -236,7 +230,7 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) } // fix side and become parent i = node.getSide(); - selectNode(signal, node, parentLoc, AccHead); + selectNode(signal, node, parentLoc); } } #endif @@ -261,7 +255,7 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) jam(); // child on the other side NodeHandle childNode(frag); - selectNode(signal, childNode, node.getLink(1 - i), AccHead); + selectNode(signal, childNode, node.getLink(1 - i)); int b2 = childNode.getBalance(); if (b2 == b) { jam(); @@ -287,7 +281,7 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) return; } i = node.getSide(); - selectNode(signal, node, parentLoc, AccHead); + selectNode(signal, node, parentLoc); } } @@ -331,7 +325,7 @@ Dbtux::treeRotateSingle(Signal* signal, */ TupLoc loc3 = node5.getLink(i); NodeHandle node3(frag); - selectNode(signal, node3, loc3, AccHead); + selectNode(signal, node3, loc3); const int bal3 = node3.getBalance(); /* 2 must always be there but is not changed. Thus we mereley check that it @@ -348,7 +342,7 @@ Dbtux::treeRotateSingle(Signal* signal, NodeHandle node4(frag); if (loc4 != NullTupLoc) { jam(); - selectNode(signal, node4, loc4, AccHead); + selectNode(signal, node4, loc4); ndbrequire(node4.getSide() == (1 - i) && node4.getLink(2) == loc3); node4.setSide(i); @@ -383,7 +377,7 @@ Dbtux::treeRotateSingle(Signal* signal, if (loc0 != NullTupLoc) { jam(); NodeHandle node0(frag); - selectNode(signal, node0, loc0, AccHead); + selectNode(signal, node0, loc0); node0.setLink(side5, loc3); } else { jam(); @@ -532,13 +526,13 @@ Dbtux::treeRotateDouble(Signal* signal, Frag& frag, NodeHandle& node, unsigned i // level 1 TupLoc loc2 = node6.getLink(i); NodeHandle node2(frag); - selectNode(signal, node2, loc2, AccHead); + selectNode(signal, node2, loc2); const int bal2 = node2.getBalance(); // level 2 TupLoc loc4 = node2.getLink(1 - i); NodeHandle node4(frag); - selectNode(signal, node4, loc4, AccHead); + selectNode(signal, node4, loc4); const int bal4 = node4.getBalance(); ndbrequire(i <= 1); @@ -556,8 +550,6 @@ Dbtux::treeRotateDouble(Signal* signal, Frag& frag, NodeHandle& node, unsigned i if (loc3 == NullTupLoc && loc5 == NullTupLoc) { jam(); TreeHead& tree = frag.m_tree; - accessNode(signal, node2, AccFull); - accessNode(signal, node4, AccFull); nodeSlide(signal, node4, node2, i); // implied by rule of merging half-leaves with leaves ndbrequire(node4.getOccup() >= tree.m_minOccup); @@ -566,14 +558,14 @@ Dbtux::treeRotateDouble(Signal* signal, Frag& frag, NodeHandle& node, unsigned i if (loc3 != NullTupLoc) { jam(); NodeHandle node3(frag); - selectNode(signal, node3, loc3, AccHead); + selectNode(signal, node3, loc3); node3.setLink(2, loc2); node3.setSide(1 - i); } if (loc5 != NullTupLoc) { jam(); NodeHandle node5(frag); - selectNode(signal, node5, loc5, AccHead); + selectNode(signal, node5, loc5); node5.setLink(2, node6.m_loc); node5.setSide(i); } @@ -596,7 +588,7 @@ Dbtux::treeRotateDouble(Signal* signal, Frag& frag, NodeHandle& node, unsigned i if (loc0 != NullTupLoc) { jam(); - selectNode(signal, node0, loc0, AccHead); + selectNode(signal, node0, loc0); node0.setLink(side6, loc4); } else { jam(); diff --git a/ndb/src/kernel/blocks/dbtux/Times.txt b/ndb/src/kernel/blocks/dbtux/Times.txt index 03473353a52..8fbb695ef82 100644 --- a/ndb/src/kernel/blocks/dbtux/Times.txt +++ b/ndb/src/kernel/blocks/dbtux/Times.txt @@ -108,4 +108,16 @@ charsets mc02/a 35 ms 60 ms 71 pct [ case b: TUX can no longer use pointers to TUP data ] +optim 15 mc02/a 34 ms 60 ms 72 pct + mc02/b 42 ms 85 ms 100 pct + mc02/c 5 ms 12 ms 110 pct + mc02/d 178 ms 242 ms 35 pct + +[ corrected wasted space in index node ] + +optim 16 mc02/a 34 ms 53 ms 53 pct + mc02/b 42 ms 75 ms 75 pct + +[ case a, b: binary search of bounding node when adding entry ] + vim: set et: diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index 29f4f341188..3699ea2626a 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -1151,11 +1151,14 @@ ndb_mgm_dump_state(NdbMgmHandle handle, int nodeId, int* _args, CHECK_CONNECTED(handle, -1); char buf[256]; - char buf2[6]; buf[0] = 0; for (int i = 0; i < _num_args; i++){ - snprintf(buf2, 6, "%d ", _args[i]); - strncat(buf, buf2, 256); + unsigned n = strlen(buf); + if (n + 20 > sizeof(buf)) { + SET_ERROR(handle, NDB_MGM_USAGE_ERROR, "arguments too long"); + return -1; + } + sprintf(buf + n, "%s%d", i ? " " : "", _args[i]); } Properties args; diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp index 7560a59a1ef..b03a4f8a419 100644 --- a/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/ndb/src/mgmclient/CommandInterpreter.cpp @@ -1363,36 +1363,29 @@ CommandInterpreter::executeLog(int processId, if (! parseBlockSpecification(parameters, blocks)) { return; } - int len=0; + int len=1; Uint32 i; for(i=0; i<blocks.size(); i++) { - ndbout_c("blocks %s %d",blocks[i], strlen(blocks[i])); - len += strlen(blocks[i]); + len += strlen(blocks[i]) + 1; } - len += blocks.size()*2; char * blockNames = (char*)my_malloc(len,MYF(MY_WME)); My_auto_ptr<char> ap1(blockNames); + blockNames[0] = 0; for(i=0; i<blocks.size(); i++) { strcat(blockNames, blocks[i]); strcat(blockNames, "|"); } - strcat(blockNames, "\0"); - ndbout_c("blocknames %s", blockNames); - /*int res =*/ndb_mgm_log_signals(m_mgmsrv, + int result = ndb_mgm_log_signals(m_mgmsrv, processId, NDB_MGM_SIGNAL_LOG_MODE_INOUT, blockNames, &reply); - -#if 0 - int result = - _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::InOut, blocks); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout_c("Execute LOG on node %d failed.", processId); + printError(); } -#endif } //***************************************************************************** @@ -1401,17 +1394,7 @@ void CommandInterpreter::executeLogIn(int /* processId */, const char* parameters, bool /* all */) { - Vector<const char*> blocks; - if (! parseBlockSpecification(parameters, blocks)) { - return; - } - -#if 0 - int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::In, blocks); - if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; - } -#endif + ndbout << "Command LOGIN not implemented." << endl; } //***************************************************************************** @@ -1420,19 +1403,7 @@ void CommandInterpreter::executeLogOut(int /*processId*/, const char* parameters, bool /*all*/) { - Vector<const char*> blocks; - if (! parseBlockSpecification(parameters, blocks)) { - return; - } - - -#if 0 - int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Out, - blocks); - if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; - } -#endif + ndbout << "Command LOGOUT not implemented." << endl; } //***************************************************************************** @@ -1441,57 +1412,45 @@ void CommandInterpreter::executeLogOff(int /*processId*/, const char* parameters, bool /*all*/) { - Vector<const char*> blocks; - if (! parseBlockSpecification(parameters, blocks)) { - return; - } - - -#if 0 - int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Off, - blocks); - if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; - } -#endif + ndbout << "Command LOGOFF not implemented." << endl; } //***************************************************************************** //***************************************************************************** void -CommandInterpreter::executeTestOn(int /*processId*/, +CommandInterpreter::executeTestOn(int processId, const char* parameters, bool /*all*/) { if (! emptyString(parameters)) { ndbout << "No parameters expected to this command." << endl; return; } - -#if 0 - int result = _mgmtSrvr.startSignalTracing(processId); + connect(); + struct ndb_mgm_reply reply; + int result = ndb_mgm_start_signallog(m_mgmsrv, processId, &reply); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout_c("Execute TESTON failed."); + printError(); } -#endif } //***************************************************************************** //***************************************************************************** void -CommandInterpreter::executeTestOff(int /*processId*/, +CommandInterpreter::executeTestOff(int processId, const char* parameters, bool /*all*/) { if (! emptyString(parameters)) { ndbout << "No parameters expected to this command." << endl; return; } - -#if 0 - int result = _mgmtSrvr.stopSignalTracing(processId); + connect(); + struct ndb_mgm_reply reply; + int result = ndb_mgm_stop_signallog(m_mgmsrv, processId, &reply); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout_c("Execute TESTOFF failed."); + printError(); } -#endif } diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp index 9629c5e8904..bff7f9be0e6 100644 --- a/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/ndb/src/mgmsrv/ConfigInfo.cpp @@ -2373,7 +2373,7 @@ ConfigInfo::getAlias(const char * section) const { bool ConfigInfo::verify(const Properties * section, const char* fname, Uint64 value) const { - Uint64 min, max; min = max + 1; + Uint64 min, max; min = getInfoInt(section, fname, "Min"); max = getInfoInt(section, fname, "Max"); diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp index 684c10dbd4d..5242237a638 100644 --- a/ndb/src/mgmsrv/Services.cpp +++ b/ndb/src/mgmsrv/Services.cpp @@ -1244,6 +1244,7 @@ operator<<(NdbOut& out, const LogLevel & ll) for(size_t i = 0; i<LogLevel::LOGLEVEL_CATEGORIES; i++) out << ll.getLogLevel((LogLevel::EventCategory)i) << " "; out << "]"; + return out; } void diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index 08d1e793db8..04632665aff 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -371,6 +371,7 @@ Ndb::hupp(NdbConnection* pBuddyTrans) // We could not get a connection to the desired node // release the connection and return NULL closeTransaction(pCon); + theError.code = 4006; DBUG_RETURN(NULL); } pCon->setTransactionId(pBuddyTrans->getTransactionId()); diff --git a/ndb/src/ndbapi/NdbApiSignal.cpp b/ndb/src/ndbapi/NdbApiSignal.cpp index d7b2b74b2bf..a1d34896968 100644 --- a/ndb/src/ndbapi/NdbApiSignal.cpp +++ b/ndb/src/ndbapi/NdbApiSignal.cpp @@ -168,7 +168,7 @@ NdbApiSignal::setSignal(int aNdbSignalType) theTrace = TestOrd::TraceAPI; theReceiversBlockNumber = DBTC; theVerId_signalNumber = GSN_TC_COMMITREQ; - theLength = 5; + theLength = 3; } break; diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp index 7939f54d846..6172e7076eb 100644 --- a/ndb/src/ndbapi/NdbBlob.cpp +++ b/ndb/src/ndbapi/NdbBlob.cpp @@ -867,7 +867,7 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count) while (n < count) { NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable); if (tOp == NULL || - tOp->readTuple() == -1 || + tOp->committedRead() == -1 || setPartKeyValue(tOp, part + n) == -1 || tOp->getValue((Uint32)3, buf) == NULL) { setErrorCode(tOp); diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp index 5e5d982444c..da2d34e270a 100644 --- a/ndb/src/ndbapi/NdbConnection.cpp +++ b/ndb/src/ndbapi/NdbConnection.cpp @@ -83,6 +83,11 @@ NdbConnection::NdbConnection( Ndb* aNdb ) : theListState = NotInList; theError.code = 0; theId = theNdb->theNdbObjectIdMap->map(this); + +#define CHECK_SZ(mask, sz) assert((sizeof(mask)/sizeof(mask[0])) == sz) + + CHECK_SZ(m_db_nodes, NdbNodeBitmask::Size); + CHECK_SZ(m_failed_db_nodes, NdbNodeBitmask::Size); }//NdbConnection::NdbConnection() /***************************************************************************** @@ -490,11 +495,6 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, theListState = InPreparedList; tNdb->theNoOfPreparedTransactions = tnoOfPreparedTransactions + 1; - if(tCommitStatus == Committed){ - tCommitStatus = Started; - tTransactionIsStarted = false; - } - if ((tCommitStatus != Started) || (aTypeOfExec == Rollback)) { /***************************************************************************** @@ -503,7 +503,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, * same action. ****************************************************************************/ if (aTypeOfExec == Rollback) { - if (theTransactionIsStarted == false) { + if (theTransactionIsStarted == false || theSimpleState) { theCommitStatus = Aborted; theSendStatus = sendCompleted; } else { @@ -528,7 +528,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, tLastOp->theCommitIndicator = 1; }//if } else { - if (aTypeOfExec == Commit) { + if (aTypeOfExec == Commit && !theSimpleState) { /********************************************************************** * A Transaction have been started and no more operations exist. * We will use the commit method. @@ -610,6 +610,8 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, theNoOfOpSent = 0; theNoOfOpCompleted = 0; theSendStatus = sendOperations; + NdbNodeBitmask::clear(m_db_nodes); + NdbNodeBitmask::clear(m_failed_db_nodes); DBUG_VOID_RETURN; }//NdbConnection::executeAsynchPrepare() @@ -1535,12 +1537,21 @@ from other transactions. const Uint32* tPtr = (Uint32 *)&keyConf->operations[0]; Uint32 tNoComp = theNoOfOpCompleted; for (Uint32 i = 0; i < tNoOfOperations ; i++) { - tOp = theNdb->void2rec(theNdb->int2void(*tPtr)); - tPtr++; - const Uint32 tAttrInfoLen = *tPtr; - tPtr++; + tOp = theNdb->void2rec(theNdb->int2void(*tPtr++)); + const Uint32 tAttrInfoLen = *tPtr++; if (tOp && tOp->checkMagicNumber()) { - tNoComp += tOp->execTCOPCONF(tAttrInfoLen); + Uint32 done = tOp->execTCOPCONF(tAttrInfoLen); + if(tAttrInfoLen > TcKeyConf::SimpleReadBit){ + Uint32 node = tAttrInfoLen & (~TcKeyConf::SimpleReadBit); + NdbNodeBitmask::set(m_db_nodes, node); + if(NdbNodeBitmask::get(m_failed_db_nodes, node) && !done) + { + done = 1; + tOp->setErrorCode(4119); + theCompletionStatus = CompletedFailure; + } + } + tNoComp += done; } else { return -1; }//if @@ -1790,7 +1801,7 @@ Parameters: aErrorCode: The error code. Remark: An operation was completed with failure. *******************************************************************************/ int -NdbConnection::OpCompleteFailure() +NdbConnection::OpCompleteFailure(Uint8 abortOption) { Uint32 tNoComp = theNoOfOpCompleted; Uint32 tNoSent = theNoOfOpSent; @@ -1804,10 +1815,7 @@ NdbConnection::OpCompleteFailure() //decide the success of the whole transaction since a simple //operation is not really part of that transaction. //------------------------------------------------------------------------ - if (theSimpleState == 1) { - theCommitStatus = NdbConnection::Aborted; - }//if - if (m_abortOption == IgnoreError){ + if (abortOption == IgnoreError){ /** * There's always a TCKEYCONF when using IgnoreError */ @@ -1842,9 +1850,6 @@ NdbConnection::OpCompleteSuccess() tNoComp++; theNoOfOpCompleted = tNoComp; if (tNoComp == tNoSent) { // Last operation completed - if (theSimpleState == 1) { - theCommitStatus = NdbConnection::Committed; - }//if return 0; } else if (tNoComp < tNoSent) { return -1; // Continue waiting for more signals @@ -1960,3 +1965,43 @@ NdbConnection::printState() } #undef CASE #endif + +int +NdbConnection::report_node_failure(Uint32 id){ + NdbNodeBitmask::set(m_failed_db_nodes, id); + if(!NdbNodeBitmask::get(m_db_nodes, id)) + { + return 0; + } + + /** + * Arrived + * TCKEYCONF TRANSIDAI + * 1) - - + * 2) - X + * 3) X - + * 4) X X + */ + NdbOperation* tmp = theFirstExecOpInList; + const Uint32 len = TcKeyConf::SimpleReadBit | id; + Uint32 tNoComp = theNoOfOpCompleted; + Uint32 tNoSent = theNoOfOpSent; + while(tmp != 0) + { + if(tmp->theReceiver.m_expected_result_length == len && + tmp->theReceiver.m_received_result_length == 0) + { + tNoComp++; + tmp->theError.code = 4119; + } + tmp = tmp->next(); + } + theNoOfOpCompleted = tNoComp; + if(tNoComp == tNoSent) + { + theError.code = 4119; + theCompletionStatus = NdbConnection::CompletedFailure; + return 1; + } + return 0; +} diff --git a/ndb/src/ndbapi/NdbIndexOperation.cpp b/ndb/src/ndbapi/NdbIndexOperation.cpp index c62f6962e25..83de6d9ef87 100644 --- a/ndb/src/ndbapi/NdbIndexOperation.cpp +++ b/ndb/src/ndbapi/NdbIndexOperation.cpp @@ -87,7 +87,19 @@ NdbIndexOperation::indxInit(const NdbIndexImpl * anIndex, int NdbIndexOperation::readTuple(NdbOperation::LockMode lm) { - return NdbOperation::readTuple(lm); + switch(lm) { + case LM_Read: + return readTuple(); + break; + case LM_Exclusive: + return readTupleExclusive(); + break; + case LM_CommittedRead: + return readTuple(); + break; + default: + return -1; + }; } int NdbIndexOperation::readTuple() @@ -108,21 +120,21 @@ int NdbIndexOperation::simpleRead() { // First check that index is unique - return NdbOperation::simpleRead(); + return NdbOperation::readTuple(); } int NdbIndexOperation::dirtyRead() { // First check that index is unique - return NdbOperation::dirtyRead(); + return NdbOperation::readTuple(); } int NdbIndexOperation::committedRead() { // First check that index is unique - return NdbOperation::committedRead(); + return NdbOperation::readTuple(); } int NdbIndexOperation::updateTuple() @@ -536,7 +548,7 @@ NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId) //------------------------------------------------------------- Uint8 tReadInd = (theOperationType == ReadRequest); Uint8 tSimpleState = tReadInd & tSimpleAlt; - theNdbCon->theSimpleState = tSimpleState; + //theNdbCon->theSimpleState = tSimpleState; tcIndxReq->transId1 = tTransId1; tcIndxReq->transId2 = tTransId2; @@ -723,23 +735,10 @@ NdbIndexOperation::receiveTCINDXREF( NdbApiSignal* aSignal) theStatus = Finished; theNdbCon->theReturnStatus = NdbConnection::ReturnFailure; - //--------------------------------------------------------------------------// - // If the transaction this operation belongs to consists only of simple reads - // we set the error code on the transaction object. - // If the transaction consists of other types of operations we set - // the error code only on the operation since the simple read is not really - // part of this transaction and we can not decide the status of the whole - // transaction based on this operation. - //--------------------------------------------------------------------------// Uint32 errorCode = tcIndxRef->errorCode; - if (theNdbCon->theSimpleState == 0) { - theError.code = errorCode; - theNdbCon->setOperationErrorCodeAbort(errorCode); - return theNdbCon->OpCompleteFailure(); - } else { - theError.code = errorCode; - return theNdbCon->OpCompleteSuccess(); - } + theError.code = errorCode; + theNdbCon->setOperationErrorCodeAbort(errorCode); + return theNdbCon->OpCompleteFailure(theNdbCon->m_abortOption); }//NdbIndexOperation::receiveTCINDXREF() diff --git a/ndb/src/ndbapi/NdbOperationDefine.cpp b/ndb/src/ndbapi/NdbOperationDefine.cpp index 4809ba0fe01..35abb15b00d 100644 --- a/ndb/src/ndbapi/NdbOperationDefine.cpp +++ b/ndb/src/ndbapi/NdbOperationDefine.cpp @@ -116,7 +116,7 @@ NdbOperation::readTuple(NdbOperation::LockMode lm) return readTupleExclusive(); break; case LM_CommittedRead: - return readTuple(); + return committedRead(); break; default: return -1; @@ -191,18 +191,24 @@ NdbOperation::readTupleExclusive() int NdbOperation::simpleRead() { + /** + * Currently/still disabled + */ + return readTuple(); +#if 0 int tErrorLine = theErrorLine; if (theStatus == Init) { theStatus = OperationDefined; theOperationType = ReadRequest; theSimpleIndicator = 1; theErrorLine = tErrorLine++; - theLockMode = LM_CommittedRead; + theLockMode = LM_Read; return 0; } else { setErrorCode(4200); return -1; }//if +#endif }//NdbOperation::simpleRead() /***************************************************************************** diff --git a/ndb/src/ndbapi/NdbOperationExec.cpp b/ndb/src/ndbapi/NdbOperationExec.cpp index cd89f953213..f1338ae01e4 100644 --- a/ndb/src/ndbapi/NdbOperationExec.cpp +++ b/ndb/src/ndbapi/NdbOperationExec.cpp @@ -161,28 +161,17 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransId) tTransId1 = (Uint32) aTransId; tTransId2 = (Uint32) (aTransId >> 32); -//------------------------------------------------------------- -// Simple is simple if simple or both start and commit is set. -//------------------------------------------------------------- -// Temporarily disable simple stuff - Uint8 tSimpleIndicator = 0; -// Uint8 tSimpleIndicator = theSimpleIndicator; + Uint8 tSimpleIndicator = theSimpleIndicator; Uint8 tCommitIndicator = theCommitIndicator; Uint8 tStartIndicator = theStartIndicator; -// if ((theNdbCon->theLastOpInList == this) && (theCommitIndicator == 0)) -// abort(); -// Temporarily disable simple stuff - Uint8 tSimpleAlt = 0; -// Uint8 tSimpleAlt = tStartIndicator & tCommitIndicator; - tSimpleIndicator = tSimpleIndicator | tSimpleAlt; + Uint8 tInterpretIndicator = theInterpretIndicator; //------------------------------------------------------------- // Simple state is set if start and commit is set and it is // a read request. Otherwise it is set to zero. //------------------------------------------------------------- Uint8 tReadInd = (theOperationType == ReadRequest); - Uint8 tSimpleState = tReadInd & tSimpleAlt; - theNdbCon->theSimpleState = tSimpleState; + Uint8 tSimpleState = tReadInd & tSimpleIndicator; tcKeyReq->transId1 = tTransId1; tcKeyReq->transId2 = tTransId2; @@ -197,7 +186,6 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransId) tcKeyReq->setSimpleFlag(tReqInfo, tSimpleIndicator); tcKeyReq->setCommitFlag(tReqInfo, tCommitIndicator); tcKeyReq->setStartFlag(tReqInfo, tStartIndicator); - const Uint8 tInterpretIndicator = theInterpretIndicator; tcKeyReq->setInterpretedFlag(tReqInfo, tInterpretIndicator); Uint8 tDirtyIndicator = theDirtyIndicator; @@ -208,6 +196,9 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransId) tcKeyReq->setDirtyFlag(tReqInfo, tDirtyIndicator); tcKeyReq->setOperationType(tReqInfo, tOperationType); tcKeyReq->setKeyLength(tReqInfo, tTupKeyLen); + + // A simple read is always ignore error + abortOption = tSimpleIndicator ? IgnoreError : abortOption; tcKeyReq->setAbortOption(tReqInfo, abortOption); Uint8 tDistrKeyIndicator = theDistrKeyIndicator; @@ -550,27 +541,29 @@ NdbOperation::receiveTCKEYREF( NdbApiSignal* aSignal) return -1; }//if + AbortOption ao = (AbortOption)theNdbCon->m_abortOption; + theReceiver.m_received_result_length = ~0; + theStatus = Finished; - theNdbCon->theReturnStatus = NdbConnection::ReturnFailure; - //-------------------------------------------------------------------------// - // If the transaction this operation belongs to consists only of simple reads - // we set the error code on the transaction object. - // If the transaction consists of other types of operations we set - // the error code only on the operation since the simple read is not really - // part of this transaction and we can not decide the status of the whole - // transaction based on this operation. - //-------------------------------------------------------------------------// - if (theNdbCon->theSimpleState == 0) { - theError.code = aSignal->readData(4); - theNdbCon->setOperationErrorCodeAbort(aSignal->readData(4)); - return theNdbCon->OpCompleteFailure(); - } else { - theError.code = aSignal->readData(4); - return theNdbCon->OpCompleteSuccess(); + + theError.code = aSignal->readData(4); + theNdbCon->setOperationErrorCodeAbort(aSignal->readData(4)); + + if(theOperationType != ReadRequest || !theSimpleIndicator) // not simple read + return theNdbCon->OpCompleteFailure(ao); + + /** + * If TCKEYCONF has arrived + * op has completed (maybe trans has completed) + */ + if(theReceiver.m_expected_result_length) + { + return theNdbCon->OpCompleteFailure(AbortOnError); } -}//NdbOperation::receiveTCKEYREF() + return -1; +} void diff --git a/ndb/src/ndbapi/NdbReceiver.cpp b/ndb/src/ndbapi/NdbReceiver.cpp index caeeac80093..3a1ea9c10d1 100644 --- a/ndb/src/ndbapi/NdbReceiver.cpp +++ b/ndb/src/ndbapi/NdbReceiver.cpp @@ -22,6 +22,7 @@ #include <AttributeHeader.hpp> #include <NdbConnection.hpp> #include <TransporterFacade.hpp> +#include <signaldata/TcKeyConf.hpp> NdbReceiver::NdbReceiver(Ndb *aNdb) : theMagicNumber(0), @@ -249,10 +250,11 @@ NdbReceiver::execTRANSID_AI(const Uint32* aDataPtr, Uint32 aLength) /** * Update m_received_result_length */ + Uint32 exp = m_expected_result_length; Uint32 tmp = m_received_result_length + aLength; m_received_result_length = tmp; - return (tmp == m_expected_result_length ? 1 : 0); + return (tmp == exp || (exp > TcKeyConf::SimpleReadBit) ? 1 : 0); } int @@ -272,3 +274,11 @@ NdbReceiver::execKEYINFO20(Uint32 info, const Uint32* aDataPtr, Uint32 aLength) return (tmp == m_expected_result_length ? 1 : 0); } + +void +NdbReceiver::setErrorCode(int code) +{ + theMagicNumber = 0; + NdbOperation* op = (NdbOperation*)getOwner(); + op->setErrorCode(code); +} diff --git a/ndb/src/ndbapi/NdbScanFilter.cpp b/ndb/src/ndbapi/NdbScanFilter.cpp index 3813ab139de..38b1c70c047 100644 --- a/ndb/src/ndbapi/NdbScanFilter.cpp +++ b/ndb/src/ndbapi/NdbScanFilter.cpp @@ -779,7 +779,9 @@ main(void){ template class Vector<NdbScanFilterImpl::State>; #if __SUNPRO_CC != 0x560 +#ifndef _FORTEC_ template int NdbScanFilterImpl::cond_col_const(Interpreter::BinaryCondition, Uint32 attrId, Uint32); template int NdbScanFilterImpl::cond_col_const(Interpreter::BinaryCondition, Uint32 attrId, Uint64); #endif +#endif diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index 8acc0695e4e..b23bc8cfe4d 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -566,6 +566,8 @@ int NdbScanOperation::nextResult(bool fetchAllowed) setErrorCode(4028); // Node fail break; case -3: // send_next_scan -> return fail (set error-code self) + if(theError.code == 0) + setErrorCode(4028); // seq changed = Node fail break; } @@ -908,6 +910,7 @@ NdbScanOperation::takeOverScanOp(OperationType opType, NdbConnection* pTrans){ if (newOp == NULL){ return NULL; } + pTrans->theSimpleState = 0; const Uint32 len = (tRecAttr->attrSize() * tRecAttr->arraySize() + 3)/4-1; diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp index 5c91467f2e5..c011c1a6a26 100644 --- a/ndb/src/ndbapi/Ndbif.cpp +++ b/ndb/src/ndbapi/Ndbif.cpp @@ -249,6 +249,7 @@ Ndb::report_node_failure(Uint32 node_id) */ the_release_ind[node_id] = 1; theWaiter.nodeFail(node_id); + return; }//Ndb::report_node_failure() @@ -271,9 +272,10 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId) Uint32 tNoSentTransactions = theNoOfSentTransactions; for (int i = tNoSentTransactions - 1; i >= 0; i--) { NdbConnection* localCon = theSentTransactionsArray[i]; - if (localCon->getConnectedNodeId() == aNodeId ) { + if (localCon->getConnectedNodeId() == aNodeId) { const NdbConnection::SendStatusType sendStatus = localCon->theSendStatus; - if (sendStatus == NdbConnection::sendTC_OP || sendStatus == NdbConnection::sendTC_COMMIT) { + if (sendStatus == NdbConnection::sendTC_OP || + sendStatus == NdbConnection::sendTC_COMMIT) { /* A transaction was interrupted in the prepare phase by a node failure. Since the transaction was not found in the phase @@ -293,7 +295,7 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId) printState("abortTransactionsAfterNodeFailure %x", this); abort(); #endif - }// + } /* All transactions arriving here have no connection to the kernel intact since the node was failing and they were aborted. Thus we @@ -302,7 +304,11 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId) localCon->theCommitStatus = NdbConnection::Aborted; localCon->theReleaseOnClose = true; completedTransaction(localCon); - }//if + } + else if(localCon->report_node_failure(aNodeId)) + { + completedTransaction(localCon); + } }//for return; }//Ndb::abortTransactionsAfterNodeFailure() diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index 8589158ae6a..28b94d31159 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -107,8 +107,6 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, theOpIdleList= NULL; theScanOpIdleList= NULL; theIndexOpIdleList= NULL; -// theSchemaConIdleList= NULL; -// theSchemaConToNdbList= NULL; theTransactionList= NULL; theConnectionArray= NULL; theRecAttrIdleList= NULL; @@ -134,10 +132,13 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, fullyQualifiedNames = true; +#ifdef POORMANSPURIFY cgetSignals =0; cfreeSignals = 0; cnewSignals = 0; creleaseSignals = 0; +#endif + theError.code = 0; theNdbObjectIdMap = new NdbObjectIdMap(1024,1024); diff --git a/ndb/src/ndbapi/Ndblist.cpp b/ndb/src/ndbapi/Ndblist.cpp index b6739b66dce..df218e00fbc 100644 --- a/ndb/src/ndbapi/Ndblist.cpp +++ b/ndb/src/ndbapi/Ndblist.cpp @@ -432,11 +432,15 @@ Ndb::getSignal() theSignalIdleList = tSignalNext; } else { tSignal = new NdbApiSignal(theMyRef); +#ifdef POORMANSPURIFY cnewSignals++; +#endif if (tSignal != NULL) tSignal->next(NULL); } +#ifdef POORMANSPURIFY cgetSignals++; +#endif return tSignal; } @@ -605,7 +609,9 @@ Ndb::releaseSignal(NdbApiSignal* aSignal) } #endif #endif +#ifdef POORMANSPURIFY creleaseSignals++; +#endif aSignal->next(theSignalIdleList); theSignalIdleList = aSignal; } @@ -769,7 +775,9 @@ Ndb::freeSignal() NdbApiSignal* tSignal = theSignalIdleList; theSignalIdleList = tSignal->next(); delete tSignal; +#ifdef POORMANSPURIFY cfreeSignals++; +#endif } void diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index fdfd8a15fb0..49fbe32d098 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -92,9 +92,10 @@ ErrorBundle ErrorCodes[] = { { 4031, NR, "Node failure caused abort of transaction" }, { 4033, NR, "Send to NDB failed" }, { 4115, NR, - "Transaction was committed but all read information was not " - "received due to node crash" }, - + "Transaction was committed but all read information was not " + "received due to node crash" }, + { 4119, NR, "Simple/dirty read failed due to node failure" }, + /** * Node shutdown */ @@ -171,7 +172,7 @@ ErrorBundle ErrorCodes[] = { { 677, OL, "Index UNDO buffers overloaded" }, { 891, OL, "Data UNDO buffers overloaded" }, { 1221, OL, "REDO log buffers overloaded" }, - { 4006, AE, "Connect failure - out of connection objects" }, + { 4006, OL, "Connect failure - out of connection objects" }, diff --git a/ndb/test/include/HugoOperations.hpp b/ndb/test/include/HugoOperations.hpp index 6bd8f7204b2..fe22e4b5649 100644 --- a/ndb/test/include/HugoOperations.hpp +++ b/ndb/test/include/HugoOperations.hpp @@ -38,16 +38,8 @@ public: int pkReadRecord(Ndb*, int recordNo, - bool exclusive = false, - int numRecords = 1); - - int pkSimpleReadRecord(Ndb*, - int recordNo, - int numRecords = 1); - - int pkDirtyReadRecord(Ndb*, - int recordNo, - int numRecords = 1); + int numRecords = 1, + NdbOperation::LockMode lm = NdbOperation::LM_Read); int pkUpdateRecord(Ndb*, int recordNo, diff --git a/ndb/test/include/HugoTransactions.hpp b/ndb/test/include/HugoTransactions.hpp index 280d9490f15..19e4cb43336 100644 --- a/ndb/test/include/HugoTransactions.hpp +++ b/ndb/test/include/HugoTransactions.hpp @@ -48,8 +48,8 @@ public: int pkReadRecords(Ndb*, int records, int batchsize = 1, - bool dirty = false); - + NdbOperation::LockMode = NdbOperation::LM_Read); + int scanUpdateRecords(Ndb*, int records, int abort = 0, diff --git a/ndb/test/include/NDBT_Test.hpp b/ndb/test/include/NDBT_Test.hpp index 6a968c491ae..176cec3cd27 100644 --- a/ndb/test/include/NDBT_Test.hpp +++ b/ndb/test/include/NDBT_Test.hpp @@ -82,6 +82,12 @@ public: */ int getNoOfRunningSteps() const ; int getNoOfCompletedSteps() const ; + + /** + * Thread sync + */ + void sync_down(const char * key); + void sync_up_and_wait(const char * key, Uint32 count = 0); private: friend class NDBT_Step; friend class NDBT_TestSuite; diff --git a/ndb/test/ndbapi/testBasic.cpp b/ndb/test/ndbapi/testBasic.cpp index 7d03016b87a..4d64b15ecfa 100644 --- a/ndb/test/ndbapi/testBasic.cpp +++ b/ndb/test/ndbapi/testBasic.cpp @@ -160,8 +160,8 @@ int runPkDirtyRead(NDBT_Context* ctx, NDBT_Step* step){ HugoTransactions hugoTrans(*ctx->getTab()); while (i<loops) { g_info << i << ": "; - if (hugoTrans.pkReadRecords(GETNDB(step), records, - batchSize, dirty) != NDBT_OK){ + if (hugoTrans.pkReadRecords(GETNDB(step), records, batchSize, + NdbOperation::LM_CommittedRead) != NDBT_OK){ g_info << endl; return NDBT_FAILED; } @@ -398,14 +398,14 @@ int runNoCommitSleep(NDBT_Context* ctx, NDBT_Step* step){ for (int i = 2; i < 8; i++){ CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); ndbout << i <<": Sleeping for " << sleepTime << " ms" << endl; NdbSleep_MilliSleep(sleepTime); // Dont care about result of these ops - hugoOps.pkReadRecord(pNdb, 1, true); + hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive); hugoOps.closeTransaction(pNdb); sleepTime = sleepTime *i; @@ -424,16 +424,16 @@ int runCommit626(NDBT_Context* ctx, NDBT_Step* step){ do{ // Commit transaction CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Commit transaction // Multiple operations CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 2, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 3, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 626); }while(false); @@ -467,7 +467,7 @@ int runCommit_TryCommit626(NDBT_Context* ctx, NDBT_Step* step){ do{ // Commit transaction, TryCommit CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb, TryCommit) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -475,11 +475,11 @@ int runCommit_TryCommit626(NDBT_Context* ctx, NDBT_Step* step){ // Several operations in one transaction // The insert is OK CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 2, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 3, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 4, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 4, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb, TryCommit) == 626); }while(false); @@ -513,20 +513,23 @@ int runCommit_CommitAsMuchAsPossible626(NDBT_Context* ctx, NDBT_Step* step){ do{ // Commit transaction, CommitAsMuchAsPossible CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb, CommitAsMuchAsPossible) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Commit transaction, CommitAsMuchAsPossible CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 2, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 3, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 4, true) == 0); CHECK(hugoOps.execute_Commit(pNdb, CommitAsMuchAsPossible) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); - }while(false); + + CHECK(hugoOps.startTransaction(pNdb) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1) == 0); + CHECK(hugoOps.execute_Commit(pNdb) == 0); + CHECK(hugoOps.closeTransaction(pNdb) == 0); + } while(false); hugoOps.closeTransaction(pNdb); @@ -542,8 +545,14 @@ int runCommit_CommitAsMuchAsPossible630(NDBT_Context* ctx, NDBT_Step* step){ // Commit transaction, CommitAsMuchAsPossible CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); + CHECK(hugoOps.pkDeleteRecord(pNdb, 2) == 0); CHECK(hugoOps.execute_Commit(pNdb, CommitAsMuchAsPossible) == 630); - }while(false); + CHECK(hugoOps.closeTransaction(pNdb) == 0); + + CHECK(hugoOps.startTransaction(pNdb) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 2) == 0); + CHECK(hugoOps.execute_Commit(pNdb) == 0); + } while(false); hugoOps.closeTransaction(pNdb); @@ -558,13 +567,13 @@ int runNoCommit626(NDBT_Context* ctx, NDBT_Step* step){ do{ // No commit transaction, readTuple CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, false) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); // No commit transaction, readTupleExcluive CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); }while(false); @@ -598,7 +607,7 @@ int runNoCommitRollback626(NDBT_Context* ctx, NDBT_Step* step){ do{ // No commit transaction, rollback CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -606,10 +615,10 @@ int runNoCommitRollback626(NDBT_Context* ctx, NDBT_Step* step){ // No commit transaction, rollback // Multiple operations CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 2, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 3, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 4, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 4, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); }while(false); @@ -647,7 +656,7 @@ int runNoCommitAndClose(NDBT_Context* ctx, NDBT_Step* step){ // Read CHECK(hugoOps.startTransaction(pNdb) == 0); for (i = 0; i < 10; i++) - CHECK(hugoOps.pkReadRecord(pNdb, i, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, i, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -701,7 +710,7 @@ int runCheckRollbackDelete(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Check record is deleted - CHECK(hugoOps.pkReadRecord(pNdb, 5, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); @@ -709,13 +718,13 @@ int runCheckRollbackDelete(NDBT_Context* ctx, NDBT_Step* step){ // Check record is not deleted CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Check record is back to original value CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.compareRecordToCopy() == NDBT_OK); @@ -736,7 +745,7 @@ int runCheckRollbackUpdate(NDBT_Context* ctx, NDBT_Step* step){ // Read value and save it for later CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, false, numRecords) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, numRecords) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); // Update value 0 CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -747,7 +756,7 @@ int runCheckRollbackUpdate(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Check record is updated - CHECK(hugoOps.pkReadRecord(pNdb, 1, true, numRecords) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, numRecords, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(5) == NDBT_OK); // Updates value 5 CHECK(hugoOps.execute_Rollback(pNdb) == 0); @@ -756,7 +765,7 @@ int runCheckRollbackUpdate(NDBT_Context* ctx, NDBT_Step* step){ // Check record is back to original value CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true, numRecords) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, numRecords, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); // Updates value 0 @@ -775,7 +784,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ do{ // Read value and save it for later CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, false, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -785,7 +794,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ for(Uint32 i = 0; i<1; i++){ // Read record 5 - 10 CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); for(j = 0; j<10; j++){ @@ -794,7 +803,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoOps.pkUpdateRecord(pNdb, 5, 10, updatesValue) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(updatesValue) == 0); } @@ -806,7 +815,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ #if 0 // Check records are deleted - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); #endif @@ -814,7 +823,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoOps.pkInsertRecord(pNdb, 5, 10, updatesValue) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(updatesValue) == 0); } @@ -823,7 +832,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Check records are deleted - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); @@ -833,7 +842,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ // Check records are not deleted // after rollback CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); @@ -853,7 +862,7 @@ int runCheckImplicitRollbackDelete(NDBT_Context* ctx, NDBT_Step* step){ do{ // Read record 5 CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -872,7 +881,7 @@ int runCheckImplicitRollbackDelete(NDBT_Context* ctx, NDBT_Step* step){ // Check record is not deleted // Close transaction should have rollbacked CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); }while(false); @@ -889,7 +898,7 @@ int runCheckCommitDelete(NDBT_Context* ctx, NDBT_Step* step){ do{ // Read 10 records CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Update 10 records @@ -905,7 +914,7 @@ int runCheckCommitDelete(NDBT_Context* ctx, NDBT_Step* step){ // Check record's are deleted CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 626); }while(false); @@ -930,7 +939,7 @@ int runRollbackNothing(NDBT_Context* ctx, NDBT_Step* step){ // Check records are not deleted CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -964,8 +973,8 @@ int runMassiveRollback(NDBT_Context* ctx, NDBT_Step* step){ for(int row = 0; row < records; row++){ int res; CHECK(hugoOps.startTransaction(pNdb) == 0); - for(int i = 0; i<OPS_TOTAL; i += OPS_PER_TRANS){ - for(int j = 0; j<OPS_PER_TRANS; j++){ + for(Uint32 i = 0; i<OPS_TOTAL; i += OPS_PER_TRANS){ + for(Uint32 j = 0; j<OPS_PER_TRANS; j++){ CHECK(hugoOps.pkUpdateRecord(pNdb, row, 1, i) == 0); } g_info << "Performed " << (i+OPS_PER_TRANS) << " updates on row: " << row @@ -1007,9 +1016,9 @@ runMassiveRollback2(NDBT_Context* ctx, NDBT_Step* step){ const Uint32 OPS_TOTAL = 4096; const Uint32 LOOPS = 10; - for(int loop = 0; loop<LOOPS; loop++){ + for(Uint32 loop = 0; loop<LOOPS; loop++){ CHECK(hugoOps.startTransaction(pNdb) == 0); - for(int i = 0; i<OPS_TOTAL-1; i ++){ + for(Uint32 i = 0; i<OPS_TOTAL-1; i ++){ if((i & 1) == 0){ CHECK(hugoOps.pkUpdateRecord(pNdb, 0, 1, loop) == 0); } else { @@ -1110,13 +1119,6 @@ TESTCASE("ReadWithLocksAndInserts", STEP(runInsertUntilStopped); FINALIZER(runClearTable); } -TESTCASE("ReadConsistency", - "Check that a read within a transaction returns the " \ - "same result no matter"){ - STEP(runInsertOne); - STEP(runReadOne); - FINALIZER(runClearTable2); -} TESTCASE("PkInsertTwice", "Verify that we can't insert an already inserted record." "Error should be returned" ){ @@ -1124,12 +1126,6 @@ TESTCASE("PkInsertTwice", STEP(runInsertTwice); FINALIZER(runClearTable); } -TESTCASE("Fill", - "Verify what happens when we fill the db" ){ - INITIALIZER(runFillTable); - INITIALIZER(runPkRead); - FINALIZER(runClearTable2); -} TESTCASE("NoCommitSleep", "Verify what happens when a NoCommit transaction is aborted by " "NDB because the application is sleeping" ){ @@ -1275,8 +1271,24 @@ TESTCASE("MassiveTransaction", INITIALIZER(runLoadTable2); FINALIZER(runClearTable2); } +TESTCASE("Fill", + "Verify what happens when we fill the db" ){ + INITIALIZER(runFillTable); + INITIALIZER(runPkRead); + FINALIZER(runClearTable2); +} NDBT_TESTSUITE_END(testBasic); +#if 0 +TESTCASE("ReadConsistency", + "Check that a read within a transaction returns the " \ + "same result no matter"){ + STEP(runInsertOne); + STEP(runReadOne); + FINALIZER(runClearTable2); +} +#endif + int main(int argc, const char** argv){ ndb_init(); return testBasic.execute(argc, argv); diff --git a/ndb/test/ndbapi/testIndex.cpp b/ndb/test/ndbapi/testIndex.cpp index bef3b310c96..aca8514c931 100644 --- a/ndb/test/ndbapi/testIndex.cpp +++ b/ndb/test/ndbapi/testIndex.cpp @@ -381,27 +381,6 @@ runVerifyIndex(NDBT_Context* ctx, NDBT_Step* step){ } int -sync_down(NDBT_Context* ctx){ - Uint32 threads = ctx->getProperty("PauseThreads", (unsigned)0); - if(threads){ - ctx->decProperty("PauseThreads"); - } - return 0; -} - -int -sync_up_and_wait(NDBT_Context* ctx){ - Uint32 threads = ctx->getProperty("Threads", (unsigned)0); - ndbout_c("Setting PauseThreads to %d", threads); - ctx->setProperty("PauseThreads", threads); - ctx->getPropertyWait("PauseThreads", (unsigned)0); - if(threads){ - ndbout_c("wait completed"); - } - return 0; -} - -int runTransactions1(NDBT_Context* ctx, NDBT_Step* step){ // Verify that data in index match // table data @@ -416,7 +395,7 @@ runTransactions1(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -425,7 +404,7 @@ runTransactions1(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); } return NDBT_OK; } @@ -446,7 +425,7 @@ runTransactions2(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } #endif - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; #if 1 @@ -455,7 +434,7 @@ runTransactions2(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } #endif - sync_down(ctx); + ctx->sync_down("PauseThreads"); } return NDBT_OK; } @@ -476,7 +455,7 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ g_err << "Load table failed" << endl; return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -485,7 +464,7 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -494,7 +473,7 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -503,7 +482,7 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -512,7 +491,7 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -521,14 +500,14 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; int count = -1; if(utilTrans.selectCount(pNdb, 64, &count) != 0 || count != 0) return NDBT_FAILED; - sync_down(ctx); + ctx->sync_down("PauseThreads"); } return NDBT_OK; } @@ -540,6 +519,7 @@ int runRestarts(NDBT_Context* ctx, NDBT_Step* step){ NdbRestarts restarts; int i = 0; int timeout = 240; + int sync_threads = ctx->getProperty("Threads", (unsigned)0); while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){ if(restarts.executeRestart("RestartRandomNodeAbort", timeout) != 0){ @@ -547,7 +527,7 @@ int runRestarts(NDBT_Context* ctx, NDBT_Step* step){ result = NDBT_FAILED; break; } - sync_up_and_wait(ctx); + ctx->sync_up_and_wait("PauseThreads", sync_threads); i++; } ctx->stopTest(); diff --git a/ndb/test/ndbapi/testNdbApi.cpp b/ndb/test/ndbapi/testNdbApi.cpp index 47987629fe3..74cb1f8bcd0 100644 --- a/ndb/test/ndbapi/testNdbApi.cpp +++ b/ndb/test/ndbapi/testNdbApi.cpp @@ -229,7 +229,7 @@ int runTestMaxOperations(NDBT_Context* ctx, NDBT_Step* step){ int i = 0; while (errors < maxErrors){ - if(hugoOps.pkReadRecord(pNdb,1, false, 1) != NDBT_OK){ + if(hugoOps.pkReadRecord(pNdb,1, 1) != NDBT_OK){ errors++; continue; } diff --git a/ndb/test/ndbapi/testNodeRestart.cpp b/ndb/test/ndbapi/testNodeRestart.cpp index 6bfe59f8d3f..e844f227034 100644 --- a/ndb/test/ndbapi/testNodeRestart.cpp +++ b/ndb/test/ndbapi/testNodeRestart.cpp @@ -100,11 +100,16 @@ int runScanReadUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ int runPkReadUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; int records = ctx->getNumRecords(); + NdbOperation::LockMode lm = + (NdbOperation::LockMode)ctx->getProperty("ReadLockMode", + (Uint32)NdbOperation::LM_Read); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (ctx->isTestStopped() == false) { g_info << i << ": "; - if (hugoTrans.pkReadRecords(GETNDB(step), records, 128) != 0){ + int rows = (rand()%records)+1; + int batch = (rand()%rows)+1; + if (hugoTrans.pkReadRecords(GETNDB(step), rows, batch, lm) != 0){ return NDBT_FAILED; } i++; @@ -119,7 +124,9 @@ int runPkUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ HugoTransactions hugoTrans(*ctx->getTab()); while (ctx->isTestStopped() == false) { g_info << i << ": "; - if (hugoTrans.pkUpdateRecords(GETNDB(step), records) != 0){ + int rows = (rand()%records)+1; + int batch = (rand()%rows)+1; + if (hugoTrans.pkUpdateRecords(GETNDB(step), rows, batch) != 0){ return NDBT_FAILED; } i++; @@ -127,6 +134,60 @@ int runPkUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int runPkReadPkUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ + int result = NDBT_OK; + int records = ctx->getNumRecords(); + Ndb* pNdb = GETNDB(step); + int i = 0; + HugoOperations hugoOps(*ctx->getTab()); + while (ctx->isTestStopped() == false) { + g_info << i++ << ": "; + int rows = (rand()%records)+1; + int batch = (rand()%rows)+1; + int row = (records - rows) ? rand() % (records - rows) : 0; + + int j,k; + for(j = 0; j<rows; j += batch) + { + k = batch; + if(j+k > rows) + k = rows - j; + + if(hugoOps.startTransaction(pNdb) != 0) + goto err; + + if(hugoOps.pkReadRecord(pNdb, row+j, k, NdbOperation::LM_Exclusive) != 0) + goto err; + + if(hugoOps.execute_NoCommit(pNdb) != 0) + goto err; + + if(hugoOps.pkUpdateRecord(pNdb, row+j, k, rand()) != 0) + goto err; + + if(hugoOps.execute_Commit(pNdb) != 0) + goto err; + + if(hugoOps.closeTransaction(pNdb) != 0) + return NDBT_FAILED; + } + + continue; +err: + NdbConnection* pCon = hugoOps.getTransaction(); + if(pCon == 0) + continue; + NdbError error = pCon->getNdbError(); + hugoOps.closeTransaction(pNdb); + if (error.status == NdbError::TemporaryError){ + NdbSleep_MilliSleep(50); + continue; + } + return NDBT_FAILED; + } + return NDBT_OK; +} + int runScanUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; int records = ctx->getNumRecords(); @@ -158,6 +219,7 @@ int runScanReadVerify(NDBT_Context* ctx, NDBT_Step* step){ int runRestarter(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; int loops = ctx->getNumLoops(); + int sync_threads = ctx->getProperty("SyncThreads", (unsigned)0); NdbRestarter restarter; int i = 0; int lastId = 0; @@ -174,11 +236,11 @@ int runRestarter(NDBT_Context* ctx, NDBT_Step* step){ loops *= restarter.getNumDbNodes(); while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){ - + int id = lastId % restarter.getNumDbNodes(); int nodeId = restarter.getDbNodeId(id); ndbout << "Restart node " << nodeId << endl; - if(restarter.restartOneDbNode(nodeId) != 0){ + if(restarter.restartOneDbNode(nodeId, false, false, true) != 0){ g_err << "Failed to restartNextDbNode" << endl; result = NDBT_FAILED; break; @@ -190,7 +252,7 @@ int runRestarter(NDBT_Context* ctx, NDBT_Step* step){ break; } - NdbSleep_SecSleep(1); + ctx->sync_up_and_wait("PauseThreads", sync_threads); lastId++; i++; @@ -234,6 +296,54 @@ int runRestarts(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int runDirtyRead(NDBT_Context* ctx, NDBT_Step* step){ + int result = NDBT_OK; + int loops = ctx->getNumLoops(); + int records = ctx->getNumRecords(); + NdbRestarter restarter; + HugoOperations hugoOps(*ctx->getTab()); + Ndb* pNdb = GETNDB(step); + + int i = 0; + while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){ + g_info << i << ": "; + + int id = i % restarter.getNumDbNodes(); + int nodeId = restarter.getDbNodeId(id); + ndbout << "Restart node " << nodeId << endl; + restarter.insertErrorInAllNodes(5041); + restarter.insertErrorInAllNodes(8048 + (i & 1)); + + for(int j = 0; j<records; j++){ + if(hugoOps.startTransaction(pNdb) != 0) + return NDBT_FAILED; + + if(hugoOps.pkReadRecord(pNdb, j, 1, NdbOperation::LM_CommittedRead) != 0) + goto err; + + int res; + if((res = hugoOps.execute_Commit(pNdb)) == 4119) + goto done; + + if(res != 0) + goto err; + + if(hugoOps.closeTransaction(pNdb) != 0) + return NDBT_FAILED; + } +done: + if(hugoOps.closeTransaction(pNdb) != 0) + return NDBT_FAILED; + + i++; + restarter.waitClusterStarted(60) ; + } + return result; +err: + hugoOps.closeTransaction(pNdb); + return NDBT_FAILED; +} + NDBT_TESTSUITE(testNodeRestart); TESTCASE("NoLoad", "Test that one node at a time can be stopped and then restarted "\ @@ -246,6 +356,27 @@ TESTCASE("NoLoad", TESTCASE("PkRead", "Test that one node at a time can be stopped and then restarted "\ "perform pk read while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", NdbOperation::LM_Read); + INITIALIZER(runCheckAllNodesStarted); + INITIALIZER(runLoadTable); + STEP(runRestarter); + STEP(runPkReadUntilStopped); + FINALIZER(runClearTable); +} +TESTCASE("PkReadCommitted", + "Test that one node at a time can be stopped and then restarted "\ + "perform pk read while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", NdbOperation::LM_CommittedRead); + INITIALIZER(runCheckAllNodesStarted); + INITIALIZER(runLoadTable); + STEP(runRestarter); + STEP(runPkReadUntilStopped); + FINALIZER(runClearTable); +} +TESTCASE("MixedPkRead", + "Test that one node at a time can be stopped and then restarted "\ + "perform pk read while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", -1); INITIALIZER(runCheckAllNodesStarted); INITIALIZER(runLoadTable); STEP(runRestarter); @@ -255,14 +386,31 @@ TESTCASE("PkRead", TESTCASE("PkReadPkUpdate", "Test that one node at a time can be stopped and then restarted "\ "perform pk read and pk update while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", NdbOperation::LM_Read); INITIALIZER(runCheckAllNodesStarted); INITIALIZER(runLoadTable); STEP(runRestarter); STEP(runPkReadUntilStopped); + STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); STEP(runPkReadUntilStopped); + STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); + FINALIZER(runClearTable); +} +TESTCASE("MixedPkReadPkUpdate", + "Test that one node at a time can be stopped and then restarted "\ + "perform pk read and pk update while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", -1); + INITIALIZER(runCheckAllNodesStarted); + INITIALIZER(runLoadTable); + STEP(runRestarter); STEP(runPkReadUntilStopped); + STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); STEP(runPkReadUntilStopped); STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); FINALIZER(runClearTable); } TESTCASE("ReadUpdateScan", @@ -273,6 +421,21 @@ TESTCASE("ReadUpdateScan", STEP(runRestarter); STEP(runPkReadUntilStopped); STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); + STEP(runScanReadUntilStopped); + STEP(runScanUpdateUntilStopped); + FINALIZER(runClearTable); +} +TESTCASE("MixedReadUpdateScan", + "Test that one node at a time can be stopped and then restarted "\ + "perform pk read, pk update and scan reads while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", -1); + INITIALIZER(runCheckAllNodesStarted); + INITIALIZER(runLoadTable); + STEP(runRestarter); + STEP(runPkReadUntilStopped); + STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); STEP(runScanReadUntilStopped); STEP(runScanUpdateUntilStopped); FINALIZER(runClearTable); @@ -431,6 +594,12 @@ TESTCASE("StopOnError", FINALIZER(runScanReadVerify); FINALIZER(runClearTable); } +TESTCASE("CommittedRead", + "Test committed read"){ + INITIALIZER(runLoadTable); + STEP(runDirtyRead); + FINALIZER(runClearTable); +} NDBT_TESTSUITE_END(testNodeRestart); int main(int argc, const char** argv){ diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp index f9eb3514926..214816a1ba1 100644 --- a/ndb/test/ndbapi/testOIBasic.cpp +++ b/ndb/test/ndbapi/testOIBasic.cpp @@ -212,6 +212,8 @@ struct Par : public Opt { // value calculation unsigned m_range; unsigned m_pctrange; + // choice of key + bool m_randomkey; // do verify after read bool m_verify; // deadlock possible @@ -227,6 +229,7 @@ struct Par : public Opt { m_totrows(m_threads * m_rows), m_range(m_rows), m_pctrange(0), + m_randomkey(false), m_verify(false), m_deadlock(false) { } @@ -1965,9 +1968,21 @@ BSet::calcpk(Par par, unsigned i) int BSet::setbnd(Par par) const { - for (unsigned j = 0; j < m_bvals; j++) { - const BVal& bval = *m_bval[j]; - CHK(bval.setbnd(par) == 0); + if (m_bvals != 0) { + unsigned p1 = urandom(m_bvals); + unsigned p2 = 10009; // prime + // random order + for (unsigned j = 0; j < m_bvals; j++) { + unsigned k = p1 + p2 * j; + const BVal& bval = *m_bval[k % m_bvals]; + CHK(bval.setbnd(par) == 0); + } + // duplicate + if (urandom(5) == 0) { + unsigned k = urandom(m_bvals); + const BVal& bval = *m_bval[k]; + CHK(bval.setbnd(par) == 0); + } } return 0; } @@ -2107,7 +2122,8 @@ pkupdate(Par par) Lst lst; bool deadlock = false; for (unsigned j = 0; j < par.m_rows; j++) { - unsigned i = thrrow(par, j); + unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); + unsigned i = thrrow(par, j2); set.lock(); if (! set.exist(i) || set.pending(i)) { set.unlock(); @@ -2710,6 +2726,7 @@ pkupdateindexbuild(Par par) if (par.m_no == 0) { CHK(createindex(par) == 0); } else { + par.m_randomkey = true; CHK(pkupdate(par) == 0); } return 0; diff --git a/ndb/test/ndbapi/testOperations.cpp b/ndb/test/ndbapi/testOperations.cpp index ba41e1d1c40..f31906dd737 100644 --- a/ndb/test/ndbapi/testOperations.cpp +++ b/ndb/test/ndbapi/testOperations.cpp @@ -86,7 +86,7 @@ OperationTestCase matrix[] = { { "DeleteRead", true, "DELETE", 0, 0, "READ", 626, 0, 0, 0 }, { "DeleteReadEx", true, "DELETE", 0, 0, "READ-EX", 626, 0, 0, 0 }, { "DeleteSimpleRead", true, "DELETE", 0, 0, "S-READ", 626, 0, 0, 0 }, - { "DeleteDirtyRead", true, "DELETE", 0, 0, "D-READ", 626, 0, 0, 0 }, + { "DeleteDirtyRead", true, "DELETE", 0, 0, "D-READ", 626, 0, 626, 0 }, { "DeleteInsert", true, "DELETE", 0, 0, "INSERT", 0, 1, 0, 1 }, { "DeleteUpdate", true, "DELETE", 0, 0, "UPDATE", 626, 1, 0, 0 }, { "DeleteDelete", true, "DELETE", 0, 0, "DELETE", 626, 0, 0, 0 } @@ -110,13 +110,13 @@ runOp(HugoOperations & hugoOps, return NDBT_FAILED; }} if(strcmp(op, "READ") == 0){ - C2(hugoOps.pkReadRecord(pNdb, 1, false, 1), 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read), 0); } else if(strcmp(op, "READ-EX") == 0){ - C2(hugoOps.pkReadRecord(pNdb, 1, true, 1), 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive), 0); } else if(strcmp(op, "S-READ") == 0){ - C2(hugoOps.pkSimpleReadRecord(pNdb, 1, 1), 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read), 0); } else if(strcmp(op, "D-READ") == 0){ - C2(hugoOps.pkDirtyReadRecord(pNdb, 1, 1), 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_CommittedRead), 0); } else if(strcmp(op, "INSERT") == 0){ C2(hugoOps.pkInsertRecord(pNdb, 1, 1, value), 0); } else if(strcmp(op, "UPDATE") == 0){ diff --git a/ndb/test/ndbapi/testRestartGci.cpp b/ndb/test/ndbapi/testRestartGci.cpp index 4cdfca29e6f..e817245af55 100644 --- a/ndb/test/ndbapi/testRestartGci.cpp +++ b/ndb/test/ndbapi/testRestartGci.cpp @@ -63,7 +63,7 @@ int runInsertRememberGci(NDBT_Context* ctx, NDBT_Step* step){ result = NDBT_FAILED; break; } - CHECK(hugoOps.pkReadRecord(pNdb, i, false) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, i) == 0); if (hugoOps.execute_Commit(pNdb) != 0){ ndbout << "Did not find record in DB " << i << endl; result = NDBT_FAILED; @@ -146,7 +146,7 @@ int runVerifyInserts(NDBT_Context* ctx, NDBT_Step* step){ // gci as in the vector for (unsigned i = 0; i < savedRecords.size(); i++){ CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, i, false) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, i) == 0); if (hugoOps.execute_Commit(pNdb) != 0){ // Record was not found in db' diff --git a/ndb/test/ndbapi/testTimeout.cpp b/ndb/test/ndbapi/testTimeout.cpp index 5cabb86541d..e310e12df81 100644 --- a/ndb/test/ndbapi/testTimeout.cpp +++ b/ndb/test/ndbapi/testTimeout.cpp @@ -108,7 +108,7 @@ int runTimeoutTrans(NDBT_Context* ctx, NDBT_Step* step){ do{ // Commit transaction CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, stepNo, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, stepNo) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); int sleep = minSleep + myRandom48(maxSleep-minSleep); @@ -162,25 +162,25 @@ int runTimeoutTrans2(NDBT_Context* ctx, NDBT_Step* step){ case 0: break; case 1: - if(hugoOps.pkReadRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkReadRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 2: - if(hugoOps.pkUpdateRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkUpdateRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 3: - if(hugoOps.pkDeleteRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkDeleteRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 4: - if(hugoOps.pkInsertRecord(pNdb, stepNo+records+l, true) != 0){ + if(hugoOps.pkInsertRecord(pNdb, stepNo+records+l) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } @@ -204,25 +204,25 @@ int runTimeoutTrans2(NDBT_Context* ctx, NDBT_Step* step){ case 0: break; case 1: - if(hugoOps.pkReadRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkReadRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 2: - if(hugoOps.pkUpdateRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkUpdateRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 3: - if(hugoOps.pkDeleteRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkDeleteRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 4: - if(hugoOps.pkInsertRecord(pNdb, stepNo+2*records+l, true) != 0){ + if(hugoOps.pkInsertRecord(pNdb, stepNo+2*records+l) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } @@ -263,7 +263,7 @@ int runDontTimeoutTrans(NDBT_Context* ctx, NDBT_Step* step){ do{ // Commit transaction CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, stepNo, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, stepNo) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); int sleep = myRandom48(maxSleep); @@ -299,7 +299,7 @@ int runBuddyTransNoTimeout(NDBT_Context* ctx, NDBT_Step* step){ // Start an insert trans CHECK(hugoOps.startTransaction(pNdb) == 0); int recordNo = records + (stepNo*loops) + l; - CHECK(hugoOps.pkInsertRecord(pNdb, recordNo, true) == 0); + CHECK(hugoOps.pkInsertRecord(pNdb, recordNo) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); for (int i = 0; i < 3; i++){ diff --git a/ndb/test/ndbapi/testTransactions.cpp b/ndb/test/ndbapi/testTransactions.cpp index 2dca9e24fb4..46be808d8a5 100644 --- a/ndb/test/ndbapi/testTransactions.cpp +++ b/ndb/test/ndbapi/testTransactions.cpp @@ -190,13 +190,13 @@ runOp(HugoOperations & hugoOps, return NDBT_FAILED; } if(strcmp(op, "READ") == 0){ - C2(hugoOps.pkReadRecord(pNdb, 1, false, 1) == 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); } else if(strcmp(op, "READ-EX") == 0){ - C2(hugoOps.pkReadRecord(pNdb, 1, true, 1) == 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); } else if(strcmp(op, "S-READ") == 0){ - C2(hugoOps.pkSimpleReadRecord(pNdb, 1, 1) == 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); } else if(strcmp(op, "D-READ") == 0){ - C2(hugoOps.pkDirtyReadRecord(pNdb, 1, 1) == 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_CommittedRead) == 0); } else if(strcmp(op, "INSERT") == 0){ C2(hugoOps.pkInsertRecord(pNdb, 1, 1, value) == 0); } else if(strcmp(op, "UPDATE") == 0){ diff --git a/ndb/test/run-test/daily-devel-tests.txt b/ndb/test/run-test/daily-devel-tests.txt index f2abc961807..5c0b2821d85 100644 --- a/ndb/test/run-test/daily-devel-tests.txt +++ b/ndb/test/run-test/daily-devel-tests.txt @@ -52,26 +52,30 @@ args: -n SR4 T6 # max-time: 1500 cmd: testSystemRestart -args: -n SR_FULLDB T1 +args: -n SR_FULLDB T6 # # NODE RESTARTS # max-time: 2500 cmd: testNodeRestart -args: -n NoLoad T6 T8 T13 +args: -n NoLoad T6 max-time: 2500 cmd: testNodeRestart -args: -n PkRead T6 T8 T13 +args: -n MixedPkRead T6 T8 T13 max-time: 2500 cmd: testNodeRestart -args: -l 1 -n PkReadPkUpdate +args: -l 1 -n MixedPkReadPkUpdate max-time: 2500 cmd: testNodeRestart -args: -l 1 -n ReadUpdateScan +args: -l 1 -n MixedReadUpdateScan + +max-time: 2500 +cmd: testNodeRestart +args: -n CommittedRead T1 max-time: 2500 cmd: testNodeRestart @@ -186,10 +190,6 @@ max-time: 2500 cmd: testDict args: -n NF1 T1 T6 T13 -max-time: 2500 -cmd: test_event -args: -n BasicEventOperation T1 T6 - # max-time: 1500 cmd: testSystemRestart @@ -206,3 +206,9 @@ args: -l 1 -n SR8 T1 max-time: 1500 cmd: testSystemRestart args: -l 1 -n SR9 T1 + +# +max-time: 2500 +cmd: test_event +args: -n BasicEventOperation T1 T6 + diff --git a/ndb/test/src/HugoOperations.cpp b/ndb/test/src/HugoOperations.cpp index 7c05cb86a93..e8e2d992345 100644 --- a/ndb/test/src/HugoOperations.cpp +++ b/ndb/test/src/HugoOperations.cpp @@ -52,8 +52,8 @@ NdbConnection* HugoOperations::getTransaction(){ int HugoOperations::pkReadRecord(Ndb* pNdb, int recordNo, - bool exclusive, - int numRecords){ + int numRecords, + NdbOperation::LockMode lm){ int a; allocRows(numRecords); int check; @@ -64,94 +64,22 @@ int HugoOperations::pkReadRecord(Ndb* pNdb, return NDBT_FAILED; } - if (exclusive == true) - check = pOp->readTupleExclusive(); - else +rand_lock_mode: + switch(lm){ + case NdbOperation::LM_Read: check = pOp->readTuple(); - if( check == -1 ) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - - // Define primary keys - for(a = 0; a<tab.getNoOfColumns(); a++){ - if (tab.getColumn(a)->getPrimaryKey() == true){ - if(equalForAttr(pOp, a, r+recordNo) != 0){ - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - } - } - - // Define attributes to read - for(a = 0; a<tab.getNoOfColumns(); a++){ - if((rows[r]->attributeStore(a) = - pOp->getValue(tab.getColumn(a)->getName())) == 0) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - } - } - return NDBT_OK; -} - -int HugoOperations::pkDirtyReadRecord(Ndb* pNdb, - int recordNo, - int numRecords){ - int a; - allocRows(numRecords); - int check; - for(int r=0; r < numRecords; r++){ - NdbOperation* pOp = pTrans->getNdbOperation(tab.getName()); - if (pOp == NULL) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - - check = pOp->dirtyRead(); - - if( check == -1 ) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - - // Define primary keys - for(a = 0; a<tab.getNoOfColumns(); a++){ - if (tab.getColumn(a)->getPrimaryKey() == true){ - if(equalForAttr(pOp, a, r+recordNo) != 0){ - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - } - } - - // Define attributes to read - for(a = 0; a<tab.getNoOfColumns(); a++){ - if((rows[r]->attributeStore(a) = - pOp->getValue(tab.getColumn(a)->getName())) == 0) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - } - } - return NDBT_OK; -} - -int HugoOperations::pkSimpleReadRecord(Ndb* pNdb, - int recordNo, - int numRecords){ - int a; - allocRows(numRecords); - int check; - for(int r=0; r < numRecords; r++){ - NdbOperation* pOp = pTrans->getNdbOperation(tab.getName()); - if (pOp == NULL) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; + break; + case NdbOperation::LM_Exclusive: + check = pOp->readTupleExclusive(); + break; + case NdbOperation::LM_CommittedRead: + check = pOp->dirtyRead(); + break; + default: + lm = (NdbOperation::LockMode)((rand() >> 16) & 3); + goto rand_lock_mode; } - check = pOp->simpleRead(); - if( check == -1 ) { ERR(pTrans->getNdbError()); return NDBT_FAILED; diff --git a/ndb/test/src/HugoTransactions.cpp b/ndb/test/src/HugoTransactions.cpp index 994a45de3dc..456bfffbb77 100644 --- a/ndb/test/src/HugoTransactions.cpp +++ b/ndb/test/src/HugoTransactions.cpp @@ -1230,7 +1230,7 @@ int HugoTransactions::pkReadRecords(Ndb* pNdb, int records, int batchsize, - bool dirty){ + NdbOperation::LockMode lm){ int reads = 0; int r = 0; int retryAttempt = 0; @@ -1275,11 +1275,22 @@ HugoTransactions::pkReadRecords(Ndb* pNdb, return NDBT_FAILED; } - if (dirty == true){ - check = pOp->dirtyRead(); - } else { + rand_lock_mode: + switch(lm){ + case NdbOperation::LM_Read: check = pOp->readTuple(); + break; + case NdbOperation::LM_Exclusive: + check = pOp->readTupleExclusive(); + break; + case NdbOperation::LM_CommittedRead: + check = pOp->dirtyRead(); + break; + default: + lm = (NdbOperation::LockMode)((rand() >> 16) & 3); + goto rand_lock_mode; } + if( check == -1 ) { ERR(pTrans->getNdbError()); pNdb->closeTransaction(pTrans); diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp index 4ff94bcf296..24446f08947 100644 --- a/ndb/test/src/NDBT_Test.cpp +++ b/ndb/test/src/NDBT_Test.cpp @@ -1150,6 +1150,20 @@ void NDBT_Step::print(){ } +void +NDBT_Context::sync_down(const char * key){ + Uint32 threads = getProperty(key, (unsigned)0); + if(threads){ + decProperty(key); + } +} + +void +NDBT_Context::sync_up_and_wait(const char * key, Uint32 value){ + setProperty(key, value); + getPropertyWait(key, (unsigned)0); +} + template class Vector<NDBT_TestCase*>; template class Vector<NDBT_TestCaseResult*>; template class Vector<NDBT_Step*>; diff --git a/ndb/test/src/UtilTransactions.cpp b/ndb/test/src/UtilTransactions.cpp index 52341c0e0e6..c0e6effd244 100644 --- a/ndb/test/src/UtilTransactions.cpp +++ b/ndb/test/src/UtilTransactions.cpp @@ -383,11 +383,20 @@ UtilTransactions::clearTable3(Ndb* pNdb, pOp = pTrans->getNdbScanOperation(tab.getName()); if (pOp == NULL) { + err = pTrans->getNdbError(); + if(err.status == NdbError::TemporaryError){ + ERR(err); + pNdb->closeTransaction(pTrans); + NdbSleep_MilliSleep(50); + par = 1; + goto restart; + } goto failed; } NdbResultSet * rs = pOp->readTuplesExclusive(par); if( rs == 0 ) { + err = pTrans->getNdbError(); goto failed; } @@ -647,8 +656,16 @@ UtilTransactions::scanReadRecords(Ndb* pNdb, pOp = pTrans->getNdbScanOperation(tab.getName()); if (pOp == NULL) { - ERR(pTrans->getNdbError()); + const NdbError err = pNdb->getNdbError(); pNdb->closeTransaction(pTrans); + + if (err.status == NdbError::TemporaryError){ + ERR(err); + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } + ERR(err); return NDBT_FAILED; } @@ -934,8 +951,15 @@ UtilTransactions::scanAndCompareUniqueIndex(Ndb* pNdb, pOp = pTrans->getNdbScanOperation(tab.getName()); if (pOp == NULL) { - ERR(pTrans->getNdbError()); + const NdbError err = pNdb->getNdbError(); pNdb->closeTransaction(pTrans); + ERR(err); + + if (err.status == NdbError::TemporaryError){ + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } return NDBT_FAILED; } |