summaryrefslogtreecommitdiff
path: root/ndb
diff options
context:
space:
mode:
Diffstat (limited to 'ndb')
-rw-r--r--ndb/include/kernel/LogLevel.hpp2
-rw-r--r--ndb/include/kernel/signaldata/TcContinueB.hpp4
-rw-r--r--ndb/include/kernel/signaldata/TcKeyConf.hpp3
-rw-r--r--ndb/include/kernel/signaldata/TuxBound.hpp1
-rw-r--r--ndb/include/mgmapi/mgmapi.h11
-rw-r--r--ndb/include/ndbapi/Ndb.hpp4
-rw-r--r--ndb/include/ndbapi/NdbConnection.hpp17
-rw-r--r--ndb/include/ndbapi/NdbIndexScanOperation.hpp46
-rw-r--r--ndb/include/ndbapi/NdbOperation.hpp7
-rw-r--r--ndb/include/ndbapi/NdbReceiver.hpp5
-rw-r--r--ndb/include/util/version.h2
-rw-r--r--ndb/src/common/debugger/signaldata/SignalNames.cpp2
-rw-r--r--ndb/src/common/debugger/signaldata/TcKeyConf.cpp42
-rw-r--r--ndb/src/common/util/version.c2
-rw-r--r--ndb/src/kernel/blocks/ERROR_codes.txt4
-rw-r--r--ndb/src/kernel/blocks/dblqh/Dblqh.hpp5
-rw-r--r--ndb/src/kernel/blocks/dblqh/DblqhMain.cpp56
-rw-r--r--ndb/src/kernel/blocks/dbtc/Dbtc.hpp2
-rw-r--r--ndb/src/kernel/blocks/dbtc/DbtcMain.cpp196
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupLCP.cpp3
-rw-r--r--ndb/src/kernel/blocks/dbtux/Dbtux.hpp122
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp66
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp51
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp4
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp4
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp14
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp34
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp158
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp74
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp52
-rw-r--r--ndb/src/kernel/blocks/dbtux/Times.txt12
-rw-r--r--ndb/src/mgmapi/mgmapi.cpp9
-rw-r--r--ndb/src/mgmclient/CommandInterpreter.cpp83
-rw-r--r--ndb/src/mgmsrv/ConfigInfo.cpp2
-rw-r--r--ndb/src/mgmsrv/Services.cpp1
-rw-r--r--ndb/src/ndbapi/Ndb.cpp1
-rw-r--r--ndb/src/ndbapi/NdbApiSignal.cpp2
-rw-r--r--ndb/src/ndbapi/NdbBlob.cpp2
-rw-r--r--ndb/src/ndbapi/NdbConnection.cpp85
-rw-r--r--ndb/src/ndbapi/NdbIndexOperation.cpp41
-rw-r--r--ndb/src/ndbapi/NdbOperationDefine.cpp10
-rw-r--r--ndb/src/ndbapi/NdbOperationExec.cpp57
-rw-r--r--ndb/src/ndbapi/NdbReceiver.cpp12
-rw-r--r--ndb/src/ndbapi/NdbScanFilter.cpp2
-rw-r--r--ndb/src/ndbapi/NdbScanOperation.cpp3
-rw-r--r--ndb/src/ndbapi/Ndbif.cpp14
-rw-r--r--ndb/src/ndbapi/Ndbinit.cpp5
-rw-r--r--ndb/src/ndbapi/Ndblist.cpp8
-rw-r--r--ndb/src/ndbapi/ndberror.c9
-rw-r--r--ndb/test/include/HugoOperations.hpp12
-rw-r--r--ndb/test/include/HugoTransactions.hpp4
-rw-r--r--ndb/test/include/NDBT_Test.hpp6
-rw-r--r--ndb/test/ndbapi/testBasic.cpp138
-rw-r--r--ndb/test/ndbapi/testIndex.cpp46
-rw-r--r--ndb/test/ndbapi/testNdbApi.cpp2
-rw-r--r--ndb/test/ndbapi/testNodeRestart.cpp179
-rw-r--r--ndb/test/ndbapi/testOIBasic.cpp25
-rw-r--r--ndb/test/ndbapi/testOperations.cpp10
-rw-r--r--ndb/test/ndbapi/testRestartGci.cpp4
-rw-r--r--ndb/test/ndbapi/testTimeout.cpp22
-rw-r--r--ndb/test/ndbapi/testTransactions.cpp8
-rw-r--r--ndb/test/run-test/daily-devel-tests.txt24
-rw-r--r--ndb/test/src/HugoOperations.cpp102
-rw-r--r--ndb/test/src/HugoTransactions.cpp19
-rw-r--r--ndb/test/src/NDBT_Test.cpp14
-rw-r--r--ndb/test/src/UtilTransactions.cpp28
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;
}