summaryrefslogtreecommitdiff
path: root/ndb
diff options
context:
space:
mode:
Diffstat (limited to 'ndb')
-rw-r--r--ndb/include/kernel/GlobalSignalNumbers.h9
-rw-r--r--ndb/include/kernel/ndb_limits.h2
-rw-r--r--ndb/include/kernel/signaldata/TupAccess.hpp174
-rw-r--r--ndb/include/ndbapi/NdbIndexScanOperation.hpp27
-rw-r--r--ndb/src/common/debugger/signaldata/Makefile.am3
-rw-r--r--ndb/src/common/debugger/signaldata/SignalDataPrint.cpp4
-rw-r--r--ndb/src/common/debugger/signaldata/SignalNames.cpp3
-rw-r--r--ndb/src/common/debugger/signaldata/TupAccess.cpp131
-rw-r--r--ndb/src/cw/cpcd/Makefile.am2
-rw-r--r--ndb/src/cw/cpcd/Process.cpp78
-rw-r--r--ndb/src/kernel/blocks/dblqh/Dblqh.hpp3
-rw-r--r--ndb/src/kernel/blocks/dblqh/DblqhMain.cpp128
-rw-r--r--ndb/src/kernel/blocks/dbtup/Dbtup.hpp13
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupGen.cpp3
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp286
-rw-r--r--ndb/src/kernel/blocks/dbtux/Dbtux.hpp162
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp256
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp95
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp45
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp112
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp2
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp35
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp201
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp333
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp106
-rw-r--r--ndb/src/kernel/blocks/dbtux/Makefile.am1
-rw-r--r--ndb/src/kernel/blocks/dbtux/Times.txt47
-rw-r--r--ndb/src/mgmapi/Makefile.am5
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.cpp12
-rw-r--r--ndb/src/ndbapi/NdbScanOperation.cpp25
-rw-r--r--ndb/src/ndbapi/Ndbif.cpp94
-rw-r--r--ndb/test/ndbapi/testBasic.cpp8
-rw-r--r--ndb/test/ndbapi/testOIBasic.cpp989
-rw-r--r--ndb/test/run-test/daily-basic-tests.txt62
-rw-r--r--ndb/test/run-test/main.cpp26
-rw-r--r--ndb/test/src/HugoTransactions.cpp2
36 files changed, 1836 insertions, 1648 deletions
diff --git a/ndb/include/kernel/GlobalSignalNumbers.h b/ndb/include/kernel/GlobalSignalNumbers.h
index a16860561b5..8941fa6b381 100644
--- a/ndb/include/kernel/GlobalSignalNumbers.h
+++ b/ndb/include/kernel/GlobalSignalNumbers.h
@@ -897,12 +897,9 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES;
#define GSN_TUX_MAINT_CONF 678
#define GSN_TUX_MAINT_REF 679
-/*
- * TUP access
- */
-#define GSN_TUP_READ_ATTRS 680
-#define GSN_TUP_QUERY_TH 712
-#define GSN_TUP_STORE_TH 681
+// not used 680
+// not used 712
+// not used 681
/**
* from mgmtsrvr to NDBCNTR
diff --git a/ndb/include/kernel/ndb_limits.h b/ndb/include/kernel/ndb_limits.h
index 68ffe310328..f35cc617e86 100644
--- a/ndb/include/kernel/ndb_limits.h
+++ b/ndb/include/kernel/ndb_limits.h
@@ -88,7 +88,7 @@
* Ordered index constants. Make configurable per index later.
*/
#define MAX_TTREE_NODE_SIZE 64 // total words in node
-#define MAX_TTREE_PREF_SIZE 4 // words in min/max prefix each
+#define MAX_TTREE_PREF_SIZE 4 // words in min prefix
#define MAX_TTREE_NODE_SLACK 3 // diff between max and min occupancy
/*
diff --git a/ndb/include/kernel/signaldata/TupAccess.hpp b/ndb/include/kernel/signaldata/TupAccess.hpp
deleted file mode 100644
index ab56a73322c..00000000000
--- a/ndb/include/kernel/signaldata/TupAccess.hpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#ifndef TUP_ACCESS_HPP
-#define TUP_ACCESS_HPP
-
-#include "SignalData.hpp"
-
-/*
- * Direct signals used by ACC and TUX to access the TUP block in the
- * same thread.
- *
- * NOTE: Caller must set errorCode to RNIL. Signal printer uses this to
- * distinguish between input and output (no better way exists).
- */
-
-/*
- * Read attributes from any table.
- */
-class TupReadAttrs {
- friend class Dbtup;
- friend class Dbacc;
- friend class Dbtux;
- friend bool printTUP_READ_ATTRS(FILE*, const Uint32*, Uint32, Uint16);
-public:
- enum Flag {
- /*
- * Read primary key attributes. No input attribute ids are
- * specified. Instead TUP fills in both input and output sections.
- * Tuple version is not used.
- */
- ReadKeys = (1 << 0)
- };
- STATIC_CONST( SignalLength = 10 );
-private:
- /*
- * Error code set by TUP. Zero means no error.
- */
- Uint32 errorCode;
- /*
- * Request info contains flags (see Flags above).
- */
- Uint32 requestInfo;
- /*
- * Table i-value.
- */
- Uint32 tableId;
- /*
- * Fragment is given by logical id within the table or by direct
- * i-value (faster). Unknown values are given as RNIL. On return TUP
- * fills in both values.
- */
- Uint32 fragId;
- Uint32 fragPtrI;
- /*
- * Logical address ("local key") of "original" tuple (the latest
- * version) consisting of logical fragment page id and tuple index
- * within the page (shifted left by 1).
- */
- Uint32 tupAddr;
- /*
- * Version of the tuple to read. Not used if ReadKeys.
- */
- Uint32 tupVersion;
- /*
- * Real page id and offset of the "original" tuple. Unknown page is
- * given as RNIL. On return TUP fills in these.
- */
- Uint32 pageId;
- Uint32 pageOffset;
- /*
- * Shared buffer id. Currently must be 0 which means to use rest of
- * signal data.
- */
- Uint32 bufferId;
- /*
- * Shared buffer 0 starts after signal class. Input is number of
- * attributes and list of attribute ids in AttributeHeader format.
- * Output is placed after the input and consists of a list of entries
- * where each entry has an AttributeHeader followed by words of data.
- */
-};
-
-/*
- * Query status of tuple version. Used by TUX to decide if a tuple
- * version found in index tree is visible to the transaction.
- */
-class TupQueryTh {
- friend class Dbtup;
- friend class Dbtux;
- friend bool printTUP_QUERY_TH(FILE*, const Uint32*, Uint32, Uint16);
-public:
- enum Flag {
- };
- STATIC_CONST( SignalLength = 7 );
-private:
- /*
- TUX wants to check if tuple is visible to the scan query.
- Input data is tuple address (tableId, fragId, tupAddr, tupVersion),
- and transaction data so that TUP knows how to deduct if tuple is
- visible (transId1, transId2, savePointId).
- returnCode is set in return signal to indicate whether tuple is visible.
- */
- union {
- Uint32 returnCode; // 1 if tuple visible
- Uint32 tableId;
- };
- Uint32 fragId;
- Uint32 tupAddr;
- Uint32 tupVersion;
- Uint32 transId1;
- Uint32 transId2;
- Uint32 savePointId;
-};
-
-/*
- * Operate on entire tuple. Used by TUX where the table has a single
- * Uint32 array attribute representing an index tree node.
- *
- * XXX this signal is no longer used by TUX and can be removed
- */
-class TupStoreTh {
- friend class Dbtup;
- friend class Dbtux;
- friend bool printTUP_STORE_TH(FILE*, const Uint32*, Uint32, Uint16);
-public:
- enum OpCode {
- OpUndefined = 0,
- OpRead = 1,
- OpInsert = 2,
- OpUpdate = 3,
- OpDelete = 4
- };
- STATIC_CONST( SignalLength = 12 );
-private:
- /*
- * These are as in TupReadAttrs (except opCode). Version must be
- * zero. Ordered index tuple (tree node) has only current version.
- */
- Uint32 errorCode;
- Uint32 opCode;
- Uint32 tableId;
- Uint32 fragId;
- Uint32 fragPtrI;
- Uint32 tupAddr;
- Uint32 tupVersion;
- Uint32 pageId;
- Uint32 pageOffset;
- Uint32 bufferId;
- /*
- * Data offset and size in words. Applies to both the buffer and the
- * tuple. Used e.g. to read only node header.
- */
- Uint32 dataOffset;
- Uint32 dataSize;
- /*
- * Shared buffer 0 starts after signal class.
- */
-};
-
-#endif
diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp
index f854fa93945..82aed04a9fc 100644
--- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp
+++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp
@@ -86,26 +86,25 @@ public:
/**
* Define bound on index key in range scan.
*
- * Each index key can have not null lower and/or upper bound, or can
- * be set equal to not null 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, or can be set
+ * equal to a value. The bounds can be defined in any order but
+ * a duplicate definition is an error.
*
- * The scan is most effective when bounds are given for an initial
- * sequence of non-nullable index keys, and all but the last one is an
- * equality. In this case the scan returns a contiguous range from
- * each ordered index fragment.
+ * 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.
*
- * @note This release implements only the case described above,
- * except for the non-nullable limitation. Other sets of
- * bounds return error or empty result set.
+ * 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
+ * setBound with null pointer (0).
*
- * @note In this release a null key value satisfies any lower
- * bound and no upper bound. This may change.
+ * An index stores also all-NULL keys (this may become optional).
+ * Doing index scan with empty bound set returns all table tuples.
*
* @param attrName Attribute name, alternatively:
- * @param anAttrId Index column id (starting from 0).
+ * @param anAttrId Index column id (starting from 0)
* @param type Type of bound
- * @param value Pointer to bound value
+ * @param value Pointer to bound value, 0 for NULL
* @param len Value length in bytes.
* Fixed per datatype and can be omitted
* @return 0 if successful otherwise -1
diff --git a/ndb/src/common/debugger/signaldata/Makefile.am b/ndb/src/common/debugger/signaldata/Makefile.am
index 0d6ed45dcef..0a5806e1e00 100644
--- a/ndb/src/common/debugger/signaldata/Makefile.am
+++ b/ndb/src/common/debugger/signaldata/Makefile.am
@@ -22,7 +22,7 @@ libsignaldataprint_la_SOURCES = \
CopyGCI.cpp SystemError.cpp StartRec.cpp NFCompleteRep.cpp \
FailRep.cpp DisconnectRep.cpp SignalDroppedRep.cpp \
SumaImpl.cpp NdbSttor.cpp CreateFragmentation.cpp \
- UtilLock.cpp TuxMaint.cpp TupAccess.cpp AccLock.cpp \
+ UtilLock.cpp TuxMaint.cpp AccLock.cpp \
LqhTrans.cpp ReadNodesConf.cpp CntrStart.cpp
include $(top_srcdir)/ndb/config/common.mk.am
@@ -30,3 +30,4 @@ include $(top_srcdir)/ndb/config/type_ndbapi.mk.am
# Don't update the files from bitkeeper
%::SCCS/s.%
+
diff --git a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp
index 6227a9994d1..65351663789 100644
--- a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp
+++ b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp
@@ -73,7 +73,6 @@
#include <signaldata/CntrStart.hpp>
#include <signaldata/ReadNodesConf.hpp>
#include <signaldata/TuxMaint.hpp>
-#include <signaldata/TupAccess.hpp>
#include <signaldata/AccLock.hpp>
bool printCONTINUEB(FILE *, const Uint32 *, Uint32, Uint16);
@@ -249,9 +248,6 @@ SignalDataPrintFunctions[] = {
,{ GSN_READ_NODESCONF, printREAD_NODES_CONF }
,{ GSN_TUX_MAINT_REQ, printTUX_MAINT_REQ }
- ,{ GSN_TUP_READ_ATTRS, printTUP_READ_ATTRS }
- ,{ GSN_TUP_QUERY_TH, printTUP_QUERY_TH }
- ,{ GSN_TUP_STORE_TH, printTUP_STORE_TH }
,{ GSN_ACC_LOCKREQ, printACC_LOCKREQ }
,{ GSN_LQH_TRANSCONF, printLQH_TRANSCONF }
};
diff --git a/ndb/src/common/debugger/signaldata/SignalNames.cpp b/ndb/src/common/debugger/signaldata/SignalNames.cpp
index bb492fa0411..9d4d5bdf6f5 100644
--- a/ndb/src/common/debugger/signaldata/SignalNames.cpp
+++ b/ndb/src/common/debugger/signaldata/SignalNames.cpp
@@ -640,9 +640,6 @@ const GsnName SignalNames [] = {
,{ GSN_TUX_MAINT_REQ, "TUX_MAINT_REQ" }
,{ GSN_TUX_MAINT_CONF, "TUX_MAINT_CONF" }
,{ GSN_TUX_MAINT_REF, "TUX_MAINT_REF" }
- ,{ GSN_TUP_READ_ATTRS, "TUP_READ_ATTRS" }
- ,{ GSN_TUP_QUERY_TH, "TUP_QUERY_TH" }
- ,{ GSN_TUP_STORE_TH, "TUP_STORE_TH" }
,{ GSN_TUX_BOUND_INFO, "TUX_BOUND_INFO" }
,{ GSN_ACC_LOCKREQ, "ACC_LOCKREQ" }
diff --git a/ndb/src/common/debugger/signaldata/TupAccess.cpp b/ndb/src/common/debugger/signaldata/TupAccess.cpp
deleted file mode 100644
index e94d4636cf5..00000000000
--- a/ndb/src/common/debugger/signaldata/TupAccess.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include <signaldata/TupAccess.hpp>
-#include <SignalLoggerManager.hpp>
-#include <AttributeHeader.hpp>
-
-bool
-printTUP_READ_ATTRS(FILE* output, const Uint32* theData, Uint32 len, Uint16 rbn)
-{
- const TupReadAttrs* const sig = (const TupReadAttrs*)theData;
- if (sig->errorCode == RNIL)
- fprintf(output, " errorCode=RNIL flags=%x\n", sig->requestInfo);
- else
- fprintf(output, " errorCode=%u flags=%x\n", sig->errorCode, sig->requestInfo);
- fprintf(output, " table: id=%u", sig->tableId);
- fprintf(output, " fragment: id=%u ptr=0x%x\n", sig->fragId, sig->fragPtrI);
- fprintf(output, " tuple: addr=0x%x version=%u", sig->tupAddr, sig->tupVersion);
- fprintf(output, " realPage=0x%x offset=%u\n", sig->pageId, sig->pageOffset);
- const Uint32* buffer = (const Uint32*)sig + TupReadAttrs::SignalLength;
- Uint32 attrCount = buffer[0];
- bool readKeys = (sig->requestInfo & TupReadAttrs::ReadKeys);
- if (sig->errorCode == RNIL && ! readKeys ||
- sig->errorCode == 0 && readKeys) {
- fprintf(output, " input: attrCount=%u\n", attrCount);
- for (unsigned i = 0; i < attrCount; i++) {
- AttributeHeader ah(buffer[1 + i]);
- fprintf(output, " %u: attrId=%u\n", i, ah.getAttributeId());
- }
- }
- if (sig->errorCode == 0) {
- fprintf(output, " output: attrCount=%u\n", attrCount);
- Uint32 pos = 1 + attrCount;
- for (unsigned i = 0; i < attrCount; i++) {
- AttributeHeader ah(buffer[pos++]);
- fprintf(output, " %u: attrId=%u dataSize=%u\n", i, ah.getAttributeId(), ah.getDataSize());
- Uint32 next = pos + ah.getDataSize();
- Uint32 printpos = 0;
- while (pos < next) {
- SignalLoggerManager::printDataWord(output, printpos, buffer[pos]);
- pos++;
- }
- if (ah.getDataSize() > 0)
- fprintf(output, "\n");
- }
- }
- return true;
-}
-
-bool
-printTUP_QUERY_TH(FILE* output, const Uint32* theData, Uint32 len, Uint16 rbn)
-{
- const TupQueryTh* const sig = (const TupQueryTh*)theData;
- fprintf(output, "tableId = %u, fragId = %u ", sig->tableId, sig->fragId);
- fprintf(output, "tuple: addr = 0x%x version = %u\n", sig->tupAddr,
- sig->tupVersion);
- fprintf(output, "transId1 = 0x%x, transId2 = 0x%x, savePointId = %u\n",
- sig->transId1, sig->transId2, sig->savePointId);
- return true;
-}
-
-bool
-printTUP_STORE_TH(FILE* output, const Uint32* theData, Uint32 len, Uint16 rbn)
-{
- const TupStoreTh* const sig = (const TupStoreTh*)theData;
- if (sig->errorCode == RNIL)
- fprintf(output, " errorCode=RNIL\n");
- else
- fprintf(output, " errorCode=%u\n", sig->errorCode);
- fprintf(output, " table: id=%u", sig->tableId);
- fprintf(output, " fragment: id=%u ptr=0x%x\n", sig->fragId, sig->fragPtrI);
- fprintf(output, " tuple: addr=0x%x", sig->tupAddr);
- if ((sig->tupAddr & 0x1) == 0) {
- fprintf(output, " fragPage=0x%x index=%u",
- sig->tupAddr >> MAX_TUPLES_BITS,
- (sig->tupAddr & ((1 <<MAX_TUPLES_BITS) - 1)) >> 1);
- fprintf(output, " realPage=0x%x offset=%u\n", sig->pageId, sig->pageOffset);
- } else {
- fprintf(output, " cacheId=%u\n",
- sig->tupAddr >> 1);
- }
- if (sig->tupVersion != 0) {
- fprintf(output, " version=%u ***invalid***\n", sig->tupVersion);
- }
- bool showdata = true;
- switch (sig->opCode) {
- case TupStoreTh::OpRead:
- fprintf(output, " operation=Read\n");
- showdata = false;
- break;
- case TupStoreTh::OpInsert:
- fprintf(output, " operation=Insert\n");
- break;
- case TupStoreTh::OpUpdate:
- fprintf(output, " operation=Update\n");
- break;
- case TupStoreTh::OpDelete:
- fprintf(output, " operation=Delete\n");
- showdata = false;
- break;
- default:
- fprintf(output, " operation=%u ***invalid***\n", sig->opCode);
- break;
- }
- fprintf(output, " data: offset=%u size=%u", sig->dataOffset, sig->dataSize);
- if (! showdata) {
- fprintf(output, " [not printed]\n");
- } else {
- fprintf(output, "\n");
- const Uint32* buffer = (const Uint32*)sig + TupStoreTh::SignalLength;
- Uint32 pos = 0;
- while (pos < sig->dataSize)
- SignalLoggerManager::printDataWord(output, pos, buffer[sig->dataOffset + pos]);
- if (sig->dataSize > 0)
- fprintf(output, "\n");
- }
- return true;
-};
diff --git a/ndb/src/cw/cpcd/Makefile.am b/ndb/src/cw/cpcd/Makefile.am
index 6345bae9bbe..1f7b0d88448 100644
--- a/ndb/src/cw/cpcd/Makefile.am
+++ b/ndb/src/cw/cpcd/Makefile.am
@@ -1,5 +1,5 @@
-ndbtools_PROGRAMS = ndb_cpcd
+ndbbin_PROGRAMS = ndb_cpcd
ndb_cpcd_SOURCES = main.cpp CPCD.cpp Process.cpp APIService.cpp Monitor.cpp common.cpp
diff --git a/ndb/src/cw/cpcd/Process.cpp b/ndb/src/cw/cpcd/Process.cpp
index 28548818b31..a67dba95dc7 100644
--- a/ndb/src/cw/cpcd/Process.cpp
+++ b/ndb/src/cw/cpcd/Process.cpp
@@ -209,49 +209,45 @@ int
set_ulimit(const BaseString & pair){
#ifdef HAVE_GETRLIMIT
errno = 0;
- do {
- Vector<BaseString> list;
- pair.split(list, ":");
- if(list.size() != 2){
- break;
- }
-
- int res;
- rlim_t value = RLIM_INFINITY;
- if(!(list[1].trim() == "unlimited")){
- value = atoi(list[1].c_str());
- }
-
- struct rlimit rlp;
+ Vector<BaseString> list;
+ pair.split(list, ":");
+ if(list.size() != 2){
+ logger.error("Unable to process ulimit: split >%s< list.size()=%d",
+ pair.c_str(), list.size());
+ return -1;
+ }
+
+ int res;
+ rlim_t value = RLIM_INFINITY;
+ if(!(list[1].trim() == "unlimited")){
+ value = atoi(list[1].c_str());
+ }
+
+ struct rlimit rlp;
#define _RLIMIT_FIX(x) { res = getrlimit(x,&rlp); if(!res){ rlp.rlim_cur = value; res = setrlimit(x, &rlp); }}
-
- if(list[0].trim() == "c"){
- _RLIMIT_FIX(RLIMIT_CORE);
- } else if(list[0] == "d"){
- _RLIMIT_FIX(RLIMIT_DATA);
- } else if(list[0] == "f"){
- _RLIMIT_FIX(RLIMIT_FSIZE);
- } else if(list[0] == "n"){
- _RLIMIT_FIX(RLIMIT_NOFILE);
- } else if(list[0] == "s"){
- _RLIMIT_FIX(RLIMIT_STACK);
- } else if(list[0] == "t"){
- _RLIMIT_FIX(RLIMIT_CPU);
- } else {
- errno = EINVAL;
- break;
- }
- if(!res)
- break;
-
- return 0;
- } while(false);
- logger.error("Unable to process ulimit: %s(%s)",
- pair.c_str(), strerror(errno));
- return -1;
-#else
- return 0; // Maybe it's ok anyway...
+
+ if(list[0].trim() == "c"){
+ _RLIMIT_FIX(RLIMIT_CORE);
+ } else if(list[0] == "d"){
+ _RLIMIT_FIX(RLIMIT_DATA);
+ } else if(list[0] == "f"){
+ _RLIMIT_FIX(RLIMIT_FSIZE);
+ } else if(list[0] == "n"){
+ _RLIMIT_FIX(RLIMIT_NOFILE);
+ } else if(list[0] == "s"){
+ _RLIMIT_FIX(RLIMIT_STACK);
+ } else if(list[0] == "t"){
+ _RLIMIT_FIX(RLIMIT_CPU);
+ } else {
+ errno = EINVAL;
+ }
+ if(res){
+ logger.error("Unable to process ulimit: %s res=%d error=%d(%s)",
+ pair.c_str(), res, errno, strerror(errno));
+ return -1;
+ }
#endif
+ return 0;
}
void
diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
index 824f74c59af..e0994955818 100644
--- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
+++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
@@ -410,7 +410,6 @@
*/
class Dblqh: public SimulatedBlock {
public:
-
enum LcpCloseState {
LCP_IDLE = 0,
LCP_RUNNING = 1, // LCP is running
@@ -1990,7 +1989,6 @@ public:
UintR nextTcLogQueue;
UintR nextTc;
UintR nextTcConnectrec;
- Uint16 nodeAfterNext[2];
UintR prevHashRec;
UintR prevLogTcrec;
UintR prevTc;
@@ -2027,6 +2025,7 @@ public:
Uint16 nextReplica;
Uint16 primKeyLen;
Uint16 save1;
+ Uint16 nodeAfterNext[3];
Uint8 activeCreat;
Uint8 apiVersionNo;
diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
index 71e5aa5c0bc..eb8e2917a8e 100644
--- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
+++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
@@ -3574,7 +3574,6 @@ void Dblqh::prepareContinueAfterBlockedLab(Signal* signal)
key.scanNumber = KeyInfo20::getScanNo(regTcPtr->tcScanInfo);
key.fragPtrI = fragptr.i;
c_scanTakeOverHash.find(scanptr, key);
- ndbassert(scanptr.i != RNIL);
}
if (scanptr.i == RNIL) {
jam();
@@ -5995,10 +5994,15 @@ void Dblqh::abortStateHandlerLab(Signal* signal)
break;
case TcConnectionrec::STOPPED:
jam();
-/* ------------------------------------------------------------------------- */
-/*WE ARE CURRENTLY QUEUED FOR ACCESS TO THE FRAGMENT BY A LOCAL CHECKPOINT. */
-/* ------------------------------------------------------------------------- */
+ /* ---------------------------------------------------------------------
+ * WE ARE CURRENTLY QUEUED FOR ACCESS TO THE FRAGMENT BY A LCP
+ * Since nothing has been done, just release operation
+ * i.e. no prepare log record has been written
+ * so no abort log records needs to be written
+ */
releaseWaitQueue(signal);
+ continueAfterLogAbortWriteLab(signal);
+ return;
break;
case TcConnectionrec::WAIT_AI_AFTER_ABORT:
jam();
@@ -9954,9 +9958,11 @@ void Dblqh::execLCP_HOLDOPCONF(Signal* signal)
return;
} else {
jam();
+
/* NO MORE HOLDOPS NEEDED */
lcpLocptr.p->lcpLocstate = LcpLocRecord::HOLDOP_READY;
checkLcpHoldop(signal);
+
if (lcpPtr.p->lcpState == LcpRecord::LCP_WAIT_ACTIVE_FINISH) {
if (fragptr.p->activeList == RNIL) {
jam();
@@ -9974,6 +9980,7 @@ void Dblqh::execLCP_HOLDOPCONF(Signal* signal)
}//if
}//if
}//if
+
/* ----------------------- */
/* ELSE */
/* ------------------------------------------------------------------------
@@ -10046,7 +10053,6 @@ void Dblqh::execTUP_LCPSTARTED(Signal* signal)
void Dblqh::lcpStartedLab(Signal* signal)
{
checkLcpStarted(signal);
-
if (lcpPtr.p->lcpState == LcpRecord::LCP_STARTED) {
jam();
/* ----------------------------------------------------------------------
@@ -10065,7 +10071,7 @@ void Dblqh::lcpStartedLab(Signal* signal)
sendAccContOp(signal); /* START OPERATIONS IN ACC */
moveAccActiveFrag(signal); /* MOVE FROM ACC BLOCKED LIST TO ACTIVE LIST
ON FRAGMENT */
- }//if
+ }
/*---------------*/
/* ELSE */
/*-------------------------------------------------------------------------*/
@@ -10126,32 +10132,27 @@ void Dblqh::execLQH_RESTART_OP(Signal* signal)
lcpPtr.i = signal->theData[1];
ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord);
- if (fragptr.p->fragStatus == Fragrecord::BLOCKED) {
- if (lcpPtr.p->lcpState == LcpRecord::LCP_STARTED) {
- jam();
- /***********************************************************************/
- /* THIS SIGNAL CAN ONLY BE RECEIVED WHEN FRAGMENT IS BLOCKED AND
- * THE LOCAL CHECKPOINT HAS BEEN STARTED. THE BLOCKING WILL BE
- * REMOVED AS SOON AS ALL OPERATIONS HAVE BEEN STARTED.
- ***********************************************************************/
- restartOperationsLab(signal);
- return;
- } else {
- jam();
- if (lcpPtr.p->lcpState == LcpRecord::LCP_BLOCKED_COMP) {
- jam();
- /*******************************************************************>
- * THE CHECKPOINT IS COMPLETED BUT HAS NOT YET STARTED UP
- * ALL OPERATIONS AGAIN.
- * WE PERFORM THIS START-UP BEFORE CONTINUING WITH THE NEXT
- * FRAGMENT OF THE LOCAL CHECKPOINT TO AVOID ANY STRANGE ERRORS.
- *******************************************************************> */
- restartOperationsLab(signal);
- return;
- }//if
- }//if
- }//if
- ndbrequire(false);
+ ndbrequire(fragptr.p->fragStatus == Fragrecord::BLOCKED);
+ if (lcpPtr.p->lcpState == LcpRecord::LCP_STARTED) {
+ jam();
+ /***********************************************************************/
+ /* THIS SIGNAL CAN ONLY BE RECEIVED WHEN FRAGMENT IS BLOCKED AND
+ * THE LOCAL CHECKPOINT HAS BEEN STARTED. THE BLOCKING WILL BE
+ * REMOVED AS SOON AS ALL OPERATIONS HAVE BEEN STARTED.
+ ***********************************************************************/
+ restartOperationsLab(signal);
+ } else if (lcpPtr.p->lcpState == LcpRecord::LCP_BLOCKED_COMP) {
+ jam();
+ /*******************************************************************>
+ * THE CHECKPOINT IS COMPLETED BUT HAS NOT YET STARTED UP
+ * ALL OPERATIONS AGAIN.
+ * WE PERFORM THIS START-UP BEFORE CONTINUING WITH THE NEXT
+ * FRAGMENT OF THE LOCAL CHECKPOINT TO AVOID ANY STRANGE ERRORS.
+ *******************************************************************> */
+ restartOperationsLab(signal);
+ } else {
+ ndbrequire(false);
+ }
}//Dblqh::execLQH_RESTART_OP()
void Dblqh::restartOperationsLab(Signal* signal)
@@ -10204,13 +10205,13 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
* WHEN ARRIVING HERE THE OPERATION IS ALREADY SET IN THE ACTIVE LIST.
* THUS WE CAN IMMEDIATELY CALL THE METHODS THAT EXECUTE FROM WHERE
* THE OPERATION WAS STOPPED.
- *------------------------------------------------------------------------- */
+ *------------------------------------------------------------------------ */
switch (tcConnectptr.p->transactionState) {
case TcConnectionrec::STOPPED:
jam();
/*-----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND ACCKEYREQ
- *----------------------------------------------------------------------- */
+ *---------------------------------------------------------------------- */
prepareContinueAfterBlockedLab(signal);
return;
break;
@@ -10218,7 +10219,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
jam();
/* ----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND ACC_COMMITREQ
- * ---------------------------------------------------------------------- */
+ * --------------------------------------------------------------------- */
releaseActiveFrag(signal);
commitContinueAfterBlockedLab(signal);
return;
@@ -10227,7 +10228,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
jam();
/* ----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND ACC_ABORTREQ
- * ---------------------------------------------------------------------- */
+ * --------------------------------------------------------------------- */
abortContinueAfterBlockedLab(signal, true);
return;
break;
@@ -10235,7 +10236,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
jam();
/* ----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING COPY FRAGMENT
- * ---------------------------------------------------------------------- */
+ * --------------------------------------------------------------------- */
continueCopyAfterBlockedLab(signal);
return;
break;
@@ -10243,7 +10244,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
jam();
/* ----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING COPY FRAGMENT
- * ---------------------------------------------------------------------- */
+ * --------------------------------------------------------------------- */
continueFirstCopyAfterBlockedLab(signal);
return;
break;
@@ -10251,7 +10252,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
jam();
/* ----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING SCAN
- * ---------------------------------------------------------------------- */
+ * --------------------------------------------------------------------- */
tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED;
continueFirstScanAfterBlockedLab(signal);
return;
@@ -10260,7 +10261,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
jam();
/* ----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING SCAN
- * ---------------------------------------------------------------------- */
+ * --------------------------------------------------------------------- */
tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED;
continueAfterCheckLcpStopBlocked(signal);
return;
@@ -10269,7 +10270,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
jam();
/* ----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING SCAN
- * ---------------------------------------------------------------------- */
+ * --------------------------------------------------------------------- */
tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED;
continueScanAfterBlockedLab(signal);
return;
@@ -10279,7 +10280,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
/* ----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING RELEASE
* LOCKS IN SCAN
- * ---------------------------------------------------------------------- */
+ * --------------------------------------------------------------------- */
tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED;
continueScanReleaseAfterBlockedLab(signal);
return;
@@ -10288,7 +10289,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
jam();
/* ----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING CLOSE OF SCAN
- * ---------------------------------------------------------------------- */
+ * --------------------------------------------------------------------- */
continueCloseScanAfterBlockedLab(signal);
return;
break;
@@ -10296,7 +10297,7 @@ void Dblqh::restartOperationsAfterStopLab(Signal* signal)
jam();
/* ----------------------------------------------------------------------
* STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING CLOSE OF COPY
- * ---------------------------------------------------------------------- */
+ * --------------------------------------------------------------------- */
continueCloseCopyAfterBlockedLab(signal);
return;
break;
@@ -10422,7 +10423,12 @@ void Dblqh::contChkpNextFragLab(Signal* signal)
* ----------------------------------------------------------------------- */
if (fragptr.p->fragStatus == Fragrecord::BLOCKED) {
jam();
+ /**
+ * LCP of fragment complete
+ * but restarting of operations isn't
+ */
lcpPtr.p->lcpState = LcpRecord::LCP_BLOCKED_COMP;
+ //restartOperationsLab(signal);
return;
}//if
@@ -10699,25 +10705,25 @@ void Dblqh::checkLcpStarted(Signal* signal)
terrorCode = ZOK;
clsLcpLocptr.i = lcpPtr.p->firstLcpLocAcc;
+ int i = 0;
do {
ptrCheckGuard(clsLcpLocptr, clcpLocrecFileSize, lcpLocRecord);
- if (clsLcpLocptr.p->lcpLocstate != LcpLocRecord::ACC_STARTED) {
- ndbrequire((clsLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_COMPLETED) ||
- (clsLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_WAIT_STARTED));
+ if (clsLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_WAIT_STARTED){
return;
}//if
clsLcpLocptr.i = clsLcpLocptr.p->nextLcpLoc;
+ i++;
} while (clsLcpLocptr.i != RNIL);
+ i = 0;
clsLcpLocptr.i = lcpPtr.p->firstLcpLocTup;
do {
ptrCheckGuard(clsLcpLocptr, clcpLocrecFileSize, lcpLocRecord);
- if (clsLcpLocptr.p->lcpLocstate != LcpLocRecord::TUP_STARTED) {
- ndbrequire((clsLcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_COMPLETED) ||
- (clsLcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_WAIT_STARTED));
+ if (clsLcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_WAIT_STARTED){
return;
}//if
clsLcpLocptr.i = clsLcpLocptr.p->nextLcpLoc;
+ i++;
} while (clsLcpLocptr.i != RNIL);
lcpPtr.p->lcpState = LcpRecord::LCP_STARTED;
}//Dblqh::checkLcpStarted()
@@ -10875,18 +10881,28 @@ void Dblqh::sendAccContOp(Signal* signal)
{
LcpLocRecordPtr sacLcpLocptr;
+ int count = 0;
sacLcpLocptr.i = lcpPtr.p->firstLcpLocAcc;
do {
ptrCheckGuard(sacLcpLocptr, clcpLocrecFileSize, lcpLocRecord);
sacLcpLocptr.p->accContCounter = 0;
-/* ------------------------------------------------------------------------- */
-/*SEND START OPERATIONS TO ACC AGAIN */
-/* ------------------------------------------------------------------------- */
- signal->theData[0] = lcpPtr.p->lcpAccptr;
- signal->theData[1] = sacLcpLocptr.p->locFragid;
- sendSignal(fragptr.p->accBlockref, GSN_ACC_CONTOPREQ, signal, 2, JBA);
+ if(sacLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_STARTED){
+ /* ------------------------------------------------------------------- */
+ /*SEND START OPERATIONS TO ACC AGAIN */
+ /* ------------------------------------------------------------------- */
+ signal->theData[0] = lcpPtr.p->lcpAccptr;
+ signal->theData[1] = sacLcpLocptr.p->locFragid;
+ sendSignal(fragptr.p->accBlockref, GSN_ACC_CONTOPREQ, signal, 2, JBA);
+ count++;
+ } else if(sacLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_COMPLETED){
+ signal->theData[0] = sacLcpLocptr.i;
+ sendSignal(reference(), GSN_ACC_CONTOPCONF, signal, 1, JBB);
+ } else {
+ ndbrequire(false);
+ }
sacLcpLocptr.i = sacLcpLocptr.p->nextLcpLoc;
} while (sacLcpLocptr.i != RNIL);
+
}//Dblqh::sendAccContOp()
/* ------------------------------------------------------------------------- */
diff --git a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
index 825de4f6c2c..71af563599c 100644
--- a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
+++ b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
@@ -1014,9 +1014,15 @@ public:
void tuxReadAttrs(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32 tupVersion, Uint32 numAttrs, const Uint32* attrIds, const Uint32** attrData);
/*
- * TUX reads primary key for md5 summing and when returning keyinfo.
+ * TUX reads primary key without headers into an array of words. Used
+ * for md5 summing and when returning keyinfo.
*/
- void tuxReadKeys(); // under construction
+ void tuxReadKeys(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32* pkSize, Uint32* pkData);
+
+ /*
+ * TUX checks if tuple is visible to scan.
+ */
+ bool tuxQueryTh(Uint32 fragPtrI, Uint32 tupAddr, Uint32 tupVersion, Uint32 transId1, Uint32 transId2, Uint32 savePointId);
private:
BLOCK_DEFINES(Dbtup);
@@ -1062,9 +1068,6 @@ private:
void execTUP_WRITELOG_REQ(Signal* signal);
// Ordered index related
- void execTUP_READ_ATTRS(Signal* signal);
- void execTUP_QUERY_TH(Signal* signal);
- void execTUP_STORE_TH(Signal* signal);
void execBUILDINDXREQ(Signal* signal);
void buildIndex(Signal* signal, Uint32 buildPtrI);
void buildIndexReply(Signal* signal, const BuildIndexRec* buildRec);
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp b/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp
index 3b54817edb0..8133f70a803 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp
@@ -132,9 +132,6 @@ Dbtup::Dbtup(const class Configuration & conf)
addRecSignal(GSN_TUP_WRITELOG_REQ, &Dbtup::execTUP_WRITELOG_REQ);
// Ordered index related
- addRecSignal(GSN_TUP_READ_ATTRS, &Dbtup::execTUP_READ_ATTRS);
- addRecSignal(GSN_TUP_QUERY_TH, &Dbtup::execTUP_QUERY_TH);
- addRecSignal(GSN_TUP_STORE_TH, &Dbtup::execTUP_STORE_TH);
addRecSignal(GSN_BUILDINDXREQ, &Dbtup::execBUILDINDXREQ);
initData();
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp b/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
index f11de5238e2..e7a431f17de 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
@@ -22,7 +22,6 @@
#include <AttributeDescriptor.hpp>
#include "AttributeOffset.hpp"
#include <AttributeHeader.hpp>
-#include <signaldata/TupAccess.hpp>
#include <signaldata/TuxMaint.hpp>
#define ljam() { jamLine(28000 + __LINE__); }
@@ -152,10 +151,10 @@ Dbtup::tuxReadAttrs(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32 tu
const Uint32* tupleHeader = &pagePtr.p->pageWord[pageOffset];
for (Uint32 i = 0; i < numAttrs; i++) {
AttributeHeader ah(attrIds[i]);
- Uint32 attrId = ah.getAttributeId();
- Uint32 index = tabDescriptor + (attrId << ZAD_LOG_SIZE);
- Uint32 desc1 = tableDescriptor[index].tabDescr;
- Uint32 desc2 = tableDescriptor[index + 1].tabDescr;
+ const Uint32 attrId = ah.getAttributeId();
+ const Uint32 index = tabDescriptor + (attrId << ZAD_LOG_SIZE);
+ const Uint32 desc1 = tableDescriptor[index].tabDescr;
+ const Uint32 desc2 = tableDescriptor[index + 1].tabDescr;
if (AttributeDescriptor::getNullable(desc1)) {
Uint32 offset = AttributeOffset::getNullFlagOffset(desc2);
ndbrequire(offset < tablePtr.p->tupNullWords);
@@ -171,275 +170,78 @@ Dbtup::tuxReadAttrs(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32 tu
}
}
-void // under construction
-Dbtup::tuxReadKeys()
-{
-}
-
-// deprecated signal interfaces
-
void
-Dbtup::execTUP_READ_ATTRS(Signal* signal)
+Dbtup::tuxReadKeys(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32* pkSize, Uint32* pkData)
{
ljamEntry();
- TupReadAttrs* const sig = (TupReadAttrs*)signal->getDataPtrSend();
- TupReadAttrs reqCopy = *sig;
- TupReadAttrs* const req = &reqCopy;
- req->errorCode = 0;
- // get table
+ FragrecordPtr fragPtr;
+ fragPtr.i = fragPtrI;
+ ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
TablerecPtr tablePtr;
- tablePtr.i = req->tableId;
+ tablePtr.i = fragPtr.p->fragTableId;
ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
- // get fragment
- FragrecordPtr fragPtr;
- if (req->fragPtrI == RNIL) {
- ljam();
- getFragmentrec(fragPtr, req->fragId, tablePtr.p);
- ndbrequire(fragPtr.i != RNIL);
- req->fragPtrI = fragPtr.i;
- } else {
- fragPtr.i = req->fragPtrI;
- ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
- ndbrequire(req->fragId == fragPtr.p->fragmentId);
- }
- // get page
PagePtr pagePtr;
- if (req->pageId == RNIL) {
- ljam();
- Uint32 fragPageId = req->tupAddr >> MAX_TUPLES_BITS;
- Uint32 pageIndex = req->tupAddr & ((1 << MAX_TUPLES_BITS ) - 1);
- ndbrequire((pageIndex & 0x1) == 0);
- // data returned for original tuple
- req->pageId = getRealpid(fragPtr.p, fragPageId);
- req->pageOffset = ZPAGE_HEADER_SIZE + (pageIndex >> 1) * tablePtr.p->tupheadsize;
- }
- pagePtr.i = req->pageId;
+ pagePtr.i = pageId;
ptrCheckGuard(pagePtr, cnoOfPage, page);
- Uint32 pageOffset = req->pageOffset;
- // search for tuple version if not original
- if (! (req->requestInfo & TupReadAttrs::ReadKeys) &&
- pagePtr.p->pageWord[pageOffset + 1] != req->tupVersion) {
- ljam();
- OperationrecPtr opPtr;
- opPtr.i = pagePtr.p->pageWord[pageOffset];
- Uint32 loopGuard = 0;
- while (true) {
- ptrCheckGuard(opPtr, cnoOfOprec, operationrec);
- if (opPtr.p->realPageIdC != RNIL) {
- pagePtr.i = opPtr.p->realPageIdC;
- pageOffset = opPtr.p->pageOffsetC;
- ptrCheckGuard(pagePtr, cnoOfPage, page);
- if (pagePtr.p->pageWord[pageOffset + 1] == req->tupVersion) {
- ljam();
- break;
- }
- }
- ljam();
- // next means before in event order
- opPtr.i = opPtr.p->nextActiveOp;
- ndbrequire(++loopGuard < (1 << ZTUP_VERSION_BITS));
+ const Uint32 tabDescriptor = tablePtr.p->tabDescriptor;
+ const Uint32 numAttrs = tablePtr.p->noOfKeyAttr;
+ const Uint32* attrIds = &tableDescriptor[tablePtr.p->readKeyArray].tabDescr;
+ const Uint32* tupleHeader = &pagePtr.p->pageWord[pageOffset];
+ Uint32 size = 0;
+ for (Uint32 i = 0; i < numAttrs; i++) {
+ AttributeHeader ah(attrIds[i]);
+ const Uint32 attrId = ah.getAttributeId();
+ const Uint32 index = tabDescriptor + (attrId << ZAD_LOG_SIZE);
+ const Uint32 desc1 = tableDescriptor[index].tabDescr;
+ const Uint32 desc2 = tableDescriptor[index + 1].tabDescr;
+ ndbrequire(! AttributeDescriptor::getNullable(desc1));
+ const Uint32 attrSize = AttributeDescriptor::getSizeInWords(desc1);
+ const Uint32* attrData = tupleHeader + AttributeOffset::getOffset(desc2);
+ for (Uint32 j = 0; j < attrSize; j++) {
+ pkData[size + j] = attrData[j];
}
+ size += attrSize;
}
- // shared buffer
- Uint32* buffer = (Uint32*)sig + TupReadAttrs::SignalLength;
- // if request is for keys then we create input section
- if (req->requestInfo & TupReadAttrs::ReadKeys) {
- ljam();
- buffer[0] = tablePtr.p->noOfKeyAttr;
- const Uint32* keyArray = &tableDescriptor[tablePtr.p->readKeyArray].tabDescr;
- MEMCOPY_NO_WORDS(&buffer[1], keyArray, tablePtr.p->noOfKeyAttr);
- }
- Uint32 inBufLen = buffer[0];
- Uint32* inBuffer = &buffer[1];
- Uint32* outBuffer = &buffer[1 + inBufLen];
- Uint32 maxRead = ZATTR_BUFFER_SIZE;
- // save globals
- TablerecPtr tabptr_old = tabptr;
- FragrecordPtr fragptr_old = fragptr;
- OperationrecPtr operPtr_old = operPtr;
- // new globals
- tabptr = tablePtr;
- fragptr = fragPtr;
- operPtr.i = RNIL; // XXX check later
- operPtr.p = NULL;
- int ret = readAttributes(pagePtr.p, pageOffset, inBuffer, inBufLen, outBuffer, maxRead);
- // restore globals
- tabptr = tabptr_old;
- fragptr = fragptr_old;
- operPtr = operPtr_old;
- // check error
- if ((Uint32)ret == (Uint32)-1) {
- ljam();
- req->errorCode = terrorCode;
- }
- // copy back
- *sig = *req;
+ *pkSize = size;
}
-void
-Dbtup::execTUP_QUERY_TH(Signal* signal)
+bool
+Dbtup::tuxQueryTh(Uint32 fragPtrI, Uint32 tupAddr, Uint32 tupVersion, Uint32 transId1, Uint32 transId2, Uint32 savePointId)
{
ljamEntry();
- Operationrec tempOp;
- TupQueryTh* const req = (TupQueryTh*)signal->getDataPtrSend();
- Uint32 tableId = req->tableId;
- Uint32 fragId = req->fragId;
- Uint32 tupAddr = req->tupAddr;
- Uint32 req_tupVersion = req->tupVersion;
- Uint32 transid1 = req->transId1;
- Uint32 transid2 = req->transId2;
- Uint32 savePointId = req->savePointId;
- Uint32 ret_result = 0;
- // get table
+ FragrecordPtr fragPtr;
+ fragPtr.i = fragPtrI;
+ ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
TablerecPtr tablePtr;
- tablePtr.i = tableId;
+ tablePtr.i = fragPtr.p->fragTableId;
ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
- // get fragment
- FragrecordPtr fragPtr;
- getFragmentrec(fragPtr, fragId, tablePtr.p);
- ndbrequire(fragPtr.i != RNIL);
// get page
PagePtr pagePtr;
Uint32 fragPageId = tupAddr >> MAX_TUPLES_BITS;
Uint32 pageIndex = tupAddr & ((1 << MAX_TUPLES_BITS ) - 1);
-
+ // use temp op rec
+ Operationrec tempOp;
tempOp.fragPageId = fragPageId;
tempOp.pageIndex = pageIndex;
- tempOp.transid1 = transid1;
- tempOp.transid2 = transid2;
+ tempOp.transid1 = transId1;
+ tempOp.transid2 = transId2;
tempOp.savePointId = savePointId;
tempOp.optype = ZREAD;
tempOp.dirtyOp = 1;
if (getPage(pagePtr, &tempOp, fragPtr.p, tablePtr.p)) {
/*
- We use the normal getPage which will return the tuple to be used
- for this transaction and savepoint id. If its tuple version equals
- the requested then we have a visible tuple otherwise not.
+ * We use the normal getPage which will return the tuple to be used
+ * for this transaction and savepoint id. If its tuple version
+ * equals the requested then we have a visible tuple otherwise not.
*/
ljam();
Uint32 read_tupVersion = pagePtr.p->pageWord[tempOp.pageOffset + 1];
- if (read_tupVersion == req_tupVersion) {
+ if (read_tupVersion == tupVersion) {
ljam();
- ret_result = 1;
- }
- }
- req->returnCode = ret_result;
- return;
-}
-
-void
-Dbtup::execTUP_STORE_TH(Signal* signal)
-{
- ljamEntry();
- TupStoreTh* const sig = (TupStoreTh*)signal->getDataPtrSend();
- TupStoreTh reqCopy = *sig;
- TupStoreTh* const req = &reqCopy;
- req->errorCode = 0;
- ndbrequire(req->tupVersion == 0);
- // get table
- TablerecPtr tablePtr;
- tablePtr.i = req->tableId;
- ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
- // offset to attribute 0
- Uint32 attrDescIndex = tablePtr.p->tabDescriptor + (0 << ZAD_LOG_SIZE);
- Uint32 attrDataOffset = AttributeOffset::getOffset(tableDescriptor[attrDescIndex + 1].tabDescr);
- // get fragment
- FragrecordPtr fragPtr;
- if (req->fragPtrI == RNIL) {
- ljam();
- getFragmentrec(fragPtr, req->fragId, tablePtr.p);
- ndbrequire(fragPtr.i != RNIL);
- req->fragPtrI = fragPtr.i;
- } else {
- fragPtr.i = req->fragPtrI;
- ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
- ndbrequire(req->fragId == fragPtr.p->fragmentId);
- }
- // handle each case
- switch (req->opCode) {
- case TupStoreTh::OpRead:
- ljam();
- {
- PagePtr pagePtr;
- if (req->pageId == RNIL) {
- ljam();
- Uint32 fragPageId = req->tupAddr >> MAX_TUPLES_BITS;
- Uint32 pageIndex = req->tupAddr & ((1 << MAX_TUPLES_BITS ) - 1);
- ndbrequire((pageIndex & 0x1) == 0);
- req->pageId = getRealpid(fragPtr.p, fragPageId);
- req->pageOffset = ZPAGE_HEADER_SIZE + (pageIndex >> 1) * tablePtr.p->tupheadsize;
- }
- pagePtr.i = req->pageId;
- ptrCheckGuard(pagePtr, cnoOfPage, page);
- Uint32* data = &pagePtr.p->pageWord[req->pageOffset] + attrDataOffset;
- Uint32* buffer = (Uint32*)sig + TupStoreTh::SignalLength;
- ndbrequire(req->dataOffset + req->dataSize <= tablePtr.p->tupheadsize);
- memcpy(buffer + req->dataOffset, data + req->dataOffset, req->dataSize << 2);
- }
- break;
- case TupStoreTh::OpInsert:
- ljam();
- {
- PagePtr pagePtr;
- if (! allocTh(fragPtr.p, tablePtr.p, NORMAL_PAGE, signal, req->pageOffset, pagePtr)) {
- ljam();
- req->errorCode = terrorCode;
- break;
- }
- req->pageId = pagePtr.i;
- Uint32 fragPageId = pagePtr.p->pageWord[ZPAGE_FRAG_PAGE_ID_POS];
- Uint32 pageIndex = ((req->pageOffset - ZPAGE_HEADER_SIZE) / tablePtr.p->tupheadsize) << 1;
- req->tupAddr = (fragPageId << MAX_TUPLES_BITS) | pageIndex;
- ndbrequire(req->dataOffset + req->dataSize <= tablePtr.p->tupheadsize);
- Uint32* data = &pagePtr.p->pageWord[req->pageOffset] + attrDataOffset;
- Uint32* buffer = (Uint32*)sig + TupStoreTh::SignalLength;
- memcpy(data + req->dataOffset, buffer + req->dataOffset, req->dataSize << 2);
+ return true;
}
- break;
- case TupStoreTh::OpUpdate:
- ljam();
- {
- PagePtr pagePtr;
- if (req->pageId == RNIL) {
- ljam();
- Uint32 fragPageId = req->tupAddr >> MAX_TUPLES_BITS;
- Uint32 pageIndex = req->tupAddr & ((1 << MAX_TUPLES_BITS ) - 1);
- ndbrequire((pageIndex & 0x1) == 0);
- req->pageId = getRealpid(fragPtr.p, fragPageId);
- req->pageOffset = ZPAGE_HEADER_SIZE + (pageIndex >> 1) * tablePtr.p->tupheadsize;
- }
- pagePtr.i = req->pageId;
- ptrCheckGuard(pagePtr, cnoOfPage, page);
- Uint32* data = &pagePtr.p->pageWord[req->pageOffset] + attrDataOffset;
- Uint32* buffer = (Uint32*)sig + TupStoreTh::SignalLength;
- ndbrequire(req->dataOffset + req->dataSize <= tablePtr.p->tupheadsize);
- memcpy(data + req->dataOffset, buffer + req->dataOffset, req->dataSize << 2);
- }
- break;
- case TupStoreTh::OpDelete:
- ljam();
- {
- PagePtr pagePtr;
- if (req->pageId == RNIL) {
- ljam();
- Uint32 fragPageId = req->tupAddr >> MAX_TUPLES_BITS;
- Uint32 pageIndex = req->tupAddr & ((1 << MAX_TUPLES_BITS ) - 1);
- ndbrequire((pageIndex & 0x1) == 0);
- req->pageId = getRealpid(fragPtr.p, fragPageId);
- req->pageOffset = ZPAGE_HEADER_SIZE + (pageIndex >> 1) * tablePtr.p->tupheadsize;
- }
- pagePtr.i = req->pageId;
- ptrCheckGuard(pagePtr, cnoOfPage, page);
- freeTh(fragPtr.p, tablePtr.p, signal, pagePtr.p, req->pageOffset);
- // null location
- req->tupAddr = (Uint32)-1;
- req->pageId = RNIL;
- req->pageOffset = 0;
- }
- break;
}
- // copy back
- *sig = *req;
+ return false;
}
// ordered index build
diff --git a/ndb/src/kernel/blocks/dbtux/Dbtux.hpp b/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
index 62f47af94bd..1a3c7f64ac3 100644
--- a/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
+++ b/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
@@ -37,7 +37,6 @@
#include <signaldata/AlterIndx.hpp>
#include <signaldata/DropTab.hpp>
#include <signaldata/TuxMaint.hpp>
-#include <signaldata/TupAccess.hpp>
#include <signaldata/AccScan.hpp>
#include <signaldata/TuxBound.hpp>
#include <signaldata/NextScan.hpp>
@@ -77,10 +76,14 @@
#define jam() jamLine(60000 + __LINE__)
#define jamEntry() jamEntryLine(60000 + __LINE__)
#endif
-#ifdef DBTUX_CMP_CPP
+#ifdef DBTUX_SEARCH_CPP
#define jam() jamLine(70000 + __LINE__)
#define jamEntry() jamEntryLine(70000 + __LINE__)
#endif
+#ifdef DBTUX_CMP_CPP
+#define jam() jamLine(80000 + __LINE__)
+#define jamEntry() jamEntryLine(80000 + __LINE__)
+#endif
#ifdef DBTUX_DEBUG_CPP
#define jam() jamLine(90000 + __LINE__)
#define jamEntry() jamEntryLine(90000 + __LINE__)
@@ -112,6 +115,7 @@ public:
static const unsigned DescPageSize = 256;
private:
static const unsigned MaxTreeNodeSize = MAX_TTREE_NODE_SIZE;
+ static const unsigned MaxPrefSize = MAX_TTREE_PREF_SIZE;
static const unsigned ScanBoundSegmentSize = 7;
static const unsigned MaxAccLockOps = MAX_PARALLEL_OP_PER_SCAN;
BLOCK_DEFINES(Dbtux);
@@ -206,19 +210,19 @@ private:
unsigned m_fragBit : 1; // which duplicated table fragment
TreeEnt();
// methods
+ bool eq(const TreeEnt ent) const;
int cmp(const TreeEnt ent) const;
};
static const unsigned TreeEntSize = sizeof(TreeEnt) >> 2;
static const TreeEnt NullTreeEnt;
/*
- * Tree node has 1) fixed part 2) actual table data for min and max
- * prefix 3) max and min entries 4) rest of entries 5) one extra entry
+ * Tree node has 1) fixed part 2) a prefix of index key data for min
+ * entry 3) max and min entries 4) rest of entries 5) one extra entry
* used as work space.
*
* struct TreeNode part 1, size 6 words
* min prefix part 2, size TreeHead::m_prefSize
- * max prefix part 2, size TreeHead::m_prefSize
* max entry part 3
* min entry part 3
* rest of entries part 4
@@ -265,14 +269,14 @@ private:
friend struct TreeHead;
struct TreeHead {
Uint8 m_nodeSize; // words in tree node
- Uint8 m_prefSize; // words in min/max prefix each
+ Uint8 m_prefSize; // words in min prefix
Uint8 m_minOccup; // min entries in internal node
Uint8 m_maxOccup; // max entries in node
TupLoc m_root; // root node
TreeHead();
// methods
unsigned getSize(AccSize acc) const;
- Data getPref(TreeNode* node, unsigned i) const;
+ Data getPref(TreeNode* node) const;
TreeEnt* getEntList(TreeNode* node) const;
};
@@ -442,6 +446,7 @@ private:
Uint32 m_descPage; // descriptor page
Uint16 m_descOff; // offset within the page
Uint16 m_numAttrs;
+ bool m_storeNullKey;
union {
Uint32 nextPool;
};
@@ -465,6 +470,7 @@ private:
Uint32 m_descPage; // copy from index level
Uint16 m_descOff;
Uint16 m_numAttrs;
+ bool m_storeNullKey;
TreeHead m_tree;
TupLoc m_freeLoc; // one node pre-allocated for insert
DLList<ScanOp> m_scanList; // current scans on this fragment
@@ -514,6 +520,8 @@ private:
NodeHandle(Frag& frag);
NodeHandle(const NodeHandle& node);
NodeHandle& operator=(const NodeHandle& node);
+ // check if unassigned
+ bool isNull();
// getters
TupLoc getLink(unsigned i);
unsigned getChilds(); // cannot spell
@@ -528,56 +536,13 @@ private:
void setBalance(int b);
void setNodeScan(Uint32 scanPtrI);
// access other parts of the node
- Data getPref(unsigned i);
+ Data getPref();
TreeEnt getEnt(unsigned pos);
TreeEnt getMinMax(unsigned i);
// for ndbrequire and ndbassert
void progError(int line, int cause, const char* file);
};
- // parameters for methods
-
- /*
- * Copy attribute data.
- */
- struct CopyPar {
- unsigned m_items; // number of attributes
- bool m_headers; // copy headers flag (default true)
- unsigned m_maxwords; // limit size (default no limit)
- // output
- unsigned m_numitems; // number of attributes fully copied
- unsigned m_numwords; // number of words copied
- CopyPar();
- };
-
- /*
- * Read index key attributes.
- */
- struct ReadPar;
- friend struct ReadPar;
- struct ReadPar {
- TreeEnt m_ent; // tuple to read
- unsigned m_first; // first index attribute
- unsigned m_count; // number of consecutive index attributes
- Data m_data; // set pointer if 0 else copy result to it
- unsigned m_size; // number of words (set in read keys only)
- ReadPar();
- };
-
- /*
- * Scan bound comparison.
- */
- struct BoundPar;
- friend struct BoundPar;
- struct BoundPar {
- ConstData m_data1; // full bound data
- ConstData m_data2; // full or prefix data
- unsigned m_count1; // number of bounds
- unsigned m_len2; // words in data2 buffer
- unsigned m_dir; // 0-lower bound 1-upper bound
- BoundPar();
- };
-
// methods
/*
@@ -589,7 +554,7 @@ private:
// utils
void setKeyAttrs(const Frag& frag);
void readKeyAttrs(const Frag& frag, TreeEnt ent, unsigned start, TableData keyData);
- void copyAttrs(Data dst, ConstData src, CopyPar& copyPar);
+ void readTablePk(const Frag& frag, TreeEnt ent, unsigned& pkSize, Data pkData);
void copyAttrs(const Frag& frag, TableData data1, Data data2, unsigned maxlen2 = MaxAttrDataSize);
/*
@@ -607,8 +572,6 @@ private:
* DbtuxMaint.cpp
*/
void execTUX_MAINT_REQ(Signal* signal);
- void tupReadAttrs(Signal* signal, const Frag& frag, ReadPar& readPar);
- void tupReadKeys(Signal* signal, const Frag& frag, ReadPar& readPar);
/*
* DbtuxNode.cpp
@@ -618,7 +581,7 @@ private:
void selectNode(Signal* signal, NodeHandle& node, TupLoc loc, AccSize acc);
void insertNode(Signal* signal, NodeHandle& node, AccSize acc);
void deleteNode(Signal* signal, NodeHandle& node);
- void setNodePref(Signal* signal, NodeHandle& node, unsigned i);
+ void setNodePref(Signal* signal, NodeHandle& node);
// node operations
void nodePushUp(Signal* signal, NodeHandle& node, unsigned pos, const TreeEnt& ent);
void nodePopDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent);
@@ -633,7 +596,6 @@ private:
/*
* DbtuxTree.cpp
*/
- void treeSearch(Signal* signal, Frag& frag, TableData searchKey, TreeEnt searchEnt, TreePos& treePos);
void treeAdd(Signal* signal, Frag& frag, TreePos treePos, TreeEnt ent);
void treeRemove(Signal* signal, Frag& frag, TreePos treePos);
void treeRotateSingle(Signal* signal, Frag& frag, NodeHandle& node, unsigned i);
@@ -658,11 +620,19 @@ private:
void releaseScanOp(ScanOpPtr& scanPtr);
/*
+ * DbtuxSearch.cpp
+ */
+ void searchToAdd(Signal* signal, Frag& frag, TableData searchKey, TreeEnt searchEnt, TreePos& treePos);
+ void searchToRemove(Signal* signal, Frag& frag, TableData searchKey, TreeEnt searchEnt, TreePos& treePos);
+ void searchToScan(Signal* signal, Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos);
+
+ /*
* DbtuxCmp.cpp
*/
- int cmpSearchKey(const Frag& frag, unsigned& start, TableData data1, ConstData data2, unsigned maxlen2 = MaxAttrDataSize);
- int cmpSearchKey(const Frag& frag, unsigned& start, TableData data1, TableData data2);
- int cmpScanBound(const Frag& frag, const BoundPar boundPar);
+ int cmpSearchKey(const Frag& frag, unsigned& start, TableData searchKey, ConstData entryData, unsigned maxlen = MaxAttrDataSize);
+ int cmpSearchKey(const Frag& frag, unsigned& start, TableData searchKey, TableData entryKey);
+ int cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigned boundCount, ConstData entryData, unsigned maxlen = MaxAttrDataSize);
+ int cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigned boundCount, TableData entryKey);
/*
* DbtuxDebug.cpp
@@ -675,6 +645,7 @@ private:
TupLoc m_parent; // expected parent address
int m_depth; // returned depth
unsigned m_occup; // returned occupancy
+ TreeEnt m_minmax[2]; // returned subtree min and max
bool m_ok; // returned status
PrintPar();
};
@@ -699,6 +670,8 @@ private:
DebugTree = 4, // log and check tree after each op
DebugScan = 8 // log scans
};
+ static const int DataFillByte = 0xa2;
+ static const int NodeFillByte = 0xa4;
#endif
// start up info
@@ -859,13 +832,18 @@ Dbtux::TreeEnt::TreeEnt() :
{
}
+inline bool
+Dbtux::TreeEnt::eq(const TreeEnt ent) const
+{
+ return
+ m_tupLoc == ent.m_tupLoc &&
+ m_tupVersion == ent.m_tupVersion &&
+ m_fragBit == ent.m_fragBit;
+}
+
inline int
Dbtux::TreeEnt::cmp(const TreeEnt ent) const
{
- if (m_fragBit < ent.m_fragBit)
- return -1;
- if (m_fragBit > ent.m_fragBit)
- return +1;
if (m_tupLoc.m_pageId < ent.m_tupLoc.m_pageId)
return -1;
if (m_tupLoc.m_pageId > ent.m_tupLoc.m_pageId)
@@ -878,6 +856,10 @@ Dbtux::TreeEnt::cmp(const TreeEnt ent) const
return -1;
if (m_tupVersion > ent.m_tupVersion)
return +1;
+ if (m_fragBit < ent.m_fragBit)
+ return -1;
+ if (m_fragBit > ent.m_fragBit)
+ return +1;
return 0;
}
@@ -920,7 +902,7 @@ Dbtux::TreeHead::getSize(AccSize acc) const
case AccHead:
return NodeHeadSize;
case AccPref:
- return NodeHeadSize + 2 * m_prefSize + 2 * TreeEntSize;
+ return NodeHeadSize + m_prefSize + 2 * TreeEntSize;
case AccFull:
return m_nodeSize;
}
@@ -929,16 +911,16 @@ Dbtux::TreeHead::getSize(AccSize acc) const
}
inline Dbtux::Data
-Dbtux::TreeHead::getPref(TreeNode* node, unsigned i) const
+Dbtux::TreeHead::getPref(TreeNode* node) const
{
- Uint32* ptr = (Uint32*)node + NodeHeadSize + i * m_prefSize;
+ Uint32* ptr = (Uint32*)node + NodeHeadSize;
return ptr;
}
inline Dbtux::TreeEnt*
Dbtux::TreeHead::getEntList(TreeNode* node) const
{
- Uint32* ptr = (Uint32*)node + NodeHeadSize + 2 * m_prefSize;
+ Uint32* ptr = (Uint32*)node + NodeHeadSize + m_prefSize;
return (TreeEnt*)ptr;
}
@@ -1013,7 +995,8 @@ Dbtux::Index::Index() :
m_numFrags(0),
m_descPage(RNIL),
m_descOff(0),
- m_numAttrs(0)
+ m_numAttrs(0),
+ m_storeNullKey(false)
{
for (unsigned i = 0; i < MaxIndexFragments; i++) {
m_fragId[i] = ZNIL;
@@ -1032,6 +1015,7 @@ Dbtux::Frag::Frag(ArrayPool<ScanOp>& scanOpPool) :
m_descPage(RNIL),
m_descOff(0),
m_numAttrs(ZNIL),
+ m_storeNullKey(false),
m_tree(),
m_freeLoc(),
m_scanList(scanOpPool),
@@ -1087,6 +1071,12 @@ Dbtux::NodeHandle::operator=(const NodeHandle& node)
return *this;
}
+inline bool
+Dbtux::NodeHandle::isNull()
+{
+ return m_node == 0;
+}
+
inline Dbtux::TupLoc
Dbtux::NodeHandle::getLink(unsigned i)
{
@@ -1161,11 +1151,11 @@ Dbtux::NodeHandle::setNodeScan(Uint32 scanPtrI)
}
inline Dbtux::Data
-Dbtux::NodeHandle::getPref(unsigned i)
+Dbtux::NodeHandle::getPref()
{
TreeHead& tree = m_frag.m_tree;
- ndbrequire(m_acc >= AccPref && i <= 1);
- return tree.getPref(m_node, i);
+ ndbrequire(m_acc >= AccPref);
+ return tree.getPref(m_node);
}
inline Dbtux::TreeEnt
@@ -1193,36 +1183,6 @@ Dbtux::NodeHandle::getMinMax(unsigned i)
// parameters for methods
-inline
-Dbtux::CopyPar::CopyPar() :
- m_items(0),
- m_headers(true),
- m_maxwords(~0), // max unsigned
- // output
- m_numitems(0),
- m_numwords(0)
-{
-}
-
-inline
-Dbtux::ReadPar::ReadPar() :
- m_first(0),
- m_count(0),
- m_data(0),
- m_size(0)
-{
-}
-
-inline
-Dbtux::BoundPar::BoundPar() :
- m_data1(0),
- m_data2(0),
- m_count1(0),
- m_len2(0),
- m_dir(255)
-{
-}
-
#ifdef VM_TRACE
inline
Dbtux::PrintPar::PrintPar() :
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp
index 7601a14a242..1b8755a1dc4 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp
@@ -25,14 +25,14 @@
* prefix may be partial in which case CmpUnknown may be returned.
*/
int
-Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, TableData data1, ConstData data2, unsigned maxlen2)
+Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, TableData searchKey, ConstData entryData, unsigned maxlen)
{
const unsigned numAttrs = frag.m_numAttrs;
const DescEnt& descEnt = getDescEnt(frag.m_descPage, frag.m_descOff);
// number of words of attribute data left
- unsigned len2 = maxlen2;
+ unsigned len2 = maxlen;
// skip to right position in search key
- data1 += start;
+ searchKey += start;
int ret = 0;
while (start < numAttrs) {
if (len2 < AttributeHeaderSize) {
@@ -41,20 +41,20 @@ Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, TableData data1, ConstDat
break;
}
len2 -= AttributeHeaderSize;
- if (*data1 != 0) {
- if (! data2.ah().isNULL()) {
+ if (*searchKey != 0) {
+ if (! entryData.ah().isNULL()) {
jam();
// current attribute
const DescAttr& descAttr = descEnt.m_descAttr[start];
const unsigned typeId = descAttr.m_typeId;
// full data size
const unsigned size1 = AttributeDescriptor::getSizeInWords(descAttr.m_attrDesc);
- ndbrequire(size1 != 0 && size1 == data2.ah().getDataSize());
+ ndbrequire(size1 != 0 && size1 == entryData.ah().getDataSize());
const unsigned size2 = min(size1, len2);
len2 -= size2;
// compare
- const Uint32* const p1 = *data1;
- const Uint32* const p2 = &data2[AttributeHeaderSize];
+ const Uint32* const p1 = *searchKey;
+ const Uint32* const p2 = &entryData[AttributeHeaderSize];
ret = NdbSqlUtil::cmp(typeId, p1, p2, size1, size2);
if (ret != 0) {
jam();
@@ -62,20 +62,20 @@ Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, TableData data1, ConstDat
}
} else {
jam();
- // not NULL < NULL
- ret = -1;
+ // not NULL > NULL
+ ret = +1;
break;
}
} else {
- if (! data2.ah().isNULL()) {
+ if (! entryData.ah().isNULL()) {
jam();
- // NULL > not NULL
- ret = +1;
+ // NULL < not NULL
+ ret = -1;
break;
}
}
- data1 += 1;
- data2 += AttributeHeaderSize + data2.ah().getDataSize();
+ searchKey += 1;
+ entryData += AttributeHeaderSize + entryData.ah().getDataSize();
start++;
}
// XXX until data format errors are handled
@@ -89,17 +89,17 @@ Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, TableData data1, ConstDat
* Start position is updated as in previous routine.
*/
int
-Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, TableData data1, TableData data2)
+Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, TableData searchKey, TableData entryKey)
{
const unsigned numAttrs = frag.m_numAttrs;
const DescEnt& descEnt = getDescEnt(frag.m_descPage, frag.m_descOff);
// skip to right position
- data1 += start;
- data2 += start;
+ searchKey += start;
+ entryKey += start;
int ret = 0;
while (start < numAttrs) {
- if (*data1 != 0) {
- if (*data2 != 0) {
+ if (*searchKey != 0) {
+ if (*entryKey != 0) {
jam();
// current attribute
const DescAttr& descAttr = descEnt.m_descAttr[start];
@@ -107,8 +107,8 @@ Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, TableData data1, TableDat
// full data size
const unsigned size1 = AttributeDescriptor::getSizeInWords(descAttr.m_attrDesc);
// compare
- const Uint32* const p1 = *data1;
- const Uint32* const p2 = *data2;
+ const Uint32* const p1 = *searchKey;
+ const Uint32* const p2 = *entryKey;
ret = NdbSqlUtil::cmp(typeId, p1, p2, size1, size1);
if (ret != 0) {
jam();
@@ -116,20 +116,20 @@ Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, TableData data1, TableDat
}
} else {
jam();
- // not NULL < NULL
- ret = -1;
+ // not NULL > NULL
+ ret = +1;
break;
}
} else {
- if (*data2 != 0) {
+ if (*entryKey != 0) {
jam();
- // NULL > not NULL
- ret = +1;
+ // NULL < not NULL
+ ret = -1;
break;
}
}
- data1 += 1;
- data2 += 1;
+ searchKey += 1;
+ entryKey += 1;
start++;
}
// XXX until data format errors are handled
@@ -137,94 +137,96 @@ Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, TableData data1, TableDat
return ret;
}
-
/*
- * Scan bound vs tree entry.
+ * Scan bound vs node prefix.
*
* 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.
+ * 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.
*
- * 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.
+ * 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.
*
* 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.
+ * 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.
*/
int
-Dbtux::cmpScanBound(const Frag& frag, const BoundPar boundPar)
+Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigned boundCount, ConstData entryData, unsigned maxlen)
{
- unsigned type = 4;
- int ret = 0;
- /*
- 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 initialising return value to 0 and set type to 4.
- */
const DescEnt& descEnt = getDescEnt(frag.m_descPage, frag.m_descOff);
- ConstData data1 = boundPar.m_data1;
- ConstData data2 = boundPar.m_data2;
// direction 0-lower 1-upper
- const unsigned dir = boundPar.m_dir;
ndbrequire(dir <= 1);
// number of words of data left
- unsigned len2 = boundPar.m_len2;
- for (unsigned i = 0; i < boundPar.m_count1; i++) {
+ 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.
+ */
+ unsigned type = 4;
+ while (boundCount != 0) {
if (len2 < AttributeHeaderSize) {
jam();
return NdbSqlUtil::CmpUnknown;
}
len2 -= AttributeHeaderSize;
// get and skip bound type
- type = data1[0];
- data1 += 1;
- ndbrequire(! data1.ah().isNULL());
- if (! data2.ah().isNULL()) {
- jam();
- // current attribute
- const unsigned index = data1.ah().getAttributeId();
- const DescAttr& descAttr = descEnt.m_descAttr[index];
- const unsigned typeId = descAttr.m_typeId;
- ndbrequire(data2.ah().getAttributeId() == descAttr.m_primaryAttrId);
- // full data size
- const unsigned size1 = data1.ah().getDataSize();
- ndbrequire(size1 != 0 && size1 == data2.ah().getDataSize());
- const unsigned size2 = min(size1, len2);
- len2 -= size2;
- // compare
- const Uint32* const p1 = &data1[AttributeHeaderSize];
- const Uint32* const p2 = &data2[AttributeHeaderSize];
- ret = NdbSqlUtil::cmp(typeId, p1, p2, size1, size2);
- if (ret != 0) {
+ type = boundInfo[0];
+ boundInfo += 1;
+ if (! boundInfo.ah().isNULL()) {
+ if (! entryData.ah().isNULL()) {
jam();
- return ret;
+ // current attribute
+ const unsigned index = boundInfo.ah().getAttributeId();
+ const DescAttr& descAttr = descEnt.m_descAttr[index];
+ const unsigned typeId = descAttr.m_typeId;
+ ndbrequire(entryData.ah().getAttributeId() == descAttr.m_primaryAttrId);
+ // full data size
+ const unsigned size1 = boundInfo.ah().getDataSize();
+ ndbrequire(size1 != 0 && size1 == entryData.ah().getDataSize());
+ const unsigned size2 = min(size1, len2);
+ len2 -= size2;
+ // compare
+ const Uint32* const p1 = &boundInfo[AttributeHeaderSize];
+ const Uint32* const p2 = &entryData[AttributeHeaderSize];
+ int ret = NdbSqlUtil::cmp(typeId, p1, p2, size1, size2);
+ // XXX until data format errors are handled
+ ndbrequire(ret != NdbSqlUtil::CmpError);
+ if (ret != 0) {
+ jam();
+ return ret;
+ }
+ } else {
+ jam();
+ // not NULL > NULL
+ return +1;
}
} else {
jam();
- /*
- NULL is bigger than any bound, thus the boundary is always to the
- left of NULL
- */
- return -1;
+ if (! entryData.ah().isNULL()) {
+ jam();
+ // NULL < not NULL
+ return -1;
+ }
}
- data1 += AttributeHeaderSize + data1.ah().getDataSize();
- data2 += AttributeHeaderSize + data2.ah().getDataSize();
+ boundInfo += AttributeHeaderSize + boundInfo.ah().getDataSize();
+ entryData += AttributeHeaderSize + entryData.ah().getDataSize();
+ boundCount -= 1;
}
- ndbassert(ret == 0);
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.
- */
+ * 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;
@@ -233,10 +235,11 @@ Dbtux::cmpScanBound(const Frag& frag, const BoundPar boundPar)
} 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.
- */
+ * 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;
@@ -245,3 +248,72 @@ Dbtux::cmpScanBound(const Frag& frag, const BoundPar boundPar)
}
}
+/*
+ * Scan bound vs tree entry.
+ */
+int
+Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigned boundCount, TableData entryKey)
+{
+ const DescEnt& descEnt = getDescEnt(frag.m_descPage, frag.m_descOff);
+ // direction 0-lower 1-upper
+ ndbrequire(dir <= 1);
+ // initialize type to equality
+ unsigned type = 4;
+ while (boundCount != 0) {
+ // get and skip bound type
+ type = boundInfo[0];
+ boundInfo += 1;
+ if (! boundInfo.ah().isNULL()) {
+ if (*entryKey != 0) {
+ jam();
+ // current attribute
+ const unsigned index = boundInfo.ah().getAttributeId();
+ const DescAttr& descAttr = descEnt.m_descAttr[index];
+ const unsigned typeId = descAttr.m_typeId;
+ // full data size
+ const unsigned size1 = AttributeDescriptor::getSizeInWords(descAttr.m_attrDesc);
+ // compare
+ const Uint32* const p1 = &boundInfo[AttributeHeaderSize];
+ const Uint32* const p2 = *entryKey;
+ int ret = NdbSqlUtil::cmp(typeId, p1, p2, size1, size1);
+ // XXX until data format errors are handled
+ ndbrequire(ret != NdbSqlUtil::CmpError);
+ if (ret != 0) {
+ jam();
+ return ret;
+ }
+ } else {
+ jam();
+ // not NULL > NULL
+ return +1;
+ }
+ } else {
+ jam();
+ if (*entryKey != 0) {
+ jam();
+ // NULL < not NULL
+ return -1;
+ }
+ }
+ boundInfo += AttributeHeaderSize + boundInfo.ah().getDataSize();
+ entryKey += 1;
+ boundCount -= 1;
+ }
+ if (dir == 0) {
+ // lower bound
+ jam();
+ if (type == 1) {
+ jam();
+ return +1;
+ }
+ return -1;
+ } else {
+ // upper bound
+ jam();
+ if (type == 3) {
+ jam();
+ return -1;
+ }
+ return +1;
+ }
+}
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
index c4931685305..11f4f12b7f6 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
@@ -137,16 +137,17 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupLoc loc, PrintPar&
par.m_ok = false;
}
}
+ static const char* const sep = " *** ";
// check child-parent links
if (node.getLink(2) != par.m_parent) {
par.m_ok = false;
- out << par.m_path << " *** ";
+ out << par.m_path << sep;
out << "parent loc " << hex << node.getLink(2);
out << " should be " << hex << par.m_parent << endl;
}
if (node.getSide() != par.m_side) {
par.m_ok = false;
- out << par.m_path << " *** ";
+ out << par.m_path << sep;
out << "side " << dec << node.getSide();
out << " should be " << dec << par.m_side << endl;
}
@@ -154,26 +155,26 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupLoc loc, PrintPar&
const int balance = -cpar[0].m_depth + cpar[1].m_depth;
if (node.getBalance() != balance) {
par.m_ok = false;
- out << par.m_path << " *** ";
+ out << par.m_path << sep;
out << "balance " << node.getBalance();
out << " should be " << balance << endl;
}
if (abs(node.getBalance()) > 1) {
par.m_ok = false;
- out << par.m_path << " *** ";
+ out << par.m_path << sep;
out << "balance " << node.getBalance() << " is invalid" << endl;
}
// check occupancy
- if (node.getOccup() > tree.m_maxOccup) {
+ if (node.getOccup() == 0 || node.getOccup() > tree.m_maxOccup) {
par.m_ok = false;
- out << par.m_path << " *** ";
+ out << par.m_path << sep;
out << "occupancy " << node.getOccup();
- out << " greater than max " << tree.m_maxOccup << endl;
+ out << " zero or greater than max " << tree.m_maxOccup << endl;
}
// check for occupancy of interior node
if (node.getChilds() == 2 && node.getOccup() < tree.m_minOccup) {
par.m_ok = false;
- out << par.m_path << " *** ";
+ out << par.m_path << sep;
out << "occupancy " << node.getOccup() << " of interior node";
out << " less than min " << tree.m_minOccup << endl;
}
@@ -183,13 +184,74 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupLoc loc, PrintPar&
node.getLink(1 - i) == NullTupLoc &&
node.getOccup() + cpar[i].m_occup <= tree.m_maxOccup) {
par.m_ok = false;
- out << par.m_path << " *** ";
+ out << par.m_path << sep;
out << "missed merge with child " << i << endl;
}
}
+ // check inline prefix
+ { ConstData data1 = node.getPref();
+ Uint32 data2[MaxPrefSize];
+ memset(data2, DataFillByte, MaxPrefSize << 2);
+ readKeyAttrs(frag, node.getMinMax(0), 0, c_searchKey);
+ copyAttrs(frag, c_searchKey, data2, tree.m_prefSize);
+ for (unsigned n = 0; n < tree.m_prefSize; n++) {
+ if (data1[n] != data2[n]) {
+ par.m_ok = false;
+ out << par.m_path << sep;
+ out << "inline prefix mismatch word " << n;
+ out << " value " << hex << data1[n];
+ out << " should be " << hex << data2[n] << endl;
+ break;
+ }
+ }
+ }
+ // check ordering within node
+ for (unsigned j = 1; j < node.getOccup(); j++) {
+ unsigned start = 0;
+ const TreeEnt ent1 = node.getEnt(j - 1);
+ const TreeEnt ent2 = node.getEnt(j);
+ if (j == 1) {
+ readKeyAttrs(frag, ent1, start, c_searchKey);
+ } else {
+ memcpy(c_searchKey, c_entryKey, frag.m_numAttrs << 2);
+ }
+ readKeyAttrs(frag, ent2, start, c_entryKey);
+ int ret = cmpSearchKey(frag, start, c_searchKey, c_entryKey);
+ if (ret == 0)
+ ret = ent1.cmp(ent2);
+ if (ret != -1) {
+ par.m_ok = false;
+ out << par.m_path << sep;
+ out << " disorder within node at pos " << j << endl;
+ }
+ }
+ // check ordering wrt subtrees
+ for (unsigned i = 0; i <= 1; i++) {
+ if (node.getLink(i) == NullTupLoc)
+ continue;
+ const TreeEnt ent1 = cpar[i].m_minmax[1 - i];
+ const TreeEnt ent2 = node.getMinMax(i);
+ unsigned start = 0;
+ readKeyAttrs(frag, ent1, start, c_searchKey);
+ readKeyAttrs(frag, ent2, start, c_entryKey);
+ int ret = cmpSearchKey(frag, start, c_searchKey, c_entryKey);
+ if (ret == 0)
+ ret = ent1.cmp(ent2);
+ if (ret != (i == 0 ? -1 : +1)) {
+ par.m_ok = false;
+ out << par.m_path << sep;
+ out << " disorder wrt subtree " << i << endl;
+ }
+ }
// return values
par.m_depth = 1 + max(cpar[0].m_depth, cpar[1].m_depth);
par.m_occup = node.getOccup();
+ for (unsigned i = 0; i <= 1; i++) {
+ if (node.getLink(i) == NullTupLoc)
+ par.m_minmax[i] = node.getMinMax(i);
+ else
+ par.m_minmax[i] = cpar[i].m_minmax[i];
+ }
}
NdbOut&
@@ -355,20 +417,19 @@ operator<<(NdbOut& out, const Dbtux::NodeHandle& node)
out << " [acc " << dec << node.m_acc << "]";
out << " [node " << *node.m_node << "]";
if (node.m_acc >= Dbtux::AccPref) {
- for (unsigned i = 0; i <= 1; i++) {
- out << " [pref " << dec << i;
- const Uint32* data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize + i * tree.m_prefSize;
- for (unsigned j = 0; j < node.m_frag.m_tree.m_prefSize; j++)
- out << " " << hex << data[j];
- 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;
if (node.m_acc < Dbtux::AccFull && numpos > 2) {
numpos = 2;
out << "(" << dec << numpos << ")";
}
- const Uint32* data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize + 2 * tree.m_prefSize;
+ 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];
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
index 93a5c78338c..22b2ce69838 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
@@ -26,8 +26,13 @@ Dbtux::Dbtux(const Configuration& conf) :
#ifdef VM_TRACE
debugFile(0),
debugOut(*new NullOutputStream()),
+ // until ndb_mgm supports dump
+#ifdef DBTUX_DEBUG_TREE
+ debugFlags(DebugTree),
+#else
debugFlags(0),
#endif
+#endif
c_internalStartPhase(0),
c_typeOfStart(NodeState::ST_ILLEGAL_TYPE),
c_dataBuffer(0)
@@ -241,37 +246,14 @@ Dbtux::readKeyAttrs(const Frag& frag, TreeEnt ent, unsigned start, TableData key
}
void
-Dbtux::copyAttrs(Data dst, ConstData src, CopyPar& copyPar)
+Dbtux::readTablePk(const Frag& frag, TreeEnt ent, unsigned& pkSize, Data pkData)
{
- CopyPar c = copyPar;
- c.m_numitems = 0;
- c.m_numwords = 0;
- while (c.m_numitems < c.m_items) {
- jam();
- if (c.m_headers) {
- unsigned i = 0;
- while (i < AttributeHeaderSize) {
- if (c.m_numwords >= c.m_maxwords) {
- copyPar = c;
- return;
- }
- dst[c.m_numwords++] = src[i++];
- }
- }
- unsigned size = src.ah().getDataSize();
- src += AttributeHeaderSize;
- unsigned i = 0;
- while (i < size) {
- if (c.m_numwords >= c.m_maxwords) {
- copyPar = c;
- return;
- }
- dst[c.m_numwords++] = src[i++];
- }
- src += size;
- c.m_numitems++;
- }
- copyPar = c;
+ const Uint32 tableFragPtrI = frag.m_tupTableFragPtrI[ent.m_fragBit];
+ const TupLoc tupLoc = ent.m_tupLoc;
+ Uint32 size = 0;
+ c_tup->tuxReadKeys(tableFragPtrI, tupLoc.m_pageId, tupLoc.m_pageOffset, &size, pkData);
+ ndbrequire(size != 0);
+ pkSize = size;
}
/*
@@ -314,6 +296,9 @@ Dbtux::copyAttrs(const Frag& frag, TableData data1, Data data2, unsigned maxlen2
keyAttrs += 1;
data1 += 1;
}
+#ifdef VM_TRACE
+ memset(data2, DataFillByte, len2 << 2);
+#endif
}
BLOCK_FUNCTIONS(Dbtux);
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
index fc72611a273..24b030bf8ec 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
@@ -82,8 +82,8 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal)
ent.m_fragBit = fragBit;
// read search key
readKeyAttrs(frag, ent, 0, c_searchKey);
- // check if all keys are null
- {
+ if (! frag.m_storeNullKey) {
+ // check if all keys are null
const unsigned numAttrs = frag.m_numAttrs;
bool allNull = true;
for (unsigned i = 0; i < numAttrs; i++) {
@@ -111,19 +111,18 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal)
debugOut << endl;
}
#endif
- // find position in tree
- TreePos treePos;
- treeSearch(signal, frag, c_searchKey, ent, treePos);
-#ifdef VM_TRACE
- if (debugFlags & DebugMaint) {
- debugOut << treePos << endl;
- }
-#endif
// do the operation
req->errorCode = 0;
+ TreePos treePos;
switch (opCode) {
case TuxMaintReq::OpAdd:
jam();
+ searchToAdd(signal, frag, c_searchKey, ent, treePos);
+#ifdef VM_TRACE
+ if (debugFlags & DebugMaint) {
+ debugOut << treePos << endl;
+ }
+#endif
if (treePos.m_match) {
jam();
// there is no "Building" state so this will have to do
@@ -152,6 +151,12 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal)
break;
case TuxMaintReq::OpRemove:
jam();
+ searchToRemove(signal, frag, c_searchKey, ent, treePos);
+#ifdef VM_TRACE
+ if (debugFlags & DebugMaint) {
+ debugOut << treePos << endl;
+ }
+#endif
if (! treePos.m_match) {
jam();
// there is no "Building" state so this will have to do
@@ -167,7 +172,6 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal)
ndbrequire(false);
break;
}
- // commit and release nodes
#ifdef VM_TRACE
if (debugFlags & DebugTree) {
printTree(signal, frag, debugOut);
@@ -176,89 +180,3 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal)
// copy back
*sig = *req;
}
-
-/*
- * Read index key attributes from TUP. If buffer is provided the data
- * is copied to it. Otherwise pointer is set to signal data.
- */
-void
-Dbtux::tupReadAttrs(Signal* signal, const Frag& frag, ReadPar& readPar)
-{
- // define the direct signal
- const TreeEnt ent = readPar.m_ent;
- TupReadAttrs* const req = (TupReadAttrs*)signal->getDataPtrSend();
- req->errorCode = RNIL;
- req->requestInfo = 0;
- req->tableId = frag.m_tableId;
- req->fragId = frag.m_fragId | (ent.m_fragBit << frag.m_fragOff);
- req->fragPtrI = frag.m_tupTableFragPtrI[ent.m_fragBit];
- req->tupAddr = (Uint32)-1;
- req->tupVersion = ent.m_tupVersion;
- req->pageId = ent.m_tupLoc.m_pageId;
- req->pageOffset = ent.m_tupLoc.m_pageOffset;
- req->bufferId = 0;
- // add count and list of attribute ids
- Data data = (Uint32*)req + TupReadAttrs::SignalLength;
- data[0] = readPar.m_count;
- data += 1;
- const DescEnt& descEnt = getDescEnt(frag.m_descPage, frag.m_descOff);
- for (Uint32 i = 0; i < readPar.m_count; i++) {
- jam();
- const DescAttr& descAttr = descEnt.m_descAttr[readPar.m_first + i];
- data.ah() = AttributeHeader(descAttr.m_primaryAttrId, 0);
- data += 1;
- }
- // execute
- EXECUTE_DIRECT(DBTUP, GSN_TUP_READ_ATTRS, signal, TupReadAttrs::SignalLength);
- jamEntry();
- ndbrequire(req->errorCode == 0);
- // data is at output
- if (readPar.m_data == 0) {
- readPar.m_data = data;
- } else {
- jam();
- CopyPar copyPar;
- copyPar.m_items = readPar.m_count;
- copyPar.m_headers = true;
- copyAttrs(readPar.m_data, data, copyPar);
- }
-}
-
-/*
- * Read primary keys. Copy the data without attribute headers into the
- * given buffer. Number of words is returned in ReadPar argument.
- */
-void
-Dbtux::tupReadKeys(Signal* signal, const Frag& frag, ReadPar& readPar)
-{
- // define the direct signal
- const TreeEnt ent = readPar.m_ent;
- TupReadAttrs* const req = (TupReadAttrs*)signal->getDataPtrSend();
- req->errorCode = RNIL;
- req->requestInfo = TupReadAttrs::ReadKeys;
- req->tableId = frag.m_tableId;
- req->fragId = frag.m_fragId | (ent.m_fragBit << frag.m_fragOff);
- req->fragPtrI = frag.m_tupTableFragPtrI[ent.m_fragBit];
- req->tupAddr = (Uint32)-1;
- req->tupVersion = RNIL; // not used
- req->pageId = ent.m_tupLoc.m_pageId;
- req->pageOffset = ent.m_tupLoc.m_pageOffset;
- req->bufferId = 0;
- // execute
- EXECUTE_DIRECT(DBTUP, GSN_TUP_READ_ATTRS, signal, TupReadAttrs::SignalLength);
- jamEntry();
- ndbrequire(req->errorCode == 0);
- // copy out in special format
- ConstData data = (Uint32*)req + TupReadAttrs::SignalLength;
- const Uint32 numKeys = data[0];
- data += 1 + numKeys;
- // copy out without headers
- ndbrequire(readPar.m_data != 0);
- CopyPar copyPar;
- copyPar.m_items = numKeys;
- copyPar.m_headers = false;
- copyAttrs(readPar.m_data, data, copyPar);
- // return counts
- readPar.m_count = numKeys;
- readPar.m_size = copyPar.m_numwords;
-}
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
index ca6a3e69931..b30b555ccad 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
@@ -85,6 +85,7 @@ Dbtux::execTUXFRAGREQ(Signal* signal)
fragPtr.p->m_fragOff = req->fragOff;
fragPtr.p->m_fragId = req->fragId;
fragPtr.p->m_numAttrs = req->noOfAttr;
+ fragPtr.p->m_storeNullKey = true; // not yet configurable
fragPtr.p->m_tupIndexFragPtrI = req->tupIndexFragPtrI;
fragPtr.p->m_tupTableFragPtrI[0] = req->tupTableFragPtrI[0];
fragPtr.p->m_tupTableFragPtrI[1] = req->tupTableFragPtrI[1];
@@ -111,6 +112,7 @@ Dbtux::execTUXFRAGREQ(Signal* signal)
indexPtr.p->m_tableId = req->primaryTableId;
indexPtr.p->m_fragOff = req->fragOff;
indexPtr.p->m_numAttrs = req->noOfAttr;
+ indexPtr.p->m_storeNullKey = true; // not yet configurable
// allocate attribute descriptors
if (! allocDescEnt(indexPtr)) {
jam();
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp
index c969e35dc82..a1bfa2179bb 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp
@@ -85,10 +85,9 @@ Dbtux::insertNode(Signal* signal, NodeHandle& node, AccSize acc)
new (node.m_node) TreeNode();
#ifdef VM_TRACE
TreeHead& tree = frag.m_tree;
- memset(node.getPref(0), 0xa2, tree.m_prefSize << 2);
- memset(node.getPref(1), 0xa2, tree.m_prefSize << 2);
+ memset(node.getPref(), DataFillByte, tree.m_prefSize << 2);
TreeEnt* entList = tree.getEntList(node.m_node);
- memset(entList, 0xa4, (tree.m_maxOccup + 1) * (TreeEntSize << 2));
+ memset(entList, NodeFillByte, (tree.m_maxOccup + 1) * (TreeEntSize << 2));
#endif
}
@@ -116,12 +115,12 @@ Dbtux::deleteNode(Signal* signal, NodeHandle& node)
* attribute headers for now. XXX use null mask instead
*/
void
-Dbtux::setNodePref(Signal* signal, NodeHandle& node, unsigned i)
+Dbtux::setNodePref(Signal* signal, NodeHandle& node)
{
const Frag& frag = node.m_frag;
const TreeHead& tree = frag.m_tree;
- readKeyAttrs(frag, node.getMinMax(i), 0, c_entryKey);
- copyAttrs(frag, c_entryKey, node.getPref(i), tree.m_prefSize);
+ readKeyAttrs(frag, node.getMinMax(0), 0, c_entryKey);
+ copyAttrs(frag, c_entryKey, node.getPref(), tree.m_prefSize);
}
// node operations
@@ -173,11 +172,9 @@ Dbtux::nodePushUp(Signal* signal, NodeHandle& node, unsigned pos, const TreeEnt&
tmpList[pos] = ent;
entList[0] = entList[occup + 1];
node.setOccup(occup + 1);
- // fix prefixes
+ // fix prefix
if (occup == 0 || pos == 0)
- setNodePref(signal, node, 0);
- if (occup == 0 || pos == occup)
- setNodePref(signal, node, 1);
+ setNodePref(signal, node);
}
/*
@@ -248,11 +245,9 @@ Dbtux::nodePopDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent)
}
entList[0] = entList[occup - 1];
node.setOccup(occup - 1);
- // fix prefixes
+ // fix prefix
if (occup != 1 && pos == 0)
- setNodePref(signal, node, 0);
- if (occup != 1 && pos == occup - 1)
- setNodePref(signal, node, 1);
+ setNodePref(signal, node);
}
/*
@@ -325,11 +320,9 @@ Dbtux::nodePushDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent
tmpList[pos] = ent;
ent = oldMin;
entList[0] = entList[occup];
- // fix prefixes
+ // fix prefix
if (true)
- setNodePref(signal, node, 0);
- if (occup == 1 || pos == occup - 1)
- setNodePref(signal, node, 1);
+ setNodePref(signal, node);
}
/*
@@ -403,11 +396,9 @@ Dbtux::nodePopUp(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent)
}
tmpList[0] = newMin;
entList[0] = entList[occup];
- // fix prefixes
+ // fix prefix
if (true)
- setNodePref(signal, node, 0);
- if (occup == 1 || pos == occup - 1)
- setNodePref(signal, node, 1);
+ setNodePref(signal, node);
}
/*
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
index 703b0abb683..c4c33ff931f 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
@@ -137,7 +137,7 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal)
const Uint32* const data = (Uint32*)sig + TuxBoundInfo::SignalLength;
unsigned offset = 5;
// walk through entries
- while (offset + 2 < req->boundAiLength) {
+ while (offset + 2 <= req->boundAiLength) {
jam();
const unsigned type = data[offset];
if (type > 4) {
@@ -379,8 +379,8 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
scanNext(signal, scanPtr);
}
// for reading tuple key in Current or Locked state
- ReadPar keyPar;
- keyPar.m_data = 0; // indicates not yet done
+ Data pkData = c_dataBuffer;
+ unsigned pkSize = 0; // indicates not yet done
if (scan.m_state == ScanOp::Current) {
// found an entry to return
jam();
@@ -389,9 +389,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
jam();
const TreeEnt ent = scan.m_scanPos.m_ent;
// read tuple key
- keyPar.m_ent = ent;
- keyPar.m_data = c_dataBuffer;
- tupReadKeys(signal, frag, keyPar);
+ readTablePk(frag, ent, pkSize, pkData);
// get read lock or exclusive lock
AccLockReq* const lockReq = (AccLockReq*)signal->getDataPtrSend();
lockReq->returnCode = RNIL;
@@ -403,9 +401,9 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
lockReq->tableId = scan.m_tableId;
lockReq->fragId = frag.m_fragId | (ent.m_fragBit << frag.m_fragOff);
lockReq->fragPtrI = frag.m_accTableFragPtrI[ent.m_fragBit];
- const Uint32* const buf32 = static_cast<Uint32*>(keyPar.m_data);
+ const Uint32* const buf32 = static_cast<Uint32*>(pkData);
const Uint64* const buf64 = reinterpret_cast<const Uint64*>(buf32);
- lockReq->hashValue = md5_hash(buf64, keyPar.m_size);
+ lockReq->hashValue = md5_hash(buf64, pkSize);
lockReq->tupAddr = getTupAddr(frag, ent);
lockReq->transId1 = scan.m_transId1;
lockReq->transId2 = scan.m_transId2;
@@ -480,11 +478,9 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
const TreeEnt ent = scan.m_scanPos.m_ent;
if (scan.m_keyInfo) {
jam();
- if (keyPar.m_data == 0) {
+ if (pkSize == 0) {
jam();
- keyPar.m_ent = ent;
- keyPar.m_data = c_dataBuffer;
- tupReadKeys(signal, frag, keyPar);
+ readTablePk(frag, ent, pkSize, pkData);
}
}
// conf signal
@@ -510,10 +506,10 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
// add key info
if (scan.m_keyInfo) {
jam();
- conf->keyLength = keyPar.m_size;
+ conf->keyLength = pkSize;
// piggy-back first 4 words of key data
for (unsigned i = 0; i < 4; i++) {
- conf->key[i] = i < keyPar.m_size ? keyPar.m_data[i] : 0;
+ conf->key[i] = i < pkSize ? pkData[i] : 0;
}
signalLength = 11;
}
@@ -525,18 +521,18 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
EXECUTE_DIRECT(blockNo, GSN_NEXT_SCANCONF, signal, signalLength);
}
// send rest of key data
- if (scan.m_keyInfo && keyPar.m_size > 4) {
+ if (scan.m_keyInfo && pkSize > 4) {
unsigned total = 4;
- while (total < keyPar.m_size) {
+ while (total < pkSize) {
jam();
- unsigned length = keyPar.m_size - total;
+ unsigned length = pkSize - total;
if (length > 20)
length = 20;
signal->theData[0] = scan.m_userPtr;
signal->theData[1] = 0;
signal->theData[2] = 0;
signal->theData[3] = length;
- memcpy(&signal->theData[4], &keyPar.m_data[total], length << 2);
+ memcpy(&signal->theData[4], &pkData[total], length << 2);
sendSignal(scan.m_userRef, GSN_ACC_SCAN_INFO24,
signal, 4 + length, JBB);
total += length;
@@ -606,6 +602,8 @@ Dbtux::execACCKEYCONF(Signal* signal)
// LQH has the ball
return;
}
+ // lose the lock
+ scan.m_accLockOp = RNIL;
// continue at ACC_ABORTCONF
}
@@ -648,6 +646,8 @@ Dbtux::execACCKEYREF(Signal* signal)
// LQH has the ball
return;
}
+ // lose the lock
+ scan.m_accLockOp = RNIL;
// continue at ACC_ABORTCONF
}
@@ -689,16 +689,9 @@ Dbtux::scanFirst(Signal* signal, ScanOpPtr scanPtr)
ScanOp& scan = *scanPtr.p;
Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI);
TreeHead& tree = frag.m_tree;
- if (tree.m_root == NullTupLoc) {
- // tree may have become empty
- jam();
- scan.m_state = ScanOp::Last;
- return;
- }
- TreePos pos;
- pos.m_loc = tree.m_root;
- NodeHandle node(frag);
- // unpack lower bound
+ // set up index keys for this operation
+ setKeyAttrs(frag);
+ // unpack lower bound into c_dataBuffer
const ScanBound& bound = *scan.m_bound[0];
ScanBoundIterator iter;
bound.first(iter);
@@ -707,103 +700,22 @@ Dbtux::scanFirst(Signal* signal, ScanOpPtr scanPtr)
c_dataBuffer[j] = *iter.data;
bound.next(iter);
}
- // comparison parameters
- BoundPar boundPar;
- boundPar.m_data1 = c_dataBuffer;
- boundPar.m_count1 = scan.m_boundCnt[0];
- boundPar.m_dir = 0;
-loop: {
+ // search for scan start position
+ TreePos treePos;
+ searchToScan(signal, frag, c_dataBuffer, scan.m_boundCnt[0], treePos);
+ if (treePos.m_loc == NullTupLoc) {
+ // empty tree
jam();
- selectNode(signal, node, pos.m_loc, AccPref);
- const unsigned occup = node.getOccup();
- ndbrequire(occup != 0);
- for (unsigned i = 0; i <= 1; i++) {
- jam();
- // compare prefix
- boundPar.m_data2 = node.getPref(i);
- boundPar.m_len2 = tree.m_prefSize;
- int ret = cmpScanBound(frag, boundPar);
- if (ret == NdbSqlUtil::CmpUnknown) {
- jam();
- // read full value
- ReadPar readPar;
- readPar.m_ent = node.getMinMax(i);
- readPar.m_first = 0;
- readPar.m_count = frag.m_numAttrs;
- readPar.m_data = 0; // leave in signal data
- tupReadAttrs(signal, frag, readPar);
- // compare full value
- boundPar.m_data2 = readPar.m_data;
- boundPar.m_len2 = ZNIL; // big
- ret = cmpScanBound(frag, boundPar);
- ndbrequire(ret != NdbSqlUtil::CmpUnknown);
- }
- if (i == 0 && ret < 0) {
- jam();
- const TupLoc loc = node.getLink(i);
- if (loc != NullTupLoc) {
- jam();
- // continue to left subtree
- pos.m_loc = loc;
- goto loop;
- }
- // start scanning this node
- pos.m_pos = 0;
- pos.m_match = false;
- pos.m_dir = 3;
- scan.m_scanPos = pos;
- scan.m_state = ScanOp::Next;
- linkScan(node, scanPtr);
- return;
- }
- if (i == 1 && ret > 0) {
- jam();
- const TupLoc loc = node.getLink(i);
- if (loc != NullTupLoc) {
- jam();
- // continue to right subtree
- pos.m_loc = loc;
- goto loop;
- }
- // start scanning upwards
- pos.m_dir = 1;
- scan.m_scanPos = pos;
- scan.m_state = ScanOp::Next;
- linkScan(node, scanPtr);
- return;
- }
- }
- // read rest of current node
- accessNode(signal, node, AccFull);
- // look for first entry
- ndbrequire(occup >= 2);
- for (unsigned j = 1; j < occup; j++) {
- jam();
- ReadPar readPar;
- readPar.m_ent = node.getEnt(j);
- readPar.m_first = 0;
- readPar.m_count = frag.m_numAttrs;
- readPar.m_data = 0; // leave in signal data
- tupReadAttrs(signal, frag, readPar);
- // compare
- boundPar.m_data2 = readPar.m_data;
- boundPar.m_len2 = ZNIL; // big
- int ret = cmpScanBound(frag, boundPar);
- ndbrequire(ret != NdbSqlUtil::CmpUnknown);
- if (ret < 0) {
- jam();
- // start scanning this node
- pos.m_pos = j;
- pos.m_match = false;
- pos.m_dir = 3;
- scan.m_scanPos = pos;
- scan.m_state = ScanOp::Next;
- linkScan(node, scanPtr);
- return;
- }
- }
- ndbrequire(false);
+ scan.m_state = ScanOp::Last;
+ return;
}
+ // set position and state
+ scan.m_scanPos = treePos;
+ scan.m_state = ScanOp::Next;
+ // link the scan to node found
+ NodeHandle node(frag);
+ selectNode(signal, node, treePos.m_loc, AccFull);
+ linkScan(node, scanPtr);
}
/*
@@ -830,7 +742,9 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
if (scan.m_state == ScanOp::Locked) {
jam();
// version of a tuple locked by us cannot disappear (assert only)
+#ifdef dbtux_wl_1942_is_done
ndbassert(false);
+#endif
AccLockReq* const lockReq = (AccLockReq*)signal->getDataPtrSend();
lockReq->returnCode = RNIL;
lockReq->requestInfo = AccLockReq::Unlock;
@@ -841,7 +755,9 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
scan.m_accLockOp = RNIL;
scan.m_state = ScanOp::Current;
}
- // unpack upper bound
+ // set up index keys for this operation
+ setKeyAttrs(frag);
+ // unpack upper bound into c_dataBuffer
const ScanBound& bound = *scan.m_bound[1];
ScanBoundIterator iter;
bound.first(iter);
@@ -850,11 +766,6 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
c_dataBuffer[j] = *iter.data;
bound.next(iter);
}
- // comparison parameters
- BoundPar boundPar;
- boundPar.m_data1 = c_dataBuffer;
- boundPar.m_count1 = scan.m_boundCnt[1];
- boundPar.m_dir = 1;
// use copy of position
TreePos pos = scan.m_scanPos;
// get and remember original node
@@ -912,17 +823,9 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
jam();
pos.m_ent = node.getEnt(pos.m_pos);
pos.m_dir = 3; // unchanged
- // XXX implement prefix optimization
- ReadPar readPar;
- readPar.m_ent = pos.m_ent;
- readPar.m_first = 0;
- readPar.m_count = frag.m_numAttrs;
- readPar.m_data = 0; // leave in signal data
- tupReadAttrs(signal, frag, readPar);
- // compare
- boundPar.m_data2 = readPar.m_data;
- boundPar.m_len2 = ZNIL; // big
- int ret = cmpScanBound(frag, boundPar);
+ // read and compare all attributes
+ readKeyAttrs(frag, pos.m_ent, 0, c_entryKey);
+ int ret = cmpScanBound(frag, 1, c_dataBuffer, scan.m_boundCnt[1], c_entryKey);
ndbrequire(ret != NdbSqlUtil::CmpUnknown);
if (ret < 0) {
jam();
@@ -994,35 +897,25 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr)
bool
Dbtux::scanVisible(Signal* signal, ScanOpPtr scanPtr, TreeEnt ent)
{
- TupQueryTh* const req = (TupQueryTh*)signal->getDataPtrSend();
const ScanOp& scan = *scanPtr.p;
const Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI);
- /* Assign table, fragment, tuple address + version */
- Uint32 tableId = frag.m_tableId;
Uint32 fragBit = ent.m_fragBit;
+ Uint32 tableFragPtrI = frag.m_tupTableFragPtrI[fragBit];
Uint32 fragId = frag.m_fragId | (fragBit << frag.m_fragOff);
Uint32 tupAddr = getTupAddr(frag, ent);
Uint32 tupVersion = ent.m_tupVersion;
- /* Check for same tuple twice in row */
+ // check for same tuple twice in row
if (scan.m_lastEnt.m_tupLoc == ent.m_tupLoc &&
scan.m_lastEnt.m_fragBit == fragBit) {
jam();
return false;
}
- req->tableId = tableId;
- req->fragId = fragId;
- req->tupAddr = tupAddr;
- req->tupVersion = tupVersion;
- /* Assign transaction info, trans id + savepoint id */
Uint32 transId1 = scan.m_transId1;
Uint32 transId2 = scan.m_transId2;
Uint32 savePointId = scan.m_savePointId;
- req->transId1 = transId1;
- req->transId2 = transId2;
- req->savePointId = savePointId;
- EXECUTE_DIRECT(DBTUP, GSN_TUP_QUERY_TH, signal, TupQueryTh::SignalLength);
+ bool ret = c_tup->tuxQueryTh(tableFragPtrI, tupAddr, tupVersion, transId1, transId2, savePointId);
jamEntry();
- return (bool)req->returnCode;
+ return ret;
}
/*
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp
new file mode 100644
index 00000000000..84048b308bc
--- /dev/null
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp
@@ -0,0 +1,333 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#define DBTUX_SEARCH_CPP
+#include "Dbtux.hpp"
+
+/*
+ * Search for entry to add.
+ *
+ * Similar to searchToRemove (see below).
+ *
+ * TODO optimize for initial equal attrs in node min/max
+ */
+void
+Dbtux::searchToAdd(Signal* signal, Frag& frag, TableData searchKey, TreeEnt searchEnt, TreePos& treePos)
+{
+ const TreeHead& tree = frag.m_tree;
+ const unsigned numAttrs = frag.m_numAttrs;
+ NodeHandle currNode(frag);
+ currNode.m_loc = tree.m_root;
+ if (currNode.m_loc == NullTupLoc) {
+ // empty tree
+ jam();
+ treePos.m_match = false;
+ return;
+ }
+ NodeHandle glbNode(frag); // potential g.l.b of final node
+ /*
+ * In order to not (yet) change old behaviour, a position between
+ * 2 nodes returns the one at the bottom of the tree.
+ */
+ NodeHandle bottomNode(frag);
+ while (true) {
+ jam();
+ selectNode(signal, currNode, currNode.m_loc, AccPref);
+ int ret;
+ // compare prefix
+ unsigned start = 0;
+ ret = cmpSearchKey(frag, start, searchKey, currNode.getPref(), tree.m_prefSize);
+ if (ret == NdbSqlUtil::CmpUnknown) {
+ jam();
+ // read and compare remaining attributes
+ ndbrequire(start < numAttrs);
+ readKeyAttrs(frag, currNode.getMinMax(0), start, c_entryKey);
+ ret = cmpSearchKey(frag, start, searchKey, c_entryKey);
+ ndbrequire(ret != NdbSqlUtil::CmpUnknown);
+ }
+ if (ret == 0) {
+ jam();
+ // keys are equal, compare entry values
+ ret = searchEnt.cmp(currNode.getMinMax(0));
+ }
+ if (ret < 0) {
+ jam();
+ const TupLoc loc = currNode.getLink(0);
+ if (loc != NullTupLoc) {
+ jam();
+ // continue to left subtree
+ currNode.m_loc = loc;
+ continue;
+ }
+ if (! glbNode.isNull()) {
+ jam();
+ // move up to the g.l.b but remember the bottom node
+ bottomNode = currNode;
+ currNode = glbNode;
+ }
+ } else if (ret > 0) {
+ jam();
+ const TupLoc loc = currNode.getLink(1);
+ if (loc != NullTupLoc) {
+ jam();
+ // save potential g.l.b
+ glbNode = currNode;
+ // continue to right subtree
+ currNode.m_loc = loc;
+ continue;
+ }
+ } else {
+ 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);
+ for (unsigned j = 0, occup = currNode.getOccup(); j < occup; j++) {
+ jam();
+ int ret;
+ // read and compare attributes
+ unsigned start = 0;
+ readKeyAttrs(frag, currNode.getEnt(j), start, c_entryKey);
+ ret = cmpSearchKey(frag, start, searchKey, c_entryKey);
+ ndbrequire(ret != NdbSqlUtil::CmpUnknown);
+ if (ret == 0) {
+ jam();
+ // keys are equal, compare entry values
+ ret = searchEnt.cmp(currNode.getEnt(j));
+ }
+ if (ret <= 0) {
+ jam();
+ treePos.m_loc = currNode.m_loc;
+ treePos.m_pos = j;
+ treePos.m_match = (ret == 0);
+ return;
+ }
+ }
+ if (! bottomNode.isNull()) {
+ jam();
+ // backwards compatible for now
+ treePos.m_loc = bottomNode.m_loc;
+ treePos.m_pos = 0;
+ treePos.m_match = false;
+ return;
+ }
+ treePos.m_loc = currNode.m_loc;
+ treePos.m_pos = currNode.getOccup();
+ treePos.m_match = false;
+}
+
+/*
+ * Search for entry to remove.
+ *
+ * Compares search key to each node min. A move to right subtree can
+ * overshoot target node. The last such node is saved. The final node
+ * is a half-leaf or leaf. If search key is less than final node min
+ * then the saved node is the g.l.b of the final node and we move back
+ * to it.
+ */
+void
+Dbtux::searchToRemove(Signal* signal, Frag& frag, TableData searchKey, TreeEnt searchEnt, TreePos& treePos)
+{
+ const TreeHead& tree = frag.m_tree;
+ const unsigned numAttrs = frag.m_numAttrs;
+ NodeHandle currNode(frag);
+ currNode.m_loc = tree.m_root;
+ if (currNode.m_loc == NullTupLoc) {
+ // empty tree
+ jam();
+ 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);
+ int ret;
+ // compare prefix
+ unsigned start = 0;
+ ret = cmpSearchKey(frag, start, searchKey, currNode.getPref(), tree.m_prefSize);
+ if (ret == NdbSqlUtil::CmpUnknown) {
+ jam();
+ // read and compare remaining attributes
+ ndbrequire(start < numAttrs);
+ readKeyAttrs(frag, currNode.getMinMax(0), start, c_entryKey);
+ ret = cmpSearchKey(frag, start, searchKey, c_entryKey);
+ ndbrequire(ret != NdbSqlUtil::CmpUnknown);
+ }
+ if (ret == 0) {
+ jam();
+ // keys are equal, compare entry values
+ ret = searchEnt.cmp(currNode.getMinMax(0));
+ }
+ if (ret < 0) {
+ jam();
+ const TupLoc loc = currNode.getLink(0);
+ if (loc != NullTupLoc) {
+ jam();
+ // continue to left subtree
+ currNode.m_loc = loc;
+ continue;
+ }
+ if (! glbNode.isNull()) {
+ jam();
+ // move up to the g.l.b
+ currNode = glbNode;
+ }
+ } else if (ret > 0) {
+ jam();
+ const TupLoc loc = currNode.getLink(1);
+ if (loc != NullTupLoc) {
+ jam();
+ // save potential g.l.b
+ glbNode = currNode;
+ // continue to right subtree
+ currNode.m_loc = loc;
+ continue;
+ }
+ } else {
+ 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);
+ // 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();
+ treePos.m_match = false;
+}
+
+/*
+ * Search for scan start position.
+ *
+ * Similar to searchToAdd.
+ */
+void
+Dbtux::searchToScan(Signal* signal, Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos)
+{
+ const TreeHead& tree = frag.m_tree;
+ NodeHandle currNode(frag);
+ currNode.m_loc = tree.m_root;
+ if (currNode.m_loc == NullTupLoc) {
+ // empty tree
+ jam();
+ treePos.m_match = false;
+ return;
+ }
+ NodeHandle glbNode(frag); // potential g.l.b of final node
+ NodeHandle bottomNode(frag);
+ while (true) {
+ jam();
+ selectNode(signal, currNode, currNode.m_loc, AccPref);
+ int ret;
+ // compare prefix
+ ret = cmpScanBound(frag, 0, boundInfo, boundCount, currNode.getPref(), tree.m_prefSize);
+ if (ret == NdbSqlUtil::CmpUnknown) {
+ jam();
+ // read and compare all attributes
+ readKeyAttrs(frag, currNode.getMinMax(0), 0, c_entryKey);
+ ret = cmpScanBound(frag, 0, boundInfo, boundCount, c_entryKey);
+ ndbrequire(ret != NdbSqlUtil::CmpUnknown);
+ }
+ if (ret < 0) {
+ jam();
+ const TupLoc loc = currNode.getLink(0);
+ if (loc != NullTupLoc) {
+ jam();
+ // continue to left subtree
+ currNode.m_loc = loc;
+ continue;
+ }
+ if (! glbNode.isNull()) {
+ jam();
+ // move up to the g.l.b but remember the bottom node
+ bottomNode = currNode;
+ currNode = glbNode;
+ } else {
+ // start scanning this node
+ treePos.m_loc = currNode.m_loc;
+ treePos.m_pos = 0;
+ treePos.m_match = false;
+ treePos.m_dir = 3;
+ return;
+ }
+ } else if (ret > 0) {
+ jam();
+ const TupLoc loc = currNode.getLink(1);
+ if (loc != NullTupLoc) {
+ jam();
+ // save potential g.l.b
+ glbNode = currNode;
+ // continue to right subtree
+ currNode.m_loc = loc;
+ continue;
+ }
+ } else {
+ ndbassert(false);
+ }
+ break;
+ }
+ // access rest of current node
+ accessNode(signal, currNode, AccFull);
+ for (unsigned j = 0, occup = currNode.getOccup(); j < occup; j++) {
+ jam();
+ int ret;
+ // read and compare attributes
+ readKeyAttrs(frag, currNode.getEnt(j), 0, c_entryKey);
+ ret = cmpScanBound(frag, 0, boundInfo, boundCount, c_entryKey);
+ ndbrequire(ret != NdbSqlUtil::CmpUnknown);
+ if (ret < 0) {
+ // start scanning from current entry
+ treePos.m_loc = currNode.m_loc;
+ treePos.m_pos = j;
+ treePos.m_match = false;
+ treePos.m_dir = 3;
+ return;
+ }
+ }
+ if (! bottomNode.isNull()) {
+ jam();
+ // start scanning the l.u.b
+ treePos.m_loc = bottomNode.m_loc;
+ treePos.m_pos = 0;
+ treePos.m_match = false;
+ treePos.m_dir = 3;
+ return;
+ }
+ // start scanning upwards (pretend we came from right child)
+ treePos.m_loc = currNode.m_loc;
+ treePos.m_dir = 1;
+}
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp
index 02ed9739f3c..3baa62998db 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp
@@ -18,112 +18,6 @@
#include "Dbtux.hpp"
/*
- * Search for entry.
- *
- * Search key is index attribute data and tree entry value. Start from
- * root node and compare the key to min/max of each node. Use linear
- * search on the final (bounding) node. Initial attributes which are
- * same in min/max need not be checked.
- */
-void
-Dbtux::treeSearch(Signal* signal, Frag& frag, TableData searchKey, TreeEnt searchEnt, TreePos& treePos)
-{
- const TreeHead& tree = frag.m_tree;
- const unsigned numAttrs = frag.m_numAttrs;
- treePos.m_loc = tree.m_root;
- if (treePos.m_loc == NullTupLoc) {
- // empty tree
- jam();
- treePos.m_pos = 0;
- treePos.m_match = false;
- return;
- }
- NodeHandle node(frag);
-loop: {
- jam();
- selectNode(signal, node, treePos.m_loc, AccPref);
- const unsigned occup = node.getOccup();
- ndbrequire(occup != 0);
- // number of equal initial attributes in bounding node
- unsigned start = ZNIL;
- for (unsigned i = 0; i <= 1; i++) {
- jam();
- unsigned start1 = 0;
- // compare prefix
- int ret = cmpSearchKey(frag, start1, searchKey, node.getPref(i), tree.m_prefSize);
- if (ret == NdbSqlUtil::CmpUnknown) {
- jam();
- // read and compare remaining attributes
- readKeyAttrs(frag, node.getMinMax(i), start1, c_entryKey);
- ret = cmpSearchKey(frag, start1, searchKey, c_entryKey);
- ndbrequire(ret != NdbSqlUtil::CmpUnknown);
- }
- if (start > start1)
- start = start1;
- if (ret == 0) {
- jam();
- // keys are equal, compare entry values
- ret = searchEnt.cmp(node.getMinMax(i));
- }
- if (i == 0 ? (ret < 0) : (ret > 0)) {
- jam();
- const TupLoc loc = node.getLink(i);
- if (loc != NullTupLoc) {
- jam();
- // continue to left/right subtree
- treePos.m_loc = loc;
- goto loop;
- }
- // position is immediately before/after this node
- treePos.m_pos = (i == 0 ? 0 : occup);
- treePos.m_match = false;
- return;
- }
- if (ret == 0) {
- jam();
- // position is at first/last entry
- treePos.m_pos = (i == 0 ? 0 : occup - 1);
- treePos.m_match = true;
- return;
- }
- }
- // access rest of the bounding node
- accessNode(signal, node, AccFull);
- // position is strictly within the node
- ndbrequire(occup >= 2);
- const unsigned numWithin = occup - 2;
- for (unsigned j = 1; j <= numWithin; j++) {
- jam();
- int ret = 0;
- if (start < numAttrs) {
- jam();
- // read and compare remaining attributes
- unsigned start1 = start;
- readKeyAttrs(frag, node.getEnt(j), start1, c_entryKey);
- ret = cmpSearchKey(frag, start1, searchKey, c_entryKey);
- ndbrequire(ret != NdbSqlUtil::CmpUnknown);
- }
- if (ret == 0) {
- jam();
- // keys are equal, compare entry values
- ret = searchEnt.cmp(node.getEnt(j));
- }
- if (ret <= 0) {
- jam();
- // position is before or at this entry
- treePos.m_pos = j;
- treePos.m_match = (ret == 0);
- return;
- }
- }
- // position is before last entry
- treePos.m_pos = occup - 1;
- treePos.m_match = false;
- return;
- }
-}
-
-/*
* Add entry.
*/
void
diff --git a/ndb/src/kernel/blocks/dbtux/Makefile.am b/ndb/src/kernel/blocks/dbtux/Makefile.am
index 0b48ad5724f..7d012924522 100644
--- a/ndb/src/kernel/blocks/dbtux/Makefile.am
+++ b/ndb/src/kernel/blocks/dbtux/Makefile.am
@@ -7,6 +7,7 @@ libdbtux_a_SOURCES = \
DbtuxNode.cpp \
DbtuxTree.cpp \
DbtuxScan.cpp \
+ DbtuxSearch.cpp \
DbtuxCmp.cpp \
DbtuxDebug.cpp
diff --git a/ndb/src/kernel/blocks/dbtux/Times.txt b/ndb/src/kernel/blocks/dbtux/Times.txt
index 16c4102249b..c4744a23c07 100644
--- a/ndb/src/kernel/blocks/dbtux/Times.txt
+++ b/ndb/src/kernel/blocks/dbtux/Times.txt
@@ -1,17 +1,32 @@
-index maintenance overhead
-==========================
+ordered index performance
+=========================
"mc02" 2x1700 MHz linux-2.4.9 gcc-2.96 -O3 one db-node
-case a: index on Unsigned
-testOIBasic -case u -table 1 -index 1 -fragtype small -threads 10 -rows 100000 -subloop 1 -nologging
+case a: maintenance: index on Unsigned
+testOIBasic -case u -table 1 -index 2 -fragtype small -threads 10 -rows 100000 -subloop 1 -nologging
-case b: index on Varchar(5) + Varchar(5) + Varchar(20) + Unsigned
-testOIBasic -case u -table 2 -index 4 -fragtype small -threads 10 -rows 100000 -subloop 1 -nologging
+case b: maintenance: index on Varchar(5) + Varchar(5) + Varchar(20) + Unsigned
+testOIBasic -case u -table 2 -index 5 -fragtype small -threads 10 -rows 100000 -subloop 1 -nologging
+case c: full scan: index on PK Unsigned
+testOIBasic -case v -table 1 -index 1 -fragtype small -threads 10 -rows 100000 -subloop 1 -nologging
+
+case d: scan 1 tuple via EQ: index on PK Unsigned
+testOIBasic -case w -table 1 -index 1 -fragtype small -threads 10 -rows 100000 -samples 10000 -subloop 1 -nologging -v2
+
+a, b
1 million rows, pk update without index, pk update with index
shows ms / 1000 rows for each and pct overhead
-the figures are based on single run on idle machine
+
+c
+1 million rows, index on PK, full table scan, full index scan
+shows ms / 1000 rows for each and index time overhead
+
+d
+1 million rows, index on PK, read table via each pk, scan index for each pk
+shows ms / 1000 rows for each and index time overhead
+samples 10% of all PKs (100,000 pk reads, 100,000 scans)
040616 mc02/a 40 ms 87 ms 114 pct
mc02/b 51 ms 128 ms 148 pct
@@ -49,4 +64,22 @@ optim 10 mc02/a 44 ms 65 ms 46 pct
optim 11 mc02/a 43 ms 63 ms 46 pct
mc02/b 52 ms 86 ms 63 pct
+optim 12 mc02/a 38 ms 55 ms 43 pct
+ mc02/b 47 ms 77 ms 63 pct
+ mc02/c 10 ms 14 ms 47 pct
+ mc02/d 176 ms 281 ms 59 pct
+
+optim 13 mc02/a 40 ms 57 ms 42 pct
+ mc02/b 47 ms 77 ms 61 pct
+ mc02/c 9 ms 13 ms 50 pct
+ mc02/d 170 ms 256 ms 50 pct
+
+after wl-1884 store all-NULL keys (the tests have pctnull=10 per column)
+[ what happened to PK read performance? ]
+
+optim 13 mc02/a 39 ms 59 ms 50 pct
+ mc02/b 47 ms 77 ms 61 pct
+ mc02/c 9 ms 12 ms 44 pct
+ mc02/d 246 ms 289 ms 17 pct
+
vim: set et:
diff --git a/ndb/src/mgmapi/Makefile.am b/ndb/src/mgmapi/Makefile.am
index e4fa1d449c6..bf209ddccb5 100644
--- a/ndb/src/mgmapi/Makefile.am
+++ b/ndb/src/mgmapi/Makefile.am
@@ -9,5 +9,10 @@ DEFS_LOC = -DNO_DEBUG_MESSAGES
include $(top_srcdir)/ndb/config/common.mk.am
include $(top_srcdir)/ndb/config/type_util.mk.am
+#ndbtest_PROGRAMS = ndb_test_mgmapi
+ndb_test_mgmapi_SOURCES = test_mgmapi.cpp
+ndb_test_mgmapi_LDFLAGS = @ndb_bin_am_ldflags@ \
+ $(top_builddir)/ndb/src/libndbclient.la
+
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp
index ca77ae9fb63..ccc63cc7e70 100644
--- a/ndb/src/mgmsrv/MgmtSrvr.cpp
+++ b/ndb/src/mgmsrv/MgmtSrvr.cpp
@@ -172,7 +172,7 @@ MgmtSrvr::signalRecvThreadRun()
siglist.push_back(SigMatch(GSN_MGM_UNLOCK_CONFIG_REQ,
&MgmtSrvr::handle_MGM_UNLOCK_CONFIG_REQ));
- while(1) {
+ while(!_isStopThread) {
SigMatch *handler = NULL;
NdbApiSignal *signal = NULL;
if(m_signalRecvQueue.waitFor(siglist, handler, signal)) {
@@ -413,14 +413,18 @@ MgmtSrvr::getPort() const {
ndbout << "Local node id " << getOwnNodeId()
<< " is not defined as management server" << endl
<< "Have you set correct NodeId for this node?" << endl;
+ ndb_mgm_destroy_iterator(iter);
return 0;
}
Uint32 port = 0;
if(ndb_mgm_get_int_parameter(iter, CFG_MGM_PORT, &port) != 0){
ndbout << "Could not find PortNumber in the configuration file." << endl;
+ ndb_mgm_destroy_iterator(iter);
return 0;
}
+
+ ndb_mgm_destroy_iterator(iter);
/*****************
* Set Stat Port *
@@ -515,6 +519,7 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId,
_isStopThread = false;
_logLevelThread = NULL;
_logLevelThreadSleep = 500;
+ m_signalRecvThread = NULL;
_startedNodeId = 0;
theFacade = 0;
@@ -696,6 +701,11 @@ MgmtSrvr::~MgmtSrvr()
NdbThread_WaitFor(_logLevelThread, &res);
NdbThread_Destroy(&_logLevelThread);
}
+
+ if (m_signalRecvThread != NULL) {
+ NdbThread_WaitFor(m_signalRecvThread, &res);
+ NdbThread_Destroy(&m_signalRecvThread);
+ }
}
//****************************************************************************
diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp
index 603ae85ad65..7d51974da7c 100644
--- a/ndb/src/ndbapi/NdbScanOperation.cpp
+++ b/ndb/src/ndbapi/NdbScanOperation.cpp
@@ -1120,7 +1120,6 @@ NdbIndexScanOperation::setBound(const NdbColumnImpl* tAttrInfo,
if (theOperationType == OpenRangeScanRequest &&
theStatus == SetBound &&
(0 <= type && type <= 4) &&
- aValue != NULL &&
len <= 8000) {
// bound type
@@ -1131,20 +1130,22 @@ NdbIndexScanOperation::setBound(const NdbColumnImpl* tAttrInfo,
setErrorCodeAbort(4209);
return -1;
}
- len = sizeInBytes;
+ len = aValue != NULL ? sizeInBytes : 0;
Uint32 tIndexAttrId = tAttrInfo->m_attrId;
Uint32 sizeInWords = (len + 3) / 4;
AttributeHeader ah(tIndexAttrId, sizeInWords);
insertATTRINFO(ah.m_value);
- // attribute data
- if ((UintPtr(aValue) & 0x3) == 0 && (len & 0x3) == 0)
- insertATTRINFOloop((const Uint32*)aValue, sizeInWords);
- else {
- Uint32 temp[2000];
- memcpy(temp, aValue, len);
- while ((len & 0x3) != 0)
- ((char*)temp)[len++] = 0;
- insertATTRINFOloop(temp, sizeInWords);
+ if (len != 0) {
+ // attribute data
+ if ((UintPtr(aValue) & 0x3) == 0 && (len & 0x3) == 0)
+ insertATTRINFOloop((const Uint32*)aValue, sizeInWords);
+ else {
+ Uint32 temp[2000];
+ memcpy(temp, aValue, len);
+ while ((len & 0x3) != 0)
+ ((char*)temp)[len++] = 0;
+ insertATTRINFOloop(temp, sizeInWords);
+ }
}
/**
@@ -1231,7 +1232,7 @@ NdbIndexScanOperation::compare(Uint32 skip, Uint32 cols,
Uint32 * d2 = (Uint32*)r2->aRef();
unsigned r1_null = r1->isNULL();
if((r1_null ^ (unsigned)r2->isNULL())){
- return (r1_null ? 1 : -1);
+ return (r1_null ? -1 : 1);
}
Uint32 type = NdbColumnImpl::getImpl(* r1->m_column).m_extType;
Uint32 size = (r1->theAttrSize * r1->theArraySize + 3) / 4;
diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp
index ee59e661cfb..7ad37401b9a 100644
--- a/ndb/src/ndbapi/Ndbif.cpp
+++ b/ndb/src/ndbapi/Ndbif.cpp
@@ -350,47 +350,46 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
return;
}
- case GSN_TRANSID_AI:
- {
- tFirstDataPtr = int2void(tFirstData);
- assert(tFirstDataPtr);
- if (tFirstDataPtr == 0) goto InvalidSignal;
- NdbReceiver* tRec = void2rec(tFirstDataPtr);
- assert(tRec->checkMagicNumber());
- assert(tRec->getTransaction());
- assert(tRec->getTransaction()->checkState_TransId(((const TransIdAI*)tDataPtr)->transId));
- if(tRec->checkMagicNumber() && (tCon = tRec->getTransaction()) &&
- tCon->checkState_TransId(((const TransIdAI*)tDataPtr)->transId)){
- Uint32 com;
- if(aSignal->m_noOfSections > 0){
- com = tRec->execTRANSID_AI(ptr[0].p, ptr[0].sz);
- } else {
- com = tRec->execTRANSID_AI(tDataPtr + TransIdAI::HeaderLength,
- tLen - TransIdAI::HeaderLength);
- }
-
- if(com == 1){
- switch(tRec->getType()){
- case NdbReceiver::NDB_OPERATION:
- case NdbReceiver::NDB_INDEX_OPERATION:
- if(tCon->OpCompleteSuccess() != -1){
- completedTransaction(tCon);
- return;
- }
- break;
- case NdbReceiver::NDB_SCANRECEIVER:
- tCon->theScanningOp->receiver_delivered(tRec);
- theWaiter.m_state = (tWaitState == WAIT_SCAN? NO_WAIT: tWaitState);
- break;
- default:
- goto InvalidSignal;
+ case GSN_TRANSID_AI:{
+ tFirstDataPtr = int2void(tFirstData);
+ NdbReceiver* tRec;
+ if (tFirstDataPtr && (tRec = void2rec(tFirstDataPtr)) &&
+ tRec->checkMagicNumber() && (tCon = tRec->getTransaction()) &&
+ tCon->checkState_TransId(((const TransIdAI*)tDataPtr)->transId)){
+ Uint32 com;
+ if(aSignal->m_noOfSections > 0){
+ com = tRec->execTRANSID_AI(ptr[0].p, ptr[0].sz);
+ } else {
+ com = tRec->execTRANSID_AI(tDataPtr + TransIdAI::HeaderLength,
+ tLen - TransIdAI::HeaderLength);
+ }
+
+ if(com == 1){
+ switch(tRec->getType()){
+ case NdbReceiver::NDB_OPERATION:
+ case NdbReceiver::NDB_INDEX_OPERATION:
+ if(tCon->OpCompleteSuccess() != -1){
+ completedTransaction(tCon);
+ return;
}
+ break;
+ case NdbReceiver::NDB_SCANRECEIVER:
+ tCon->theScanningOp->receiver_delivered(tRec);
+ theWaiter.m_state = (tWaitState == WAIT_SCAN ? NO_WAIT : tWaitState);
+ break;
+ default:
+ goto InvalidSignal;
}
- break;
- } else {
- goto InvalidSignal;
}
+ break;
+ } else {
+ /**
+ * This is ok as transaction can have been aborted before TRANSID_AI
+ * arrives (if TUP on other node than TC)
+ */
+ return;
}
+ }
case GSN_TCKEY_FAILCONF:
{
tFirstDataPtr = int2void(tFirstData);
@@ -695,7 +694,8 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
(tCon = void2con(tFirstDataPtr)) && (tCon->checkMagicNumber() == 0)){
if(aSignal->m_noOfSections > 0){
- tReturnCode = tCon->receiveSCAN_TABCONF(aSignal, ptr[0].p, ptr[0].sz);
+ tReturnCode = tCon->receiveSCAN_TABCONF(aSignal,
+ ptr[0].p, ptr[0].sz);
} else {
tReturnCode =
tCon->receiveSCAN_TABCONF(aSignal,
@@ -730,12 +730,11 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
}
case GSN_KEYINFO20: {
tFirstDataPtr = int2void(tFirstData);
- if (tFirstDataPtr == 0) goto InvalidSignal;
- NdbReceiver* tRec = void2rec(tFirstDataPtr);
-
- if(tRec->checkMagicNumber() && (tCon = tRec->getTransaction()) &&
- tCon->checkState_TransId(&((const KeyInfo20*)tDataPtr)->transId1)){
-
+ NdbReceiver* tRec;
+ if (tFirstDataPtr && (tRec = void2rec(tFirstDataPtr)) &&
+ tRec->checkMagicNumber() && (tCon = tRec->getTransaction()) &&
+ tCon->checkState_TransId(&((const KeyInfo20*)tDataPtr)->transId1)){
+
Uint32 len = ((const KeyInfo20*)tDataPtr)->keyLen;
Uint32 info = ((const KeyInfo20*)tDataPtr)->scanInfo_Node;
int com = -1;
@@ -756,8 +755,13 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
goto InvalidSignal;
}
break;
+ } else {
+ /**
+ * This is ok as transaction can have been aborted before KEYINFO20
+ * arrives (if TUP on other node than TC)
+ */
+ return;
}
- goto InvalidSignal;
}
case GSN_TCINDXCONF:{
tFirstDataPtr = int2void(tFirstData);
diff --git a/ndb/test/ndbapi/testBasic.cpp b/ndb/test/ndbapi/testBasic.cpp
index 24bb8058f4b..26622f9b066 100644
--- a/ndb/test/ndbapi/testBasic.cpp
+++ b/ndb/test/ndbapi/testBasic.cpp
@@ -962,6 +962,7 @@ int runMassiveRollback(NDBT_Context* ctx, NDBT_Step* step){
const Uint32 OPS_TOTAL = 4096;
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++){
@@ -972,7 +973,12 @@ int runMassiveRollback(NDBT_Context* ctx, NDBT_Step* step){
if(result != NDBT_OK){
break;
}
- CHECK(hugoOps.execute_NoCommit(pNdb) == 0);
+ res = hugoOps.execute_NoCommit(pNdb);
+ if(res != 0){
+ NdbError err = pNdb->getNdbError(res);
+ CHECK(err.classification == NdbError::TimeoutExpired);
+ break;
+ }
}
if(result != NDBT_OK){
break;
diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp
index cd7b34b647b..c58dd8538e9 100644
--- a/ndb/test/ndbapi/testOIBasic.cpp
+++ b/ndb/test/ndbapi/testOIBasic.cpp
@@ -33,14 +33,18 @@
struct Opt {
// common options
+ unsigned m_batch;
const char* m_case;
bool m_core;
bool m_dups;
NdbDictionary::Object::FragmentType m_fragtype;
+ unsigned m_idxloop;
const char* m_index;
unsigned m_loop;
bool m_nologging;
+ bool m_msglock;
unsigned m_rows;
+ unsigned m_samples;
unsigned m_scanrd;
unsigned m_scanex;
unsigned m_seed;
@@ -49,17 +53,21 @@ struct Opt {
unsigned m_threads;
unsigned m_v;
Opt() :
+ m_batch(32),
m_case(0),
m_core(false),
m_dups(false),
m_fragtype(NdbDictionary::Object::FragUndefined),
+ m_idxloop(4),
m_index(0),
m_loop(1),
m_nologging(false),
+ m_msglock(true),
m_rows(1000),
+ m_samples(0),
m_scanrd(240),
m_scanex(240),
- m_seed(1),
+ m_seed(0),
m_subloop(4),
m_table(0),
m_threads(4),
@@ -78,17 +86,19 @@ printhelp()
Opt d;
ndbout
<< "usage: testOIbasic [options]" << endl
+ << " -batch N pk operations in batch [" << d.m_batch << "]" << endl
<< " -case abc only given test cases (letters a-z)" << endl
<< " -core core dump on error [" << d.m_core << "]" << endl
<< " -dups allow duplicate tuples from index scan [" << d.m_dups << "]" << endl
<< " -fragtype T fragment type single/small/medium/large" << endl
<< " -index xyz only given index numbers (digits 1-9)" << endl
- << " -loop N loop count full suite forever=0 [" << d.m_loop << "]" << endl
+ << " -loop N loop count full suite 0=forever [" << d.m_loop << "]" << endl
<< " -nologging create tables in no-logging mode" << endl
<< " -rows N rows per thread [" << d.m_rows << "]" << endl
+ << " -samples N samples for some timings (0=all) [" << d.m_samples << "]" << endl
<< " -scanrd N scan read parallelism [" << d.m_scanrd << "]" << endl
<< " -scanex N scan exclusive parallelism [" << d.m_scanex << "]" << endl
- << " -seed N srandom seed [" << d.m_seed << "]" << endl
+ << " -seed N srandom seed 0=loop number[" << d.m_seed << "]" << endl
<< " -subloop N subtest loop count [" << d.m_subloop << "]" << endl
<< " -table xyz only given table numbers (digits 1-9)" << endl
<< " -threads N number of threads [" << d.m_threads << "]" << endl
@@ -99,6 +109,12 @@ printhelp()
printtables();
}
+// not yet configurable
+static const bool g_store_null_key = true;
+
+// compare NULL like normal value (NULL < not NULL, NULL == NULL)
+static const bool g_compare_null = true;
+
// log and error macros
static NdbMutex ndbout_mutex = NDB_MUTEX_INITIALIZER;
@@ -124,9 +140,9 @@ getthrstr()
#define LLN(n, s) \
do { \
if ((n) > g_opt.m_v) break; \
- NdbMutex_Lock(&ndbout_mutex); \
+ if (g_opt.m_msglock) NdbMutex_Lock(&ndbout_mutex); \
ndbout << getthrstr() << s << endl; \
- NdbMutex_Unlock(&ndbout_mutex); \
+ if (g_opt.m_msglock) NdbMutex_Unlock(&ndbout_mutex); \
} while(0)
#define LL0(s) LLN(0, s)
@@ -139,11 +155,10 @@ getthrstr()
// following check a condition and return -1 on failure
#undef CHK // simple check
-#undef CHKTRY // execute action (try-catch) on failure
-#undef CHKMSG // print extra message on failure
+#undef CHKTRY // check with action on fail
#undef CHKCON // print NDB API errors on failure
-#define CHK(x) CHKTRY(x, ;)
+#define CHK(x) CHKTRY(x, ;)
#define CHKTRY(x, act) \
do { \
@@ -154,14 +169,6 @@ getthrstr()
return -1; \
} while (0)
-#define CHKMSG(x, msg) \
- do { \
- if (x) break; \
- LL0("line " << __LINE__ << ": " << #x << " failed: " << msg); \
- if (g_opt.m_core) abort(); \
- return -1; \
- } while (0)
-
#define CHKCON(x, con) \
do { \
if (x) break; \
@@ -177,6 +184,7 @@ class Thr;
class Con;
class Tab;
class Set;
+class Tmr;
struct Par : public Opt {
unsigned m_no;
@@ -186,14 +194,17 @@ struct Par : public Opt {
const Tab& tab() const { assert(m_tab != 0); return *m_tab; }
Set* m_set;
Set& set() const { assert(m_set != 0); return *m_set; }
+ Tmr* m_tmr;
+ Tmr& tmr() const { assert(m_tmr != 0); return *m_tmr; }
unsigned m_totrows;
- unsigned m_batch;
// value calculation
unsigned m_pctnull;
unsigned m_range;
unsigned m_pctrange;
// do verify after read
bool m_verify;
+ // deadlock possible
+ bool m_deadlock;
// timer location
Par(const Opt& opt) :
Opt(opt),
@@ -201,12 +212,13 @@ struct Par : public Opt {
m_con(0),
m_tab(0),
m_set(0),
+ m_tmr(0),
m_totrows(m_threads * m_rows),
- m_batch(32),
m_pctnull(10),
m_range(m_rows),
m_pctrange(0),
- m_verify(false) {
+ m_verify(false),
+ m_deadlock(false) {
}
};
@@ -241,19 +253,20 @@ struct Tmr {
void on();
void off(unsigned cnt = 0);
const char* time();
+ const char* pct(const Tmr& t1);
const char* over(const Tmr& t1);
NDB_TICKS m_on;
unsigned m_ms;
unsigned m_cnt;
char m_time[100];
- char m_over[100];
+ char m_text[100];
Tmr() { clr(); }
};
void
Tmr::clr()
{
- m_on = m_ms = m_cnt = m_time[0] = m_over[0] = 0;
+ m_on = m_ms = m_cnt = m_time[0] = m_text[0] = 0;
}
void
@@ -285,14 +298,63 @@ Tmr::time()
}
const char*
+Tmr::pct(const Tmr& t1)
+{
+ if (0 < t1.m_ms) {
+ sprintf(m_text, "%u pct", (100 * m_ms) / t1.m_ms);
+ } else {
+ sprintf(m_text, "[cannot measure]");
+ }
+ return m_text;
+}
+
+const char*
Tmr::over(const Tmr& t1)
{
- if (0 < t1.m_ms && t1.m_ms < m_ms) {
- sprintf(m_over, "%u pct", (100 * (m_ms - t1.m_ms)) / t1.m_ms);
+ if (0 < t1.m_ms) {
+ if (t1.m_ms <= m_ms)
+ sprintf(m_text, "%u pct", (100 * (m_ms - t1.m_ms)) / t1.m_ms);
+ else
+ sprintf(m_text, "-%u pct", (100 * (t1.m_ms - m_ms)) / t1.m_ms);
} else {
- sprintf(m_over, "[cannot measure]");
+ sprintf(m_text, "[cannot measure]");
}
- return m_over;
+ return m_text;
+}
+
+// list of ints
+
+struct Lst {
+ Lst();
+ unsigned m_arr[1000];
+ unsigned m_cnt;
+ void push(unsigned i);
+ unsigned cnt() const;
+ void reset();
+};
+
+Lst::Lst() :
+ m_cnt(0)
+{
+}
+
+void
+Lst::push(unsigned i)
+{
+ assert(m_cnt < sizeof(m_arr)/sizeof(m_arr[0]));
+ m_arr[m_cnt++] = i;
+}
+
+unsigned
+Lst::cnt() const
+{
+ return m_cnt;
+}
+
+void
+Lst::reset()
+{
+ m_cnt = 0;
}
// tables and indexes
@@ -409,7 +471,7 @@ operator<<(NdbOut& out, const Tab& tab)
return out;
}
-// tt1 + tt1x1 tt1x2 tt1x3 tt1x4
+// tt1 + tt1x1 tt1x2 tt1x3 tt1x4 tt1x5
static const Col
tt1col[] = {
@@ -422,24 +484,29 @@ tt1col[] = {
static const ICol
tt1x1col[] = {
- { 0, tt1col[1] }
+ { 0, tt1col[0] }
};
static const ICol
tt1x2col[] = {
+ { 0, tt1col[1] }
+};
+
+static const ICol
+tt1x3col[] = {
{ 0, tt1col[1] },
{ 1, tt1col[2] }
};
static const ICol
-tt1x3col[] = {
+tt1x4col[] = {
{ 0, tt1col[3] },
{ 1, tt1col[2] },
{ 2, tt1col[1] }
};
static const ICol
-tt1x4col[] = {
+tt1x5col[] = {
{ 0, tt1col[1] },
{ 1, tt1col[4] },
{ 2, tt1col[2] },
@@ -453,17 +520,22 @@ tt1x1 = {
static const ITab
tt1x2 = {
- "TT1X2", 2, tt1x2col
+ "TT1X2", 1, tt1x2col
};
static const ITab
tt1x3 = {
- "TT1X3", 3, tt1x3col
+ "TT1X3", 2, tt1x3col
};
static const ITab
tt1x4 = {
- "TT1X4", 4, tt1x4col
+ "TT1X4", 3, tt1x4col
+};
+
+static const ITab
+tt1x5 = {
+ "TT1X5", 4, tt1x5col
};
static const ITab
@@ -471,15 +543,16 @@ tt1itab[] = {
tt1x1,
tt1x2,
tt1x3,
- tt1x4
+ tt1x4,
+ tt1x5
};
static const Tab
tt1 = {
- "TT1", 5, tt1col, 4, tt1itab
+ "TT1", 5, tt1col, 5, tt1itab
};
-// tt2 + tt2x1 tt2x2 tt2x3 tt2x4
+// tt2 + tt2x1 tt2x2 tt2x3 tt2x4 tt2x5
static const Col
tt2col[] = {
@@ -492,24 +565,29 @@ tt2col[] = {
static const ICol
tt2x1col[] = {
+ { 0, tt2col[0] }
+};
+
+static const ICol
+tt2x2col[] = {
{ 0, tt2col[1] },
{ 1, tt2col[2] }
};
static const ICol
-tt2x2col[] = {
+tt2x3col[] = {
{ 0, tt2col[2] },
{ 1, tt2col[1] }
};
static const ICol
-tt2x3col[] = {
+tt2x4col[] = {
{ 0, tt2col[3] },
{ 1, tt2col[4] }
};
static const ICol
-tt2x4col[] = {
+tt2x5col[] = {
{ 0, tt2col[4] },
{ 1, tt2col[3] },
{ 2, tt2col[2] },
@@ -518,7 +596,7 @@ tt2x4col[] = {
static const ITab
tt2x1 = {
- "TT2X1", 2, tt2x1col
+ "TT2X1", 1, tt2x1col
};
static const ITab
@@ -533,7 +611,12 @@ tt2x3 = {
static const ITab
tt2x4 = {
- "TT2X4", 4, tt2x4col
+ "TT2X4", 2, tt2x4col
+};
+
+static const ITab
+tt2x5 = {
+ "TT2X5", 4, tt2x5col
};
static const ITab
@@ -541,12 +624,13 @@ tt2itab[] = {
tt2x1,
tt2x2,
tt2x3,
- tt2x4
+ tt2x4,
+ tt2x5
};
static const Tab
tt2 = {
- "TT2", 5, tt2col, 4, tt2itab
+ "TT2", 5, tt2col, 5, tt2itab
};
// all tables
@@ -577,10 +661,14 @@ struct Con {
Con() :
m_ndb(0), m_dic(0), m_tx(0), m_op(0),
m_scanop(0), m_indexscanop(0), m_resultset(0), m_scanmode(ScanNo), m_errtype(ErrNone) {}
+ ~Con() {
+ if (m_tx != 0)
+ closeTransaction();
+ }
int connect();
+ void connect(const Con& con);
void disconnect();
int startTransaction();
- int startBuddyTransaction(const Con& con);
int getNdbOperation(const Tab& tab);
int getNdbScanOperation(const Tab& tab);
int getNdbScanOperation(const ITab& itab, const Tab& tab);
@@ -589,20 +677,16 @@ struct Con {
int setValue(int num, const char* addr);
int setBound(int num, int type, const void* value);
int execute(ExecType t);
+ int execute(ExecType t, bool& deadlock);
int openScanRead(unsigned parallelism);
int openScanExclusive(unsigned parallelism);
int executeScan();
- int nextScanResult();
- int takeOverForUpdate(Con& scan);
- int takeOverForDelete(Con& scan);
+ int nextScanResult(bool fetchAllowed);
+ int nextScanResult(bool fetchAllowed, bool& deadlock);
+ int updateScanTuple(Con& con2);
+ int deleteScanTuple(Con& con2);
void closeTransaction();
void printerror(NdbOut& out);
- // flush dict cache
- int bugger() {
- //disconnect();
- //CHK(connect() == 0);
- return 0;
- }
};
int
@@ -612,12 +696,18 @@ Con::connect()
m_ndb = new Ndb("TEST_DB");
CHKCON(m_ndb->init() == 0, *this);
CHKCON(m_ndb->waitUntilReady(30) == 0, *this);
- m_dic = m_ndb->getDictionary();
m_tx = 0, m_op = 0;
return 0;
}
void
+Con::connect(const Con& con)
+{
+ assert(m_ndb == 0);
+ m_ndb = con.m_ndb;
+}
+
+void
Con::disconnect()
{
delete m_ndb;
@@ -627,20 +717,14 @@ Con::disconnect()
int
Con::startTransaction()
{
- assert(m_ndb != 0 && m_tx == 0);
+ assert(m_ndb != 0);
+ if (m_tx != 0)
+ closeTransaction();
CHKCON((m_tx = m_ndb->startTransaction()) != 0, *this);
return 0;
}
int
-Con::startBuddyTransaction(const Con& con)
-{
- assert(m_ndb != 0 && m_tx == 0 && con.m_ndb == m_ndb && con.m_tx != 0);
- CHKCON((m_tx = m_ndb->hupp(con.m_tx)) != 0, *this);
- return 0;
-}
-
-int
Con::getNdbOperation(const Tab& tab)
{
assert(m_tx != 0);
@@ -705,6 +789,22 @@ Con::execute(ExecType t)
}
int
+Con::execute(ExecType t, bool& deadlock)
+{
+ int ret = execute(t);
+ if (ret != 0) {
+ if (deadlock && m_errtype == ErrDeadlock) {
+ LL3("caught deadlock");
+ ret = 0;
+ }
+ } else {
+ deadlock = false;
+ }
+ CHK(ret == 0);
+ return 0;
+}
+
+int
Con::openScanRead(unsigned parallelism)
{
assert(m_tx != 0 && m_op != 0);
@@ -728,28 +828,44 @@ Con::executeScan()
}
int
-Con::nextScanResult()
+Con::nextScanResult(bool fetchAllowed)
{
int ret;
assert(m_resultset != 0);
- CHKCON((ret = m_resultset->nextResult()) != -1, *this);
- assert(ret == 0 || ret == 1);
+ CHKCON((ret = m_resultset->nextResult(fetchAllowed)) != -1, *this);
+ assert(ret == 0 || ret == 1 || (! fetchAllowed && ret == 2));
return ret;
}
int
-Con::takeOverForUpdate(Con& scan)
+Con::nextScanResult(bool fetchAllowed, bool& deadlock)
{
- assert(m_tx != 0 && scan.m_op != 0);
- CHKCON((m_op = scan.m_resultset->updateTuple(m_tx)) != 0, scan);
+ int ret = nextScanResult(fetchAllowed);
+ if (ret == -1) {
+ if (deadlock && m_errtype == ErrDeadlock) {
+ LL3("caught deadlock");
+ ret = 0;
+ }
+ } else {
+ deadlock = false;
+ }
+ CHK(ret == 0 || ret == 1 || (! fetchAllowed && ret == 2));
+ return ret;
+}
+
+int
+Con::updateScanTuple(Con& con2)
+{
+ assert(con2.m_tx != 0);
+ CHKCON((con2.m_op = m_resultset->updateTuple(con2.m_tx)) != 0, *this);
return 0;
}
int
-Con::takeOverForDelete(Con& scan)
+Con::deleteScanTuple(Con& con2)
{
- assert(m_tx != 0 && scan.m_op != 0);
- CHKCON(scan.m_resultset->deleteTuple(m_tx) == 0, scan);
+ assert(con2.m_tx != 0);
+ CHKCON(m_resultset->deleteTuple(con2.m_tx) == 0, *this);
return 0;
}
@@ -777,7 +893,7 @@ Con::printerror(NdbOut& out)
if (m_tx) {
if ((code = m_tx->getNdbError().code) != 0) {
LL0(++any << " con: error " << m_tx->getNdbError());
- if (code == 266 || code == 274 || code == 296 || code == 297)
+ if (code == 266 || code == 274 || code == 296 || code == 297 || code == 499)
m_errtype = ErrDeadlock;
}
if (m_op && m_op->getNdbError().code != 0) {
@@ -797,7 +913,7 @@ invalidateindex(Par par, const ITab& itab)
{
Con& con = par.con();
const Tab& tab = par.tab();
- con.m_dic->invalidateIndex(itab.m_name, tab.m_name);
+ con.m_ndb->getDictionary()->invalidateIndex(itab.m_name, tab.m_name);
return 0;
}
@@ -821,7 +937,7 @@ invalidatetable(Par par)
Con& con = par.con();
const Tab& tab = par.tab();
invalidateindex(par);
- con.m_dic->invalidateTable(tab.m_name);
+ con.m_ndb->getDictionary()->invalidateTable(tab.m_name);
return 0;
}
@@ -830,6 +946,7 @@ droptable(Par par)
{
Con& con = par.con();
const Tab& tab = par.tab();
+ con.m_dic = con.m_ndb->getDictionary();
if (con.m_dic->getTable(tab.m_name) == 0) {
// how to check for error
LL4("no table " << tab.m_name);
@@ -837,6 +954,7 @@ droptable(Par par)
LL3("drop table " << tab.m_name);
CHKCON(con.m_dic->dropTable(tab.m_name) == 0, con);
}
+ con.m_dic = 0;
return 0;
}
@@ -844,7 +962,6 @@ static int
createtable(Par par)
{
Con& con = par.con();
- CHK(con.bugger() == 0);
const Tab& tab = par.tab();
LL3("create table " << tab.m_name);
LL4(tab);
@@ -864,7 +981,9 @@ createtable(Par par)
c.setNullable(col.m_nullable);
t.addColumn(c);
}
+ con.m_dic = con.m_ndb->getDictionary();
CHKCON(con.m_dic->createTable(t) == 0, con);
+ con.m_dic = 0;
return 0;
}
@@ -873,6 +992,7 @@ dropindex(Par par, const ITab& itab)
{
Con& con = par.con();
const Tab& tab = par.tab();
+ con.m_dic = con.m_ndb->getDictionary();
if (con.m_dic->getIndex(itab.m_name, tab.m_name) == 0) {
// how to check for error
LL4("no index " << itab.m_name);
@@ -880,6 +1000,7 @@ dropindex(Par par, const ITab& itab)
LL3("drop index " << itab.m_name);
CHKCON(con.m_dic->dropIndex(itab.m_name, tab.m_name) == 0, con);
}
+ con.m_dic = 0;
return 0;
}
@@ -900,7 +1021,6 @@ static int
createindex(Par par, const ITab& itab)
{
Con& con = par.con();
- CHK(con.bugger() == 0);
const Tab& tab = par.tab();
LL3("create index " << itab.m_name);
LL4(itab);
@@ -912,7 +1032,9 @@ createindex(Par par, const ITab& itab)
const Col& col = itab.m_icol[k].m_col;
x.addColumnName(col.m_name);
}
+ con.m_dic = con.m_ndb->getDictionary();
CHKCON(con.m_dic->createIndex(x) == 0, con);
+ con.m_dic = 0;
return 0;
}
@@ -1127,9 +1249,9 @@ Val::cmp(const Val& val2) const
assert(col.m_type == col2.m_type && col.m_length == col2.m_length);
if (m_null || val2.m_null) {
if (! m_null)
- return -1;
- if (! val2.m_null)
return +1;
+ if (! val2.m_null)
+ return -1;
return 0;
}
// verify data formats
@@ -1187,6 +1309,8 @@ struct Row {
const Tab& m_tab;
Val** m_val;
bool m_exist;
+ enum Op { NoOp = 0, ReadOp, InsOp, UpdOp, DelOp };
+ Op m_pending;
Row(const Tab& tab);
~Row();
void copy(const Row& row2);
@@ -1211,6 +1335,7 @@ Row::Row(const Tab& tab) :
m_val[k] = new Val(col);
}
m_exist = false;
+ m_pending = NoOp;
}
Row::~Row()
@@ -1248,7 +1373,7 @@ int
Row::verify(const Row& row2) const
{
const Tab& tab = m_tab;
- assert(&tab == &row2.m_tab);
+ assert(&tab == &row2.m_tab && m_exist && row2.m_exist);
for (unsigned k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k];
const Val& val2 = *row2.m_val[k];
@@ -1269,7 +1394,7 @@ Row::insrow(Par par)
const Val& val = *m_val[k];
CHK(val.setval(par) == 0);
}
- m_exist = true;
+ m_pending = InsOp;
return 0;
}
@@ -1285,6 +1410,7 @@ Row::updrow(Par par)
const Val& val = *m_val[k];
CHK(val.setval(par) == 0);
}
+ m_pending = UpdOp;
return 0;
}
@@ -1302,7 +1428,7 @@ Row::delrow(Par par)
if (col.m_pk)
CHK(val.setval(par) == 0);
}
- m_exist = false;
+ m_pending = DelOp;
return 0;
}
@@ -1319,7 +1445,6 @@ Row::selrow(Par par)
if (col.m_pk)
CHK(val.setval(par) == 0);
}
- m_exist = false;
return 0;
}
@@ -1334,6 +1459,7 @@ Row::setrow(Par par)
if (! col.m_pk)
CHK(val.setval(par) == 0);
}
+ m_pending = UpdOp;
return 0;
}
@@ -1361,6 +1487,10 @@ operator<<(NdbOut& out, const Row& row)
out << " ";
out << *row.m_val[i];
}
+ out << " [exist=" << row.m_exist;
+ if (row.m_pending)
+ out << " pending=" << row.m_pending;
+ out << "]";
return out;
}
@@ -1369,15 +1499,19 @@ operator<<(NdbOut& out, const Row& row)
struct Set {
const Tab& m_tab;
unsigned m_rows;
- unsigned m_count;
Row** m_row;
Row** m_saverow;
Row* m_keyrow;
NdbRecAttr** m_rec;
Set(const Tab& tab, unsigned rows);
~Set();
+ void reset();
+ unsigned count() const;
// row methods
bool exist(unsigned i) const;
+ Row::Op pending(unsigned i) const;
+ void notpending(unsigned i);
+ void notpending(const Lst& lst);
void calc(Par par, unsigned i);
int insrow(Par par, unsigned i);
int updrow(Par par, unsigned i);
@@ -1392,7 +1526,7 @@ struct Set {
void savepoint();
void commit();
void rollback();
- // locking (not perfect since ops may complete in different order)
+ // protect structure
NdbMutex* m_mutex;
void lock() {
NdbMutex_Lock(m_mutex);
@@ -1408,9 +1542,9 @@ Set::Set(const Tab& tab, unsigned rows) :
m_tab(tab)
{
m_rows = rows;
- m_count = 0;
m_row = new Row* [m_rows];
for (unsigned i = 0; i < m_rows; i++) {
+ // allocate on need to save space
m_row[i] = 0;
}
m_saverow = 0;
@@ -1437,11 +1571,47 @@ Set::~Set()
NdbMutex_Destroy(m_mutex);
}
+void
+Set::reset()
+{
+ for (unsigned i = 0; i < m_rows; i++) {
+ if (m_row[i] != 0) {
+ Row& row = *m_row[i];
+ row.m_exist = false;
+ }
+ }
+}
+
+unsigned
+Set::count() const
+{
+ unsigned count = 0;
+ for (unsigned i = 0; i < m_rows; i++) {
+ if (m_row[i] != 0) {
+ Row& row = *m_row[i];
+ if (row.m_exist)
+ count++;
+ }
+ }
+ return count;
+}
+
bool
Set::exist(unsigned i) const
{
assert(i < m_rows);
- return m_row[i] != 0 && m_row[i]->m_exist;
+ if (m_row[i] == 0) // not allocated => not exist
+ return false;
+ return m_row[i]->m_exist;
+}
+
+Row::Op
+Set::pending(unsigned i) const
+{
+ assert(i < m_rows);
+ if (m_row[i] == 0) // not allocated => not pending
+ return Row::NoOp;
+ return m_row[i]->m_pending;
}
void
@@ -1460,9 +1630,9 @@ Set::calc(Par par, unsigned i)
int
Set::insrow(Par par, unsigned i)
{
- assert(m_row[i] != 0 && m_count < m_rows);
- CHK(m_row[i]->insrow(par) == 0);
- m_count++;
+ assert(m_row[i] != 0);
+ Row& row = *m_row[i];
+ CHK(row.insrow(par) == 0);
return 0;
}
@@ -1470,16 +1640,17 @@ int
Set::updrow(Par par, unsigned i)
{
assert(m_row[i] != 0);
- CHK(m_row[i]->updrow(par) == 0);
+ Row& row = *m_row[i];
+ CHK(row.updrow(par) == 0);
return 0;
}
int
Set::delrow(Par par, unsigned i)
{
- assert(m_row[i] != 0 && m_count != 0);
- CHK(m_row[i]->delrow(par) == 0);
- m_count--;
+ assert(m_row[i] != 0);
+ Row& row = *m_row[i];
+ CHK(row.delrow(par) == 0);
return 0;
}
@@ -1519,7 +1690,7 @@ Set::getkey(Par par, unsigned* i)
assert(m_rec[0] != 0);
const char* aRef0 = m_rec[0]->aRef();
Uint32 key = *(const Uint32*)aRef0;
- CHKMSG(key < m_rows, "key=" << key << " rows=" << m_rows);
+ CHK(key < m_rows);
*i = key;
return 0;
}
@@ -1544,19 +1715,37 @@ Set::putval(unsigned i, bool force)
val.copy(aRef);
val.m_null = false;
}
- if (! row.m_exist) {
+ if (! row.m_exist)
row.m_exist = true;
- m_count++;
- }
return 0;
}
+void
+Set::notpending(unsigned i)
+{
+ assert(m_row[i] != 0);
+ Row& row = *m_row[i];
+ if (row.m_pending == Row::InsOp)
+ row.m_exist = true;
+ if (row.m_pending == Row::DelOp)
+ row.m_exist = false;
+ row.m_pending = Row::NoOp;
+}
+
+void
+Set::notpending(const Lst& lst)
+{
+ for (unsigned j = 0; j < lst.m_cnt; j++) {
+ unsigned i = lst.m_arr[j];
+ notpending(i);
+ }
+}
+
int
Set::verify(const Set& set2) const
{
const Tab& tab = m_tab;
assert(&tab == &set2.m_tab && m_rows == set2.m_rows);
- CHKMSG(m_count == set2.m_count, "set=" << m_count << " set2=" << set2.m_count);
for (unsigned i = 0; i < m_rows; i++) {
CHK(exist(i) == set2.exist(i));
if (! exist(i))
@@ -1630,8 +1819,8 @@ int
BVal::setbnd(Par par) const
{
Con& con = par.con();
- const char* addr = (const char*)dataaddr();
- assert(! m_null);
+ assert(g_compare_null || ! m_null);
+ const char* addr = ! m_null ? (const char*)dataaddr() : 0;
const ICol& icol = m_icol;
CHK(con.setBound(icol.m_num, m_type, addr) == 0);
return 0;
@@ -1659,7 +1848,10 @@ struct BSet {
unsigned m_bvals;
BVal** m_bval;
BSet(const Tab& tab, const ITab& itab, unsigned rows);
+ ~BSet();
+ void reset();
void calc(Par par);
+ void calcpk(Par par, unsigned i);
int setbnd(Par par) const;
void filter(const Set& set, Set& set2) const;
};
@@ -1671,12 +1863,31 @@ BSet::BSet(const Tab& tab, const ITab& itab, unsigned rows) :
m_bvals(0)
{
m_bval = new BVal* [m_alloc];
+ for (unsigned i = 0; i < m_alloc; i++) {
+ m_bval[i] = 0;
+ }
+}
+
+BSet::~BSet()
+{
+ delete [] m_bval;
+}
+
+void
+BSet::reset()
+{
+ while (m_bvals > 0) {
+ unsigned i = --m_bvals;
+ delete m_bval[i];
+ m_bval[i] = 0;
+ }
}
void
BSet::calc(Par par)
{
const ITab& itab = m_itab;
+ reset();
for (unsigned k = 0; k < itab.m_icols; k++) {
const ICol& icol = itab.m_icol[k];
const Col& col = icol.m_col;
@@ -1698,7 +1909,8 @@ BSet::calc(Par par)
if (k + 1 < itab.m_icols)
bval.m_type = 4;
// value generation parammeters
- par.m_pctnull = 0;
+ if (! g_compare_null)
+ par.m_pctnull = 0;
par.m_pctrange = 50; // bit higher
do {
bval.calc(par, 0);
@@ -1717,6 +1929,23 @@ BSet::calc(Par par)
}
}
+void
+BSet::calcpk(Par par, unsigned i)
+{
+ const ITab& itab = m_itab;
+ reset();
+ for (unsigned k = 0; k < itab.m_icols; k++) {
+ const ICol& icol = itab.m_icol[k];
+ const Col& col = icol.m_col;
+ assert(col.m_pk);
+ assert(m_bvals < m_alloc);
+ BVal& bval = *new BVal(icol);
+ m_bval[m_bvals++] = &bval;
+ bval.m_type = 4;
+ bval.calc(par, i);
+ }
+}
+
int
BSet::setbnd(Par par) const
{
@@ -1733,23 +1962,25 @@ BSet::filter(const Set& set, Set& set2) const
const Tab& tab = m_tab;
const ITab& itab = m_itab;
assert(&tab == &set2.m_tab && set.m_rows == set2.m_rows);
- assert(set2.m_count == 0);
+ assert(set2.count() == 0);
for (unsigned i = 0; i < set.m_rows; i++) {
if (! set.exist(i))
continue;
const Row& row = *set.m_row[i];
- bool ok1 = false;
- for (unsigned k = 0; k < itab.m_icols; k++) {
- const ICol& icol = itab.m_icol[k];
- const Col& col = icol.m_col;
- const Val& val = *row.m_val[col.m_num];
- if (! val.m_null) {
- ok1 = true;
- break;
+ if (! g_store_null_key) {
+ bool ok1 = false;
+ for (unsigned k = 0; k < itab.m_icols; k++) {
+ const ICol& icol = itab.m_icol[k];
+ const Col& col = icol.m_col;
+ const Val& val = *row.m_val[col.m_num];
+ if (! val.m_null) {
+ ok1 = true;
+ break;
+ }
}
+ if (! ok1)
+ continue;
}
- if (! ok1)
- continue;
bool ok2 = true;
for (unsigned j = 0; j < m_bvals; j++) {
const BVal& bval = *m_bval[j];
@@ -1781,7 +2012,6 @@ BSet::filter(const Set& set, Set& set2) const
assert(! row2.m_exist);
row2.copy(row);
row2.m_exist = true;
- set2.m_count++;
}
}
@@ -1806,28 +2036,46 @@ pkinsert(Par par)
Set& set = par.set();
LL3("pkinsert");
CHK(con.startTransaction() == 0);
- unsigned n = 0;
+ Lst lst;
for (unsigned j = 0; j < par.m_rows; j++) {
unsigned i = thrrow(par, j);
set.lock();
- if (set.exist(i)) {
+ if (set.exist(i) || set.pending(i)) {
set.unlock();
continue;
}
set.calc(par, i);
- LL4("pkinsert " << i << ": " << *set.m_row[i]);
- CHKTRY(set.insrow(par, i) == 0, set.unlock());
+ CHK(set.insrow(par, i) == 0);
set.unlock();
- if (++n == par.m_batch) {
- CHK(con.execute(Commit) == 0);
+ LL4("pkinsert " << i << ": " << *set.m_row[i]);
+ lst.push(i);
+ if (lst.cnt() == par.m_batch) {
+ bool deadlock = par.m_deadlock;
+ CHK(con.execute(Commit, deadlock) == 0);
con.closeTransaction();
+ if (deadlock) {
+ LL1("pkinsert: stop on deadlock");
+ return 0;
+ }
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ lst.reset();
CHK(con.startTransaction() == 0);
- n = 0;
}
}
- if (n != 0) {
- CHK(con.execute(Commit) == 0);
- n = 0;
+ if (lst.cnt() != 0) {
+ bool deadlock = par.m_deadlock;
+ CHK(con.execute(Commit, deadlock) == 0);
+ con.closeTransaction();
+ if (deadlock) {
+ LL1("pkinsert: stop on deadlock");
+ return 0;
+ }
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ return 0;
}
con.closeTransaction();
return 0;
@@ -1840,28 +2088,45 @@ pkupdate(Par par)
Set& set = par.set();
LL3("pkupdate");
CHK(con.startTransaction() == 0);
- unsigned n = 0;
+ Lst lst;
+ bool deadlock = false;
for (unsigned j = 0; j < par.m_rows; j++) {
unsigned i = thrrow(par, j);
set.lock();
- if (! set.exist(i)) {
+ if (! set.exist(i) || set.pending(i)) {
set.unlock();
continue;
}
set.calc(par, i);
- LL4("pkupdate " << i << ": " << *set.m_row[i]);
- CHKTRY(set.updrow(par, i) == 0, set.unlock());
+ CHK(set.updrow(par, i) == 0);
set.unlock();
- if (++n == par.m_batch) {
- CHK(con.execute(Commit) == 0);
+ LL4("pkupdate " << i << ": " << *set.m_row[i]);
+ lst.push(i);
+ if (lst.cnt() == par.m_batch) {
+ deadlock = par.m_deadlock;
+ CHK(con.execute(Commit, deadlock) == 0);
+ if (deadlock) {
+ LL1("pkupdate: stop on deadlock");
+ break;
+ }
con.closeTransaction();
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ lst.reset();
CHK(con.startTransaction() == 0);
- n = 0;
}
}
- if (n != 0) {
- CHK(con.execute(Commit) == 0);
- n = 0;
+ if (! deadlock && lst.cnt() != 0) {
+ deadlock = par.m_deadlock;
+ CHK(con.execute(Commit, deadlock) == 0);
+ if (deadlock) {
+ LL1("pkupdate: stop on deadlock");
+ } else {
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ }
}
con.closeTransaction();
return 0;
@@ -1874,27 +2139,44 @@ pkdelete(Par par)
Set& set = par.set();
LL3("pkdelete");
CHK(con.startTransaction() == 0);
- unsigned n = 0;
+ Lst lst;
+ bool deadlock = false;
for (unsigned j = 0; j < par.m_rows; j++) {
unsigned i = thrrow(par, j);
set.lock();
- if (! set.exist(i)) {
+ if (! set.exist(i) || set.pending(i)) {
set.unlock();
continue;
}
- LL4("pkdelete " << i << ": " << *set.m_row[i]);
- CHKTRY(set.delrow(par, i) == 0, set.unlock());
+ CHK(set.delrow(par, i) == 0);
set.unlock();
- if (++n == par.m_batch) {
- CHK(con.execute(Commit) == 0);
+ LL4("pkdelete " << i << ": " << *set.m_row[i]);
+ lst.push(i);
+ if (lst.cnt() == par.m_batch) {
+ deadlock = par.m_deadlock;
+ CHK(con.execute(Commit, deadlock) == 0);
+ if (deadlock) {
+ LL1("pkdelete: stop on deadlock");
+ break;
+ }
con.closeTransaction();
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ lst.reset();
CHK(con.startTransaction() == 0);
- n = 0;
}
}
- if (n != 0) {
- CHK(con.execute(Commit) == 0);
- n = 0;
+ if (! deadlock && lst.cnt() != 0) {
+ deadlock = par.m_deadlock;
+ CHK(con.execute(Commit, deadlock) == 0);
+ if (deadlock) {
+ LL1("pkdelete: stop on deadlock");
+ } else {
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ }
}
con.closeTransaction();
return 0;
@@ -1905,21 +2187,25 @@ pkread(Par par)
{
Con& con = par.con();
const Tab& tab = par.tab();
- const Set& set = par.set();
+ Set& set = par.set();
LL3((par.m_verify ? "pkverify " : "pkread ") << tab.m_name);
// expected
const Set& set1 = set;
Set set2(tab, set.m_rows);
for (unsigned i = 0; i < set.m_rows; i++) {
- if (! set.exist(i))
+ set.lock();
+ if (! set.exist(i) || set.pending(i)) {
+ set.unlock();
continue;
+ }
+ set.unlock();
CHK(con.startTransaction() == 0);
CHK(set2.selrow(par, i) == 0);
CHK(con.execute(Commit) == 0);
unsigned i2 = (unsigned)-1;
CHK(set2.getkey(par, &i2) == 0 && i == i2);
CHK(set2.putval(i, false) == 0);
- LL4("row " << set2.m_count << ": " << *set2.m_row[i]);
+ LL4("row " << set2.count() << ": " << *set2.m_row[i]);
con.closeTransaction();
}
if (par.m_verify)
@@ -1927,6 +2213,32 @@ pkread(Par par)
return 0;
}
+static int
+pkreadfast(Par par, unsigned count)
+{
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ const Set& set = par.set();
+ LL3("pkfast " << tab.m_name);
+ Row keyrow(tab);
+ // not batched on purpose
+ for (unsigned j = 0; j < count; j++) {
+ unsigned i = urandom(set.m_rows);
+ assert(set.exist(i));
+ CHK(con.startTransaction() == 0);
+ // define key
+ keyrow.calc(par, i);
+ CHK(keyrow.selrow(par) == 0);
+ NdbRecAttr* rec;
+ CHK(con.getValue((Uint32)0, rec) == 0);
+ CHK(con.executeScan() == 0);
+ // get 1st column
+ CHK(con.execute(Commit) == 0);
+ con.closeTransaction();
+ }
+ return 0;
+}
+
// scan read
static int
@@ -1946,13 +2258,13 @@ scanreadtable(Par par)
CHK(con.executeScan() == 0);
while (1) {
int ret;
- CHK((ret = con.nextScanResult()) == 0 || ret == 1);
+ CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
if (ret == 1)
break;
unsigned i = (unsigned)-1;
CHK(set2.getkey(par, &i) == 0);
CHK(set2.putval(i, false) == 0);
- LL4("row " << set2.m_count << ": " << *set2.m_row[i]);
+ LL4("row " << set2.count() << ": " << *set2.m_row[i]);
}
con.closeTransaction();
if (par.m_verify)
@@ -1961,6 +2273,33 @@ scanreadtable(Par par)
}
static int
+scanreadtablefast(Par par, unsigned countcheck)
+{
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ const Set& set = par.set();
+ LL3("scanfast " << tab.m_name);
+ CHK(con.startTransaction() == 0);
+ CHK(con.getNdbScanOperation(tab) == 0);
+ CHK(con.openScanRead(par.m_scanrd) == 0);
+ // get 1st column
+ NdbRecAttr* rec;
+ CHK(con.getValue((Uint32)0, rec) == 0);
+ CHK(con.executeScan() == 0);
+ unsigned count = 0;
+ while (1) {
+ int ret;
+ CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
+ if (ret == 1)
+ break;
+ count++;
+ }
+ con.closeTransaction();
+ CHK(count == countcheck);
+ return 0;
+}
+
+static int
scanreadindex(Par par, const ITab& itab, const BSet& bset)
{
Con& con = par.con();
@@ -1980,14 +2319,14 @@ scanreadindex(Par par, const ITab& itab, const BSet& bset)
CHK(con.executeScan() == 0);
while (1) {
int ret;
- CHK((ret = con.nextScanResult()) == 0 || ret == 1);
+ CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
if (ret == 1)
break;
unsigned i = (unsigned)-1;
CHK(set2.getkey(par, &i) == 0);
LL4("key " << i);
CHK(set2.putval(i, par.m_dups) == 0);
- LL4("row " << set2.m_count << ": " << *set2.m_row[i]);
+ LL4("row " << set2.count() << ": " << *set2.m_row[i]);
}
con.closeTransaction();
if (par.m_verify)
@@ -1996,10 +2335,39 @@ scanreadindex(Par par, const ITab& itab, const BSet& bset)
}
static int
+scanreadindexfast(Par par, const ITab& itab, const BSet& bset, unsigned countcheck)
+{
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ const Set& set = par.set();
+ LL3("scanfast " << itab.m_name << " bounds=" << bset.m_bvals);
+ LL4(bset);
+ CHK(con.startTransaction() == 0);
+ CHK(con.getNdbScanOperation(itab, tab) == 0);
+ CHK(con.openScanRead(par.m_scanrd) == 0);
+ CHK(bset.setbnd(par) == 0);
+ // get 1st column
+ NdbRecAttr* rec;
+ CHK(con.getValue((Uint32)0, rec) == 0);
+ CHK(con.executeScan() == 0);
+ unsigned count = 0;
+ while (1) {
+ int ret;
+ CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
+ if (ret == 1)
+ break;
+ count++;
+ }
+ con.closeTransaction();
+ CHK(count == countcheck);
+ return 0;
+}
+
+static int
scanreadindex(Par par, const ITab& itab)
{
const Tab& tab = par.tab();
- for (unsigned i = 0; i < par.m_subloop; i++) {
+ for (unsigned i = 0; i < par.m_idxloop; i++) {
BSet bset(tab, itab, par.m_rows);
bset.calc(par);
CHK(scanreadindex(par, itab, bset) == 0);
@@ -2029,6 +2397,60 @@ scanreadall(Par par)
return 0;
}
+// timing scans
+
+static int
+timescantable(Par par)
+{
+ par.tmr().on();
+ CHK(scanreadtablefast(par, par.m_totrows) == 0);
+ par.tmr().off(par.set().m_rows);
+ return 0;
+}
+
+static int
+timescanpkindex(Par par)
+{
+ const Tab& tab = par.tab();
+ const ITab& itab = tab.m_itab[0]; // 1st index is on PK
+ BSet bset(tab, itab, par.m_rows);
+ par.tmr().on();
+ CHK(scanreadindexfast(par, itab, bset, par.m_totrows) == 0);
+ par.tmr().off(par.set().m_rows);
+ return 0;
+}
+
+static int
+timepkreadtable(Par par)
+{
+ par.tmr().on();
+ unsigned count = par.m_samples;
+ if (count == 0)
+ count = par.m_totrows;
+ CHK(pkreadfast(par, count) == 0);
+ par.tmr().off(count);
+ return 0;
+}
+
+static int
+timepkreadindex(Par par)
+{
+ const Tab& tab = par.tab();
+ const ITab& itab = tab.m_itab[0]; // 1st index is on PK
+ BSet bset(tab, itab, par.m_rows);
+ unsigned count = par.m_samples;
+ if (count == 0)
+ count = par.m_totrows;
+ par.tmr().on();
+ for (unsigned j = 0; j < count; j++) {
+ unsigned i = urandom(par.m_totrows);
+ bset.calcpk(par, i);
+ CHK(scanreadindexfast(par, itab, bset, 1) == 0);
+ }
+ par.tmr().off(count);
+ return 0;
+}
+
// scan update
static int
@@ -2047,29 +2469,63 @@ scanupdatetable(Par par)
unsigned count = 0;
// updating trans
Con con2;
- con2.m_ndb = con.m_ndb;
- CHK(con2.startBuddyTransaction(con) == 0);
+ con2.connect(con);
+ CHK(con2.startTransaction() == 0);
+ Lst lst;
+ bool deadlock = false;
while (1) {
int ret;
- CHK((ret = con.nextScanResult()) == 0 || ret == 1);
+ deadlock = par.m_deadlock;
+ CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
+ if (ret == 1)
+ break;
+ if (deadlock) {
+ LL1("scanupdatetable: stop on deadlock");
+ break;
+ }
+ do {
+ unsigned i = (unsigned)-1;
+ CHK(set2.getkey(par, &i) == 0);
+ const Row& row = *set.m_row[i];
+ set.lock();
+ if (! set.exist(i) || set.pending(i)) {
+ LL4("scan update " << tab.m_name << ": skip: " << row);
+ } else {
+ CHKTRY(set2.putval(i, false) == 0, set.unlock());
+ CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
+ Par par2 = par;
+ par2.m_con = &con2;
+ set.calc(par, i);
+ CHKTRY(set.setrow(par2, i) == 0, set.unlock());
+ LL4("scan update " << tab.m_name << ": " << row);
+ lst.push(i);
+ }
+ set.unlock();
+ if (lst.cnt() == par.m_batch) {
+ CHK(con2.execute(Commit) == 0);
+ con2.closeTransaction();
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ count += lst.cnt();
+ lst.reset();
+ CHK(con2.startTransaction() == 0);
+ }
+ CHK((ret = con.nextScanResult(false)) == 0 || ret == 1 || ret == 2);
+ if (ret == 2 && lst.cnt() != 0) {
+ CHK(con2.execute(Commit) == 0);
+ con2.closeTransaction();
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ count += lst.cnt();
+ lst.reset();
+ CHK(con2.startTransaction() == 0);
+ }
+ } while (ret == 0);
if (ret == 1)
break;
- unsigned i = (unsigned)-1;
- CHK(set2.getkey(par, &i) == 0);
- LL4("key " << i);
- CHK(set2.putval(i, false) == 0);
- CHK(con2.takeOverForUpdate(con) == 0);
- Par par2 = par;
- par2.m_con = &con2;
- set.lock();
- set.calc(par, i);
- LL4("scan update " << tab.m_name << ": " << *set.m_row[i]);
- CHKTRY(set.setrow(par2, i) == 0, set.unlock());
- set.unlock();
- CHK(con2.execute(NoCommit) == 0);
- count++;
}
- CHK(con2.execute(Commit) == 0);
con2.closeTransaction();
LL3("scan update " << tab.m_name << " rows updated=" << count);
con.closeTransaction();
@@ -2093,32 +2549,61 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
unsigned count = 0;
// updating trans
Con con2;
- con2.m_ndb = con.m_ndb;
- CHK(con2.startBuddyTransaction(con) == 0);
+ con2.connect(con);
+ CHK(con2.startTransaction() == 0);
+ Lst lst;
+ bool deadlock = false;
while (1) {
int ret;
- CHK((ret = con.nextScanResult()) == 0 || ret == 1);
+ deadlock = par.m_deadlock;
+ CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
if (ret == 1)
break;
- unsigned i = (unsigned)-1;
- CHK(set2.getkey(par, &i) == 0);
- LL4("key " << i);
- CHK(set2.putval(i, par.m_dups) == 0);
- // avoid deadlock for now
- //if (! isthrrow(par, i))
- //continue;
- CHK(con2.takeOverForUpdate(con) == 0);
- Par par2 = par;
- par2.m_con = &con2;
- set.lock();
- set.calc(par, i);
- LL4("scan update " << itab.m_name << ": " << *set.m_row[i]);
- CHKTRY(set.setrow(par2, i) == 0, set.unlock());
- set.unlock();
- CHK(con2.execute(NoCommit) == 0);
- count++;
+ if (deadlock) {
+ LL1("scanupdateindex: stop on deadlock");
+ break;
+ }
+ do {
+ unsigned i = (unsigned)-1;
+ CHK(set2.getkey(par, &i) == 0);
+ const Row& row = *set.m_row[i];
+ set.lock();
+ if (! set.exist(i) || set.pending(i)) {
+ LL4("scan update " << itab.m_name << ": skip: " << row);
+ } else {
+ CHKTRY(set2.putval(i, par.m_dups) == 0, set.unlock());
+ CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
+ Par par2 = par;
+ par2.m_con = &con2;
+ set.calc(par, i);
+ CHKTRY(set.setrow(par2, i) == 0, set.unlock());
+ LL4("scan update " << itab.m_name << ": " << row);
+ lst.push(i);
+ }
+ set.unlock();
+ if (lst.cnt() == par.m_batch) {
+ CHK(con2.execute(Commit) == 0);
+ con2.closeTransaction();
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ count += lst.cnt();
+ lst.reset();
+ CHK(con2.startTransaction() == 0);
+ }
+ CHK((ret = con.nextScanResult(false)) == 0 || ret == 1 || ret == 2);
+ if (ret == 2 && lst.cnt() != 0) {
+ CHK(con2.execute(Commit) == 0);
+ con2.closeTransaction();
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ count += lst.cnt();
+ lst.reset();
+ CHK(con2.startTransaction() == 0);
+ }
+ } while (ret == 0);
}
- CHK(con2.execute(Commit) == 0);
con2.closeTransaction();
LL3("scan update " << itab.m_name << " rows updated=" << count);
con.closeTransaction();
@@ -2129,7 +2614,7 @@ static int
scanupdateindex(Par par, const ITab& itab)
{
const Tab& tab = par.tab();
- for (unsigned i = 0; i < par.m_subloop; i++) {
+ for (unsigned i = 0; i < par.m_idxloop; i++) {
BSet bset(tab, itab, par.m_rows);
bset.calc(par);
CHK(scanupdateindex(par, itab, bset) == 0);
@@ -2160,41 +2645,15 @@ scanupdateall(Par par)
// medium level routines
-static bool
-ignoreverifyerror(Par par)
-{
- Con& con = par.con();
- bool b = par.m_threads > 1;
- if (b) {
- LL1("ignore verify error");
- if (con.m_tx != 0)
- con.closeTransaction();
- return true;
- }
- return b;
-}
-
static int
readverify(Par par)
{
par.m_verify = true;
- CHK(pkread(par) == 0 || ignoreverifyerror(par));
- CHK(scanreadall(par) == 0 || ignoreverifyerror(par));
+ CHK(pkread(par) == 0);
+ CHK(scanreadall(par) == 0);
return 0;
}
-static bool
-ignoredeadlock(Par par)
-{
- Con& con = par.con();
- if (con.m_errtype == Con::ErrDeadlock) {
- LL1("ignore deadlock");
- con.closeTransaction();
- return true;
- }
- return false;
-}
-
static int
pkupdatescanread(Par par)
{
@@ -2216,15 +2675,16 @@ static int
mixedoperations(Par par)
{
par.m_dups = true;
+ par.m_deadlock = true;
unsigned sel = urandom(10);
if (sel < 2) {
- CHK(pkdelete(par) == 0 || ignoredeadlock(par));
+ CHK(pkdelete(par) == 0);
} else if (sel < 4) {
- CHK(pkupdate(par) == 0 || ignoredeadlock(par));
+ CHK(pkupdate(par) == 0);
} else if (sel < 6) {
- CHK(scanupdatetable(par) == 0 || ignoredeadlock(par));
+ CHK(scanupdatetable(par) == 0);
} else {
- CHK(scanupdateindex(par) == 0 || ignoredeadlock(par));
+ CHK(scanupdateindex(par) == 0);
}
return 0;
}
@@ -2358,7 +2818,6 @@ Thr::run()
break;
}
LL4("start");
- CHK(con.bugger() == 0);
assert(m_state == Start);
m_ret = (*m_func)(m_par);
m_state = Stopped;
@@ -2438,6 +2897,7 @@ runstep(Par par, const char* fname, TFunc func, unsigned mode)
Thr& thr = *g_thrlist[n];
thr.m_par.m_tab = par.m_tab;
thr.m_par.m_set = par.m_set;
+ thr.m_par.m_tmr = par.m_tmr;
thr.m_func = func;
thr.start();
}
@@ -2488,13 +2948,13 @@ tpkops(Par par)
RUNSTEP(par, pkinsert, MT);
RUNSTEP(par, createindex, ST);
RUNSTEP(par, invalidateindex, MT);
- RUNSTEP(par, readverify, MT);
+ RUNSTEP(par, readverify, ST);
for (unsigned i = 0; i < par.m_subloop; i++) {
RUNSTEP(par, pkupdatescanread, MT);
- RUNSTEP(par, readverify, MT);
+ RUNSTEP(par, readverify, ST);
}
RUNSTEP(par, pkdelete, MT);
- RUNSTEP(par, readverify, MT);
+ RUNSTEP(par, readverify, ST);
return 0;
}
@@ -2507,10 +2967,10 @@ tmixedops(Par par)
RUNSTEP(par, pkinsert, MT);
RUNSTEP(par, createindex, ST);
RUNSTEP(par, invalidateindex, MT);
- RUNSTEP(par, readverify, MT);
+ RUNSTEP(par, readverify, ST);
for (unsigned i = 0; i < par.m_subloop; i++) {
RUNSTEP(par, mixedoperations, MT);
- RUNSTEP(par, readverify, MT);
+ RUNSTEP(par, readverify, ST);
}
return 0;
}
@@ -2525,7 +2985,7 @@ tbusybuild(Par par)
for (unsigned i = 0; i < par.m_subloop; i++) {
RUNSTEP(par, pkupdateindexbuild, MT);
RUNSTEP(par, invalidateindex, MT);
- RUNSTEP(par, readverify, MT);
+ RUNSTEP(par, readverify, ST);
RUNSTEP(par, dropindex, ST);
}
return 0;
@@ -2576,6 +3036,50 @@ ttimemaint(Par par)
}
static int
+ttimescan(Par par)
+{
+ Tmr t1, t2;
+ RUNSTEP(par, droptable, ST);
+ RUNSTEP(par, createtable, ST);
+ RUNSTEP(par, invalidatetable, MT);
+ for (unsigned i = 0; i < par.m_subloop; i++) {
+ RUNSTEP(par, pkinsert, MT);
+ RUNSTEP(par, createindex, ST);
+ par.m_tmr = &t1;
+ RUNSTEP(par, timescantable, ST);
+ par.m_tmr = &t2;
+ RUNSTEP(par, timescanpkindex, ST);
+ RUNSTEP(par, dropindex, ST);
+ }
+ LL1("full scan table - " << t1.time());
+ LL1("full scan PK index - " << t2.time());
+ LL1("overhead - " << t2.over(t1));
+ return 0;
+}
+
+static int
+ttimepkread(Par par)
+{
+ Tmr t1, t2;
+ RUNSTEP(par, droptable, ST);
+ RUNSTEP(par, createtable, ST);
+ RUNSTEP(par, invalidatetable, MT);
+ for (unsigned i = 0; i < par.m_subloop; i++) {
+ RUNSTEP(par, pkinsert, MT);
+ RUNSTEP(par, createindex, ST);
+ par.m_tmr = &t1;
+ RUNSTEP(par, timepkreadtable, ST);
+ par.m_tmr = &t2;
+ RUNSTEP(par, timepkreadindex, ST);
+ RUNSTEP(par, dropindex, ST);
+ }
+ LL1("pk read table - " << t1.time());
+ LL1("pk read PK index - " << t2.time());
+ LL1("overhead - " << t2.over(t1));
+ return 0;
+}
+
+static int
tdrop(Par par)
{
RUNSTEP(par, droptable, ST);
@@ -2601,6 +3105,8 @@ tcaselist[] = {
TCase("d", tbusybuild, "pk operations and index build"),
TCase("t", ttimebuild, "time index build"),
TCase("u", ttimemaint, "time index maintenance"),
+ TCase("v", ttimescan, "time full scan table vs index on pk"),
+ TCase("w", ttimepkread, "time pk read table vs index on pk"),
TCase("z", tdrop, "drop test tables")
};
@@ -2620,7 +3126,7 @@ printcases()
static void
printtables()
{
- ndbout << "tables and indexes:" << endl;
+ ndbout << "tables and indexes (X1 is on table PK):" << endl;
for (unsigned j = 0; j < tabcount; j++) {
const Tab& tab = tablist[j];
ndbout << " " << tab.m_name;
@@ -2636,7 +3142,8 @@ static int
runtest(Par par)
{
LL1("start");
- srandom(par.m_seed);
+ if (par.m_seed != 0)
+ srandom(par.m_seed);
Con con;
CHK(con.connect() == 0);
par.m_con = &con;
@@ -2651,6 +3158,8 @@ runtest(Par par)
}
for (unsigned l = 0; par.m_loop == 0 || l < par.m_loop; l++) {
LL1("loop " << l);
+ if (par.m_seed == 0)
+ srandom(l);
for (unsigned i = 0; i < tcasecount; i++) {
const TCase& tcase = tcaselist[i];
if (par.m_case != 0 && strchr(par.m_case, tcase.m_name[0]) == 0)
@@ -2661,8 +3170,8 @@ runtest(Par par)
continue;
const Tab& tab = tablist[j];
par.m_tab = &tab;
- Set set(tab, par.m_totrows);
- par.m_set = &set;
+ delete par.m_set;
+ par.m_set = new Set(tab, par.m_totrows);
LL1("table " << tab.m_name);
CHK(tcase.m_func(par) == 0);
}
@@ -2692,6 +3201,12 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535)
ndbout << "testOIBasic: unknown argument " << arg;
goto usage;
}
+ if (strcmp(arg, "-batch") == 0) {
+ if (++argv, --argc > 0) {
+ g_opt.m_batch = atoi(argv[0]);
+ continue;
+ }
+ }
if (strcmp(arg, "-case") == 0) {
if (++argv, --argc > 0) {
g_opt.m_case = strdup(argv[0]);
@@ -2748,6 +3263,12 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535)
continue;
}
}
+ if (strcmp(arg, "-samples") == 0) {
+ if (++argv, --argc > 0) {
+ g_opt.m_samples = atoi(argv[0]);
+ continue;
+ }
+ }
if (strcmp(arg, "-scanrd") == 0) {
if (++argv, --argc > 0) {
g_opt.m_scanrd = atoi(argv[0]);
diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt
index 0b64d9cf9c2..d34c37021bf 100644
--- a/ndb/test/run-test/daily-basic-tests.txt
+++ b/ndb/test/run-test/daily-basic-tests.txt
@@ -152,33 +152,33 @@ cmd: testBasic
args: -n MassiveRollback2 T1 T6 T13
#-m 500 1: testBasic -n ReadConsistency T6
-max-time: 500
-cmd: testTimeout
-args: -n DontTimeoutTransaction T1
-
-max-time: 500
-cmd: testTimeout
-args: -n DontTimeoutTransaction5 T1
-
-max-time: 500
-cmd: testTimeout
-args: -n TimeoutTransaction T1
-
-max-time: 500
-cmd: testTimeout
-args: -n TimeoutTransaction5 T1
-
-max-time: 500
-cmd: testTimeout
-args: -n BuddyTransNoTimeout T1
-
-max-time: 500
-cmd: testTimeout
-args: -n BuddyTransNoTimeout5 T1
-
-max-time: 500
-cmd: testTimeout
-args: -n TimeoutRandTransaction T1
+#max-time: 500
+#cmd: testTimeout
+#args: -n DontTimeoutTransaction T1
+#
+#max-time: 500
+#cmd: testTimeout
+#args: -n DontTimeoutTransaction5 T1
+#
+#max-time: 500
+#cmd: testTimeout
+#args: -n TimeoutTransaction T1
+#
+#max-time: 500
+#cmd: testTimeout
+#args: -n TimeoutTransaction5 T1
+#
+#max-time: 500
+#cmd: testTimeout
+#args: -n BuddyTransNoTimeout T1
+#
+#max-time: 500
+#cmd: testTimeout
+#args: -n BuddyTransNoTimeout5 T1
+#
+#max-time: 500
+#cmd: testTimeout
+#args: -n TimeoutRandTransaction T1
#
# SCAN TESTS
#
@@ -474,10 +474,10 @@ max-time: 500
cmd: testNdbApi
args: -n UpdateWithoutValues T6
-max-time: 500
-cmd: testInterpreter
-args: T1
-
+#max-time: 500
+#cmd: testInterpreter
+#args: T1
+#
max-time: 1500
cmd: testOperations
args: -n ReadRead
diff --git a/ndb/test/run-test/main.cpp b/ndb/test/run-test/main.cpp
index fa9ebcb9170..0ea700e1d66 100644
--- a/ndb/test/run-test/main.cpp
+++ b/ndb/test/run-test/main.cpp
@@ -106,13 +106,6 @@ main(int argc, const char ** argv){
if(!setup_hosts(g_config))
goto end;
- if(!start_processes(g_config, atrt_process::NDB_MGM))
- goto end;
-
- if(!connect_ndb_mgm(g_config)){
- goto end;
- }
-
/**
* Main loop
*/
@@ -122,25 +115,32 @@ main(int argc, const char ** argv){
*/
if(restart){
g_logger.info("(Re)starting ndb processes");
+ if(!stop_processes(g_config, atrt_process::NDB_MGM))
+ goto end;
+
if(!stop_processes(g_config, atrt_process::NDB_DB))
goto end;
- if(!wait_ndb(g_config, NDB_MGM_NODE_STATUS_NO_CONTACT))
+ if(!start_processes(g_config, atrt_process::NDB_MGM))
+ goto end;
+
+ if(!connect_ndb_mgm(g_config)){
goto end;
+ }
if(!start_processes(g_config, atrt_process::NDB_DB))
goto end;
-
+
if(!wait_ndb(g_config, NDB_MGM_NODE_STATUS_NOT_STARTED))
goto end;
-
+
for(Uint32 i = 0; i<3; i++)
if(wait_ndb(g_config, NDB_MGM_NODE_STATUS_STARTED))
goto started;
-
+
goto end;
-
-started:
+
+ started:
g_logger.info("Ndb start completed");
}
diff --git a/ndb/test/src/HugoTransactions.cpp b/ndb/test/src/HugoTransactions.cpp
index bd90908a01a..05039562c76 100644
--- a/ndb/test/src/HugoTransactions.cpp
+++ b/ndb/test/src/HugoTransactions.cpp
@@ -1364,7 +1364,7 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb,
allocRows(batch);
- g_info << "|- Updating records..." << endl;
+ g_info << "|- Updating records (batch=" << batch << ")..." << endl;
while (r < records){
if (retryAttempt >= retryMax){