#At file:///home/jonas/src/719-deferred/ based on revid:jonas@stripped
3946 jonas oreland 2011-04-05
ndb - backport deferred constraints to 7.1.9 - commit to test
modified:
mysql-test/suite/ndb/r/ndb_basic.result
sql/ha_ndbcluster.cc
storage/ndb/include/kernel/GlobalSignalNumbers.h
storage/ndb/include/kernel/signaldata/FireTrigOrd.hpp
storage/ndb/include/kernel/signaldata/LqhKey.hpp
storage/ndb/include/kernel/signaldata/PackedSignal.hpp
storage/ndb/include/kernel/signaldata/TcContinueB.hpp
storage/ndb/include/kernel/signaldata/TcKeyReq.hpp
storage/ndb/include/kernel/signaldata/TupKey.hpp
storage/ndb/include/kernel/trigger_definitions.h
storage/ndb/include/ndbapi/NdbOperation.hpp
storage/ndb/src/common/debugger/signaldata/LqhKey.cpp
storage/ndb/src/common/debugger/signaldata/PackedSignal.cpp
storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp
storage/ndb/src/kernel/blocks/ERROR_codes.txt
storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp
storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp
storage/ndb/src/ndbapi/NdbOperation.cpp
storage/ndb/src/ndbapi/NdbOperationDefine.cpp
storage/ndb/src/ndbapi/NdbOperationExec.cpp
storage/ndb/test/include/HugoCalculator.hpp
storage/ndb/test/ndbapi/testIndex.cpp
storage/ndb/test/run-test/daily-basic-tests.txt
storage/ndb/test/src/HugoCalculator.cpp
=== modified file 'mysql-test/suite/ndb/r/ndb_basic.result'
--- a/mysql-test/suite/ndb/r/ndb_basic.result 2010-11-01 09:13:06 +0000
+++ b/mysql-test/suite/ndb/r/ndb_basic.result 2011-04-05 19:12:29 +0000
@@ -28,6 +28,7 @@ ndb_batch_size #
ndb_cache_check_time #
ndb_cluster_connection_pool #
ndb_connectstring #
+ndb_deferred_constraints #
ndb_distribution #
ndb_extra_logging #
ndb_force_send #
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2010-10-22 14:25:43 +0000
+++ b/sql/ha_ndbcluster.cc 2011-04-05 19:12:29 +0000
@@ -221,6 +221,17 @@ static MYSQL_THDVAR_BOOL(
FALSE /* default */
);
+static MYSQL_THDVAR_UINT(
+ deferred_constraints, /* name */
+ PLUGIN_VAR_RQCMDARG,
+ "Specified that constraints should be checked deferred (when supported)",
+ NULL, /* check func */
+ NULL, /* update func */
+ 0, /* default */
+ 0, /* min */
+ 1, /* max */
+ 0 /* block */
+);
/*
Default value for max number of transactions createable against NDB from
@@ -3830,6 +3841,12 @@ int ha_ndbcluster::ndb_write_row(uchar *
options.extraSetValues= sets;
options.numExtraSetValues= num_sets;
}
+ if (thd->slave_thread || THDVAR(thd, deferred_constraints))
+ {
+ options.optionsPresent |=
+ NdbOperation::OperationOptions::OO_DEFERRED_CONSTAINTS;
+ }
+
if (options.optionsPresent != 0)
poptions=&options;
@@ -4577,6 +4594,12 @@ int ha_ndbcluster::ndb_update_row(const
bool need_flush= add_row_check_if_batch_full(thd_ndb);
+ if (thd->slave_thread || THDVAR(thd, deferred_constraints))
+ {
+ options.optionsPresent |=
+ NdbOperation::OperationOptions::OO_DEFERRED_CONSTAINTS;
+ }
+
if (cursor)
{
/*
@@ -4793,6 +4816,12 @@ int ha_ndbcluster::ndb_delete_row(const
uint delete_size= 12 + (m_bytes_per_write >> 2);
bool need_flush= add_row_check_if_batch_full_size(thd_ndb, delete_size);
+ if (thd->slave_thread || THDVAR(thd, deferred_constraints))
+ {
+ options.optionsPresent |=
+ NdbOperation::OperationOptions::OO_DEFERRED_CONSTAINTS;
+ }
+
if (cursor)
{
if (options.optionsPresent != 0)
@@ -14616,7 +14645,7 @@ static struct st_mysql_sys_var* system_v
MYSQL_SYSVAR(connectstring),
MYSQL_SYSVAR(mgmd_host),
MYSQL_SYSVAR(nodeid),
-
+ MYSQL_SYSVAR(deferred_constraints),
NULL
};
=== modified file 'storage/ndb/include/kernel/GlobalSignalNumbers.h'
--- a/storage/ndb/include/kernel/GlobalSignalNumbers.h 2010-10-20 07:12:58 +0000
+++ b/storage/ndb/include/kernel/GlobalSignalNumbers.h 2011-04-05 19:12:29 +0000
@@ -338,9 +338,11 @@ extern const GlobalSignalNumber NO_OF_SI
/* 233 unused */
/* 234 unused */
#define GSN_DISCONNECT_REP 235
-/* 236 unused */
-/* 237 unused */
-/* 238 unused */
+
+#define GSN_FIRE_TRIG_REQ 236
+#define GSN_FIRE_TRIG_REF 237
+#define GSN_FIRE_TRIG_CONF 238
+
#define GSN_DIVERIFYCONF 239
#define GSN_DIVERIFYREF 240
#define GSN_DIVERIFYREQ 241
=== modified file 'storage/ndb/include/kernel/signaldata/FireTrigOrd.hpp'
--- a/storage/ndb/include/kernel/signaldata/FireTrigOrd.hpp 2009-05-27 15:21:45 +0000
+++ b/storage/ndb/include/kernel/signaldata/FireTrigOrd.hpp 2011-04-05 19:12:29 +0000
@@ -225,5 +225,47 @@ void FireTrigOrd::setAnyValue(Uint32 any
m_any_value = any_value;
}
+struct FireTrigReq
+{
+ STATIC_CONST( SignalLength = 4 );
+
+ Uint32 tcOpRec;
+ Uint32 transId[2];
+ Uint32 pass;
+};
+
+struct FireTrigRef
+{
+ STATIC_CONST( SignalLength = 4 );
+
+ Uint32 tcOpRec;
+ Uint32 transId[2];
+ Uint32 errCode;
+
+ enum ErrorCode
+ {
+ FTR_UnknownOperation = 1235
+ ,FTR_IncorrectState = 1236
+ };
+};
+
+struct FireTrigConf
+{
+ STATIC_CONST( SignalLength = 4 );
+
+ Uint32 tcOpRec;
+ Uint32 transId[2];
+ Uint32 noFiredTriggers; // bit 31 defered trigger
+
+ static Uint32 getFiredCount(Uint32 v) {
+ return NoOfFiredTriggers::getFiredCount(v);
+ }
+ static Uint32 getDeferredBit(Uint32 v) {
+ return NoOfFiredTriggers::getDeferredBit(v);
+ }
+ static void setDeferredBit(Uint32 & v) {
+ NoOfFiredTriggers::setDeferredBit(v);
+ }
+};
#endif
=== modified file 'storage/ndb/include/kernel/signaldata/LqhKey.hpp'
--- a/storage/ndb/include/kernel/signaldata/LqhKey.hpp 2010-11-01 16:11:10 +0000
+++ b/storage/ndb/include/kernel/signaldata/LqhKey.hpp 2011-04-05 19:12:29 +0000
@@ -20,6 +20,7 @@
#define LQH_KEY_H
#include "SignalData.hpp"
+#include <trigger_definitions.h>
class LqhKeyReq {
/**
@@ -151,6 +152,9 @@ private:
static UintR getNrCopyFlag(const UintR & requestInfo);
static void setNrCopyFlag(UintR & requestInfo, UintR val);
+
+ static UintR getDeferredConstraints(const UintR & requestInfo);
+ static void setDeferredConstraints(UintR & requestInfo, UintR val);
};
/**
@@ -214,6 +218,7 @@ private:
#define RI_ROWID_SHIFT (31)
#define RI_GCI_SHIFT (12)
#define RI_NR_COPY_SHIFT (13)
+#define RI_DEFERRED_CONSTAINTS (26)
/**
* Scan Info
@@ -578,6 +583,19 @@ LqhKeyReq::getNrCopyFlag(const UintR & r
}
inline
+void
+LqhKeyReq::setDeferredConstraints(UintR & requestInfo, UintR val){
+ ASSERT_BOOL(val, "LqhKeyReq::setDeferredConstraints");
+ requestInfo |= (val << RI_DEFERRED_CONSTAINTS);
+}
+
+inline
+UintR
+LqhKeyReq::getDeferredConstraints(const UintR & requestInfo){
+ return (requestInfo >> RI_DEFERRED_CONSTAINTS) & 1;
+}
+
+inline
Uint32
table_version_major_lqhkeyreq(Uint32 x)
{
@@ -626,7 +644,17 @@ private:
};
Uint32 transId1;
Uint32 transId2;
- Uint32 noFiredTriggers;
+ Uint32 noFiredTriggers; // bit 31 defered trigger
+
+ static Uint32 getFiredCount(Uint32 v) {
+ return NoOfFiredTriggers::getFiredCount(v);
+ }
+ static Uint32 getDeferredBit(Uint32 v) {
+ return NoOfFiredTriggers::getDeferredBit(v);
+ }
+ static void setDeferredBit(Uint32 & v) {
+ NoOfFiredTriggers::setDeferredBit(v);
+ }
};
class LqhKeyRef {
=== modified file 'storage/ndb/include/kernel/signaldata/PackedSignal.hpp'
--- a/storage/ndb/include/kernel/signaldata/PackedSignal.hpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/include/kernel/signaldata/PackedSignal.hpp 2011-04-05 19:12:29 +0000
@@ -28,6 +28,8 @@
#define ZCOMPLETED 3
#define ZLQHKEYCONF 4
#define ZREMOVE_MARKER 5
+#define ZFIRE_TRIG_REQ 6
+#define ZFIRE_TRIG_CONF 7
class PackedSignal {
=== modified file 'storage/ndb/include/kernel/signaldata/TcContinueB.hpp'
--- a/storage/ndb/include/kernel/signaldata/TcContinueB.hpp 2009-05-27 15:21:45 +0000
+++ b/storage/ndb/include/kernel/signaldata/TcContinueB.hpp 2011-04-05 19:12:29 +0000
@@ -46,7 +46,8 @@ private:
TRIGGER_PENDING = 17,
DelayTCKEYCONF = 18,
- ZNF_CHECK_TRANSACTIONS = 19
+ ZNF_CHECK_TRANSACTIONS = 19,
+ ZSEND_FIRE_TRIG_REQ = 20
};
};
=== modified file 'storage/ndb/include/kernel/signaldata/TcKeyReq.hpp'
--- a/storage/ndb/include/kernel/signaldata/TcKeyReq.hpp 2010-01-28 15:16:46 +0000
+++ b/storage/ndb/include/kernel/signaldata/TcKeyReq.hpp 2011-04-05 19:12:29 +0000
@@ -200,6 +200,13 @@ private:
static void setReorgFlag(UintR & requestInfo, UintR val);
static UintR getReorgFlag(const UintR & requestInfo);
+
+ /**
+ * Check constraints deferred
+ */
+ static UintR getDeferredConstraints(const UintR & requestInfo);
+ static void setDeferredConstraints(UintR & requestInfo, UintR val);
+
/**
* Set:ers for scanInfo
*/
@@ -259,6 +266,8 @@ private:
#define TC_REORG_SHIFT (19)
+#define TC_DEFERRED_CONSTAINTS_SHIFT (17)
+
/**
* Scan Info
*
@@ -574,4 +583,18 @@ TcKeyReq::setReorgFlag(UintR & requestIn
requestInfo |= (flag << TC_REORG_SHIFT);
}
+inline
+void
+TcKeyReq::setDeferredConstraints(UintR & requestInfo, UintR val){
+ ASSERT_BOOL(val, "TcKeyReq::setDeferredConstraints");
+ requestInfo |= (val << TC_DEFERRED_CONSTAINTS_SHIFT);
+}
+
+inline
+UintR
+TcKeyReq::getDeferredConstraints(const UintR & requestInfo){
+ return (requestInfo >> TC_DEFERRED_CONSTAINTS_SHIFT) & 1;
+}
+
+
#endif
=== modified file 'storage/ndb/include/kernel/signaldata/TupKey.hpp'
--- a/storage/ndb/include/kernel/signaldata/TupKey.hpp 2009-05-27 15:21:45 +0000
+++ b/storage/ndb/include/kernel/signaldata/TupKey.hpp 2011-04-05 19:12:29 +0000
@@ -38,7 +38,7 @@ class TupKeyReq {
friend bool printTUPKEYREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo);
public:
- STATIC_CONST( SignalLength = 19 );
+ STATIC_CONST( SignalLength = 20 );
private:
@@ -64,6 +64,7 @@ private:
Uint32 m_row_id_page_no;
Uint32 m_row_id_page_idx;
Uint32 attrInfoIVal;
+ Uint32 deferred_constraints;
};
class TupKeyConf {
=== modified file 'storage/ndb/include/kernel/trigger_definitions.h'
--- a/storage/ndb/include/kernel/trigger_definitions.h 2009-05-27 15:21:45 +0000
+++ b/storage/ndb/include/kernel/trigger_definitions.h 2011-04-05 19:12:29 +0000
@@ -196,4 +196,19 @@ struct TriggerInfo {
}
};
+struct NoOfFiredTriggers
+{
+ STATIC_CONST( DeferredBit = (Uint32(1) << 31) );
+
+ static Uint32 getFiredCount(Uint32 v) {
+ return v & ~(Uint32(DeferredBit));
+ }
+ static Uint32 getDeferredBit(Uint32 v) {
+ return (v & Uint32(DeferredBit)) != 0;
+ }
+ static void setDeferredBit(Uint32 & v) {
+ v |= Uint32(DeferredBit);
+ }
+};
+
#endif
=== modified file 'storage/ndb/include/ndbapi/NdbOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbOperation.hpp 2010-10-13 09:33:02 +0000
+++ b/storage/ndb/include/ndbapi/NdbOperation.hpp 2011-04-05 19:12:29 +0000
@@ -1039,7 +1039,9 @@ public:
OO_INTERPRETED = 0x10,
OO_ANYVALUE = 0x20,
OO_CUSTOMDATA = 0x40,
- OO_LOCKHANDLE = 0x80 };
+ OO_LOCKHANDLE = 0x80,
+ OO_DEFERRED_CONSTAINTS = 0x400
+ };
/* An operation-specific abort option.
* Only necessary if the default abortoption behaviour
@@ -1511,6 +1513,7 @@ protected:
* to LM_Read?
*/
+ bool m_deferred_constraints;
private:
NdbOperation(const NdbOperation&); // Not impl.
NdbOperation&operator=(const NdbOperation&);
=== modified file 'storage/ndb/src/common/debugger/signaldata/LqhKey.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/LqhKey.cpp 2009-05-27 15:21:45 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/LqhKey.cpp 2011-04-05 19:12:29 +0000
@@ -59,6 +59,8 @@ printLQHKEYREQ(FILE * output, const Uint
fprintf(output, "NrCopy ");
if(LqhKeyReq::getGCIFlag(reqInfo))
fprintf(output, "GCI ");
+ if(LqhKeyReq::getDeferredConstraints(reqInfo))
+ fprintf(output, "Deferred-constraints ");
fprintf(output, "ScanInfo/noFiredTriggers: H\'%x\n", sig->scanInfo);
=== modified file 'storage/ndb/src/common/debugger/signaldata/PackedSignal.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/PackedSignal.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/PackedSignal.cpp 2011-04-05 19:12:29 +0000
@@ -97,6 +97,24 @@ printPACKED_SIGNAL(FILE * output, const
fprintf(output,"\n");
break;
}
+ case ZFIRE_TRIG_REQ: {
+ Uint32 signalLength = 3;
+
+ fprintf(output, "--------------- Signal ----------------\n");
+ fprintf(output, "r.bn: %u \"%s\", length: %u \"FIRE_TRIG_REQ\"\n",
+ receiverBlockNo, getBlockName(receiverBlockNo,""), signalLength);
+ i += signalLength;
+ break;
+ }
+ case ZFIRE_TRIG_CONF: {
+ Uint32 signalLength = 4;
+
+ fprintf(output, "--------------- Signal ----------------\n");
+ fprintf(output, "r.bn: %u \"%s\", length: %u \"FIRE_TRIG_CONF\"\n",
+ receiverBlockNo, getBlockName(receiverBlockNo,""), signalLength);
+ i += signalLength;
+ break;
+ }
default:
fprintf(output, "Unknown signal type\n");
i = len; // terminate printing
=== modified file 'storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp 2010-01-28 15:16:46 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp 2011-04-05 19:12:29 +0000
@@ -74,6 +74,8 @@ printTCKEYREQ(FILE * output, const Uint3
if(sig->getDistributionKeyFlag(sig->requestInfo)){
fprintf(output, " d-key");
}
+ if(sig->getDeferredConstraints(sig->requestInfo))
+ fprintf(output, "Deferred-constraints ");
fprintf(output, "\n");
}
=== modified file 'storage/ndb/src/kernel/blocks/ERROR_codes.txt'
--- a/storage/ndb/src/kernel/blocks/ERROR_codes.txt 2010-10-28 12:59:31 +0000
+++ b/storage/ndb/src/kernel/blocks/ERROR_codes.txt 2011-04-05 19:12:29 +0000
@@ -3,10 +3,10 @@ Next NDBCNTR 1002
Next NDBFS 2000
Next DBACC 3002
Next DBTUP 4035
-Next DBLQH 5061
+Next DBLQH 5072
Next DBDICT 6026
Next DBDIH 7229
-Next DBTC 8088
+Next DBTC 8092
Next CMVMI 9000
Next BACKUP 10042
Next DBUTIL 11002
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp 2010-10-28 12:59:31 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp 2011-04-05 19:12:29 +0000
@@ -2044,10 +2044,12 @@ public:
Uint8 m_disk_table;
Uint8 m_use_rowid;
Uint8 m_dealloc;
+ Uint8 m_fire_trig_pass;
enum op_flags {
OP_ISLONGREQ = 0x1,
OP_SAVEATTRINFO = 0x2,
- OP_SCANKEYINFOPOSSAVED = 0x4
+ OP_SCANKEYINFOPOSSAVED = 0x4,
+ OP_DEFERRED_CONSTRAINTS = 0x8
};
Uint32 m_flags;
Uint32 m_log_part_ptr_i;
@@ -2238,6 +2240,8 @@ private:
void execBUILD_INDX_IMPL_REF(Signal* signal);
void execBUILD_INDX_IMPL_CONF(Signal* signal);
+ void execFIRE_TRIG_REQ(Signal*);
+
// Statement blocks
void init_acc_ptr_list(ScanRecord*);
@@ -3187,6 +3191,9 @@ public:
void suspendFile(Signal* signal, Ptr<LogFileRecord> logFile, Uint32 millis);
void send_runredo_event(Signal*, LogPartRecord *, Uint32 currgci);
+
+ void sendFireTrigConfTc(Signal* signal, BlockReference ref, Uint32 Tdata[]);
+ bool check_fire_trig_pass(Uint32 op, Uint32 pass);
};
inline
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp 2010-03-10 07:43:06 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp 2011-04-05 19:12:29 +0000
@@ -419,6 +419,8 @@ Dblqh::Dblqh(Block_context& ctx, Uint32
&Dblqh::execFSWRITEREQ);
addRecSignal(GSN_DBINFO_SCANREQ, &Dblqh::execDBINFO_SCANREQ);
+ addRecSignal(GSN_FIRE_TRIG_REQ, &Dblqh::execFIRE_TRIG_REQ);
+
initData();
#ifdef VM_TRACE
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2010-11-01 16:11:10 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2011-04-05 19:12:29 +0000
@@ -74,6 +74,7 @@
#include <signaldata/SignalDroppedRep.hpp>
#include <signaldata/FsReadWriteReq.hpp>
#include <signaldata/DbinfoScan.hpp>
+#include <signaldata/FireTrigOrd.hpp>
#include <NdbEnv.h>
#include "../suma/Suma.hpp"
@@ -3094,6 +3095,7 @@ void Dblqh::execPACKED_SIGNAL(Signal* si
jamEntry();
Tlength = signal->length();
+ Uint32 TsenderRef = signal->getSendersBlockRef();
Uint32 TcommitLen = 5;
Uint32 Tgci_lo_mask = ~(Uint32)0;
@@ -3138,8 +3140,7 @@ void Dblqh::execPACKED_SIGNAL(Signal* si
break;
case ZLQHKEYCONF: {
jam();
- LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr();
-
+ LqhKeyConf * lqhKeyConf = CAST_PTR(LqhKeyConf, signal->theData);
sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF;
sig1 = TpackedData[Tstep + 1];
sig2 = TpackedData[Tstep + 2];
@@ -3168,6 +3169,22 @@ void Dblqh::execPACKED_SIGNAL(Signal* si
execREMOVE_MARKER_ORD(signal);
Tstep += 3;
break;
+ case ZFIRE_TRIG_REQ:
+ jam();
+ ndbassert(FireTrigReq::SignalLength == 4);
+ sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF;
+ sig1 = TpackedData[Tstep + 1];
+ sig2 = TpackedData[Tstep + 2];
+ sig3 = TpackedData[Tstep + 3];
+ signal->theData[0] = sig0;
+ signal->theData[1] = sig1;
+ signal->theData[2] = sig2;
+ signal->theData[3] = sig3;
+ signal->header.theLength = FireTrigReq::SignalLength;
+ signal->header.theSendersBlockRef = TsenderRef;
+ execFIRE_TRIG_REQ(signal);
+ Tstep += FireTrigReq::SignalLength;
+ break;
default:
ndbrequire(false);
return;
@@ -4411,6 +4428,13 @@ void Dblqh::execLQHKEYREQ(Signal* signal
nextPos++;
}//if
+ Uint32 Tdeferred = LqhKeyReq::getDeferredConstraints(Treqinfo);
+ if (isLongReq && Tdeferred)
+ {
+ regTcPtr->m_flags |= TcConnectionrec::OP_DEFERRED_CONSTRAINTS;
+ regTcPtr->m_fire_trig_pass = 0;
+ }
+
UintR TitcKeyLen = 0;
Uint32 keyLenWithLQHReq = 0;
UintR TreclenAiLqhkey = 0;
@@ -5751,6 +5775,7 @@ Dblqh::acckeyconf_tupkeyreq(Signal* sign
Uint32 page_idx = local_key & MAX_TUPLES_PER_PAGE;
Uint32 page_no = local_key >> MAX_TUPLES_BITS;
Uint32 Ttupreq = regTcPtr->dirtyOp;
+ Uint32 flags = regTcPtr->m_flags;
Ttupreq = Ttupreq + (regTcPtr->opSimple << 1);
Ttupreq = Ttupreq + (op << 6);
Ttupreq = Ttupreq + (regTcPtr->opExec << 10);
@@ -5813,6 +5838,8 @@ Dblqh::acckeyconf_tupkeyreq(Signal* sign
regTcPtr->m_row_id.m_page_idx = page_idx;
tupKeyReq->attrInfoIVal= RNIL;
+ tupKeyReq->deferred_constraints =
+ (flags & TcConnectionrec::OP_DEFERRED_CONSTRAINTS) != 0;
/* Pass AttrInfo section if available in the TupKeyReq signal
* We are still responsible for releasing it, TUP is just
@@ -7116,6 +7143,151 @@ void Dblqh::errorReport(Signal* signal,
return;
}//Dblqh::errorReport()
+void
+Dblqh::execFIRE_TRIG_REQ(Signal* signal)
+{
+ Uint32 tcOprec = signal->theData[0];
+ Uint32 transid1 = signal->theData[1];
+ Uint32 transid2 = signal->theData[2];
+ Uint32 pass = signal->theData[3];
+ Uint32 senderRef = signal->getSendersBlockRef();
+
+ jamEntry();
+
+ if (ERROR_INSERTED_CLEAR(5064))
+ {
+ // throw away...should cause timeout in TC
+ return;
+ }
+
+ CRASH_INSERTION(5072);
+
+ Uint32 err;
+ if (findTransaction(transid1, transid2, tcOprec, 0) == ZOK &&
+ !ERROR_INSERTED_CLEAR(5065) &&
+ !ERROR_INSERTED(5070) &&
+ !ERROR_INSERTED(5071))
+ {
+ TcConnectionrec * const regTcPtr = tcConnectptr.p;
+
+ if (unlikely(regTcPtr->transactionState != TcConnectionrec::PREPARED ||
+ ERROR_INSERTED_CLEAR(5067)))
+ {
+ err = FireTrigRef::FTR_IncorrectState;
+ goto do_err;
+ }
+
+ /**
+ *
+ */
+ signal->theData[0] = regTcPtr->tupConnectrec;
+ signal->theData[1] = regTcPtr->tcBlockref;
+ signal->theData[2] = regTcPtr->tcOprec;
+ signal->theData[3] = transid1;
+ signal->theData[4] = transid2;
+ signal->theData[5] = pass;
+ Uint32 tup = refToMain(regTcPtr->tcTupBlockref);
+ EXECUTE_DIRECT(tup, GSN_FIRE_TRIG_REQ, signal, 6);
+
+ err = signal->theData[0];
+ Uint32 cnt = signal->theData[1];
+
+ if (ERROR_INSERTED_CLEAR(5066))
+ {
+ err = 5066;
+ }
+
+ if (ERROR_INSERTED_CLEAR(5068))
+ tcOprec++;
+ if (ERROR_INSERTED_CLEAR(5069))
+ transid1++;
+
+ if (err == 0)
+ {
+ jam();
+ Uint32 Tdata[FireTrigConf::SignalLength];
+ FireTrigConf * conf = CAST_PTR(FireTrigConf, Tdata);
+ conf->tcOpRec = tcOprec;
+ conf->transId[0] = transid1;
+ conf->transId[1] = transid2;
+ conf->noFiredTriggers = cnt;
+ sendFireTrigConfTc(signal, regTcPtr->tcBlockref, Tdata);
+ return;
+ }
+ }
+ else
+ {
+ jam();
+ err = FireTrigRef::FTR_UnknownOperation;
+ }
+
+do_err:
+ if (ERROR_INSERTED_CLEAR(5070))
+ tcOprec++;
+
+ if (ERROR_INSERTED_CLEAR(5071))
+ transid1++;
+
+ FireTrigRef * ref = CAST_PTR(FireTrigRef, signal->getDataPtrSend());
+ ref->tcOpRec = tcOprec;
+ ref->transId[0] = transid1;
+ ref->transId[1] = transid2;
+ ref->errCode = err;
+ sendSignal(senderRef, GSN_FIRE_TRIG_REF,
+ signal, FireTrigRef::SignalLength, JBB);
+
+ return;
+}
+
+void
+Dblqh::sendFireTrigConfTc(Signal* signal,
+ BlockReference atcBlockref,
+ Uint32 Tdata[])
+{
+ HostRecordPtr Thostptr;
+ Uint32 len = FireTrigConf::SignalLength;
+
+ Thostptr.i = refToNode(atcBlockref);
+ ptrCheckGuard(Thostptr, chostFileSize, hostRecord);
+
+ if (Thostptr.p->noOfPackedWordsTc > (25 - len))
+ {
+ jam();
+ sendPackedSignalTc(signal, Thostptr.p);
+ }
+ else
+ {
+ jam();
+ updatePackedList(signal, Thostptr.p, Thostptr.i);
+ }
+
+ ndbassert(FireTrigConf::SignalLength == 4);
+ Uint32 * dst = &Thostptr.p->packedWordsTc[Thostptr.p->noOfPackedWordsTc];
+ Thostptr.p->noOfPackedWordsTc += len;
+ dst[0] = Tdata[0] | (ZFIRE_TRIG_CONF << 28);
+ dst[1] = Tdata[1];
+ dst[2] = Tdata[2];
+ dst[3] = Tdata[3];
+}
+
+bool
+Dblqh::check_fire_trig_pass(Uint32 opId, Uint32 pass)
+{
+ /**
+ * Check that trigger only fires once per pass
+ * (per primary key)
+ */
+ TcConnectionrecPtr regTcPtr;
+ regTcPtr.i= opId;
+ ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec);
+ if (regTcPtr.p->m_fire_trig_pass <= pass)
+ {
+ regTcPtr.p->m_fire_trig_pass = pass + 1;
+ return true;
+ }
+ return false;
+}
+
/* ************************************************************************>>
* COMMIT: Start commit request from TC. This signal is originally sent as a
* packed signal and this function is called from execPACKED_SIGNAL.
=== modified file 'storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp 2010-03-26 07:13:06 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp 2011-04-05 19:12:29 +0000
@@ -171,7 +171,17 @@ public:
CS_FAIL_COMMITTING = 22,
CS_FAIL_COMMITTED = 23,
CS_FAIL_COMPLETED = 24,
- CS_START_SCAN = 25
+ CS_START_SCAN = 25,
+
+ /**
+ * Sending FIRE_TRIG_REQ
+ */
+ CS_SEND_FIRE_TRIG_REQ = 26,
+
+ /**
+ * Waiting for FIRE_TRIG_CONF/REF (or operations generated by this)
+ */
+ CS_WAIT_FIRE_TRIG_REQ = 27
};
enum OperationState {
@@ -192,7 +202,9 @@ public:
OS_WAIT_COMMIT_CONF = 15,
OS_WAIT_ABORT_CONF = 16,
OS_WAIT_COMPLETE_CONF = 17,
- OS_WAIT_SCAN = 18
+ OS_WAIT_SCAN = 18,
+
+ OS_FIRE_TRIG_REQ = 19,
};
enum AbortState {
@@ -238,8 +250,7 @@ public:
IOS_NOOP = 0,
IOS_INDEX_ACCESS = 1,
IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF = 2,
- IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI = 3,
- IOS_INDEX_OPERATION = 4
+ IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI = 3
};
enum IndexState {
@@ -695,7 +706,10 @@ public:
//---------------------------------------------------
UintR lastTcConnect;
UintR lqhkeyreqrec;
- Uint32 buddyPtr;
+ union {
+ Uint32 buddyPtr;
+ Int32 pendingTriggers; // For deferred triggers
+ };
union {
UintR apiScanRec;
UintR commitAckMarker;
@@ -705,15 +719,22 @@ public:
ReturnSignal returnsignal;
AbortState abortState;
- Uint8 indexOpReturn;
- Uint8 triggerPending; // Used to mark waiting for a CONTINUEB
+ enum TransactionFlags
+ {
+ TF_INDEX_OP_RETURN = 1,
+ TF_TRIGGER_PENDING = 2, // Used to mark waiting for a CONTINUEB
+ TF_EXEC_FLAG = 4,
+ TF_COMMIT_ACK_MARKER_RECEIVED = 8,
+ TF_DEFERRED_CONSTRAINTS = 16, // check constraints in deferred fashion
+ TF_DEFERRED_TRIGGERS = 32, // trans has deferred triggers
+ TF_END = 0
+ };
+ Uint32 m_flags;
- Uint8 m_exec_flag;
Uint8 m_special_op_flags; // Used to mark on-going TcKeyReq as indx table
Uint8 takeOverRec;
Uint8 currentReplicaNo;
- Uint8 m_commit_ack_marker_received;
Uint8 tckeyrec; // Changed from R
@@ -776,6 +797,12 @@ public:
#ifdef ERROR_INSERT
Uint32 continueBCount; // ERROR_INSERT 8082
#endif
+ Uint8 m_pre_commit_pass;
+
+ bool isExecutingDeferredTriggers() const {
+ return apiConnectstate == CS_SEND_FIRE_TRIG_REQ ||
+ apiConnectstate == CS_WAIT_FIRE_TRIG_REQ ;
+ }
};
typedef Ptr<ApiConnectRecord> ApiConnectRecordPtr;
@@ -840,7 +867,8 @@ public:
SOF_REORG_MOVING = 8, // A record that should be moved
SOF_TRIGGER = 16, // A trigger
SOF_REORG_COPY = 32,
- SOF_REORG_DELETE = 64
+ SOF_REORG_DELETE = 64,
+ SOF_DEFERRED_TRIGGER = 128 // Op has deferred trigger
};
static inline bool isIndexOp(Uint8 flags) {
@@ -863,12 +891,12 @@ public:
Uint16 lqhInstanceKey;
// Trigger data
- FiredTriggerPtr accumulatingTriggerData;
- UintR noFiredTriggers;
- UintR noReceivedTriggers;
- UintR triggerExecutionCount;
- UintR triggeringOperation;
+ UintR noFiredTriggers; // As reported by lqhKeyConf
+ UintR noReceivedTriggers; // FIRE_TRIG_ORD
+ UintR triggerExecutionCount;// No of outstanding op due to triggers
UintR savedState[LqhKeyConf::SignalLength];
+
+ UintR triggeringOperation; // Which operation was "cause" of this op
// Index data
UintR indexOp;
@@ -956,8 +984,6 @@ public:
UintR packedWordsLqh[26];
UintR noOfWordsTCKEYCONF;
UintR packedWordsTCKEYCONF[30];
- UintR noOfWordsTCINDXCONF;
- UintR packedWordsTCINDXCONF[30];
BlockReference hostLqhBlockRef;
enum NodeFailBits
@@ -1361,6 +1387,8 @@ private:
void execALTER_INDX_IMPL_REQ(Signal* signal);
void execSIGNAL_DROPPED_REP(Signal* signal);
+ void execFIRE_TRIG_REF(Signal*);
+ void execFIRE_TRIG_CONF(Signal*);
// Index table lookup
void execTCKEYCONF(Signal* signal);
@@ -1395,14 +1423,15 @@ private:
void sendPackedTCKEYCONF(Signal* signal,
HostRecord * ahostptr,
UintR hostId);
- void sendPackedTCINDXCONF(Signal* signal,
- HostRecord * ahostptr,
- UintR hostId);
void sendPackedSignalLqh(Signal* signal, HostRecord * ahostptr);
Uint32 sendCommitLqh(Signal* signal,
TcConnectRecord * const regTcPtr);
Uint32 sendCompleteLqh(Signal* signal,
TcConnectRecord * const regTcPtr);
+
+ void sendFireTrigReq(Signal*, Ptr<ApiConnectRecord>, Uint32 firstTcConnect);
+ Uint32 sendFireTrigReqLqh(Signal*, Ptr<TcConnectRecord>, Uint32 pass);
+
void sendTCKEY_FAILREF(Signal* signal, ApiConnectRecord *);
void sendTCKEY_FAILCONF(Signal* signal, ApiConnectRecord *);
void routeTCKEY_FAILREFCONF(Signal* signal, const ApiConnectRecord *,
@@ -1495,7 +1524,6 @@ private:
BlockReference TBRef);
void sendSystemError(Signal* signal, int line);
void sendtckeyconf(Signal* signal, UintR TcommitFlag);
- void sendTcIndxConf(Signal* signal, UintR TcommitFlag);
void unlinkApiConnect(Ptr<GcpRecord>, Ptr<ApiConnectRecord>);
void unlinkGcp(Ptr<GcpRecord>);
void unlinkReadyTcCon(Signal* signal);
@@ -1540,11 +1568,10 @@ private:
TcConnectRecord* trigOp);
void restoreTriggeringOpState(Signal* signal,
TcConnectRecord* trigOp);
- void continueTriggeringOp(Signal* signal,
- TcConnectRecord* trigOp);
+ void trigger_op_finished(Signal* signal, ApiConnectRecordPtr,
+ TcConnectRecord* triggeringOp);
+ void continueTriggeringOp(Signal* signal, TcConnectRecord* trigOp);
- void scheduleFiredTrigger(ApiConnectRecordPtr* transPtr,
- TcConnectRecordPtr* opPtr);
void executeTriggers(Signal* signal, ApiConnectRecordPtr* transPtr);
void executeTrigger(Signal* signal,
TcFiredTriggerData* firedTriggerData,
@@ -1564,14 +1591,12 @@ private:
TcFiredTriggerData* firedTriggerData,
ApiConnectRecordPtr* transPtr,
TcConnectRecordPtr* opPtr,
- TcIndexData* indexData,
- bool holdOperation = false);
+ TcIndexData* indexData);
void deleteFromIndexTable(Signal* signal,
TcFiredTriggerData* firedTriggerData,
ApiConnectRecordPtr* transPtr,
TcConnectRecordPtr* opPtr,
- TcIndexData* indexData,
- bool holdOperation = false);
+ TcIndexData* indexData);
void executeReorgTrigger(Signal* signal,
TcDefinedTriggerData* definedTriggerData,
=== modified file 'storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp 2010-02-22 14:05:33 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp 2011-04-05 19:12:29 +0000
@@ -297,7 +297,10 @@ Dbtc::Dbtc(Block_context& ctx):
addRecSignal(GSN_ALTER_TAB_REQ, &Dbtc::execALTER_TAB_REQ);
addRecSignal(GSN_ROUTE_ORD, &Dbtc::execROUTE_ORD);
addRecSignal(GSN_TCKEY_FAILREFCONF_R, &Dbtc::execTCKEY_FAILREFCONF_R);
-
+
+ addRecSignal(GSN_FIRE_TRIG_REF, &Dbtc::execFIRE_TRIG_REF);
+ addRecSignal(GSN_FIRE_TRIG_CONF, &Dbtc::execFIRE_TRIG_CONF);
+
cacheRecord = 0;
apiConnectRecord = 0;
tcConnectRecord = 0;
=== modified file 'storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp 2010-10-28 07:11:34 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp 2011-04-05 19:12:29 +0000
@@ -186,6 +186,22 @@ Dbtc::updateBuddyTimer(ApiConnectRecordP
}//if
}
+static
+inline
+bool
+tc_testbit(Uint32 flags, Uint32 flag)
+{
+ return (flags & flag) != 0;
+}
+
+static
+inline
+void
+tc_clearbit(Uint32 & flags, Uint32 flag)
+{
+ flags &= ~(Uint32)flag;
+}
+
void Dbtc::execCONTINUEB(Signal* signal)
{
UintR tcase;
@@ -314,8 +330,9 @@ void Dbtc::execCONTINUEB(Signal* signal)
if (likely((transPtr.p->transid[0] == Tdata1) &&
(transPtr.p->transid[1] == Tdata2)))
{
- ndbrequire(transPtr.p->triggerPending);
- transPtr.p->triggerPending = false;
+ ndbrequire(tc_testbit(transPtr.p->m_flags,
+ ApiConnectRecord::TF_TRIGGER_PENDING));
+ tc_clearbit(transPtr.p->m_flags, ApiConnectRecord::TF_TRIGGER_PENDING);
/* Try executing triggers now */
executeTriggers(signal, &transPtr);
}
@@ -326,6 +343,19 @@ void Dbtc::execCONTINUEB(Signal* signal)
ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
sendtckeyconf(signal, Tdata1);
return;
+ case TcContinueB::ZSEND_FIRE_TRIG_REQ:
+ jam();
+ apiConnectptr.i = Tdata0;
+ ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
+ if (unlikely(! (apiConnectptr.p->transid[0] == Tdata1 &&
+ apiConnectptr.p->transid[1] == Tdata2 &&
+ apiConnectptr.p->apiConnectstate == CS_SEND_FIRE_TRIG_REQ)))
+ {
+ warningReport(signal, 29);
+ return;
+ }
+ sendFireTrigReq(signal, apiConnectptr, signal->theData[4]);
+ return;
default:
ndbrequire(false);
}//switch
@@ -1764,7 +1794,7 @@ start_failure:
{
jam();
initApiConnectRec(signal, apiConnectptr.p, true);
- apiConnectptr.p->m_exec_flag = 1;
+ apiConnectptr.p->m_flags |= ApiConnectRecord::TF_EXEC_FLAG;
goto start_failure;
}
case 61:
@@ -1899,7 +1929,6 @@ void Dbtc::execKEYINFO(Signal* signal)
}//switch
}//Dbtc::execKEYINFO()
-
/**
* sendKeyInfoTrain
* Method to send a KeyInfo signal train from KeyInfo in the supplied
@@ -2299,7 +2328,7 @@ void Dbtc::initApiConnectRec(Signal* sig
UintR Ttransid0 = tcKeyReq->transId1;
UintR Ttransid1 = tcKeyReq->transId2;
- regApiPtr->m_exec_flag = 0;
+ tc_clearbit(regApiPtr->m_flags, ApiConnectRecord::TF_EXEC_FLAG);
regApiPtr->returncode = 0;
regApiPtr->returnsignal = RS_TCKEYCONF;
ndbassert(regApiPtr->firstTcConnect == RNIL);
@@ -2310,7 +2339,8 @@ void Dbtc::initApiConnectRec(Signal* sig
regApiPtr->lqhkeyreqrec = 0;
regApiPtr->tckeyrec = 0;
regApiPtr->tcindxrec = 0;
- regApiPtr->m_commit_ack_marker_received = 0;
+ tc_clearbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_COMMIT_ACK_MARKER_RECEIVED);
regApiPtr->no_commit_ack_markers = 0;
regApiPtr->failureNr = TfailureNr;
regApiPtr->transid[0] = Ttransid0;
@@ -2320,15 +2350,19 @@ void Dbtc::initApiConnectRec(Signal* sig
regApiPtr->currSavePointId = 0;
regApiPtr->m_transaction_nodes.clear();
regApiPtr->singleUserMode = 0;
+ regApiPtr->m_pre_commit_pass = 0;
// Trigger data
releaseFiredTriggerData(®ApiPtr->theFiredTriggers),
// Index data
- regApiPtr->indexOpReturn = false;
+ tc_clearbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_INDEX_OP_RETURN);
regApiPtr->noIndexOp = 0;
if(releaseIndexOperations)
releaseAllSeizedIndexOperations(regApiPtr);
regApiPtr->immediateTriggerId = RNIL;
+ tc_clearbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_DEFERRED_CONSTRAINTS);
c_counters.ctransCount++;
#ifdef ERROR_INSERT
@@ -2369,8 +2403,6 @@ Dbtc::seizeTcRecord(Signal* signal)
regTcPtr->prevTcConnect = TlastTcConnect;
regTcPtr->nextTcConnect = RNIL;
- regTcPtr->accumulatingTriggerData.i = RNIL;
- regTcPtr->accumulatingTriggerData.p = NULL;
regTcPtr->noFiredTriggers = 0;
regTcPtr->noReceivedTriggers = 0;
regTcPtr->triggerExecutionCount = 0;
@@ -2479,13 +2511,15 @@ void Dbtc::execTCKEYREQ(Signal* signal)
apiConnectptr.p = regApiPtr;
Uint32 TstartFlag = TcKeyReq::getStartFlag(Treqinfo);
- Uint32 TexecFlag = TcKeyReq::getExecuteFlag(Treqinfo);
+ Uint32 TexecFlag =
+ TcKeyReq::getExecuteFlag(Treqinfo) ? ApiConnectRecord::TF_EXEC_FLAG : 0;
Uint8 Tspecial_op_flags = regApiPtr->m_special_op_flags;
- bool isIndexOpReturn = regApiPtr->indexOpReturn;
+ bool isIndexOpReturn = tc_testbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_INDEX_OP_RETURN);
bool isExecutingTrigger = Tspecial_op_flags & TcConnectRecord::SOF_TRIGGER;
regApiPtr->m_special_op_flags = 0; // Reset marker
- regApiPtr->m_exec_flag |= TexecFlag;
+ regApiPtr->m_flags |= TexecFlag;
TableRecordPtr localTabptr;
localTabptr.i = TtabIndex;
localTabptr.p = &tableRecord[TtabIndex];
@@ -2497,7 +2531,7 @@ void Dbtc::execTCKEYREQ(Signal* signal)
//---------------------------------------------------------------------
jam();
initApiConnectRec(signal, regApiPtr);
- regApiPtr->m_exec_flag = TexecFlag;
+ regApiPtr->m_flags |= TexecFlag;
} else {
releaseSections(handle);
if(getAllowStartTransaction(sendersNodeId, localTabptr.p->singleUserMode) == true){
@@ -2536,7 +2570,7 @@ void Dbtc::execTCKEYREQ(Signal* signal)
return;
}
initApiConnectRec(signal, regApiPtr);
- regApiPtr->m_exec_flag = TexecFlag;
+ regApiPtr->m_flags |= TexecFlag;
} else {
//----------------------------------------------------------------------
// Transaction is started already.
@@ -2567,7 +2601,7 @@ void Dbtc::execTCKEYREQ(Signal* signal)
//--------------------------------------------------------------------
jam();
initApiConnectRec(signal, regApiPtr);
- regApiPtr->m_exec_flag = TexecFlag;
+ regApiPtr->m_flags |= TexecFlag;
} else if(TexecFlag) {
releaseSections(handle);
TCKEY_abort(signal, 59);
@@ -2608,6 +2642,8 @@ void Dbtc::execTCKEYREQ(Signal* signal)
}//if
break;
case CS_START_COMMITTING:
+ case CS_SEND_FIRE_TRIG_REQ:
+ case CS_WAIT_FIRE_TRIG_REQ:
jam();
if(isIndexOpReturn || isExecutingTrigger){
break;
@@ -2730,6 +2766,11 @@ void Dbtc::execTCKEYREQ(Signal* signal)
SegmentedSectionPtr attrInfoSec;
if (handle.getSection(attrInfoSec, TcKeyReq::AttrInfoSectionNum))
TattrLen= attrInfoSec.sz;
+
+ if (TcKeyReq::getDeferredConstraints(Treqinfo))
+ {
+ regApiPtr->m_flags |= ApiConnectRecord::TF_DEFERRED_CONSTRAINTS;
+ }
}
else
{
@@ -2754,6 +2795,7 @@ void Dbtc::execTCKEYREQ(Signal* signal)
if (isExecutingTrigger)
{
+ ndbassert(tcConnectptr.i != TsenderData);
// Save the TcOperationPtr for fireing operation
regTcPtr->triggeringOperation = TsenderData;
// Grab trigger Id from ApiConnectRecord
@@ -2934,7 +2976,8 @@ void Dbtc::execTCKEYREQ(Signal* signal)
else
{
/* Insert, Update, Write, Delete */
- if (!regApiPtr->m_commit_ack_marker_received)
+ if (!tc_testbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_COMMIT_ACK_MARKER_RECEIVED))
{
if(regApiPtr->commitAckMarker != RNIL)
regTcPtr->commitAckMarker = regApiPtr->commitAckMarker;
@@ -3021,7 +3064,7 @@ void Dbtc::execTCKEYREQ(Signal* signal)
jam();
// Trigger execution at commit
regApiPtr->apiConnectstate = CS_REC_COMMITTING;
- } else {
+ } else if (!regApiPtr->isExecutingDeferredTriggers()) {
jam();
regApiPtr->apiConnectstate = CS_RECEIVING;
}//if
@@ -3317,6 +3360,10 @@ void Dbtc::tckeyreq050Lab(Signal* signal
jam();
regApiPtr->apiConnectstate = CS_START_COMMITTING;
break;
+ case CS_SEND_FIRE_TRIG_REQ:
+ case CS_WAIT_FIRE_TRIG_REQ:
+ jam();
+ break;
default:
jam();
systemErrorLab(signal, __LINE__);
@@ -3391,16 +3438,7 @@ void Dbtc::attrinfoDihReceivedLab(Signal
TcConnectRecordPtr opPtr;
opPtr.i = trigOp;
ptrCheckGuard(opPtr, ctcConnectFilesize, tcConnectRecord);
- opPtr.p->triggerExecutionCount--;
- if (opPtr.p->triggerExecutionCount == 0)
- {
- /**
- * We have completed current trigger execution
- * Continue triggering operation
- */
- jam();
- continueTriggeringOp(signal, opPtr.p);
- }
+ trigger_op_finished(signal, apiConnectptr, opPtr.p);
return;
}
else
@@ -3481,6 +3519,8 @@ void Dbtc::sendlqhkeyreq(Signal* signal,
}//if
}//if
#endif
+ Uint32 Tdeferred = tc_testbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_DEFERRED_CONSTRAINTS);
Uint32 reorg = 0;
Uint32 Tspecial_op = regTcPtr->m_special_op_flags;
if (Tspecial_op == 0)
@@ -3546,6 +3586,7 @@ void Dbtc::sendlqhkeyreq(Signal* signal,
LqhKeyReq::setSimpleFlag(Tdata10, sig0);
LqhKeyReq::setOperation(Tdata10, sig1);
LqhKeyReq::setNoDiskFlag(Tdata10, regCachePtr->m_no_disk_flag);
+ LqhKeyReq::setDeferredConstraints(Tdata10, Tdeferred);
/* -----------------------------------------------------------------------
* If we are sending a short LQHKEYREQ, then there will be some AttrInfo
@@ -3626,8 +3667,6 @@ void Dbtc::sendlqhkeyreq(Signal* signal,
}//if
// Reset trigger count
- regTcPtr->accumulatingTriggerData.i = RNIL;
- regTcPtr->accumulatingTriggerData.p = NULL;
regTcPtr->noFiredTriggers = 0;
regTcPtr->triggerExecutionCount = 0;
@@ -3951,6 +3990,13 @@ void Dbtc::execPACKED_SIGNAL(Signal* sig
execLQHKEYCONF(signal);
Tstep += LqhKeyConf::SignalLength;
break;
+ case ZFIRE_TRIG_CONF:
+ jam();
+ signal->header.theLength = 4;
+ signal->theData[3] = TpackDataPtr[3];
+ execFIRE_TRIG_CONF(signal);
+ Tstep += 4;
+ break;
default:
systemErrorLab(signal, __LINE__);
return;
@@ -4025,10 +4071,13 @@ void Dbtc::execSIGNAL_DROPPED_REP(Signal
apiConnectptr.p->returncode = ZGET_DATAREC_ERROR;
/* Set m_exec_flag according to the dropped request */
- apiConnectptr.p->m_exec_flag =
- TcKeyReq::getExecuteFlag(truncatedTcKeyReq->requestInfo);
-
- DEBUG(" Execute flag set to " << apiConnectptr.p->m_exec_flag);
+ apiConnectptr.p->m_flags |=
+ TcKeyReq::getExecuteFlag(truncatedTcKeyReq->requestInfo) ?
+ ApiConnectRecord::TF_EXEC_FLAG : 0;
+
+ DEBUG(" Execute flag set to " << tc_testbit(apiConnectptr.p->m_flags,
+ ApiConnectRecord::TF_EXEC_FLAG)
+ );
abortErrorLab(signal);
@@ -4085,7 +4134,8 @@ void Dbtc::execSIGNAL_DROPPED_REP(Signal
void Dbtc::execLQHKEYCONF(Signal* signal)
{
- const LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr();
+ const LqhKeyConf * lqhKeyConf = CAST_CONSTPTR(LqhKeyConf,
+ signal->getDataPtr());
UintR compare_transid1, compare_transid2;
BlockReference tlastLqhBlockref;
UintR tlastLqhConnect;
@@ -4134,7 +4184,8 @@ void Dbtc::execLQHKEYCONF(Signal* signal
UintR TapiConnectFilesize = capiConnectFilesize;
UintR Ttrans1 = lqhKeyConf->transId1;
UintR Ttrans2 = lqhKeyConf->transId2;
- Uint32 noFired = lqhKeyConf->noFiredTriggers;
+ Uint32 noFired = LqhKeyConf::getFiredCount(lqhKeyConf->noFiredTriggers);
+ Uint32 deferred = LqhKeyConf::getDeferredBit(lqhKeyConf->noFiredTriggers);
if (TapiConnectptrIndex >= TapiConnectFilesize) {
TCKEY_abort(signal, 29);
@@ -4190,6 +4241,10 @@ void Dbtc::execLQHKEYCONF(Signal* signal
regTcPtr->lastLqhCon = tlastLqhConnect;
regTcPtr->lastLqhNodeId = refToNode(tlastLqhBlockref);
regTcPtr->noFiredTriggers = noFired;
+ regTcPtr->m_special_op_flags |= (deferred) ?
+ TcConnectRecord::SOF_DEFERRED_TRIGGER : 0;
+ regApiPtr.p->m_flags |= (deferred) ?
+ ApiConnectRecord::TF_DEFERRED_TRIGGERS : 0;
UintR Ttckeyrec = (UintR)regApiPtr.p->tckeyrec;
UintR TclientData = regTcPtr->clientData;
@@ -4197,10 +4252,7 @@ void Dbtc::execLQHKEYCONF(Signal* signal
Uint32 TopSimple = regTcPtr->opSimple;
Uint32 Toperation = regTcPtr->operation;
ConnectionState TapiConnectstate = regApiPtr.p->apiConnectstate;
- if (Ttckeyrec > (ZTCOPCONF_SIZE - 2)) {
- TCKEY_abort(signal, 30);
- return;
- }
+
if (TapiConnectstate == CS_ABORTING) {
warningReport(signal, 27);
return;
@@ -4225,7 +4277,7 @@ void Dbtc::execLQHKEYCONF(Signal* signal
const Uint32 noOfLqhs = regTcPtr->noOfNodes;
CommitAckMarker * tmp = m_commitAckMarkerHash.getPtr(commitAckMarker);
jam();
- regApiPtr.p->m_commit_ack_marker_received = TRUE;
+ regApiPtr.p->m_flags |= ApiConnectRecord::TF_COMMIT_ACK_MARKER_RECEIVED;
/**
* Populate LQH array
*/
@@ -4240,6 +4292,12 @@ void Dbtc::execLQHKEYCONF(Signal* signal
} else {
if (noFired == 0 && regTcPtr->triggeringOperation == RNIL) {
jam();
+
+ if (Ttckeyrec > (ZTCOPCONF_SIZE - 2)) {
+ TCKEY_abort(signal, 30);
+ return;
+ }
+
/*
* Skip counting triggering operations the first round
* since they will enter execLQHKEYCONF a second time
@@ -4353,23 +4411,17 @@ void Dbtc::execLQHKEYCONF(Signal* signal
/**
* And now decide what to do next
*/
- if (regTcPtr->triggeringOperation != RNIL) {
+ if (regTcPtr->triggeringOperation != RNIL &&
+ !regApiPtr.p->isExecutingDeferredTriggers()) {
jam();
// This operation was created by a trigger execting operation
// Restart it if we have executed all it's triggers
TcConnectRecordPtr opPtr;
opPtr.i = regTcPtr->triggeringOperation;
+ ndbassert(opPtr.i != TtcConnectptrIndex);
ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord);
- opPtr.p->triggerExecutionCount--;
- if (opPtr.p->triggerExecutionCount == 0) {
- /*
- We have completed current trigger execution
- Continue triggering operation
- */
- jam();
- continueTriggeringOp(signal, opPtr.p);
- }
+ trigger_op_finished(signal, regApiPtr, opPtr.p);
} else if (noFired == 0) {
// This operation did not fire any triggers, finish operation
jam();
@@ -4395,7 +4447,7 @@ void Dbtc::execLQHKEYCONF(Signal* signal
void Dbtc::setupIndexOpReturn(ApiConnectRecord* regApiPtr,
TcConnectRecord* regTcPtr)
{
- regApiPtr->indexOpReturn = true;
+ regApiPtr->m_flags |= ApiConnectRecord::TF_INDEX_OP_RETURN;
regApiPtr->indexOp = regTcPtr->indexOp;
regApiPtr->clientData = regTcPtr->clientData;
regApiPtr->attrInfoLen = regTcPtr->attrInfoLen;
@@ -4426,6 +4478,7 @@ Dbtc::lqhKeyConf_checkTransactionState(S
UintR Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec;
int TnoOfOutStanding = Tlqhkeyreqrec - Tlqhkeyconfrec;
+ apiConnectptr = regApiPtr;
switch (TapiConnectstate) {
case CS_START_COMMITTING:
if (TnoOfOutStanding == 0) {
@@ -4437,7 +4490,10 @@ Dbtc::lqhKeyConf_checkTransactionState(S
jam();
sendtckeyconf(signal, 0);
return;
- } else if (regApiPtr.p->indexOpReturn) {
+ }
+ else if (tc_testbit(regApiPtr.p->m_flags,
+ ApiConnectRecord::TF_INDEX_OP_RETURN))
+ {
jam();
sendtckeyconf(signal, 0);
return;
@@ -4460,11 +4516,14 @@ Dbtc::lqhKeyConf_checkTransactionState(S
jam();
sendtckeyconf(signal, 0);
return;
- } else if (regApiPtr.p->indexOpReturn) {
+ }
+ else if (tc_testbit(regApiPtr.p->m_flags,
+ ApiConnectRecord::TF_INDEX_OP_RETURN))
+ {
jam();
sendtckeyconf(signal, 0);
return;
- }//if
+ }//if
jam();
}//if
return;
@@ -4474,7 +4533,10 @@ Dbtc::lqhKeyConf_checkTransactionState(S
jam();
sendtckeyconf(signal, 0);
return;
- } else if (regApiPtr.p->indexOpReturn) {
+ }
+ else if (tc_testbit(regApiPtr.p->m_flags,
+ ApiConnectRecord::TF_INDEX_OP_RETURN))
+ {
jam();
sendtckeyconf(signal, 0);
return;
@@ -4493,6 +4555,17 @@ Dbtc::lqhKeyConf_checkTransactionState(S
/*---------------------------------------------------------------*/
regApiPtr.p->tckeyrec = 0;
return;
+ case CS_SEND_FIRE_TRIG_REQ:
+ return;
+ case CS_WAIT_FIRE_TRIG_REQ:
+ if (TnoOfOutStanding == 0 && regApiPtr.p->pendingTriggers == 0)
+ {
+ jam();
+ regApiPtr.p->apiConnectstate = CS_START_COMMITTING;
+ diverify010Lab(signal);
+ return;
+ }
+ return;
default:
TCKEY_abort(signal, 46);
return;
@@ -4526,7 +4599,8 @@ void Dbtc::sendtckeyconf(Signal* signal,
const UintR TpacketLen = 6 + TopWords;
regApiPtr->tckeyrec = 0;
- if (regApiPtr->indexOpReturn) {
+ if (tc_testbit(regApiPtr->m_flags, ApiConnectRecord::TF_INDEX_OP_RETURN))
+ {
jam();
// Return internally generated TCKEY
TcKeyConf * const tcKeyConf = (TcKeyConf *)signal->getDataPtrSend();
@@ -4543,7 +4617,7 @@ void Dbtc::sendtckeyconf(Signal* signal,
Uint32 sigLen = 1 /** gci_lo */ +
TcKeyConf::StaticLength + TcKeyConf::OperationLength;
EXECUTE_DIRECT(DBTC, GSN_TCKEYCONF, signal, sigLen);
- regApiPtr->indexOpReturn = false;
+ tc_clearbit(regApiPtr->m_flags, ApiConnectRecord::TF_INDEX_OP_RETURN);
if (TopWords == 0) {
jam();
return; // No queued TcKeyConf
@@ -4551,7 +4625,7 @@ void Dbtc::sendtckeyconf(Signal* signal,
}//if
if(TcommitFlag){
jam();
- regApiPtr->m_exec_flag = 0;
+ tc_clearbit(regApiPtr->m_flags, ApiConnectRecord::TF_EXEC_FLAG);
}
TcKeyConf::setNoOfOperations(confInfo, (TopWords >> 1));
if ((TpacketLen + 1 /** gci_lo */ > 25) || !is_api){
@@ -4651,7 +4725,6 @@ void Dbtc::execSEND_PACKED(Signal* signa
arrGuard(Thostptr.i - 1, MAX_NODES - 1);
UintR TnoOfPackedWordsLqh = Thostptr.p->noOfPackedWordsLqh;
UintR TnoOfWordsTCKEYCONF = Thostptr.p->noOfWordsTCKEYCONF;
- UintR TnoOfWordsTCINDXCONF = Thostptr.p->noOfWordsTCINDXCONF;
jam();
if (TnoOfPackedWordsLqh > 0) {
jam();
@@ -4661,10 +4734,6 @@ void Dbtc::execSEND_PACKED(Signal* signa
jam();
sendPackedTCKEYCONF(signal, Thostptr.p, (Uint32)Thostptr.i);
}//if
- if (TnoOfWordsTCINDXCONF > 0) {
- jam();
- sendPackedTCINDXCONF(signal, Thostptr.p, (Uint32)Thostptr.i);
- }//if
Thostptr.p->inPackedList = false;
}//for
cpackedListIndex = 0;
@@ -4726,27 +4795,6 @@ void Dbtc::sendPackedTCKEYCONF(Signal* s
sendSignal(TBref, GSN_TCKEYCONF, signal, TnoOfWords, JBB);
}//Dbtc::sendPackedTCKEYCONF()
-void Dbtc::sendPackedTCINDXCONF(Signal* signal,
- HostRecord * ahostptr,
- UintR hostId)
-{
- UintR Tj;
- UintR TnoOfWords = ahostptr->noOfWordsTCINDXCONF;
- BlockReference TBref = numberToRef(API_PACKED, hostId);
- for (Tj = 0; Tj < ahostptr->noOfWordsTCINDXCONF; Tj += 4) {
- UintR sig0 = ahostptr->packedWordsTCINDXCONF[Tj + 0];
- UintR sig1 = ahostptr->packedWordsTCINDXCONF[Tj + 1];
- UintR sig2 = ahostptr->packedWordsTCINDXCONF[Tj + 2];
- UintR sig3 = ahostptr->packedWordsTCINDXCONF[Tj + 3];
- signal->theData[Tj + 0] = sig0;
- signal->theData[Tj + 1] = sig1;
- signal->theData[Tj + 2] = sig2;
- signal->theData[Tj + 3] = sig3;
- }//for
- ahostptr->noOfWordsTCINDXCONF = 0;
- sendSignal(TBref, GSN_TCINDXCONF, signal, TnoOfWords, JBB);
-}//Dbtc::sendPackedTCINDXCONF()
-
/*
4.3.11 DIVERIFY
---------------
@@ -4765,6 +4813,19 @@ void Dbtc::diverify010Lab(Signal* signal
systemErrorLab(signal, __LINE__);
}//if
+ if (tc_testbit(regApiPtr->m_flags, ApiConnectRecord::TF_DEFERRED_TRIGGERS))
+ {
+ jam();
+ /**
+ * If trans has deferred triggers, let them fire just before
+ * transaction starts to commit
+ */
+ regApiPtr->pendingTriggers = 0;
+ tc_clearbit(regApiPtr->m_flags, ApiConnectRecord::TF_DEFERRED_TRIGGERS);
+ sendFireTrigReq(signal, apiConnectptr, regApiPtr->firstTcConnect);
+ return;
+ }
+
if (regApiPtr->lqhkeyreqrec)
{
if (TfirstfreeApiConnectCopy != RNIL) {
@@ -4823,7 +4884,8 @@ void Dbtc::seizeApiConnectCopy(Signal* s
cfirstfreeApiConnectCopy = locApiConnectptr.p->nextApiConnect;
locApiConnectptr.p->nextApiConnect = RNIL;
regApiPtr->apiCopyRecord = locApiConnectptr.i;
- regApiPtr->triggerPending = false;
+ tc_clearbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_TRIGGER_PENDING);
regApiPtr->m_special_op_flags = 0;
}//Dbtc::seizeApiConnectCopy()
@@ -5536,6 +5598,237 @@ Dbtc::sendCompleteLqh(Signal* signal,
}
void
+Dbtc::sendFireTrigReq(Signal* signal,
+ Ptr<ApiConnectRecord> regApiPtr,
+ Uint32 TopPtrI)
+{
+ UintR TtcConnectFilesize = ctcConnectFilesize;
+ TcConnectRecord *localTcConnectRecord = tcConnectRecord;
+ TcConnectRecordPtr localTcConnectptr;
+
+ setApiConTimer(regApiPtr.i, ctcTimer, __LINE__);
+ regApiPtr.p->apiConnectstate = CS_SEND_FIRE_TRIG_REQ;
+
+ localTcConnectptr.i = TopPtrI;
+ ndbassert(TopPtrI != RNIL);
+ Uint32 Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec;
+ Uint32 pass = regApiPtr.p->m_pre_commit_pass;
+ for (Uint32 i = 0; localTcConnectptr.i != RNIL && i < 16; i++)
+ {
+ ptrCheckGuard(localTcConnectptr,
+ TtcConnectFilesize, localTcConnectRecord);
+
+ const Uint32 nextTcConnect = localTcConnectptr.p->nextTcConnect;
+ Uint32 flags = localTcConnectptr.p->m_special_op_flags;
+ if (flags & TcConnectRecord::SOF_DEFERRED_TRIGGER)
+ {
+ jam();
+ tc_clearbit(flags, TcConnectRecord::SOF_DEFERRED_TRIGGER);
+ ndbrequire(localTcConnectptr.p->tcConnectstate == OS_PREPARED);
+ localTcConnectptr.p->tcConnectstate = OS_FIRE_TRIG_REQ;
+ localTcConnectptr.p->m_special_op_flags = flags;
+ i += sendFireTrigReqLqh(signal, localTcConnectptr, pass);
+ Tlqhkeyreqrec++;
+ }
+ localTcConnectptr.i = nextTcConnect;
+ }
+
+ regApiPtr.p->lqhkeyreqrec = Tlqhkeyreqrec;
+ if (localTcConnectptr.i == RNIL)
+ {
+ /**
+ * Now wait for FIRE_TRIG_CONF
+ */
+ jam();
+ regApiPtr.p->apiConnectstate = CS_WAIT_FIRE_TRIG_REQ;
+ ndbrequire(pass < 255);
+ regApiPtr.p->m_pre_commit_pass = (Uint8)(pass + 1);
+ return;
+ }
+ else
+ {
+ jam();
+ signal->theData[0] = TcContinueB::ZSEND_FIRE_TRIG_REQ;
+ signal->theData[1] = regApiPtr.i;
+ signal->theData[2] = regApiPtr.p->transid[0];
+ signal->theData[3] = regApiPtr.p->transid[1];
+ signal->theData[4] = localTcConnectptr.i;
+ if (ERROR_INSERTED_CLEAR(8090))
+ {
+ sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 5000, 5);
+ }
+ else
+ {
+ sendSignal(cownref, GSN_CONTINUEB, signal, 5, JBB);
+ }
+ }
+}
+
+Uint32
+Dbtc::sendFireTrigReqLqh(Signal* signal,
+ Ptr<TcConnectRecord> regTcPtr,
+ Uint32 pass)
+{
+ HostRecordPtr Thostptr;
+ UintR ThostFilesize = chostFilesize;
+ ApiConnectRecord * const regApiPtr = apiConnectptr.p;
+ Thostptr.i = regTcPtr.p->tcNodedata[0];
+ ptrCheckGuard(Thostptr, ThostFilesize, hostRecord);
+
+ Uint32 Tnode = Thostptr.i;
+ Uint32 self = getOwnNodeId();
+ Uint32 ret = (Tnode == self) ? 4 : 1;
+
+ Uint32 Tdata[FireTrigReq::SignalLength];
+ FireTrigReq * req = CAST_PTR(FireTrigReq, Tdata);
+ req->tcOpRec = regTcPtr.i;
+ req->transId[0] = regApiPtr->transid[0];
+ req->transId[1] = regApiPtr->transid[1];
+ req->pass = pass;
+ Uint32 len = FireTrigReq::SignalLength;
+
+ // currently packed signal cannot address specific instance
+ const bool send_unpacked = getNodeInfo(Thostptr.i).m_lqh_workers > 1;
+ if (send_unpacked) {
+ memcpy(signal->theData, Tdata, len << 2);
+ Uint32 instanceKey = regTcPtr.p->lqhInstanceKey;
+ BlockReference lqhRef = numberToRef(DBLQH, instanceKey, Tnode);
+ sendSignal(lqhRef, GSN_FIRE_TRIG_REQ, signal, len, JBB);
+ return ret;
+ }
+
+ if (Thostptr.p->noOfPackedWordsLqh > 25 - len) {
+ jam();
+ sendPackedSignalLqh(signal, Thostptr.p);
+ } else {
+ jam();
+ ret = 1;
+ updatePackedList(signal, Thostptr.p, Thostptr.i);
+ }
+
+ Tdata[0] |= (ZFIRE_TRIG_REQ << 28);
+ UintR Tindex = Thostptr.p->noOfPackedWordsLqh;
+ UintR* TDataPtr = &Thostptr.p->packedWordsLqh[Tindex];
+ memcpy(TDataPtr, Tdata, len << 2);
+ Thostptr.p->noOfPackedWordsLqh = Tindex + len;
+ return ret;
+}
+
+void
+Dbtc::execFIRE_TRIG_CONF(Signal* signal)
+{
+ TcConnectRecordPtr localTcConnectptr;
+ ApiConnectRecordPtr regApiPtr;
+
+ UintR TtcConnectFilesize = ctcConnectFilesize;
+ UintR TapiConnectFilesize = capiConnectFilesize;
+ TcConnectRecord *localTcConnectRecord = tcConnectRecord;
+ ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
+
+ const FireTrigConf * conf = CAST_CONSTPTR(FireTrigConf, signal->theData);
+ localTcConnectptr.i = conf->tcOpRec;
+ jamEntry();
+ ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
+ regApiPtr.i = localTcConnectptr.p->apiConnect;
+ if (localTcConnectptr.p->tcConnectstate != OS_FIRE_TRIG_REQ)
+ {
+ warningReport(signal, 28);
+ return;
+ }//if
+ ptrCheckGuard(regApiPtr, TapiConnectFilesize,
+ localApiConnectRecord);
+
+ Uint32 Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec;
+ Uint32 TapiConnectstate = regApiPtr.p->apiConnectstate;
+ UintR Tdata1 = regApiPtr.p->transid[0] - conf->transId[0];
+ UintR Tdata2 = regApiPtr.p->transid[1] - conf->transId[1];
+ Uint32 TcheckCondition =
+ (TapiConnectstate - CS_SEND_FIRE_TRIG_REQ) &
+ (TapiConnectstate - CS_WAIT_FIRE_TRIG_REQ);
+
+ Tdata1 = Tdata1 | Tdata2 | TcheckCondition;
+
+ if (Tdata1 != 0) {
+ warningReport(signal, 28);
+ return;
+ }//if
+
+ if (ERROR_INSERTED_CLEAR(8091))
+ {
+ jam();
+ return;
+ }
+
+ CRASH_INSERTION(8092);
+
+ setApiConTimer(regApiPtr.i, ctcTimer, __LINE__);
+ ndbassert(Tlqhkeyreqrec > 0);
+ regApiPtr.p->lqhkeyreqrec = Tlqhkeyreqrec - 1;
+ localTcConnectptr.p->tcConnectstate = OS_PREPARED;
+
+ Uint32 noFired = FireTrigConf::getFiredCount(conf->noFiredTriggers);
+ Uint32 deferred = FireTrigConf::getDeferredBit(conf->noFiredTriggers);
+
+ regApiPtr.p->pendingTriggers += noFired;
+ regApiPtr.p->m_flags |= (deferred) ?
+ ApiConnectRecord::TF_DEFERRED_TRIGGERS : 0;
+ localTcConnectptr.p->m_special_op_flags |= (deferred) ?
+ TcConnectRecord::SOF_DEFERRED_TRIGGER : 0;
+
+ if (regApiPtr.p->pendingTriggers == 0)
+ {
+ jam();
+ lqhKeyConf_checkTransactionState(signal, regApiPtr);
+ }
+}
+
+void
+Dbtc::execFIRE_TRIG_REF(Signal* signal)
+{
+ TcConnectRecordPtr localTcConnectptr;
+ ApiConnectRecordPtr regApiPtr;
+
+ UintR TtcConnectFilesize = ctcConnectFilesize;
+ UintR TapiConnectFilesize = capiConnectFilesize;
+ TcConnectRecord *localTcConnectRecord = tcConnectRecord;
+ ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
+
+ const FireTrigRef * ref = CAST_CONSTPTR(FireTrigRef, signal->theData);
+ localTcConnectptr.i = ref->tcOpRec;
+ jamEntry();
+ ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
+ regApiPtr.i = localTcConnectptr.p->apiConnect;
+ if (localTcConnectptr.p->tcConnectstate != OS_FIRE_TRIG_REQ)
+ {
+ warningReport(signal, 28);
+ return;
+ }//if
+ ptrCheckGuard(regApiPtr, TapiConnectFilesize,
+ localApiConnectRecord);
+
+ apiConnectptr = regApiPtr;
+
+ UintR Tdata1 = regApiPtr.p->transid[0] - ref->transId[0];
+ UintR Tdata2 = regApiPtr.p->transid[1] - ref->transId[1];
+ Tdata1 = Tdata1 | Tdata2;
+ if (Tdata1 != 0) {
+ warningReport(signal, 28);
+ return;
+ }//if
+
+ if (regApiPtr.p->apiConnectstate != CS_SEND_FIRE_TRIG_REQ &&
+ regApiPtr.p->apiConnectstate != CS_WAIT_FIRE_TRIG_REQ)
+ {
+ jam();
+ warningReport(signal, 28);
+ return;
+ }
+
+ terrorCode = ref->errCode;
+ abortErrorLab(signal);
+}
+
+void
Dbtc::execTC_COMMIT_ACK(Signal* signal){
jamEntry();
@@ -5844,6 +6137,7 @@ void Dbtc::execLQHKEYREF(Signal* signal)
TcConnectRecord *localTcConnectRecord = tcConnectRecord;
opPtr.i = triggeringOp;
+ ndbassert(opPtr.i != tcConnectptr.i);
ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord);
const Uint32 opType = regTcPtr->operation;
@@ -5919,19 +6213,16 @@ void Dbtc::execLQHKEYREF(Signal* signal)
*/
regApiPtr->lqhkeyreqrec--;
+ /**
+ * An failing op in LQH, never leaves the commit ack marker around
+ * TODO: This can be bug in ordinary code too!!!
+ */
+ clearCommitAckMarker(regApiPtr, regTcPtr);
+
unlinkReadyTcCon(signal);
releaseTcCon();
- opPtr.p->triggerExecutionCount--;
- if (opPtr.p->triggerExecutionCount == 0)
- {
- /**
- * We have completed current trigger execution
- * Continue triggering operation
- */
- jam();
- continueTriggeringOp(signal, opPtr.p);
- }
+ trigger_op_finished(signal, apiConnectptr, opPtr.p);
return;
}
@@ -5996,7 +6287,10 @@ void Dbtc::execLQHKEYREF(Signal* signal)
jam();
diverify010Lab(signal);
return;
- } else if (regApiPtr->tckeyrec > 0 || regApiPtr->m_exec_flag) {
+ }
+ else if (regApiPtr->tckeyrec > 0 ||
+ tc_testbit(regApiPtr->m_flags, ApiConnectRecord::TF_EXEC_FLAG))
+ {
jam();
sendtckeyconf(signal, 2);
return;
@@ -6032,7 +6326,8 @@ void Dbtc::clearCommitAckMarker(ApiConne
if (regApiPtr->no_commit_ack_markers == 0)
{
regApiPtr->commitAckMarker = RNIL;
- regApiPtr->m_commit_ack_marker_received = FALSE;
+ tc_clearbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_COMMIT_ACK_MARKER_RECEIVED);
m_commitAckMarkerHash.release(commitAckMarker);
}
}
@@ -6080,7 +6375,7 @@ void Dbtc::execTC_COMMITREQ(Signal* sign
const Uint32 transId2 = regApiPtr->transid[1];
Uint32 errorCode = 0;
- regApiPtr->m_exec_flag = 1;
+ regApiPtr->m_flags |= ApiConnectRecord::TF_EXEC_FLAG;
switch (regApiPtr->apiConnectstate) {
case CS_STARTED:
tcConnectptr.i = regApiPtr->firstTcConnect;
@@ -6232,7 +6527,7 @@ void Dbtc::execTCROLLBACKREQ(Signal* sig
return;
}//if
- apiConnectptr.p->m_exec_flag = 1;
+ apiConnectptr.p->m_flags |= ApiConnectRecord::TF_EXEC_FLAG;
switch (apiConnectptr.p->apiConnectstate) {
case CS_STARTED:
case CS_RECEIVING:
@@ -6518,6 +6813,18 @@ void Dbtc::warningReport(Signal* signal,
ndbout << "Received LQHKEYCONF in wrong api-state in Dbtc" << endl;
#endif
break;
+ case 28:
+ jam();
+#ifdef ABORT_TRACE
+ ndbout << "Discarding FIRE_TRIG_REF/CONF in Dbtc" << endl;
+#endif
+ break;
+ case 29:
+ jam();
+#ifdef ABORT_TRACE
+ ndbout << "Discarding TcContinueB::ZSEND_FIRE_TRIG_REQ in Dbtc" << endl;
+#endif
+ break;
default:
jam();
break;
@@ -6768,6 +7075,8 @@ ABORT020:
jam();
case OS_OPERATING:
jam();
+ case OS_FIRE_TRIG_REQ:
+ jam();
/*----------------------------------------------------------------------
* WE HAVE SENT LQHKEYREQ AND ARE IN SOME STATE OF EITHER STILL
* SENDING THE OPERATION, WAITING FOR REPLIES, WAITING FOR MORE
@@ -7071,7 +7380,8 @@ void Dbtc::timeOutFoundLab(Signal* signa
<< " H'" << apiConnectptr.p->transid[1] << "] " << dec
<< "Time-out in state = " << apiConnectptr.p->apiConnectstate
<< " apiConnectptr.i = " << apiConnectptr.i
- << " - exec: " << apiConnectptr.p->m_exec_flag
+ << " - exec: "
+ << tc_testbit(apiConnectptr.p->m_flags, ApiConnectRecord::TF_EXEC_FLAG)
<< " - place: " << c_apiConTimer_line[apiConnectptr.i]
<< " code: " << errCode);
switch (apiConnectptr.p->apiConnectstate) {
@@ -7097,6 +7407,8 @@ void Dbtc::timeOutFoundLab(Signal* signa
case CS_RECEIVING:
case CS_REC_COMMITTING:
case CS_START_COMMITTING:
+ case CS_WAIT_FIRE_TRIG_REQ:
+ case CS_SEND_FIRE_TRIG_REQ:
jam();
/*------------------------------------------------------------------*/
/* WE ARE STILL IN THE PREPARE PHASE AND THE TRANSACTION HAS */
@@ -9390,7 +9702,7 @@ void Dbtc::initTcConnectFail(Signal* sig
tcConnectptr.p->lastReplicaNo = LqhTransConf::getLastReplicaNo(treqinfo);
tcConnectptr.p->dirtyOp = LqhTransConf::getDirtyFlag(treqinfo);
tcConnectptr.p->lqhInstanceKey = instanceKey;
-
+ tcConnectptr.p->triggeringOperation = RNIL;
}//Dbtc::initTcConnectFail()
/*----------------------------------------------------------*/
@@ -11637,7 +11949,7 @@ void Dbtc::initApiConnect(Signal* signal
apiConnectptr.p->commitAckMarker = RNIL;
apiConnectptr.p->firstTcConnect = RNIL;
apiConnectptr.p->lastTcConnect = RNIL;
- apiConnectptr.p->triggerPending = false;
+ apiConnectptr.p->m_flags = 0;
apiConnectptr.p->m_special_op_flags = 0;
apiConnectptr.p->accumulatingIndexOp = RNIL;
apiConnectptr.p->executingIndexOp = RNIL;
@@ -11666,7 +11978,7 @@ void Dbtc::initApiConnect(Signal* signal
apiConnectptr.p->commitAckMarker = RNIL;
apiConnectptr.p->firstTcConnect = RNIL;
apiConnectptr.p->lastTcConnect = RNIL;
- apiConnectptr.p->triggerPending = false;
+ apiConnectptr.p->m_flags = 0;
apiConnectptr.p->m_special_op_flags = 0;
apiConnectptr.p->accumulatingIndexOp = RNIL;
apiConnectptr.p->executingIndexOp = RNIL;
@@ -11695,7 +12007,7 @@ void Dbtc::initApiConnect(Signal* signal
apiConnectptr.p->commitAckMarker = RNIL;
apiConnectptr.p->firstTcConnect = RNIL;
apiConnectptr.p->lastTcConnect = RNIL;
- apiConnectptr.p->triggerPending = false;
+ apiConnectptr.p->m_flags = 0;
apiConnectptr.p->m_special_op_flags = 0;
apiConnectptr.p->accumulatingIndexOp = RNIL;
apiConnectptr.p->executingIndexOp = RNIL;
@@ -11737,7 +12049,6 @@ void Dbtc::inithost(Signal* signal)
hostptr.p->inPackedList = false;
hostptr.p->lqhTransStatus = LTS_IDLE;
hostptr.p->noOfWordsTCKEYCONF = 0;
- hostptr.p->noOfWordsTCINDXCONF = 0;
hostptr.p->noOfPackedWordsLqh = 0;
hostptr.p->hostLqhBlockRef = calcLqhBlockRef(hostptr.i);
hostptr.p->m_nf_bits = 0;
@@ -12002,13 +12313,15 @@ void Dbtc::releaseAbortResources(Signal*
apiConnectptr.p->abortState = AS_IDLE;
releaseAllSeizedIndexOperations(apiConnectptr.p);
- if(apiConnectptr.p->m_exec_flag || apiConnectptr.p->apiFailState == ZTRUE){
+ if (tc_testbit(apiConnectptr.p->m_flags, ApiConnectRecord::TF_EXEC_FLAG) ||
+ apiConnectptr.p->apiFailState == ZTRUE)
+ {
jam();
bool ok = false;
Uint32 blockRef = apiConnectptr.p->ndbapiBlockref;
ReturnSignal ret = apiConnectptr.p->returnsignal;
apiConnectptr.p->returnsignal = RS_NO_RETURN;
- apiConnectptr.p->m_exec_flag = 0;
+ tc_clearbit(apiConnectptr.p->m_flags, ApiConnectRecord::TF_EXEC_FLAG);
switch(ret){
case RS_TCROLLBACKCONF:
jam();
@@ -12110,7 +12423,8 @@ void Dbtc::seizeApiConnect(Signal* signa
apiConnectptr.p->nextApiConnect = RNIL;
setApiConTimer(apiConnectptr.i, 0, __LINE__);
apiConnectptr.p->apiConnectstate = CS_CONNECTED; /* STATE OF CONNECTION */
- apiConnectptr.p->triggerPending = false;
+ tc_clearbit(apiConnectptr.p->m_flags,
+ ApiConnectRecord::TF_TRIGGER_PENDING);
apiConnectptr.p->m_special_op_flags = 0;
} else {
jam();
@@ -13325,11 +13639,12 @@ void Dbtc::execFIRE_TRIG_ORD(Signal* sig
{
jam();
opPtr.p->noReceivedTriggers++;
- opPtr.p->triggerExecutionCount++;
+ opPtr.p->triggerExecutionCount++; // Default 1 LQHKEYREQ per trigger
// Insert fired trigger in execution queue
transPtr.p->theFiredTriggers.add(trigPtr);
- if (opPtr.p->noReceivedTriggers == opPtr.p->noFiredTriggers) {
+ if (opPtr.p->noReceivedTriggers == opPtr.p->noFiredTriggers ||
+ transPtr.p->isExecutingDeferredTriggers()) {
executeTriggers(signal, &transPtr);
}
return;
@@ -13528,7 +13843,9 @@ void Dbtc::execTCINDXREQ(Signal* signal)
jam();
releaseSections(handle);
terrorCode = ZCLUSTER_IN_SINGLEUSER_MODE;
- regApiPtr->m_exec_flag |= TcKeyReq::getExecuteFlag(tcIndxRequestInfo);
+ regApiPtr->m_flags |=
+ TcKeyReq::getExecuteFlag(tcIndxRequestInfo) ?
+ ApiConnectRecord::TF_EXEC_FLAG : 0;
apiConnectptr = transPtr;
abortErrorLab(signal);
return;
@@ -13539,7 +13856,9 @@ void Dbtc::execTCINDXREQ(Signal* signal)
releaseSections(handle);
// Failed to allocate index operation
terrorCode = 288;
- regApiPtr->m_exec_flag |= TcKeyReq::getExecuteFlag(tcIndxRequestInfo);
+ regApiPtr->m_flags |=
+ TcKeyReq::getExecuteFlag(tcIndxRequestInfo) ?
+ ApiConnectRecord::TF_EXEC_FLAG : 0;
apiConnectptr = transPtr;
abortErrorLab(signal);
return;
@@ -13630,94 +13949,6 @@ void Dbtc::execTCINDXREQ(Signal* signal)
}
}
-
-void Dbtc::sendTcIndxConf(Signal* signal, UintR TcommitFlag)
-{
- HostRecordPtr localHostptr;
- ApiConnectRecord * const regApiPtr = apiConnectptr.p;
- const UintR TopWords = (UintR)regApiPtr->tcindxrec;
- localHostptr.i = refToNode(regApiPtr->ndbapiBlockref);
- const Uint32 type = getNodeInfo(localHostptr.i).m_type;
- const bool is_api = (type >= NodeInfo::API && type <= NodeInfo::MGM);
- const BlockNumber TblockNum = refToBlock(regApiPtr->ndbapiBlockref);
- const Uint32 Tmarker = (regApiPtr->commitAckMarker == RNIL ? 0 : 1);
- ptrAss(localHostptr, hostRecord);
- UintR TcurrLen = localHostptr.p->noOfWordsTCINDXCONF;
- UintR confInfo = 0;
- TcIndxConf::setNoOfOperations(confInfo, (TopWords >> 1));
- TcIndxConf::setCommitFlag(confInfo, TcommitFlag == 1);
- TcIndxConf::setMarkerFlag(confInfo, Tmarker);
- const UintR TpacketLen = 6 + TopWords;
- regApiPtr->tcindxrec = 0;
-
- if(TcommitFlag || (regApiPtr->lqhkeyreqrec == regApiPtr->lqhkeyconfrec)){
- jam();
- regApiPtr->m_exec_flag = 0;
- }
-
- if ((TpacketLen + 1 /** gci_lo */ > 25) || !is_api){
- TcIndxConf * const tcIndxConf = (TcIndxConf *)signal->getDataPtrSend();
-
- jam();
- tcIndxConf->apiConnectPtr = regApiPtr->ndbapiConnect;
- tcIndxConf->gci_hi = Uint32(regApiPtr->globalcheckpointid >> 32);
- Uint32 *gci_lo = (Uint32*)&tcIndxConf->operations[TopWords >> 1];
- * gci_lo = Uint32(regApiPtr->globalcheckpointid);
- tcIndxConf->confInfo = confInfo;
- tcIndxConf->transId1 = regApiPtr->transid[0];
- tcIndxConf->transId2 = regApiPtr->transid[1];
- copyFromToLen(®ApiPtr->tcIndxSendArray[0],
- (UintR*)&tcIndxConf->operations,
- (UintR)ZTCOPCONF_SIZE);
- sendSignal(regApiPtr->ndbapiBlockref,
- GSN_TCINDXCONF, signal,
- (TpacketLen - 1) + 1 /** gci_lo */, JBB);
- return;
- } else if (((TcurrLen + TpacketLen + 1 /** gci_lo */) > 25) &&
- (TcurrLen > 0)) {
- jam();
- sendPackedTCINDXCONF(signal, localHostptr.p, localHostptr.i);
- TcurrLen = 0;
- } else {
- jam();
- updatePackedList(signal, localHostptr.p, localHostptr.i);
- }//if
-// -------------------------------------------------------------------------
-// The header contains the block reference of receiver plus the real signal
-// length - 3, since we have the real signal length plus one additional word
-// for the header we have to do - 4.
-// -------------------------------------------------------------------------
- UintR Tpack0 = (TblockNum << 16) + (TpacketLen - 4 + 1 /** gci_lo */);
- UintR Tpack1 = regApiPtr->ndbapiConnect;
- UintR Tpack2 = Uint32(regApiPtr->globalcheckpointid >> 32);
- UintR Tpack3 = confInfo;
- UintR Tpack4 = regApiPtr->transid[0];
- UintR Tpack5 = regApiPtr->transid[1];
- UintR Tpack6 = Uint32(regApiPtr->globalcheckpointid);
-
- localHostptr.p->noOfWordsTCINDXCONF = TcurrLen + TpacketLen + 1 /* gci_lo */;
-
- localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 0] = Tpack0;
- localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 1] = Tpack1;
- localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 2] = Tpack2;
- localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 3] = Tpack3;
- localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 4] = Tpack4;
- localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 5] = Tpack5;
-
- UintR Ti;
- for (Ti = 6; Ti < TpacketLen; Ti++) {
- localHostptr.p->packedWordsTCINDXCONF[TcurrLen + Ti] =
- regApiPtr->tcIndxSendArray[Ti - 6];
- }//for
- localHostptr.p->packedWordsTCINDXCONF[TcurrLen + TpacketLen] = Tpack6;
-
- if (unlikely(!ndb_check_micro_gcp(getNodeInfo(localHostptr.i).m_version)))
- {
- jam();
- ndbassert(Tpack6 == 0 || getNodeInfo(localHostptr.i).m_version == 0);
- }
-}//Dbtc::sendTcIndxConf()
-
void Dbtc::execINDXKEYINFO(Signal* signal)
{
jamEntry();
@@ -13842,7 +14073,7 @@ Dbtc::saveINDXKEYINFO(Signal* signal,
releaseIndexOperation(apiConnectptr.p, indexOp);
terrorCode = 289;
if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo))
- apiConnectptr.p->m_exec_flag= 1;
+ apiConnectptr.p->m_flags |= ApiConnectRecord::TF_EXEC_FLAG;
abortErrorLab(signal);
return -1;
}
@@ -13884,7 +14115,7 @@ Dbtc::saveINDXATTRINFO(Signal* signal,
releaseIndexOperation(apiConnectptr.p, indexOp);
terrorCode = 289;
if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo))
- apiConnectptr.p->m_exec_flag= 1;
+ apiConnectptr.p->m_flags |= ApiConnectRecord::TF_EXEC_FLAG;
abortErrorLab(signal);
return -1;
}
@@ -14071,7 +14302,7 @@ void Dbtc::execTCKEYCONF(Signal* signal)
/**
* Check on TCKEYCONF whether the the transaction was committed
*/
- Uint32 Tcommit = TcKeyConf::getCommitFlag(confInfo);
+ ndbassert(TcKeyConf::getCommitFlag(confInfo) == false);
indexOpPtr.p = indexOp;
if (!indexOp) {
@@ -14124,28 +14355,6 @@ void Dbtc::execTCKEYCONF(Signal* signal)
executeIndexOperation(signal, regApiPtr, indexOp);
break;
}
- case(IOS_INDEX_OPERATION): {
- // We are done, send TCINDXCONF
- jam();
- Uint32 Ttcindxrec = regApiPtr->tcindxrec;
- // Copy reply from TcKeyConf
-
- ndbassert(regApiPtr->noIndexOp);
- regApiPtr->noIndexOp--; // Decrease count
- regApiPtr->tcIndxSendArray[Ttcindxrec] = indexOp->tcIndxReq.senderData;
- regApiPtr->tcIndxSendArray[Ttcindxrec + 1] =
- tcKeyConf->operations[0].attrInfoLen;
- regApiPtr->tcindxrec = Ttcindxrec + 2;
- if (regApiPtr->noIndexOp == 0) {
- jam();
- sendTcIndxConf(signal, Tcommit);
- } else if (regApiPtr->tcindxrec == ZTCOPCONF_SIZE) {
- jam();
- sendTcIndxConf(signal, 0);
- }
- releaseIndexOperation(regApiPtr, indexOp);
- break;
- }
}
}
@@ -14176,23 +14385,11 @@ void Dbtc::execTCKEYREF(Signal* signal)
case(IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI):
case(IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF): {
jam();
- /**
- * Increase count as it will be decreased below...
- * (and the code is written to handle failing lookup on "real" table
- * not lookup on index table)
- */
- regApiPtr->noIndexOp++;
- // else continue
- }
- case(IOS_INDEX_OPERATION): {
// Send TCINDXREF
- jam();
TcKeyReq * const tcIndxReq = &indexOp->tcIndxReq;
TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
- ndbassert(regApiPtr->noIndexOp);
- regApiPtr->noIndexOp--; // Decrease count
tcIndxRef->connectPtr = tcIndxReq->senderData;
tcIndxRef->transId[0] = tcKeyRef->transId[0];
tcIndxRef->transId[1] = tcKeyRef->transId[1];
@@ -14388,20 +14585,6 @@ void Dbtc::execTRANSID_AI(Signal* signal
// else continue waiting for more TRANSID_AI
break;
}
- case(IOS_INDEX_OPERATION): {
- // Should never receive TRANSID_AI in this state!!
- jam();
- TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
-
- tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
- tcIndxRef->transId[0] = regApiPtr->transid[0];
- tcIndxRef->transId[1] = regApiPtr->transid[1];
- tcIndxRef->errorCode = 4349;
- tcIndxRef->errorData = regApiPtr->errorData;
- sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
- TcKeyRef::SignalLength, JBB);
- return;
- }
}
}
@@ -14597,10 +14780,8 @@ void Dbtc::executeIndexOperation(Signal*
tcKeyReq->scanInfo = indexOp->fragmentId; // As read from Index table
TcKeyReq::setDistributionKeyFlag(tcKeyRequestInfo, 1U);
}
- indexOp->indexOpState = IOS_INDEX_OPERATION;
- regApiPtr->m_special_op_flags = TcConnectRecord::SOF_INDEX_BASE_TABLE_ACCESS;
- regApiPtr->executingIndexOp = indexOp->indexOpId;;
- regApiPtr->noIndexOp++; // Increase count
+ regApiPtr->m_special_op_flags = 0;
+ regApiPtr->executingIndexOp = 0;
/* KeyInfo section
* Get the KeyInfo we received from the index table lookup
@@ -14631,6 +14812,9 @@ void Dbtc::executeIndexOperation(Signal*
signal->header.m_noOfSections = 2;
indexOp->attrInfoSectionIVal = RNIL;
}
+
+ releaseIndexOperation(regApiPtr, indexOp);
+
TcKeyReq::setKeyLength(tcKeyRequestInfo, keyInfoFromTransIdAI.sz);
TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0);
TcKeyReq::setCommitFlag(tcKeyRequestInfo, 0);
@@ -14658,12 +14842,27 @@ void Dbtc::executeIndexOperation(Signal*
const Uint32 currSavePointId = regApiPtr->currSavePointId;
regApiPtr->currSavePointId = tmp.p->savePointId;
+#ifdef ERROR_INSERT
+ bool err8072 = ERROR_INSERTED(8072);
+ if (err8072)
+ {
+ CLEAR_ERROR_INSERT_VALUE;
+ }
+#endif
+
/* Execute TCKEYREQ now - it is now responsible for freeing
* the KeyInfo and AttrInfo sections
*/
EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, TcKeyReq::StaticLength);
jamEntry();
-
+
+#ifdef ERROR_INSERT
+ if (err8072)
+ {
+ SET_ERROR_INSERT_VALUE(8072);
+ }
+#endif
+
if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING))
{
// TODO : Presumably the abort cleans up the operation
@@ -14743,6 +14942,31 @@ void Dbtc::saveTriggeringOpState(Signal*
LqhKeyConf::SignalLength);
}
+void
+Dbtc::trigger_op_finished(Signal* signal, ApiConnectRecordPtr regApiPtr,
+ TcConnectRecord* triggeringOp)
+{
+ if (!regApiPtr.p->isExecutingDeferredTriggers())
+ {
+ ndbassert(triggeringOp->triggerExecutionCount > 0);
+ triggeringOp->triggerExecutionCount--;
+ if (triggeringOp->triggerExecutionCount == 0)
+ {
+ /**
+ * We have completed current trigger execution
+ * Continue triggering operation
+ */
+ jam();
+ continueTriggeringOp(signal, triggeringOp);
+ }
+ }
+ else
+ {
+ jam();
+ lqhKeyConf_checkTransactionState(signal, regApiPtr);
+ }
+}
+
void Dbtc::continueTriggeringOp(Signal* signal, TcConnectRecord* trigOp)
{
LqhKeyConf * lqhKeyConf = (LqhKeyConf *)signal->getDataPtr();
@@ -14750,6 +14974,9 @@ void Dbtc::continueTriggeringOp(Signal*
(UintR*)lqhKeyConf,
LqhKeyConf::SignalLength);
+ ndbassert(trigOp->savedState[LqhKeyConf::SignalLength-1] != ~Uint32(0));
+ trigOp->savedState[LqhKeyConf::SignalLength-1] = ~Uint32(0);
+
lqhKeyConf->noFiredTriggers = 0;
trigOp->noReceivedTriggers = 0;
@@ -14757,18 +14984,6 @@ void Dbtc::continueTriggeringOp(Signal*
execLQHKEYCONF(signal);
}
-void Dbtc::scheduleFiredTrigger(ApiConnectRecordPtr* transPtr,
- TcConnectRecordPtr* opPtr)
-{
- // Set initial values for trigger fireing operation
- opPtr->p->triggerExecutionCount++;
-
- // Insert fired trigger in execution queue
- transPtr->p->theFiredTriggers.add(opPtr->p->accumulatingTriggerData);
- opPtr->p->accumulatingTriggerData.i = RNIL;
- opPtr->p->accumulatingTriggerData.p = NULL;
-}
-
void Dbtc::executeTriggers(Signal* signal, ApiConnectRecordPtr* transPtr)
{
ApiConnectRecord* regApiPtr = transPtr->p;
@@ -14779,7 +14994,10 @@ void Dbtc::executeTriggers(Signal* signa
if (!regApiPtr->theFiredTriggers.isEmpty()) {
jam();
if ((regApiPtr->apiConnectstate == CS_STARTED) ||
- (regApiPtr->apiConnectstate == CS_START_COMMITTING)) {
+ (regApiPtr->apiConnectstate == CS_START_COMMITTING) ||
+ (regApiPtr->apiConnectstate == CS_SEND_FIRE_TRIG_REQ) ||
+ (regApiPtr->apiConnectstate == CS_WAIT_FIRE_TRIG_REQ))
+ {
jam();
regApiPtr->theFiredTriggers.first(trigPtr);
while (trigPtr.i != RNIL) {
@@ -14789,7 +15007,8 @@ void Dbtc::executeTriggers(Signal* signa
ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord);
FiredTriggerPtr nextTrigPtr = trigPtr;
regApiPtr->theFiredTriggers.next(nextTrigPtr);
- if (opPtr.p->noReceivedTriggers == opPtr.p->noFiredTriggers) {
+ if (opPtr.p->noReceivedTriggers == opPtr.p->noFiredTriggers ||
+ regApiPtr->isExecutingDeferredTriggers()) {
jam();
// Fireing operation is ready to have a trigger executing
executeTrigger(signal, trigPtr.p, transPtr, &opPtr);
@@ -14822,9 +15041,11 @@ void Dbtc::executeTriggers(Signal* signa
{
// Wait until transaction is ready to execute a trigger
jam();
- if (!regApiPtr->triggerPending) {
+ if (!tc_testbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_TRIGGER_PENDING))
+ {
jam();
- regApiPtr->triggerPending = true;
+ regApiPtr->m_flags |= ApiConnectRecord::TF_TRIGGER_PENDING;
signal->theData[0] = TcContinueB::TRIGGER_PENDING;
signal->theData[1] = transPtr->i;
signal->theData[2] = regApiPtr->transid[0];
@@ -14856,6 +15077,7 @@ void Dbtc::executeTrigger(Signal* signal
c_theDefinedTriggers.getPtr(firedTriggerData->triggerId))
!= NULL)
{
+ transPtr->p->pendingTriggers--;
switch(firedTriggerData->triggerType) {
case(TriggerType::SECONDARY_INDEX):
jam();
@@ -14895,8 +15117,8 @@ void Dbtc::executeIndexTrigger(Signal* s
}
case(TriggerEvent::TE_UPDATE): {
jam();
- deleteFromIndexTable(signal, firedTriggerData, transPtr, opPtr,
- indexData, true); // Hold the triggering operation
+ opPtr->p->triggerExecutionCount++; // One is already added...and this is 2
+ deleteFromIndexTable(signal, firedTriggerData, transPtr, opPtr, indexData);
insertIntoIndexTable(signal, firedTriggerData, transPtr, opPtr, indexData);
break;
}
@@ -15019,8 +15241,7 @@ void Dbtc::insertIntoIndexTable(Signal*
TcFiredTriggerData* firedTriggerData,
ApiConnectRecordPtr* transPtr,
TcConnectRecordPtr* opPtr,
- TcIndexData* indexData,
- bool holdOperation)
+ TcIndexData* indexData)
{
ApiConnectRecord* regApiPtr = transPtr->p;
TcConnectRecord* opRecord = opPtr->p;
@@ -15034,10 +15255,6 @@ void Dbtc::insertIntoIndexTable(Signal*
ptrCheckGuard(indexTabPtr, ctabrecFilesize, tableRecord);
tcKeyReq->apiConnectPtr = transPtr->i;
tcKeyReq->senderData = opPtr->i;
- if (holdOperation) {
- jam();
- opRecord->triggerExecutionCount++;
- }//if
/* Key for insert to unique index table is the afterValues from the
* base table operation (from update or insert on base).
@@ -15050,6 +15267,15 @@ void Dbtc::insertIntoIndexTable(Signal*
LocalDataBuffer<11> afterValues(pool, firedTriggerData->afterValues);
LocalDataBuffer<11> keyValues(pool, firedTriggerData->keyValues);
+ if (afterValues.getSize() == 0)
+ {
+ jam();
+ ndbrequire(tc_testbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_DEFERRED_CONSTRAINTS));
+ trigger_op_finished(signal, *transPtr, opRecord);
+ return;
+ }
+
Uint32 keyIVal= RNIL;
Uint32 attrIVal= RNIL;
bool appendOk= false;
@@ -15082,15 +15308,7 @@ void Dbtc::insertIntoIndexTable(Signal*
{
jam();
releaseSection(keyIVal);
- opRecord->triggerExecutionCount--;
- if (opRecord->triggerExecutionCount == 0) {
- /*
- We have completed current trigger execution
- Continue triggering operation
- */
- jam();
- continueTriggeringOp(signal, opRecord);
- }//if
+ trigger_op_finished(signal, *transPtr, opRecord);
return;
}
@@ -15184,8 +15402,7 @@ void Dbtc::deleteFromIndexTable(Signal*
TcFiredTriggerData* firedTriggerData,
ApiConnectRecordPtr* transPtr,
TcConnectRecordPtr* opPtr,
- TcIndexData* indexData,
- bool holdOperation)
+ TcIndexData* indexData)
{
ApiConnectRecord* regApiPtr = transPtr->p;
TcConnectRecord* opRecord = opPtr->p;
@@ -15197,10 +15414,7 @@ void Dbtc::deleteFromIndexTable(Signal*
ptrCheckGuard(indexTabPtr, ctabrecFilesize, tableRecord);
tcKeyReq->apiConnectPtr = transPtr->i;
tcKeyReq->senderData = opPtr->i;
- if (holdOperation) {
- jam();
- opRecord->triggerExecutionCount++;
- }//if
+
// Calculate key length and renumber attribute id:s
AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
LocalDataBuffer<11> beforeValues(pool, firedTriggerData->beforeValues);
@@ -15208,7 +15422,16 @@ void Dbtc::deleteFromIndexTable(Signal*
Uint32 keyIVal= RNIL;
Uint32 attrId= 0;
bool hasNull= false;
-
+
+ if (beforeValues.getSize() == 0)
+ {
+ jam();
+ ndbrequire(tc_testbit(regApiPtr->m_flags,
+ ApiConnectRecord::TF_DEFERRED_CONSTRAINTS));
+ trigger_op_finished(signal, *transPtr, opRecord);
+ return;
+ }
+
/* Build Delete KeyInfo section from beforevalues */
if (unlikely((! appendAttrDataToSection(keyIVal,
beforeValues,
@@ -15230,15 +15453,7 @@ void Dbtc::deleteFromIndexTable(Signal*
{
jam();
releaseSection(keyIVal);
- opRecord->triggerExecutionCount--;
- if (opRecord->triggerExecutionCount == 0) {
- /*
- We have completed current trigger execution
- Continue triggering operation
- */
- jam();
- continueTriggeringOp(signal, opRecord);
- }//if
+ trigger_op_finished(signal, *transPtr, opRecord);
return;
}
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp 2010-09-24 18:19:07 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp 2011-04-05 19:12:29 +0000
@@ -954,7 +954,10 @@ ArrayPool<TupTriggerData> c_triggerPool;
subscriptionDeleteTriggers(triggerPool),
subscriptionUpdateTriggers(triggerPool),
constraintUpdateTriggers(triggerPool),
- tuxCustomTriggers(triggerPool)
+ tuxCustomTriggers(triggerPool),
+ deferredInsertTriggers(triggerPool),
+ deferredDeleteTriggers(triggerPool),
+ deferredUpdateTriggers(triggerPool)
{}
Bitmask<MAXNROFATTRIBUTESINWORDS> notNullAttributeMask;
@@ -1084,7 +1087,10 @@ ArrayPool<TupTriggerData> c_triggerPool;
DLList<TupTriggerData> subscriptionDeleteTriggers;
DLList<TupTriggerData> subscriptionUpdateTriggers;
DLList<TupTriggerData> constraintUpdateTriggers;
-
+ DLList<TupTriggerData> deferredInsertTriggers;
+ DLList<TupTriggerData> deferredUpdateTriggers;
+ DLList<TupTriggerData> deferredDeleteTriggers;
+
// List of ordered indexes
DLList<TupTriggerData> tuxCustomTriggers;
@@ -1496,19 +1502,31 @@ typedef Ptr<HostBuffer> HostBufferPtr;
STATIC_CONST( SZ32 = 1 );
};
+ enum When
+ {
+ KRS_PREPARE = 0,
+ KRS_COMMIT = 1,
+ KRS_PRE_COMMIT0 = 2, // There can be multiple pre commit phases...
+ KRS_PRE_COMMIT1 = 3
+ };
+
struct KeyReqStruct {
- KeyReqStruct(EmulatedJamBuffer * _jamBuffer) {
+ KeyReqStruct(EmulatedJamBuffer * _jamBuffer, When when = KRS_PREPARE) {
#if defined VM_TRACE || defined ERROR_INSERT
memset(this, 0xf3, sizeof(* this));
#endif
jamBuffer = _jamBuffer;
+ m_when = when;
+ m_deferred_constraints = true;
}
- KeyReqStruct(Dbtup* tup) {
+ KeyReqStruct(Dbtup* tup, When when = KRS_PREPARE) {
#if defined VM_TRACE || defined ERROR_INSERT
memset(this, 0xf3, sizeof(* this));
#endif
jamBuffer = tup->jamBuffer();
+ m_when = when;
+ m_deferred_constraints = true;
}
/**
@@ -1555,6 +1573,7 @@ struct KeyReqStruct {
/* Flag: is tuple in expanded or in shrunken/stored format? */
bool is_expanded;
bool m_is_lcp;
+ enum When m_when;
struct Var_data {
/*
@@ -1602,6 +1621,7 @@ struct KeyReqStruct {
bool last_row;
bool m_use_rowid;
Uint8 m_reorg;
+ bool m_deferred_constraints;
Signal* signal;
Uint32 no_fired_triggers;
@@ -1973,6 +1993,12 @@ private:
//------------------------------------------------------------------
void execDROP_TRIG_IMPL_REQ(Signal* signal);
+ /**
+ * Deferred triggers execute when execFIRE_TRIG_REQ
+ * is called
+ */
+ void execFIRE_TRIG_REQ(Signal* signal);
+
// *****************************************************************
// Setting up the environment for reads, inserts, updates and deletes.
// *****************************************************************
@@ -2551,11 +2577,11 @@ private:
Tablerec* tablePtr,
bool disk);
-#if 0
- void checkDeferredTriggers(Signal* signal,
+ void checkDeferredTriggers(KeyReqStruct *req_struct,
Operationrec* regOperPtr,
- Tablerec* regTablePtr);
-#endif
+ Tablerec* regTablePtr,
+ bool disk);
+
void checkDetachedTriggers(KeyReqStruct *req_struct,
Operationrec* regOperPtr,
Tablerec* regTablePtr,
@@ -2566,9 +2592,19 @@ private:
Operationrec* regOperPtr,
bool disk);
+ void checkDeferredTriggersDuringPrepare(KeyReqStruct *req_struct,
+ DLList<TupTriggerData>& triggerList,
+ Operationrec* const regOperPtr,
+ bool disk);
void fireDeferredTriggers(KeyReqStruct *req_struct,
DLList<TupTriggerData>& triggerList,
- Operationrec* regOperPtr);
+ Operationrec* const regOperPtr,
+ bool disk);
+
+ void fireDeferredConstraints(KeyReqStruct *req_struct,
+ DLList<TupTriggerData>& triggerList,
+ Operationrec* const regOperPtr,
+ bool disk);
void fireDetachedTriggers(KeyReqStruct *req_struct,
DLList<TupTriggerData>& triggerList,
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp 2010-09-03 05:35:51 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp 2011-04-05 19:12:29 +0000
@@ -501,7 +501,7 @@ void Dbtup::execTUP_COMMITREQ(Signal* si
FragrecordPtr regFragPtr;
OperationrecPtr regOperPtr;
TablerecPtr regTabPtr;
- KeyReqStruct req_struct(this);
+ KeyReqStruct req_struct(this, KRS_COMMIT);
TransState trans_state;
Uint32 no_of_fragrec, no_of_tablerec;
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2010-09-07 06:44:00 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2011-04-05 19:12:29 +0000
@@ -251,6 +251,7 @@ Dbtup::setup_read(KeyReqStruct *req_stru
(req_struct->m_reorg == 2 && moved != 0)))
{
terrorCode= ZTUPLE_DELETED_ERROR;
+ jam();
return false;
}
}
@@ -289,6 +290,7 @@ Dbtup::setup_read(KeyReqStruct *req_stru
if((found && currOp == ZDELETE) ||
((dirty || !found) && currOp == ZINSERT))
{
+ jam();
terrorCode= ZTUPLE_DELETED_ERROR;
break;
}
@@ -597,9 +599,11 @@ void Dbtup::execTUPKEYREQ(Signal* signal
sig1 = tupKeyReq->m_row_id_page_no;
sig2 = tupKeyReq->m_row_id_page_idx;
+ sig3 = tupKeyReq->deferred_constraints;
req_struct.m_row_id.m_page_no = sig1;
req_struct.m_row_id.m_page_idx = sig2;
+ req_struct.m_deferred_constraints = sig3;
/* Get AttrInfo section if this is a long TUPKEYREQ */
Uint32 attrInfoIVal= tupKeyReq->attrInfoIVal;
@@ -1784,6 +1788,7 @@ int Dbtup::handleDeleteReq(Signal* signa
{
regOperPtr->tupVersion= req_struct->m_tuple_ptr->get_tuple_version();
}
+ req_struct->changeMask.set();
if(disk && regOperPtr->m_undo_buffer_space == 0)
{
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp 2010-09-07 06:44:00 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp 2011-04-05 19:12:29 +0000
@@ -129,6 +129,8 @@ Dbtup::Dbtup(Block_context& ctx, Uint32
addRecSignal(GSN_DROP_FRAG_REQ, &Dbtup::execDROP_FRAG_REQ);
addRecSignal(GSN_SUB_GCP_COMPLETE_REP, &Dbtup::execSUB_GCP_COMPLETE_REP);
+ addRecSignal(GSN_FIRE_TRIG_REQ, &Dbtup::execFIRE_TRIG_REQ);
+
fragoperrec = 0;
fragrecord = 0;
alterTabOperRec = 0;
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp 2010-09-07 09:54:47 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp 2011-04-05 19:12:29 +0000
@@ -476,6 +476,21 @@ Dbtup::execACCKEYCONF(Signal* signal)
jamEntry();
ScanOpPtr scanPtr;
scanPtr.i = signal->theData[0];
+
+ Uint32 localKey1 = signal->theData[3];
+ Uint32 localKey2 = signal->theData[4];
+ Uint32 localKeyFlag = signal->theData[5];
+ Local_key tmp;
+ if (localKeyFlag == 1)
+ {
+ tmp.assref(localKey1);
+ }
+ else
+ {
+ tmp.m_page_no = localKey1;
+ tmp.m_page_idx = localKey2;
+ }
+
c_scanOpPool.getPtr(scanPtr);
ScanOp& scan = *scanPtr.p;
ndbrequire(scan.m_bits & ScanOp::SCAN_LOCK_WAIT && scan.m_accLockOp != RNIL);
@@ -483,10 +498,37 @@ Dbtup::execACCKEYCONF(Signal* signal)
if (scan.m_state == ScanOp::Blocked) {
// the lock wait was for current entry
jam();
- scan.m_state = ScanOp::Locked;
- // LQH has the ball
- return;
+
+ if (likely(scan.m_scanPos.m_key_mm.m_page_no == tmp.m_page_no &&
+ scan.m_scanPos.m_key_mm.m_page_idx == tmp.m_page_idx))
+ {
+ jam();
+ scan.m_state = ScanOp::Locked;
+ // LQH has the ball
+ return;
+ }
+ else
+ {
+ jam();
+ /**
+ * This means that there was DEL/INS on rowid that we tried to lock
+ * and the primary key that was previously located on this rowid
+ * (scanPos.m_key_mm) has moved.
+ * (DBACC keeps of track of primary keys)
+ *
+ * We don't care about the primary keys, but is interested in ROWID
+ * so rescan this position.
+ * Which is implemented by using execACCKEYREF...
+ */
+ ndbout << "execACCKEYCONF "
+ << scan.m_scanPos.m_key_mm
+ << " != " << tmp << " ";
+ scan.m_bits |= ScanOp::SCAN_LOCK_WAIT;
+ execACCKEYREF(signal);
+ return;
+ }
}
+
if (scan.m_state != ScanOp::Aborting) {
// we were moved, release lock
jam();
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp 2010-09-03 05:35:51 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp 2011-04-05 19:12:29 +0000
@@ -32,6 +32,7 @@
#include <signaldata/DropTrig.hpp>
#include <signaldata/DropTrigImpl.hpp>
#include <signaldata/TuxMaint.hpp>
+#include "../dblqh/Dblqh.hpp"
/* **************************************************************** */
/* ---------------------------------------------------------------- */
@@ -503,6 +504,93 @@ Dbtup::dropTrigger(Tablerec* table, cons
return 0;
}//Dbtup::dropTrigger()
+void
+Dbtup::execFIRE_TRIG_REQ(Signal* signal)
+{
+ jam();
+ Uint32 opPtrI = signal->theData[0];
+ Uint32 pass = signal->theData[5];
+
+ FragrecordPtr regFragPtr;
+ OperationrecPtr regOperPtr;
+ TablerecPtr regTabPtr;
+ KeyReqStruct req_struct(this, (When)(KRS_PRE_COMMIT0 + pass));
+
+ regOperPtr.i = opPtrI;
+
+ jamEntry();
+
+ c_operation_pool.getPtr(regOperPtr);
+
+ regFragPtr.i = regOperPtr.p->fragmentPtr;
+ Uint32 no_of_fragrec = cnoOfFragrec;
+ ptrCheckGuard(regFragPtr, no_of_fragrec, fragrecord);
+
+ TransState trans_state = get_trans_state(regOperPtr.p);
+ ndbrequire(trans_state == TRANS_STARTED);
+
+ Uint32 no_of_tablerec = cnoOfTablerec;
+ regTabPtr.i = regFragPtr.p->fragTableId;
+ ptrCheckGuard(regTabPtr, no_of_tablerec, tablerec);
+
+ req_struct.signal = signal;
+ req_struct.TC_ref = signal->theData[1];
+ req_struct.TC_index = signal->theData[2];
+ req_struct.trans_id1 = signal->theData[3];
+ req_struct.trans_id2 = signal->theData[4];
+
+ PagePtr page;
+ Tuple_header* tuple_ptr = (Tuple_header*)
+ get_ptr(&page, ®OperPtr.p->m_tuple_location, regTabPtr.p);
+ req_struct.m_tuple_ptr = tuple_ptr;
+
+ OperationrecPtr lastOperPtr;
+ lastOperPtr.i = tuple_ptr->m_operation_ptr_i;
+ c_operation_pool.getPtr(lastOperPtr);
+
+ /**
+ * Deferred triggers should fire only once per primary key (per pass)
+ * regardless of no of DML on that primary key
+ *
+ * We keep track of this on *last* operation (which btw, implies that
+ * a trigger can't update "own" tuple...i.e first op would be better...)
+ *
+ */
+ if (!c_lqh->check_fire_trig_pass(lastOperPtr.p->userpointer, pass))
+ {
+ jam();
+ signal->theData[0] = 0;
+ signal->theData[1] = 0;
+ return;
+ }
+
+ /**
+ * This is deferred triggers...
+ * which is basically the same as detached,
+ * i.e before value is <before transaction>
+ * and after values is <after transaction>
+ * with the difference that they execute (fire) while
+ * still having a transaction context...
+ * i.e can abort transactions, modify transaction
+ */
+ req_struct.no_fired_triggers = 0;
+
+ /**
+ * See DbtupCommit re "Setting the op-list has this effect"
+ */
+ Uint32 save[2] = { lastOperPtr.p->nextActiveOp, lastOperPtr.p->prevActiveOp };
+ lastOperPtr.p->nextActiveOp = RNIL;
+ lastOperPtr.p->prevActiveOp = RNIL;
+
+ checkDeferredTriggers(&req_struct, lastOperPtr.p, regTabPtr.p, false);
+
+ lastOperPtr.p->nextActiveOp = save[0];
+ lastOperPtr.p->prevActiveOp = save[1];
+
+ signal->theData[0] = 0;
+ signal->theData[1] = req_struct.no_fired_triggers;
+}
+
/* ---------------------------------------------------------------- */
/* -------------- checkImmediateTriggersAfterOp ------------------ */
/* */
@@ -522,13 +610,24 @@ Dbtup::checkImmediateTriggersAfterInsert
return;
}
- if ((regOperPtr->op_struct.primary_replica) &&
- (!(regTablePtr->afterInsertTriggers.isEmpty()))) {
- jam();
- fireImmediateTriggers(req_struct,
- regTablePtr->afterInsertTriggers,
- regOperPtr,
- disk);
+ if (regOperPtr->op_struct.primary_replica)
+ {
+ if (! regTablePtr->afterInsertTriggers.isEmpty())
+ {
+ jam();
+ fireImmediateTriggers(req_struct,
+ regTablePtr->afterInsertTriggers,
+ regOperPtr,
+ disk);
+ }
+
+ if (! regTablePtr->deferredInsertTriggers.isEmpty())
+ {
+ checkDeferredTriggersDuringPrepare(req_struct,
+ regTablePtr->deferredInsertTriggers,
+ regOperPtr,
+ disk);
+ }
}
}
@@ -542,21 +641,34 @@ Dbtup::checkImmediateTriggersAfterUpdate
return;
}
- if ((regOperPtr->op_struct.primary_replica) &&
- (!(regTablePtr->afterUpdateTriggers.isEmpty()))) {
- jam();
- fireImmediateTriggers(req_struct,
- regTablePtr->afterUpdateTriggers,
- regOperPtr,
- disk);
- }
- if ((regOperPtr->op_struct.primary_replica) &&
- (!(regTablePtr->constraintUpdateTriggers.isEmpty()))) {
- jam();
- fireImmediateTriggers(req_struct,
- regTablePtr->constraintUpdateTriggers,
- regOperPtr,
- disk);
+ if (regOperPtr->op_struct.primary_replica)
+ {
+ if (! regTablePtr->afterUpdateTriggers.isEmpty())
+ {
+ jam();
+ fireImmediateTriggers(req_struct,
+ regTablePtr->afterUpdateTriggers,
+ regOperPtr,
+ disk);
+ }
+
+ if (! regTablePtr->constraintUpdateTriggers.isEmpty())
+ {
+ jam();
+ fireImmediateTriggers(req_struct,
+ regTablePtr->constraintUpdateTriggers,
+ regOperPtr,
+ disk);
+ }
+
+ if (! regTablePtr->deferredUpdateTriggers.isEmpty())
+ {
+ jam();
+ checkDeferredTriggersDuringPrepare(req_struct,
+ regTablePtr->deferredUpdateTriggers,
+ regOperPtr,
+ disk);
+ }
}
}
@@ -570,17 +682,48 @@ Dbtup::checkImmediateTriggersAfterDelete
return;
}
- if ((regOperPtr->op_struct.primary_replica) &&
- (!(regTablePtr->afterDeleteTriggers.isEmpty()))) {
+ if (regOperPtr->op_struct.primary_replica)
+ {
+ if (! regTablePtr->afterDeleteTriggers.isEmpty())
+ {
+ fireImmediateTriggers(req_struct,
+ regTablePtr->afterDeleteTriggers,
+ regOperPtr,
+ disk);
+ }
+
+ if (! regTablePtr->deferredDeleteTriggers.isEmpty())
+ {
+ checkDeferredTriggersDuringPrepare(req_struct,
+ regTablePtr->deferredDeleteTriggers,
+ regOperPtr,
+ disk);
+ }
+ }
+}
+
+void
+Dbtup::checkDeferredTriggersDuringPrepare(KeyReqStruct *req_struct,
+ DLList<TupTriggerData>& triggerList,
+ Operationrec* const regOperPtr,
+ bool disk)
+{
+ jam();
+ TriggerPtr trigPtr;
+ triggerList.first(trigPtr);
+ while (trigPtr.i != RNIL)
+ {
jam();
- executeTriggers(req_struct,
- regTablePtr->afterDeleteTriggers,
- regOperPtr,
- disk);
+ if (trigPtr.p->monitorAllAttributes ||
+ trigPtr.p->attributeMask.overlaps(req_struct->changeMask))
+ {
+ jam();
+ NoOfFiredTriggers::setDeferredBit(req_struct->no_fired_triggers);
+ return;
+ }
}
}
-#if 0
/* ---------------------------------------------------------------- */
/* --------------------- checkDeferredTriggers -------------------- */
/* */
@@ -590,14 +733,95 @@ Dbtup::checkImmediateTriggersAfterDelete
/* Executes deferred triggers by sending FIRETRIGORD */
/* */
/* ---------------------------------------------------------------- */
-void Dbtup::checkDeferredTriggers(Signal* signal,
- Operationrec* const regOperPtr,
- Tablerec* const regTablePtr)
+void Dbtup::checkDeferredTriggers(KeyReqStruct *req_struct,
+ Operationrec* regOperPtr,
+ Tablerec* regTablePtr,
+ bool disk)
{
jam();
- // NYI
+ Uint32 save_type = regOperPtr->op_struct.op_type;
+ Tuple_header *save_ptr = req_struct->m_tuple_ptr;
+ DLList<TupTriggerData> * deferred_list = 0;
+ DLList<TupTriggerData> * constraint_list = 0;
+
+ switch (save_type) {
+ case ZUPDATE:
+ case ZINSERT:
+ req_struct->m_tuple_ptr =get_copy_tuple(®OperPtr->m_copy_tuple_location);
+ break;
+ }
+
+ /**
+ * Set correct operation type and fix change mask
+ * Note ALLOC is set in "orig" tuple
+ */
+ if (save_ptr->m_header_bits & Tuple_header::ALLOC) {
+ if (save_type == ZDELETE) {
+ // insert + delete = nothing
+ jam();
+ return;
+ goto end;
+ }
+ regOperPtr->op_struct.op_type = ZINSERT;
+ }
+ else if (save_type == ZINSERT) {
+ /**
+ * Tuple was not created but last op is INSERT.
+ * This is possible only on DELETE + INSERT
+ */
+ regOperPtr->op_struct.op_type = ZUPDATE;
+ }
+
+ switch(regOperPtr->op_struct.op_type) {
+ case(ZINSERT):
+ jam();
+ deferred_list = ®TablePtr->deferredInsertTriggers;
+ constraint_list = ®TablePtr->afterInsertTriggers;
+ break;
+ case(ZDELETE):
+ jam();
+ deferred_list = ®TablePtr->deferredDeleteTriggers;
+ constraint_list = ®TablePtr->afterDeleteTriggers;
+ break;
+ case(ZUPDATE):
+ jam();
+ deferred_list = ®TablePtr->deferredUpdateTriggers;
+ constraint_list = ®TablePtr->afterUpdateTriggers;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+
+ if (req_struct->m_deferred_constraints == false)
+ {
+ constraint_list = 0;
+ }
+
+ if (deferred_list->isEmpty() &&
+ (constraint_list == 0 || constraint_list->isEmpty()))
+ {
+ goto end;
+ }
+
+ /**
+ * Compute change-mask
+ */
+ set_commit_change_mask_info(regTablePtr, req_struct, regOperPtr);
+ if (!deferred_list->isEmpty())
+ {
+ fireDeferredTriggers(req_struct, * deferred_list, regOperPtr, disk);
+ }
+
+ if (constraint_list && !constraint_list->isEmpty())
+ {
+ fireDeferredConstraints(req_struct, * constraint_list, regOperPtr, disk);
+ }
+
+end:
+ regOperPtr->op_struct.op_type = save_type;
+ req_struct->m_tuple_ptr = save_ptr;
}//Dbtup::checkDeferredTriggers()
-#endif
/* ---------------------------------------------------------------- */
/* --------------------- checkDetachedTriggers -------------------- */
@@ -696,6 +920,13 @@ end:
req_struct->m_tuple_ptr = save_ptr;
}
+static
+bool
+is_constraint(const Dbtup::TupTriggerData * trigPtr)
+{
+ return trigPtr->triggerType == TriggerType::SECONDARY_INDEX;
+}
+
void
Dbtup::fireImmediateTriggers(KeyReqStruct *req_struct,
DLList<TupTriggerData>& triggerList,
@@ -709,6 +940,38 @@ Dbtup::fireImmediateTriggers(KeyReqStruc
if (trigPtr.p->monitorAllAttributes ||
trigPtr.p->attributeMask.overlaps(req_struct->changeMask)) {
jam();
+
+ if (req_struct->m_when == KRS_PREPARE &&
+ req_struct->m_deferred_constraints &&
+ is_constraint(trigPtr.p))
+ {
+ NoOfFiredTriggers::setDeferredBit(req_struct->no_fired_triggers);
+ }
+ else
+ {
+ executeTrigger(req_struct,
+ trigPtr.p,
+ regOperPtr,
+ disk);
+ }
+ }
+ triggerList.next(trigPtr);
+ }//while
+}//Dbtup::fireImmediateTriggers()
+
+void
+Dbtup::fireDeferredConstraints(KeyReqStruct *req_struct,
+ DLList<TupTriggerData>& triggerList,
+ Operationrec* const regOperPtr,
+ bool disk)
+{
+ TriggerPtr trigPtr;
+ triggerList.first(trigPtr);
+ while (trigPtr.i != RNIL) {
+ jam();
+ if (trigPtr.p->monitorAllAttributes ||
+ trigPtr.p->attributeMask.overlaps(req_struct->changeMask)) {
+ jam();
executeTrigger(req_struct,
trigPtr.p,
regOperPtr,
@@ -716,14 +979,13 @@ Dbtup::fireImmediateTriggers(KeyReqStruc
}//if
triggerList.next(trigPtr);
}//while
-}//Dbtup::fireImmediateTriggers()
+}//Dbtup::fireDeferredTriggers()
-#if 0
-void
-Dbtup::fireDeferredTriggers(Signal* signal,
- KeyReqStruct *req_struct,
- DLList<TupTriggerData>& triggerList,
- Operationrec* const regOperPtr)
+void
+Dbtup::fireDeferredTriggers(KeyReqStruct *req_struct,
+ DLList<TupTriggerData>& triggerList,
+ Operationrec* const regOperPtr,
+ bool disk)
{
TriggerPtr trigPtr;
triggerList.first(trigPtr);
@@ -733,13 +995,13 @@ Dbtup::fireDeferredTriggers(Signal* sign
trigPtr.p->attributeMask.overlaps(req_struct->changeMask)) {
jam();
executeTrigger(req_struct,
- trigPtr,
- regOperPtr);
+ trigPtr.p,
+ regOperPtr,
+ disk);
}//if
triggerList.next(trigPtr);
}//while
}//Dbtup::fireDeferredTriggers()
-#endif
void
Dbtup::fireDetachedTriggers(KeyReqStruct *req_struct,
@@ -1044,6 +1306,44 @@ out:
return;
}
+ if (triggerType == TriggerType::SECONDARY_INDEX &&
+ req_struct->m_when != KRS_PREPARE)
+ {
+ ndbrequire(req_struct->m_deferred_constraints);
+ if (req_struct->m_when == KRS_PRE_COMMIT0)
+ {
+ switch(regOperPtr->op_struct.op_type){
+ case ZINSERT:
+ NoOfFiredTriggers::setDeferredBit(req_struct->no_fired_triggers);
+ return;
+ break;
+ case ZUPDATE:
+ NoOfFiredTriggers::setDeferredBit(req_struct->no_fired_triggers);
+ noAfterWords = 0;
+ break;
+ case ZDELETE:
+ break;
+ default:
+ ndbrequire(false);
+ }
+ }
+ else
+ {
+ ndbrequire(req_struct->m_when == KRS_PRE_COMMIT1);
+ switch(regOperPtr->op_struct.op_type){
+ case ZINSERT:
+ break;
+ case ZUPDATE:
+ noBeforeWords = 0;
+ break;
+ case ZDELETE:
+ return;
+ default:
+ ndbrequire(false);
+ }
+ }
+ }
+
req_struct->no_fired_triggers++;
if (longsignal == false)
=== modified file 'storage/ndb/src/ndbapi/NdbOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperation.cpp 2010-09-30 09:32:28 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperation.cpp 2011-04-05 19:12:29 +0000
@@ -71,7 +71,8 @@ NdbOperation::NdbOperation(Ndb* aNdb, Nd
m_abortOption(-1),
m_noErrorPropagation(false),
theLockHandle(NULL),
- m_blob_lock_upgraded(false)
+ m_blob_lock_upgraded(false),
+ m_deferred_constraints(false)
{
theReceiver.init(NdbReceiver::NDB_OPERATION, false, this);
theError.code = 0;
@@ -175,6 +176,7 @@ NdbOperation::init(const NdbTableImpl* t
m_extraSetValues = NULL;
m_numExtraSetValues = 0;
m_use_any_value = 0;
+ m_deferred_constraints = false;
tSignal = theNdb->getSignal();
if (tSignal == NULL)
=== modified file 'storage/ndb/src/ndbapi/NdbOperationDefine.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationDefine.cpp 2010-09-29 13:25:19 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationDefine.cpp 2011-04-05 19:12:29 +0000
@@ -1386,5 +1386,14 @@ NdbOperation::handleOperationOptions (co
}
}
+ if (opts->optionsPresent & OperationOptions::OO_DEFERRED_CONSTAINTS)
+ {
+ op->m_deferred_constraints = 1;
+ }
+ else
+ {
+ op->m_deferred_constraints = 0;
+ }
+
return 0;
}
=== modified file 'storage/ndb/src/ndbapi/NdbOperationExec.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationExec.cpp 2010-09-30 09:32:28 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationExec.cpp 2011-04-05 19:12:29 +0000
@@ -473,6 +473,7 @@ NdbOperation::prepareSend(Uint32 aTC_Con
Uint8 tStartIndicator = theStartIndicator;
Uint8 tInterpretIndicator = theInterpretIndicator;
Uint8 tNoDisk = m_no_disk_flag;
+ Uint8 tDeferred = m_deferred_constraints;
/**
* A dirty read, can not abort the transaction
@@ -490,6 +491,7 @@ NdbOperation::prepareSend(Uint32 aTC_Con
tcKeyReq->setStartFlag(tReqInfo, tStartIndicator);
tcKeyReq->setInterpretedFlag(tReqInfo, tInterpretIndicator);
tcKeyReq->setNoDiskFlag(tReqInfo, tNoDisk);
+ tcKeyReq->setDeferredConstraints(tReqInfo, tDeferred);
OperationType tOperationType = theOperationType;
Uint8 abortOption = (ao == DefaultAbortOption) ? (Uint8) m_abortOption : (Uint8) ao;
@@ -1416,12 +1418,16 @@ NdbOperation::prepareSendNdbRecord(Abort
m_abortOption= theSimpleIndicator && theOperationType==ReadRequest ?
(Uint8) AO_IgnoreError : (Uint8) abortOption;
+ Uint8 tDeferred = m_deferred_constraints;
+
TcKeyReq::setAbortOption(tcKeyReq->requestInfo, m_abortOption);
TcKeyReq::setCommitFlag(tcKeyReq->requestInfo, theCommitIndicator);
TcKeyReq::setStartFlag(tcKeyReq->requestInfo, theStartIndicator);
TcKeyReq::setSimpleFlag(tcKeyReq->requestInfo, theSimpleIndicator);
TcKeyReq::setDirtyFlag(tcKeyReq->requestInfo, theDirtyIndicator);
+ TcKeyReq::setDeferredConstraints(tcKeyReq->requestInfo, tDeferred);
+
theStatus= WaitResponse;
theReceiver.prepareSend();
=== modified file 'storage/ndb/test/include/HugoCalculator.hpp'
--- a/storage/ndb/test/include/HugoCalculator.hpp 2009-10-06 10:39:02 +0000
+++ b/storage/ndb/test/include/HugoCalculator.hpp 2011-04-05 19:12:29 +0000
@@ -44,6 +44,9 @@ public:
int getUpdatesValue(NDBT_ResultRow* const pRow) const;
int isIdCol(int colId) { return m_idCol == colId; };
int isUpdateCol(int colId){ return m_updatesCol == colId; };
+
+ int equalForRow(Uint8 *, const NdbRecord*, int rowid);
+ int setValues(Uint8*, const NdbRecord*, int rowid, int updateval);
private:
const NdbDictionary::Table& m_tab;
int m_idCol;
=== modified file 'storage/ndb/test/ndbapi/testIndex.cpp'
--- a/storage/ndb/test/ndbapi/testIndex.cpp 2010-09-24 18:19:07 +0000
+++ b/storage/ndb/test/ndbapi/testIndex.cpp 2011-04-05 19:12:29 +0000
@@ -2720,6 +2720,361 @@ runBug56829(NDBT_Context* ctx, NDBT_Step
return result;
}
+#define CHK_RET_FAILED(x) if (!(x)) { ndbout_c("Failed on line: %u", __LINE__); return NDBT_FAILED; }
+
+int
+runBug12315582(NDBT_Context* ctx, NDBT_Step* step)
+{
+ const NdbDictionary::Table * pTab = ctx->getTab();
+ Ndb* pNdb = GETNDB(step);
+ NdbDictionary::Dictionary * dict = pNdb->getDictionary();
+
+ const NdbDictionary::Index* pIdx= dict->getIndex(pkIdxName, pTab->getName());
+ CHK_RET_FAILED(pIdx != 0);
+
+ const NdbRecord * pRowRecord = pTab->getDefaultRecord();
+ CHK_RET_FAILED(pRowRecord != 0);
+ const NdbRecord * pIdxRecord = pIdx->getDefaultRecord();
+ CHK_RET_FAILED(pIdxRecord != 0);
+
+ const Uint32 len = NdbDictionary::getRecordRowLength(pRowRecord);
+ Uint8 * pRow = new Uint8[len];
+ bzero(pRow, len);
+
+ HugoCalculator calc(* pTab);
+ calc.equalForRow(pRow, pRowRecord, 0);
+
+ NdbTransaction* pTrans = pNdb->startTransaction();
+ CHK_RET_FAILED(pTrans != 0);
+
+ const NdbOperation * pOp[2] = { 0, 0 };
+ for (Uint32 i = 0; i<2; i++)
+ {
+ NdbInterpretedCode code;
+ if (i == 0)
+ code.interpret_exit_ok();
+ else
+ code.interpret_exit_nok();
+
+ code.finalise();
+
+ NdbOperation::OperationOptions opts;
+ bzero(&opts, sizeof(opts));
+ opts.optionsPresent = NdbOperation::OperationOptions::OO_INTERPRETED;
+ opts.interpretedCode = &code;
+
+ pOp[i] = pTrans->readTuple(pIdxRecord, (char*)pRow,
+ pRowRecord, (char*)pRow,
+ NdbOperation::LM_Read,
+ 0,
+ &opts,
+ sizeof(opts));
+ CHK_RET_FAILED(pOp[i]);
+ }
+
+ int res = pTrans->execute(Commit, AO_IgnoreError);
+
+ CHK_RET_FAILED(res == 0);
+ CHK_RET_FAILED(pOp[0]->getNdbError().code == 0);
+ CHK_RET_FAILED(pOp[1]->getNdbError().code != 0);
+
+ delete [] pRow;
+
+ return NDBT_OK;
+}
+
+static
+const int
+deferred_errors[] = {
+ 5064, 0,
+ 5065, 0,
+ 5066, 0,
+ 5067, 0,
+ 5068, 0,
+ 5069, 0,
+ 5070, 0,
+ 5071, 0,
+ 5072, 1,
+ 8090, 0,
+ 8091, 0,
+ 8092, 2, // connected tc
+ 0, 0 // trailer
+};
+
+int
+runTestDeferredError(NDBT_Context* ctx, NDBT_Step* step)
+{
+ NdbRestarter res;
+ Ndb* pNdb = GETNDB(step);
+ const NdbDictionary::Table* pTab = ctx->getTab();
+
+ const int rows = ctx->getNumRecords();
+
+ const NdbRecord * pRowRecord = pTab->getDefaultRecord();
+ CHK_RET_FAILED(pRowRecord != 0);
+
+ const Uint32 len = NdbDictionary::getRecordRowLength(pRowRecord);
+ Uint8 * pRow = new Uint8[len];
+
+ for (int i = 0; deferred_errors[i] != 0; i += 2)
+ {
+ const int errorno = deferred_errors[i];
+ const int nodefail = deferred_errors[i+1];
+
+ for (int j = 0; j<3; j++)
+ {
+ NdbTransaction* pTrans = pNdb->startTransaction();
+ CHK_RET_FAILED(pTrans != 0);
+
+ int nodeId =
+ nodefail == 0 ? 0 :
+ nodefail == 1 ? res.getNode(NdbRestarter::NS_RANDOM) :
+ nodefail == 2 ? pTrans->getConnectedNodeId() :
+ 0;
+
+ ndbout_c("errorno: %u(nf: %u - %u) j: %u : %s", errorno,
+ nodefail, nodeId, j,
+ j == 0 ? "test before error insert" :
+ j == 1 ? "test with error insert" :
+ j == 2 ? "test after error insert" :
+ "");
+ if (j == 0 || j == 2)
+ {
+ // First time succeed
+ // Last time succeed
+ }
+ else if (nodefail == 0)
+ {
+ CHK_RET_FAILED(res.insertErrorInAllNodes(errorno) == 0);
+ }
+ else
+ {
+ int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
+ CHK_RET_FAILED(res.dumpStateOneNode(nodeId, val2, 2) == 0);
+ CHK_RET_FAILED(res.insertErrorInNode(nodeId, errorno) == 0);
+ }
+
+ for (int rowNo = 0; rowNo < 100; rowNo++)
+ {
+ int rowId = rand() % rows;
+ bzero(pRow, len);
+
+ HugoCalculator calc(* pTab);
+ calc.setValues(pRow, pRowRecord, rowId, rand());
+
+ NdbOperation::OperationOptions opts;
+ bzero(&opts, sizeof(opts));
+ opts.optionsPresent =
+ NdbOperation::OperationOptions::OO_DEFERRED_CONSTAINTS;
+
+ const NdbOperation * pOp = pTrans->updateTuple(pRowRecord, (char*)pRow,
+ pRowRecord, (char*)pRow,
+ 0,
+ &opts,
+ sizeof(opts));
+ CHK_RET_FAILED(pOp != 0);
+ }
+
+ int result = pTrans->execute(Commit, AO_IgnoreError);
+ if (j == 0 || j == 2)
+ {
+ CHK_RET_FAILED(result == 0);
+ }
+ else
+ {
+ CHK_RET_FAILED(result != 0);
+ }
+ pTrans->close();
+
+
+ if (j == 0 || j == 2)
+ {
+ }
+ else
+ {
+ if (nodefail)
+ {
+ ndbout_c(" waiting for %u to enter not-started", nodeId);
+ // Wait for a node to enter not-started
+ CHK_RET_FAILED(res.waitNodesNoStart(&nodeId, 1) == 0);
+
+ ndbout_c(" starting all");
+ CHK_RET_FAILED(res.startAll() == 0);
+ ndbout_c(" wait cluster started");
+ CHK_RET_FAILED(res.waitClusterStarted() == 0);
+ ndbout_c(" cluster started");
+ }
+ CHK_RET_FAILED(res.insertErrorInAllNodes(0) == 0);
+ }
+ }
+ }
+
+ delete [] pRow;
+
+ return NDBT_OK;
+}
+
+int
+runMixedDML(NDBT_Context* ctx, NDBT_Step* step)
+{
+ Ndb* pNdb = GETNDB(step);
+ const NdbDictionary::Table* pTab = ctx->getTab();
+
+ unsigned seed = (unsigned)NdbTick_CurrentMillisecond();
+
+ const int rows = ctx->getNumRecords();
+ const int loops = 10 * ctx->getNumLoops();
+ const int until_stopped = ctx->getProperty("UntilStopped");
+ const int deferred = ctx->getProperty("Deferred");
+ const int batch = ctx->getProperty("Batch", Uint32(50));
+
+ const NdbRecord * pRowRecord = pTab->getDefaultRecord();
+ CHK_RET_FAILED(pRowRecord != 0);
+
+ const Uint32 len = NdbDictionary::getRecordRowLength(pRowRecord);
+ Uint8 * pRow = new Uint8[len];
+
+ int count_ok = 0;
+ int count_failed = 0;
+ for (int i = 0; i < loops || (until_stopped && !ctx->isTestStopped()); i++)
+ {
+ NdbTransaction* pTrans = pNdb->startTransaction();
+ CHK_RET_FAILED(pTrans != 0);
+
+ int lastrow = 0;
+ int result = 0;
+ for (int rowNo = 0; rowNo < batch; rowNo++)
+ {
+ int left = rows - lastrow;
+ int rowId = lastrow;
+ if (left)
+ {
+ rowId += ndb_rand_r(&seed) % (left / 10 + 1);
+ }
+ else
+ {
+ break;
+ }
+ lastrow = rowId;
+
+ bzero(pRow, len);
+
+ HugoCalculator calc(* pTab);
+ calc.setValues(pRow, pRowRecord, rowId, rand());
+
+ NdbOperation::OperationOptions opts;
+ bzero(&opts, sizeof(opts));
+ if (deferred)
+ {
+ opts.optionsPresent =
+ NdbOperation::OperationOptions::OO_DEFERRED_CONSTAINTS;
+ }
+
+ const NdbOperation* pOp = 0;
+ switch(ndb_rand_r(&seed) % 3){
+ case 0:
+ pOp = pTrans->writeTuple(pRowRecord, (char*)pRow,
+ pRowRecord, (char*)pRow,
+ 0,
+ &opts,
+ sizeof(opts));
+ break;
+ case 1:
+ pOp = pTrans->deleteTuple(pRowRecord, (char*)pRow,
+ pRowRecord, (char*)pRow,
+ 0,
+ &opts,
+ sizeof(opts));
+ break;
+ case 2:
+ pOp = pTrans->updateTuple(pRowRecord, (char*)pRow,
+ pRowRecord, (char*)pRow,
+ 0,
+ &opts,
+ sizeof(opts));
+ break;
+ }
+ CHK_RET_FAILED(pOp != 0);
+ result = pTrans->execute(NoCommit, AO_IgnoreError);
+ if (result != 0)
+ {
+ goto found_error;
+ }
+ }
+
+ result = pTrans->execute(Commit, AO_IgnoreError);
+ if (result != 0)
+ {
+ found_error:
+ count_failed++;
+ NdbError err = pTrans->getNdbError();
+ ndbout << err << endl;
+ CHK_RET_FAILED(err.code == 1235 ||
+ err.code == 1236 ||
+ err.code == 5066 ||
+ err.status == NdbError::TemporaryError ||
+ err.classification == NdbError::NoDataFound ||
+ err.classification == NdbError::ConstraintViolation);
+ }
+ else
+ {
+ count_ok++;
+ }
+ pTrans->close();
+ }
+
+ ndbout_c("count_ok: %d count_failed: %d",
+ count_ok, count_failed);
+ delete [] pRow;
+
+ return NDBT_OK;
+}
+
+int
+runDeferredError(NDBT_Context* ctx, NDBT_Step* step)
+{
+ NdbRestarter res;
+
+ for (int l = 0; l<ctx->getNumLoops() && !ctx->isTestStopped(); l++)
+ {
+ for (int i = 0; deferred_errors[i] != 0 && !ctx->isTestStopped(); i += 2)
+ {
+ const int errorno = deferred_errors[i];
+ const int nodefail = deferred_errors[i+1];
+
+ int nodeId = res.getNode(NdbRestarter::NS_RANDOM);
+
+ ndbout_c("errorno: %u (nf: %u - %u)",
+ errorno,
+ nodefail, nodeId);
+
+ if (nodefail == 0)
+ {
+ CHK_RET_FAILED(res.insertErrorInNode(nodeId, errorno) == 0);
+ NdbSleep_MilliSleep(300);
+ CHK_RET_FAILED(res.insertErrorInNode(nodeId, errorno) == 0);
+ }
+ else
+ {
+ int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
+ CHK_RET_FAILED(res.dumpStateOneNode(nodeId, val2, 2) == 0);
+ CHK_RET_FAILED(res.insertErrorInNode(nodeId, errorno) == 0);
+ ndbout_c(" waiting for %u to enter not-started", nodeId);
+ // Wait for a node to enter not-started
+ CHK_RET_FAILED(res.waitNodesNoStart(&nodeId, 1) == 0);
+
+ ndbout_c(" starting all");
+ CHK_RET_FAILED(res.startAll() == 0);
+ ndbout_c(" wait cluster started");
+ CHK_RET_FAILED(res.waitClusterStarted() == 0);
+ ndbout_c(" cluster started");
+ }
+ }
+ }
+
+ ctx->stopTest();
+ return NDBT_OK;
+}
NDBT_TESTSUITE(testIndex);
TESTCASE("CreateAll",
@@ -3121,12 +3476,80 @@ TESTCASE("FireTrigOverload", ""){
FINALIZER(runClearError);
FINALIZER(createRandomIndex_Drop);
}
+TESTCASE("DeferredError",
+ "Test with deferred unique index handling and error inserts")
+{
+ TC_PROPERTY("LoggedIndexes", Uint32(0));
+ TC_PROPERTY("OrderedIndex", Uint32(0));
+ INITIALIZER(createPkIndex);
+ INITIALIZER(runLoadTable);
+ STEP(runTestDeferredError);
+ FINALIZER(createPkIndex_Drop);
+}
+TESTCASE("DeferredMixedLoad",
+ "Test mixed load of DML with deferred indexes")
+{
+ TC_PROPERTY("LoggedIndexes", Uint32(0));
+ TC_PROPERTY("OrderedIndex", Uint32(0));
+ TC_PROPERTY("UntilStopped", Uint32(0));
+ TC_PROPERTY("Deferred", Uint32(1));
+ INITIALIZER(createPkIndex);
+ INITIALIZER(runLoadTable);
+ STEPS(runMixedDML, 10);
+ FINALIZER(createPkIndex_Drop);
+}
+TESTCASE("DeferredMixedLoadError",
+ "Test mixed load of DML with deferred indexes")
+{
+ TC_PROPERTY("LoggedIndexes", Uint32(0));
+ TC_PROPERTY("OrderedIndex", Uint32(0));
+ TC_PROPERTY("UntilStopped", Uint32(1));
+ TC_PROPERTY("Deferred", Uint32(1));
+ INITIALIZER(createPkIndex);
+ INITIALIZER(runLoadTable);
+ STEPS(runMixedDML, 4);
+ STEP(runDeferredError);
+ FINALIZER(createPkIndex_Drop);
+}
+TESTCASE("NF_DeferredMixed",
+ "Test mixed load of DML with deferred indexes")
+{
+ TC_PROPERTY("LoggedIndexes", Uint32(0));
+ TC_PROPERTY("OrderedIndex", Uint32(0));
+ TC_PROPERTY("UntilStopped", Uint32(1));
+ TC_PROPERTY("Deferred", Uint32(1));
+ INITIALIZER(createPkIndex);
+ INITIALIZER(runLoadTable);
+ STEPS(runMixedDML, 4);
+ STEP(runRestarts);
+ FINALIZER(createPkIndex_Drop);
+}
+TESTCASE("NF_Mixed",
+ "Test mixed load of DML")
+{
+ TC_PROPERTY("LoggedIndexes", Uint32(0));
+ TC_PROPERTY("OrderedIndex", Uint32(0));
+ TC_PROPERTY("UntilStopped", Uint32(1));
+ INITIALIZER(createPkIndex);
+ INITIALIZER(runLoadTable);
+ STEPS(runMixedDML, 4);
+ STEP(runRestarts);
+ FINALIZER(createPkIndex_Drop);
+}
TESTCASE("Bug56829",
"Return empty ordered index nodes to index fragment "
"so that empty fragment pages can be freed"){
STEP(runBug56829);
}
-
+TESTCASE("Bug12315582", "")
+{
+ TC_PROPERTY("LoggedIndexes", Uint32(0));
+ TC_PROPERTY("OrderedIndex", Uint32(0));
+ INITIALIZER(createPkIndex);
+ INITIALIZER(runLoadTable);
+ INITIALIZER(runBug12315582);
+ FINALIZER(createPkIndex_Drop);
+}
NDBT_TESTSUITE_END(testIndex);
int main(int argc, const char** argv){
=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt 2010-11-02 14:53:26 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt 2011-04-05 19:12:29 +0000
@@ -1,3 +1,23 @@
+max-time: 900
+cmd: testIndex
+args: -n DeferredError
+
+max-time: 900
+cmd: testIndex
+args: -n DeferredMixedLoad T1 T6 T13
+
+max-time: 900
+cmd: testIndex
+args: -n DeferredMixedLoadError T1 T6 T13
+
+max-time: 900
+cmd: testIndex
+args: -n NF_DeferredMixed T1 T6 T13
+
+max-time: 900
+cmd: testIndex
+args: -n NF_Mixed T1 T6 T13
+
max-time: 600
cmd: atrt-testBackup
args: -n NFMaster T1
@@ -1617,6 +1637,10 @@ max-time: 300
cmd: testIndex
args: -n Bug56829 T1
+max-time: 300
+cmd: testIndex
+args: -n Bug12315582 T1
+
max-time: 500
cmd testNodeRestart
args: -n ForceStopAndRestart T1
=== modified file 'storage/ndb/test/src/HugoCalculator.cpp'
--- a/storage/ndb/test/src/HugoCalculator.cpp 2010-06-17 05:20:22 +0000
+++ b/storage/ndb/test/src/HugoCalculator.cpp 2011-04-05 19:12:29 +0000
@@ -446,3 +446,75 @@ HugoCalculator::getUpdatesValue(NDBT_Res
return pRow->attributeStore(m_updatesCol)->u_32_value();
}
+int
+HugoCalculator::equalForRow(Uint8 * pRow,
+ const NdbRecord* pRecord,
+ int rowId)
+{
+ for(int attrId = 0; attrId < m_tab.getNoOfColumns(); attrId++)
+ {
+ const NdbDictionary::Column* attr = m_tab.getColumn(attrId);
+
+ if (attr->getPrimaryKey() == true)
+ {
+ char buf[8000];
+ int len = attr->getSizeInBytes();
+ memset(buf, 0, sizeof(buf));
+ Uint32 real_len;
+ const char * value = calcValue(rowId, attrId, 0, buf,
+ len, &real_len);
+ assert(value != 0); // NULLable PK not supported...
+ Uint32 off = 0;
+ bool ret = NdbDictionary::getOffset(pRecord, attrId, off);
+ if (!ret)
+ abort();
+ memcpy(pRow + off, buf, real_len);
+ }
+ }
+ return NDBT_OK;
+}
+
+int
+HugoCalculator::setValues(Uint8 * pRow,
+ const NdbRecord* pRecord,
+ int rowId,
+ int updateVal)
+{
+ int res = equalForRow(pRow, pRecord, rowId);
+ if (res != 0)
+ {
+ return res;
+ }
+
+ for(int attrId = 0; attrId < m_tab.getNoOfColumns(); attrId++)
+ {
+ const NdbDictionary::Column* attr = m_tab.getColumn(attrId);
+
+ if (attr->getPrimaryKey() == false)
+ {
+ char buf[8000];
+ int len = attr->getSizeInBytes();
+ memset(buf, 0, sizeof(buf));
+ Uint32 real_len;
+ const char * value = calcValue(rowId, attrId, updateVal, buf,
+ len, &real_len);
+ if (value != 0)
+ {
+ Uint32 off = 0;
+ bool ret = NdbDictionary::getOffset(pRecord, attrId, off);
+ if (!ret)
+ abort();
+ memcpy(pRow + off, buf, real_len);
+ if (attr->getNullable())
+ NdbDictionary::setNull(pRecord, (char*)pRow, attrId, false);
+ }
+ else
+ {
+ assert(attr->getNullable());
+ NdbDictionary::setNull(pRecord, (char*)pRow, attrId, true);
+ }
+ }
+ }
+
+ return NDBT_OK;
+}
Attachment: [text/bzr-bundle] bzr/jonas@mysql.com-20110405191229-s8efbduqkdfhoa5w.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-7.1 branch (jonas:3946) | jonas oreland | 5 Apr |