4596 Ole John Aske 2012-08-24 [merge]
Merge 7-0 > 7.1
modified:
storage/ndb/include/kernel/signaldata/DbspjErr.hpp
storage/ndb/include/ndb_version.h.in
storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp
storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp
storage/ndb/src/kernel/blocks/dbspj/DbspjProxy.hpp
4595 Jan Wedvik 2012-08-22 [merge]
Merged 7.0->7.1
modified:
storage/ndb/include/kernel/signaldata/SchemaTrans.hpp
storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
storage/ndb/test/ndbapi/testDict.cpp
storage/ndb/test/run-test/daily-basic-tests.txt
=== modified file 'storage/ndb/include/kernel/signaldata/DbspjErr.hpp'
--- a/storage/ndb/include/kernel/signaldata/DbspjErr.hpp 2011-02-23 19:28:26 +0000
+++ b/storage/ndb/include/kernel/signaldata/DbspjErr.hpp 2012-08-24 11:46:00 +0000
@@ -39,6 +39,7 @@ struct DbspjErr
,OutOfRowMemory = 20015
,NodeFailure = 20016
,InvalidTreeNodeCount = 20017
+ ,IndexFragNotFound = 20018
};
};
=== modified file 'storage/ndb/include/ndb_version.h.in'
--- a/storage/ndb/include/ndb_version.h.in 2012-06-21 15:17:40 +0000
+++ b/storage/ndb/include/ndb_version.h.in 2012-08-24 11:49:11 +0000
@@ -772,4 +772,41 @@ ndbd_scan_tabreq_implicit_parallelism(Ui
return x >= NDBD_SCAN_TABREQ_IMPLICIT_PARALLELISM_72;
}
+#define NDBD_FIXED_LOOKUP_QUERY_ABORT_72 NDB_MAKE_VERSION(7,2,5)
+
+static
+inline
+int
+ndbd_fixed_lookup_query_abort(Uint32 x)
+{
+ const Uint32 major = (x >> 16) & 0xFF;
+ const Uint32 minor = (x >> 8) & 0xFF;
+
+ if (major == 7 && minor < 2)
+ {
+ // Only experimental support of SPJ pre 7.2.0.
+ // Assume we support 'fixed-abort' as we want it tested.
+ return 1;
+ }
+ return x >= NDBD_FIXED_LOOKUP_QUERY_ABORT_72;
+}
+
+/**
+ * NOTE1:
+ * Even though pushed join support wasn't GA intil 7.2.4
+ * we claim support for it in all 7.2.x versions.
+ * NOTE2:
+ * By a mistake this online upgrade check was not
+ * added until version 7.2.6
+ */
+#define NDBD_JOIN_PUSHDOWN NDB_MAKE_VERSION(7,2,0)
+
+static
+inline
+int
+ndb_join_pushdown(Uint32 x)
+{
+ return x >= NDBD_JOIN_PUSHDOWN;
+}
+
#endif
=== modified file 'storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp 2011-11-10 14:23:53 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp 2012-08-24 11:49:11 +0000
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -69,6 +69,8 @@ private:
void execDIH_SCAN_GET_NODES_REF(Signal*);
void execDIH_SCAN_GET_NODES_CONF(Signal*);
+ void execSIGNAL_DROPPED_REP(Signal*);
+
/**
* Signals from LQH
*/
@@ -296,7 +298,6 @@ public:
Uint32 m_senderRef; // TC (used for routing)
Uint32 m_scan_cnt;
Signal* m_start_signal; // Argument to first node in tree
- SegmentedSectionPtr m_keyPtr;
TreeNodeBitMask m_scans; // TreeNodes doing scans
@@ -1087,8 +1088,6 @@ private:
void releaseRow(Ptr<Request>, RowRef ref);
void registerActiveCursor(Ptr<Request>, Ptr<TreeNode>);
void nodeFail_checkRequests(Signal*);
-
- void cleanupChildBranch(Ptr<Request>, Ptr<TreeNode>);
void cleanup_common(Ptr<Request>, Ptr<TreeNode>);
/**
@@ -1232,13 +1231,13 @@ private:
void scanIndex_execSCAN_FRAGCONF(Signal*, Ptr<Request>, Ptr<TreeNode>, Ptr<ScanFragHandle>);
void scanIndex_parent_row(Signal*,Ptr<Request>,Ptr<TreeNode>, const RowPtr&);
void scanIndex_fixupBound(Ptr<ScanFragHandle> fragPtr, Uint32 ptrI, Uint32);
- void scanIndex_send(Signal* signal,
- Ptr<Request> requestPtr,
- Ptr<TreeNode> treeNodePtr,
- Uint32 noOfFrags,
- Uint32 bs_bytes,
- Uint32 bs_rows,
- Uint32& batchRange);
+ Uint32 scanIndex_send(Signal* signal,
+ Ptr<Request> requestPtr,
+ Ptr<TreeNode> treeNodePtr,
+ Uint32 noOfFrags,
+ Uint32 bs_bytes,
+ Uint32 bs_rows,
+ Uint32& batchRange);
void scanIndex_batchComplete(Signal* signal);
Uint32 scanIndex_findFrag(Local_ScanFragHandle_list &, Ptr<ScanFragHandle>&,
Uint32 fragId);
@@ -1264,11 +1263,18 @@ private:
SLList<RowPage>::Head m_free_page_list;
ArrayPool<RowPage> m_page_pool;
+ /* Random fault injection */
+
+#ifdef ERROR_INSERT
+ bool appendToSection(Uint32& firstSegmentIVal,
+ const Uint32* src, Uint32 len);
+#endif
+
/**
* Scratch buffers...
*/
- Uint32 m_buffer0[8192]; // 32k
- Uint32 m_buffer1[8192]; // 32k
+ Uint32 m_buffer0[16*1024]; // 64k
+ Uint32 m_buffer1[16*1024]; // 64k
};
#endif
=== modified file 'storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp 2011-11-15 17:47:11 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp 2012-08-24 11:49:11 +0000
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
#define DBSPJ_C
#include "Dbspj.hpp"
+#include <ndb_version.h>
#include <SectionReader.hpp>
#include <signaldata/LqhKey.hpp>
#include <signaldata/QueryTree.hpp>
@@ -36,6 +37,7 @@
#include <signaldata/NodeFailRep.hpp>
#include <signaldata/ReadNodesConf.hpp>
+#include <signaldata/SignalDroppedRep.hpp>
// Use DEBUG to print messages that should be
// seen only when we debug the product
@@ -52,11 +54,7 @@
#endif
-#if 1
-#define DEBUG_CRASH() ndbrequire(false)
-#else
-#define DEBUG_CRASH()
-#endif
+#define DEBUG_CRASH() ndbassert(false)
#if 1
#undef DEBUG
@@ -68,6 +66,50 @@
const Ptr<Dbspj::TreeNode> Dbspj::NullTreeNodePtr = { 0, RNIL };
const Dbspj::RowRef Dbspj::NullRowRef = { RNIL, GLOBAL_PAGE_SIZE_WORDS, { 0 } };
+
+void Dbspj::execSIGNAL_DROPPED_REP(Signal* signal)
+{
+ /* An incoming signal was dropped, handle it.
+ * Dropped signal really means that we ran out of
+ * long signal buffering to store its sections.
+ */
+ jamEntry();
+
+ if (!assembleDroppedFragments(signal))
+ {
+ jam();
+ return;
+ }
+
+ const SignalDroppedRep* rep = (SignalDroppedRep*) &signal->theData[0];
+ Uint32 originalGSN= rep->originalGsn;
+
+ DEBUG("SignalDroppedRep received for GSN " << originalGSN);
+
+ switch(originalGSN) {
+ case GSN_SCAN_FRAGREQ:
+ {
+ jam();
+ /* Get information necessary to send SCAN_FRAGREF back to TC */
+ // TODO : Handle dropped signal fragments
+
+ const ScanFragReq * const truncatedScanFragReq =
+ (ScanFragReq *) &rep->originalData[0];
+
+ handle_early_scanfrag_ref(signal, truncatedScanFragReq,
+ DbspjErr::OutOfSectionMemory);
+ break;
+ }
+ default:
+ jam();
+ /* Don't expect dropped signals for other GSNs
+ */
+ SimulatedBlock::execSIGNAL_DROPPED_REP(signal);
+ };
+
+ return;
+}
+
/** A noop for now.*/
void Dbspj::execREAD_CONFIG_REQ(Signal* signal)
{
@@ -384,9 +426,10 @@ void Dbspj::execLQHKEYREQ(Signal* signal
* (unless StoredProcId is set, when only paramters are sent,
* but this is not yet implemented)
*/
+ SegmentedSectionPtr attrPtr;
SectionHandle handle = SectionHandle(this, signal);
- SegmentedSectionPtr ssPtr;
- handle.getSection(ssPtr, LqhKeyReq::AttrInfoSectionNum);
+ handle.getSection(attrPtr, LqhKeyReq::AttrInfoSectionNum);
+ const Uint32 keyPtrI = handle.m_ptr[LqhKeyReq::KeyInfoSectionNum].i;
Uint32 err;
Ptr<Request> requestPtr = { 0, RNIL };
@@ -397,16 +440,25 @@ void Dbspj::execLQHKEYREQ(Signal* signal
if (unlikely(!m_arenaAllocator.seize(ah)))
break;
-
- m_request_pool.seize(ah, requestPtr);
-
+ if (ERROR_INSERTED_CLEAR(17001))
+ {
+ ndbout_c("Injecting OutOfQueryMem error 17001 at line %d file %s",
+ __LINE__, __FILE__);
+ jam();
+ break;
+ }
+ if (unlikely(!m_request_pool.seize(ah, requestPtr)))
+ {
+ jam();
+ break;
+ }
new (requestPtr.p) Request(ah);
do_init(requestPtr.p, req, signal->getSendersBlockRef());
Uint32 len_cnt;
{
- SectionReader r0(ssPtr, getSectionSegmentPool());
+ SectionReader r0(attrPtr, getSectionSegmentPool());
err = DbspjErr::ZeroLengthQueryTree;
if (unlikely(!r0.getWord(&len_cnt)))
@@ -417,8 +469,8 @@ void Dbspj::execLQHKEYREQ(Signal* signal
Uint32 cnt = QueryTree::getNodeCnt(len_cnt);
{
- SectionReader treeReader(ssPtr, getSectionSegmentPool());
- SectionReader paramReader(ssPtr, getSectionSegmentPool());
+ SectionReader treeReader(attrPtr, getSectionSegmentPool());
+ SectionReader paramReader(attrPtr, getSectionSegmentPool());
paramReader.step(len); // skip over tree to parameters
Build_context ctx;
@@ -426,31 +478,39 @@ void Dbspj::execLQHKEYREQ(Signal* signal
ctx.m_savepointId = req->savePointId;
ctx.m_scanPrio = 1;
ctx.m_start_signal = signal;
- ctx.m_keyPtr.i = handle.m_ptr[LqhKeyReq::KeyInfoSectionNum].i;
ctx.m_senderRef = signal->getSendersBlockRef();
err = build(ctx, requestPtr, treeReader, paramReader);
if (unlikely(err != 0))
break;
- }
- /**
- * a query being shipped as a LQHKEYREQ may only return finite rows
- * i.e be a (multi-)lookup
- */
- ndbassert(requestPtr.p->isLookup());
- ndbassert(requestPtr.p->m_node_cnt == cnt);
- err = DbspjErr::InvalidRequest;
- if (unlikely(!requestPtr.p->isLookup() || requestPtr.p->m_node_cnt != cnt))
- break;
+ /**
+ * Root TreeNode in Request takes ownership of keyPtr
+ * section when build has completed.
+ * We are done with attrPtr which is now released.
+ */
+ Ptr<TreeNode> rootNodePtr = ctx.m_node_list[0];
+ rootNodePtr.p->m_send.m_keyInfoPtrI = keyPtrI;
+ release(attrPtr);
+ handle.clear();
+ }
/**
* Store request in list(s)/hash(es)
*/
store_lookup(requestPtr);
- release(ssPtr);
- handle.clear();
+ /**
+ * A query being shipped as a LQHKEYREQ may return at most a row
+ * per operation i.e be a (multi-)lookup
+ */
+ if (ERROR_INSERTED_CLEAR(17013) ||
+ unlikely(!requestPtr.p->isLookup() || requestPtr.p->m_node_cnt != cnt))
+ {
+ jam();
+ err = DbspjErr::InvalidRequest;
+ break;
+ }
start(signal, requestPtr);
return;
@@ -463,9 +523,9 @@ void Dbspj::execLQHKEYREQ(Signal* signal
if (!requestPtr.isNull())
{
jam();
- m_request_pool.release(requestPtr);
+ cleanup(requestPtr);
}
- releaseSections(handle);
+ releaseSections(handle); // a NOOP, if we reached 'handle.clear()' above
handle_early_lqhkey_ref(signal, req, err);
}
@@ -678,8 +738,8 @@ Dbspj::execSCAN_FRAGREQ(Signal* signal)
* if first op is lookup - contains keyinfo for lookup
*/
SectionHandle handle = SectionHandle(this, signal);
- SegmentedSectionPtr ssPtr;
- handle.getSection(ssPtr, ScanFragReq::AttrInfoSectionNum);
+ SegmentedSectionPtr attrPtr;
+ handle.getSection(attrPtr, ScanFragReq::AttrInfoSectionNum);
Uint32 err;
Ptr<Request> requestPtr = { 0, RNIL };
@@ -690,14 +750,24 @@ Dbspj::execSCAN_FRAGREQ(Signal* signal)
if (unlikely(!m_arenaAllocator.seize(ah)))
break;
- m_request_pool.seize(ah, requestPtr);
-
+ if (ERROR_INSERTED_CLEAR(17002))
+ {
+ ndbout_c("Injecting OutOfQueryMem error 17002 at line %d file %s",
+ __LINE__, __FILE__);
+ jam();
+ break;
+ }
+ if (unlikely(!m_request_pool.seize(ah, requestPtr)))
+ {
+ jam();
+ break;
+ }
new (requestPtr.p) Request(ah);
do_init(requestPtr.p, req, signal->getSendersBlockRef());
Uint32 len_cnt;
{
- SectionReader r0(ssPtr, getSectionSegmentPool());
+ SectionReader r0(attrPtr, getSectionSegmentPool());
err = DbspjErr::ZeroLengthQueryTree;
if (unlikely(!r0.getWord(&len_cnt)))
break;
@@ -707,8 +777,8 @@ Dbspj::execSCAN_FRAGREQ(Signal* signal)
Uint32 cnt = QueryTree::getNodeCnt(len_cnt);
{
- SectionReader treeReader(ssPtr, getSectionSegmentPool());
- SectionReader paramReader(ssPtr, getSectionSegmentPool());
+ SectionReader treeReader(attrPtr, getSectionSegmentPool());
+ SectionReader paramReader(attrPtr, getSectionSegmentPool());
paramReader.step(len); // skip over tree to parameters
Build_context ctx;
@@ -719,35 +789,38 @@ Dbspj::execSCAN_FRAGREQ(Signal* signal)
ctx.m_start_signal = signal;
ctx.m_senderRef = signal->getSendersBlockRef();
+ err = build(ctx, requestPtr, treeReader, paramReader);
+ if (unlikely(err != 0))
+ break;
+
+ /**
+ * Root TreeNode in Request takes ownership of keyPtr
+ * section when build has completed.
+ * We are done with attrPtr which is now released.
+ */
+ Ptr<TreeNode> rootNodePtr = ctx.m_node_list[0];
if (handle.m_cnt > 1)
{
jam();
- ctx.m_keyPtr.i = handle.m_ptr[ScanFragReq::KeyInfoSectionNum].i;
- }
- else
- {
- jam();
- ctx.m_keyPtr.i = RNIL;
+ const Uint32 keyPtrI = handle.m_ptr[ScanFragReq::KeyInfoSectionNum].i;
+ rootNodePtr.p->m_send.m_keyInfoPtrI = keyPtrI;
}
-
- err = build(ctx, requestPtr, treeReader, paramReader);
- if (unlikely(err != 0))
- break;
+ release(attrPtr);
+ handle.clear();
}
- ndbassert(requestPtr.p->isScan());
- ndbassert(requestPtr.p->m_node_cnt == cnt);
- err = DbspjErr::InvalidRequest;
- if (unlikely(!requestPtr.p->isScan() || requestPtr.p->m_node_cnt != cnt))
- break;
-
/**
* Store request in list(s)/hash(es)
*/
store_scan(requestPtr);
- release(ssPtr);
- handle.clear();
+ if (ERROR_INSERTED_CLEAR(17013) ||
+ unlikely(!requestPtr.p->isScan() || requestPtr.p->m_node_cnt != cnt))
+ {
+ jam();
+ err = DbspjErr::InvalidRequest;
+ break;
+ }
start(signal, requestPtr);
return;
@@ -756,9 +829,9 @@ Dbspj::execSCAN_FRAGREQ(Signal* signal)
if (!requestPtr.isNull())
{
jam();
- m_request_pool.release(requestPtr);
+ cleanup(requestPtr);
}
- releaseSections(handle);
+ releaseSections(handle); // a NOOP, if we reached 'handle.clear()' above
handle_early_scanfrag_ref(signal, req, err);
}
@@ -841,7 +914,7 @@ Dbspj::build(Build_context& ctx,
err = DbspjErr::InvalidTreeNodeCount;
if (loop == 0 || loop > NDB_SPJ_MAX_TREE_NODES)
{
- DEBUG_CRASH();
+ jam();
goto error;
}
@@ -858,28 +931,28 @@ Dbspj::build(Build_context& ctx,
err = DbspjErr::QueryNodeTooBig;
if (unlikely(node_len >= NDB_ARRAY_SIZE(m_buffer0)))
{
- DEBUG_CRASH();
+ jam();
goto error;
}
err = DbspjErr::QueryNodeParametersTooBig;
if (unlikely(param_len >= NDB_ARRAY_SIZE(m_buffer1)))
{
- DEBUG_CRASH();
+ jam();
goto error;
}
err = DbspjErr::InvalidTreeNodeSpecification;
if (unlikely(tree.getWords(m_buffer0, node_len) == false))
{
- DEBUG_CRASH();
+ jam();
goto error;
}
err = DbspjErr::InvalidTreeParametersSpecification;
if (unlikely(param.getWords(m_buffer1, param_len) == false))
{
- DEBUG_CRASH();
+ jam();
goto error;
}
@@ -898,14 +971,21 @@ Dbspj::build(Build_context& ctx,
err = DbspjErr::UnknowQueryOperation;
if (unlikely(node_op != param_op))
{
- DEBUG_CRASH();
+ jam();
+ goto error;
+ }
+ if (ERROR_INSERTED_CLEAR(17006))
+ {
+ ndbout_c("Injecting UnknowQueryOperation error 17006 at line %d file %s",
+ __LINE__, __FILE__);
+ jam();
goto error;
}
const OpInfo* info = getOpInfo(node_op);
if (unlikely(info == 0))
{
- DEBUG_CRASH();
+ jam();
goto error;
}
@@ -916,7 +996,7 @@ Dbspj::build(Build_context& ctx,
err = (this->*(info->m_build))(ctx, requestPtr, qn, qp);
if (unlikely(err != 0))
{
- DEBUG_CRASH();
+ jam();
goto error;
}
@@ -925,9 +1005,6 @@ Dbspj::build(Build_context& ctx,
*/
ctx.m_start_signal = 0;
- /**
- * TODO handle error, by aborting request
- */
ndbrequire(ctx.m_cnt < NDB_ARRAY_SIZE(ctx.m_node_list));
ctx.m_cnt++;
}
@@ -992,6 +1069,13 @@ Dbspj::createNode(Build_context& ctx, Pt
* that can be setup using the Build_context
*
*/
+ if (ERROR_INSERTED_CLEAR(17005))
+ {
+ ndbout_c("Injecting OutOfOperations error 17005 at line %d file %s",
+ __LINE__, __FILE__);
+ jam();
+ return DbspjErr::OutOfOperations;
+ }
if (m_treenode_pool.seize(requestPtr.p->m_arena, treeNodePtr))
{
DEBUG("createNode - seize -> ptrI: " << treeNodePtr.i);
@@ -1133,7 +1217,7 @@ Dbspj::batchComplete(Signal* signal, Ptr
{
jam();
/**
- * release unneeded buffers and position cursor for SCAN_NEXTREQ
+ * release unneeded buffers as preparation for later SCAN_NEXTREQ
*/
releaseScanBuffers(requestPtr);
}
@@ -1166,6 +1250,8 @@ Dbspj::prepareNextBatch(Signal* signal,
return;
}
+ DEBUG("prepareNextBatch, request: " << requestPtr.i);
+
if (requestPtr.p->m_bits & Request::RT_REPEAT_SCAN_RESULT)
{
/**
@@ -1400,43 +1486,36 @@ Dbspj::releaseScanBuffers(Ptr<Request> r
{
Ptr<TreeNode> treeNodePtr;
Local_TreeNode_list list(m_treenode_pool, requestPtr.p->m_nodes);
- TreeNodeBitMask ancestors_of_active;
- for (list.last(treeNodePtr); !treeNodePtr.isNull(); list.prev(treeNodePtr))
+ for (list.first(treeNodePtr); !treeNodePtr.isNull(); list.next(treeNodePtr))
{
/**
- * If there are no active children,
- * then we can cleanup in our sub-branch
+ * Release buffered rows for all treeNodes getting more rows
+ * in the following NEXTREQ, including all its childs.
*/
- if (!ancestors_of_active.get(treeNodePtr.p->m_node_no))
+ if (requestPtr.p->m_active_nodes.get(treeNodePtr.p->m_node_no) ||
+ requestPtr.p->m_active_nodes.overlaps(treeNodePtr.p->m_ancestors))
{
if (treeNodePtr.p->m_bits & TreeNode::T_ROW_BUFFER)
{
jam();
releaseNodeRows(requestPtr, treeNodePtr);
}
-
- /**
- * Cleanup ACTIVE nodes fetching more rows in a NEXTREQ,
- * or nodes being in 'm_active_nodes' as they will 'repeat'.
- * (and then become active)
- */
- if (treeNodePtr.p->m_state == TreeNode::TN_ACTIVE ||
- requestPtr.p->m_active_nodes.get(treeNodePtr.p->m_node_no))
- {
- jam();
- cleanupChildBranch(requestPtr, treeNodePtr);
- }
}
/**
- * Collect ancestors of all nodes which are, or will
- * become active in NEXTREQ (possibly repeated)
- */
- if (treeNodePtr.p->m_state == TreeNode::TN_ACTIVE ||
- requestPtr.p->m_active_nodes.get(treeNodePtr.p->m_node_no))
+ * Do further cleanup in treeNodes having ancestor getting more rows.
+ * (Which excludes the restarted treeNode itself)
+ */
+ if (requestPtr.p->m_active_nodes.overlaps(treeNodePtr.p->m_ancestors))
{
- ancestors_of_active.bitOR(treeNodePtr.p->m_ancestors);
+ jam();
+ if (treeNodePtr.p->m_info->m_parent_batch_cleanup != 0)
+ {
+ jam();
+ (this->*(treeNodePtr.p->m_info->m_parent_batch_cleanup))(requestPtr,
+ treeNodePtr);
+ }
}
}
/**
@@ -1467,32 +1546,15 @@ Dbspj::registerActiveCursor(Ptr<Request>
}
void
-Dbspj::cleanupChildBranch(Ptr<Request> requestPtr, Ptr<TreeNode> treeNodePtr)
-{
- LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
- Local_dependency_map list(pool, treeNodePtr.p->m_dependent_nodes);
- Dependency_map::ConstDataBufferIterator it;
- for (list.first(it); !it.isNull(); list.next(it))
- {
- jam();
- Ptr<TreeNode> childPtr;
- m_treenode_pool.getPtr(childPtr, *it.data);
- if (childPtr.p->m_info->m_parent_batch_cleanup != 0)
- {
- jam();
- (this->*(childPtr.p->m_info->m_parent_batch_cleanup))(requestPtr,
- childPtr);
- }
- cleanupChildBranch(requestPtr,childPtr);
- }
-}
-
-void
Dbspj::releaseNodeRows(Ptr<Request> requestPtr, Ptr<TreeNode> treeNodePtr)
{
/**
* Release all rows associated with tree node
*/
+ DEBUG("releaseNodeRows"
+ << ", node: " << treeNodePtr.p->m_node_no
+ << ", request: " << requestPtr.i
+ );
// only when var-alloc, or else stack will be popped wo/ consideration
// to individual rows
@@ -1556,16 +1618,42 @@ Dbspj::releaseRow(Ptr<Request> requestPt
m_page_pool.getPtr(ptr, pos.m_page_id);
((Var_page*)ptr.p)->free_record(pos.m_page_pos, Var_page::CHAIN);
Uint32 free_space = ((Var_page*)ptr.p)->free_space;
- if (free_space == 0)
+ if (free_space == Var_page::DATA_WORDS - 1)
{
jam();
LocalDLFifoList<RowPage> list(m_page_pool,
requestPtr.p->m_rowBuffer.m_page_list);
+ const bool last = list.hasNext(ptr) == false;
list.remove(ptr);
- releasePage(ptr);
+ if (list.isEmpty())
+ {
+ jam();
+ /**
+ * Don't remove last page...
+ */
+ list.addLast(ptr);
+ requestPtr.p->m_rowBuffer.m_var.m_free = free_space;
+ }
+ else
+ {
+ jam();
+ if (last)
+ {
+ jam();
+ /**
+ * If we were last...set m_var.m_free to free_space of newLastPtr
+ */
+ Ptr<RowPage> newLastPtr;
+ ndbrequire(list.last(newLastPtr));
+ requestPtr.p->m_rowBuffer.m_var.m_free =
+ ((Var_page*)newLastPtr.p)->free_space;
+ }
+ releasePage(ptr);
+ }
}
else if (free_space > requestPtr.p->m_rowBuffer.m_var.m_free)
{
+ jam();
LocalDLFifoList<RowPage> list(m_page_pool,
requestPtr.p->m_rowBuffer.m_page_list);
list.remove(ptr);
@@ -1577,6 +1665,9 @@ Dbspj::releaseRow(Ptr<Request> requestPt
void
Dbspj::releaseRequestBuffers(Ptr<Request> requestPtr, bool reset)
{
+ DEBUG("releaseRequestBuffers"
+ << ", request: " << requestPtr.i
+ );
/**
* Release all pages for request
*/
@@ -1650,6 +1741,22 @@ Dbspj::abort(Signal* signal, Ptr<Request
{
jam();
+ /**
+ * Need to handle online upgrade as the protocoll for
+ * signaling errors for Lookup-request changed in 7.2.5.
+ * If API-version is <= 7.2.4 we increase the severity
+ * of the error to a 'NodeFailure' as this is the only
+ * errorcode for which the API will stop further
+ * 'outstanding-counting' in pre 7.2.5.
+ * (Starting from 7.2.5 we will stop counting for all 'hard errors')
+ */
+ if (requestPtr.p->isLookup() &&
+ !ndbd_fixed_lookup_query_abort(getNodeInfo(getResultRef(requestPtr)).m_version))
+ {
+ jam();
+ errCode = DbspjErr::NodeFailure;
+ }
+
if ((requestPtr.p->m_state & Request::RS_ABORTING) != 0)
{
jam();
@@ -1805,33 +1912,12 @@ Dbspj::cleanup(Ptr<Request> requestPtr)
requestPtr.p->m_state = Request::RS_ABORTED;
return;
}
-
-#ifdef VM_TRACE
- {
- Request key;
- key.m_transId[0] = requestPtr.p->m_transId[0];
- key.m_transId[1] = requestPtr.p->m_transId[1];
- key.m_senderData = requestPtr.p->m_senderData;
- Ptr<Request> tmp;
- ndbrequire(m_scan_request_hash.find(tmp, key));
- }
-#endif
- m_scan_request_hash.remove(requestPtr);
+ m_scan_request_hash.remove(requestPtr, *requestPtr.p);
}
else
{
jam();
-#ifdef VM_TRACE
- {
- Request key;
- key.m_transId[0] = requestPtr.p->m_transId[0];
- key.m_transId[1] = requestPtr.p->m_transId[1];
- key.m_senderData = requestPtr.p->m_senderData;
- Ptr<Request> tmp;
- ndbrequire(m_lookup_request_hash.find(tmp, key));
- }
-#endif
- m_lookup_request_hash.remove(requestPtr);
+ m_lookup_request_hash.remove(requestPtr, *requestPtr.p);
}
releaseRequestBuffers(requestPtr, false);
ArenaHead ah = requestPtr.p->m_arena;
@@ -1883,13 +1969,18 @@ Dbspj::execLQHKEYREF(Signal* signal)
const LqhKeyRef* ref = reinterpret_cast<const LqhKeyRef*>(signal->getDataPtr());
- DEBUG("execLQHKEYREF, errorCode:" << ref->errorCode);
Ptr<TreeNode> treeNodePtr;
m_treenode_pool.getPtr(treeNodePtr, ref->connectPtr);
Ptr<Request> requestPtr;
m_request_pool.getPtr(requestPtr, treeNodePtr.p->m_requestPtrI);
+ DEBUG("execLQHKEYREF"
+ << ", node: " << treeNodePtr.p->m_node_no
+ << ", request: " << requestPtr.i
+ << ", errorCode: " << ref->errorCode
+ );
+
ndbrequire(treeNodePtr.p->m_info && treeNodePtr.p->m_info->m_execLQHKEYREF);
(this->*(treeNodePtr.p->m_info->m_execLQHKEYREF))(signal,
requestPtr,
@@ -1901,8 +1992,6 @@ Dbspj::execLQHKEYCONF(Signal* signal)
{
jamEntry();
- DEBUG("execLQHKEYCONF");
-
const LqhKeyConf* conf = reinterpret_cast<const LqhKeyConf*>(signal->getDataPtr());
Ptr<TreeNode> treeNodePtr;
m_treenode_pool.getPtr(treeNodePtr, conf->opPtr);
@@ -1910,6 +1999,11 @@ Dbspj::execLQHKEYCONF(Signal* signal)
Ptr<Request> requestPtr;
m_request_pool.getPtr(requestPtr, treeNodePtr.p->m_requestPtrI);
+ DEBUG("execLQHKEYCONF"
+ << ", node: " << treeNodePtr.p->m_node_no
+ << ", request: " << requestPtr.i
+ );
+
ndbrequire(treeNodePtr.p->m_info && treeNodePtr.p->m_info->m_execLQHKEYCONF);
(this->*(treeNodePtr.p->m_info->m_execLQHKEYCONF))(signal,
requestPtr,
@@ -1922,8 +2016,6 @@ Dbspj::execSCAN_FRAGREF(Signal* signal)
jamEntry();
const ScanFragRef* ref = reinterpret_cast<const ScanFragRef*>(signal->getDataPtr());
- DEBUG("execSCAN_FRAGREF, errorCode:" << ref->errorCode);
-
Ptr<ScanFragHandle> scanFragHandlePtr;
m_scanfraghandle_pool.getPtr(scanFragHandlePtr, ref->senderData);
Ptr<TreeNode> treeNodePtr;
@@ -1931,6 +2023,12 @@ Dbspj::execSCAN_FRAGREF(Signal* signal)
Ptr<Request> requestPtr;
m_request_pool.getPtr(requestPtr, treeNodePtr.p->m_requestPtrI);
+ DEBUG("execSCAN_FRAGCONF"
+ << ", node: " << treeNodePtr.p->m_node_no
+ << ", request: " << requestPtr.i
+ << ", errorCode: " << ref->errorCode
+ );
+
ndbrequire(treeNodePtr.p->m_info&&treeNodePtr.p->m_info->m_execSCAN_FRAGREF);
(this->*(treeNodePtr.p->m_info->m_execSCAN_FRAGREF))(signal,
requestPtr,
@@ -1952,6 +2050,10 @@ Dbspj::execSCAN_HBREP(Signal* signal)
m_treenode_pool.getPtr(treeNodePtr, scanFragHandlePtr.p->m_treeNodePtrI);
Ptr<Request> requestPtr;
m_request_pool.getPtr(requestPtr, treeNodePtr.p->m_requestPtrI);
+ DEBUG("execSCAN_HBREP"
+ << ", node: " << treeNodePtr.p->m_node_no
+ << ", request: " << requestPtr.i
+ );
Uint32 ref = requestPtr.p->m_senderRef;
signal->theData[0] = requestPtr.p->m_senderData;
@@ -1962,7 +2064,6 @@ void
Dbspj::execSCAN_FRAGCONF(Signal* signal)
{
jamEntry();
- DEBUG("execSCAN_FRAGCONF");
const ScanFragConf* conf = reinterpret_cast<const ScanFragConf*>(signal->getDataPtr());
@@ -1979,6 +2080,10 @@ Dbspj::execSCAN_FRAGCONF(Signal* signal)
m_treenode_pool.getPtr(treeNodePtr, scanFragHandlePtr.p->m_treeNodePtrI);
Ptr<Request> requestPtr;
m_request_pool.getPtr(requestPtr, treeNodePtr.p->m_requestPtrI);
+ DEBUG("execSCAN_FRAGCONF"
+ << ", node: " << treeNodePtr.p->m_node_no
+ << ", request: " << requestPtr.i
+ );
ndbrequire(treeNodePtr.p->m_info&&treeNodePtr.p->m_info->m_execSCAN_FRAGCONF);
(this->*(treeNodePtr.p->m_info->m_execSCAN_FRAGCONF))(signal,
@@ -1993,8 +2098,8 @@ Dbspj::execSCAN_NEXTREQ(Signal* signal)
jamEntry();
const ScanFragNextReq * req = (ScanFragNextReq*)&signal->theData[0];
- DEBUG("Incomming SCAN_NEXTREQ");
#ifdef DEBUG_SCAN_FRAGREQ
+ DEBUG("Incomming SCAN_NEXTREQ");
printSCANFRAGNEXTREQ(stdout, &signal->theData[0],
ScanFragNextReq::SignalLength, DBLQH);
#endif
@@ -2011,6 +2116,7 @@ Dbspj::execSCAN_NEXTREQ(Signal* signal)
ndbrequire(req->requestInfo == ScanFragNextReq::ZCLOSE);
return;
}
+ DEBUG("execSCAN_NEXTREQ, request: " << requestPtr.i);
#ifdef SPJ_TRACE_TIME
Uint64 now = spj_now();
@@ -2063,7 +2169,7 @@ Dbspj::execSCAN_NEXTREQ(Signal* signal)
if (treeNodePtr.p->m_state == TreeNode::TN_ACTIVE)
{
jam();
- DEBUG("SCAN_NEXTREQ on TreeNode: " << treeNodePtr.i
+ DEBUG("SCAN_NEXTREQ on TreeNode: "
<< ", m_node_no: " << treeNodePtr.p->m_node_no
<< ", w/ m_parentPtrI: " << treeNodePtr.p->m_parentPtrI);
@@ -2082,7 +2188,7 @@ Dbspj::execSCAN_NEXTREQ(Signal* signal)
*/
jam();
ndbrequire(requestPtr.p->m_bits & Request::RT_REPEAT_SCAN_RESULT);
- DEBUG(" Restart TreeNode: " << treeNodePtr.i
+ DEBUG("Restart TreeNode "
<< ", m_node_no: " << treeNodePtr.p->m_node_no
<< ", w/ m_parentPtrI: " << treeNodePtr.p->m_parentPtrI);
@@ -2103,7 +2209,6 @@ void
Dbspj::execTRANSID_AI(Signal* signal)
{
jamEntry();
- DEBUG("execTRANSID_AI");
TransIdAI * req = (TransIdAI *)signal->getDataPtr();
Uint32 ptrI = req->connectPtr;
//Uint32 transId[2] = { req->transId[0], req->transId[1] };
@@ -2113,7 +2218,12 @@ Dbspj::execTRANSID_AI(Signal* signal)
Ptr<Request> requestPtr;
m_request_pool.getPtr(requestPtr, treeNodePtr.p->m_requestPtrI);
- ndbrequire(signal->getNoOfSections() != 0); // TODO check if this can happen
+ DEBUG("execTRANSID_AI"
+ << ", node: " << treeNodePtr.p->m_node_no
+ << ", request: " << requestPtr.i
+ );
+
+ ndbrequire(signal->getNoOfSections() != 0);
SegmentedSectionPtr dataPtr;
{
@@ -2149,8 +2259,18 @@ Dbspj::execTRANSID_AI(Signal* signal)
if (treeNodePtr.p->m_bits & TreeNode::T_ROW_BUFFER)
{
jam();
- Uint32 err = storeRow(requestPtr, treeNodePtr, row);
- ndbrequire(err == 0);
+ Uint32 err;
+ if (ERROR_INSERTED_CLEAR(17120) ||
+ (treeNodePtr.p->m_parentPtrI != RNIL && ERROR_INSERTED_CLEAR(17121)))
+ {
+ jam();
+ abort(signal, requestPtr, DbspjErr::OutOfRowMemory);
+ }
+ else if ((err = storeRow(requestPtr, treeNodePtr, row)) != 0)
+ {
+ jam();
+ abort(signal, requestPtr, err);
+ }
}
ndbrequire(treeNodePtr.p->m_info&&treeNodePtr.p->m_info->m_execTRANSID_AI);
@@ -2170,6 +2290,11 @@ Dbspj::storeRow(Ptr<Request> requestPtr,
Uint32 * headptr = (Uint32*)row.m_row_data.m_section.m_header;
Uint32 headlen = 1 + row.m_row_data.m_section.m_header->m_len;
+ DEBUG("storeRow"
+ << ", node: " << treeNodePtr.p->m_node_no
+ << ", request: " << requestPtr.i
+ );
+
/**
* If rows are not in map, then they are kept in linked list
*/
@@ -2637,11 +2762,19 @@ Dbspj::allocPage(Ptr<RowPage> & ptr)
if (m_free_page_list.firstItem == RNIL)
{
jam();
+ if (ERROR_INSERTED_CLEAR(17003))
+ {
+ ndbout_c("Injecting failed '::allocPage', error 17003 at line %d file %s",
+ __LINE__, __FILE__);
+ jam();
+ return false;
+ }
ptr.p = (RowPage*)m_ctx.m_mm.alloc_page(RT_SPJ_DATABUFFER,
&ptr.i,
Ndbd_mem_manager::NDB_ZONE_ANY);
if (ptr.p == 0)
{
+ jam();
return false;
}
return true;
@@ -2736,7 +2869,6 @@ Dbspj::lookup_build(Build_context& ctx,
if (unlikely(node->len < QN_LookupNode::NodeSize))
{
jam();
- DEBUG_CRASH();
break;
}
@@ -2745,14 +2877,13 @@ Dbspj::lookup_build(Build_context& ctx,
if (unlikely(param->len < QN_LookupParameters::NodeSize))
{
jam();
- DEBUG_CRASH();
break;
}
err = createNode(ctx, requestPtr, treeNodePtr);
if (unlikely(err != 0))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -2830,7 +2961,7 @@ Dbspj::lookup_build(Build_context& ctx,
nodeDA, treeBits, paramDA, paramBits);
if (unlikely(err != 0))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -2907,7 +3038,6 @@ Dbspj::lookup_build(Build_context& ctx,
dst->fragmentData = fragId;
dst->attrLen = attrLen; // fragdist is in here
- treeNodePtr.p->m_send.m_keyInfoPtrI = ctx.m_keyPtr.i;
treeNodePtr.p->m_bits |= TreeNode::T_ONE_SHOT;
}
return 0;
@@ -2977,112 +3107,201 @@ Dbspj::lookup_send(Signal* signal,
Uint32 keyInfoPtrI = treeNodePtr.p->m_send.m_keyInfoPtrI;
Uint32 attrInfoPtrI = treeNodePtr.p->m_send.m_attrInfoPtrI;
- if (treeNodePtr.p->m_bits & TreeNode::T_ONE_SHOT)
- {
- jam();
- /**
- * Pass sections to send
- */
- treeNodePtr.p->m_send.m_attrInfoPtrI = RNIL;
- treeNodePtr.p->m_send.m_keyInfoPtrI = RNIL;
- }
- else
+ Uint32 err = 0;
+
+ do
{
- if ((treeNodePtr.p->m_bits & TreeNode::T_KEYINFO_CONSTRUCTED) == 0)
- {
- jam();
- Uint32 tmp = RNIL;
- ndbrequire(dupSection(tmp, keyInfoPtrI)); // TODO handle error
- keyInfoPtrI = tmp;
- }
- else
+ if (treeNodePtr.p->m_bits & TreeNode::T_ONE_SHOT)
{
jam();
+ /**
+ * Pass sections to send
+ */
+ treeNodePtr.p->m_send.m_attrInfoPtrI = RNIL;
treeNodePtr.p->m_send.m_keyInfoPtrI = RNIL;
}
-
- if ((treeNodePtr.p->m_bits & TreeNode::T_ATTRINFO_CONSTRUCTED) == 0)
- {
- jam();
- Uint32 tmp = RNIL;
- ndbrequire(dupSection(tmp, attrInfoPtrI)); // TODO handle error
- attrInfoPtrI = tmp;
- }
else
{
- jam();
- treeNodePtr.p->m_send.m_attrInfoPtrI = RNIL;
- }
- }
-
- getSection(handle.m_ptr[0], keyInfoPtrI);
- getSection(handle.m_ptr[1], attrInfoPtrI);
- handle.m_cnt = 2;
+ if ((treeNodePtr.p->m_bits & TreeNode::T_KEYINFO_CONSTRUCTED) == 0)
+ {
+ jam();
+ Uint32 tmp = RNIL;
+ if (!dupSection(tmp, keyInfoPtrI))
+ {
+ jam();
+ ndbassert(tmp == RNIL); // Guard for memleak
+ err = DbspjErr::OutOfSectionMemory;
+ break;
+ }
-#if defined DEBUG_LQHKEYREQ
- ndbout_c("LQHKEYREQ to %x", ref);
- printLQHKEYREQ(stdout, signal->getDataPtrSend(),
- NDB_ARRAY_SIZE(treeNodePtr.p->m_lookup_data.m_lqhKeyReq),
- DBLQH);
- printf("KEYINFO: ");
- print(handle.m_ptr[0], stdout);
- printf("ATTRINFO: ");
- print(handle.m_ptr[1], stdout);
-#endif
+ keyInfoPtrI = tmp;
+ }
+ else
+ {
+ jam();
+ treeNodePtr.p->m_send.m_keyInfoPtrI = RNIL;
+ }
- Uint32 Tnode = refToNode(ref);
- if (Tnode == getOwnNodeId())
- {
- c_Counters.incr_counter(CI_LOCAL_READS_SENT, 1);
- }
- else
- {
- c_Counters.incr_counter(CI_REMOTE_READS_SENT, 1);
- }
+ if ((treeNodePtr.p->m_bits & TreeNode::T_ATTRINFO_CONSTRUCTED) == 0)
+ {
+ jam();
+ Uint32 tmp = RNIL;
- if (unlikely(!c_alive_nodes.get(Tnode)))
- {
- jam();
- releaseSections(handle);
- abort(signal, requestPtr, DbspjErr::NodeFailure);
- return;
- }
- else if (! (treeNodePtr.p->isLeaf() && requestPtr.p->isLookup()))
- {
- jam();
- ndbassert(Tnode < NDB_ARRAY_SIZE(requestPtr.p->m_lookup_node_data));
- requestPtr.p->m_outstanding += cnt;
- requestPtr.p->m_lookup_node_data[Tnode] += cnt;
- // number wrapped
- ndbrequire(! (requestPtr.p->m_lookup_node_data[Tnode] == 0));
- }
+ /**
+ * Test execution terminated due to 'OutOfSectionMemory' which
+ * may happen for different treeNodes in the request:
+ * - 17070: Fail on any lookup_send()
+ * - 17071: Fail on lookup_send() if 'isLeaf'
+ * - 17072: Fail on lookup_send() if treeNode not root
+ */
- sendSignal(ref, GSN_LQHKEYREQ, signal,
- NDB_ARRAY_SIZE(treeNodePtr.p->m_lookup_data.m_lqhKeyReq),
- JBB, &handle);
+ if (ERROR_INSERTED_CLEAR(17070) ||
+ (treeNodePtr.p->isLeaf() && ERROR_INSERTED_CLEAR(17071)) ||
+ (treeNodePtr.p->m_parentPtrI != RNIL && ERROR_INSERTED_CLEAR(17072)))
+ {
+ jam();
+ ndbout_c("Injecting OutOfSectionMemory error at line %d file %s",
+ __LINE__, __FILE__);
+ releaseSection(keyInfoPtrI);
+ err = DbspjErr::OutOfSectionMemory;
+ break;
+ }
+
+ if (!dupSection(tmp, attrInfoPtrI))
+ {
+ jam();
+ ndbassert(tmp == RNIL); // Guard for memleak
+ releaseSection(keyInfoPtrI);
+ err = DbspjErr::OutOfSectionMemory;
+ break;
+ }
+
+ attrInfoPtrI = tmp;
+ }
+ else
+ {
+ jam();
+ treeNodePtr.p->m_send.m_attrInfoPtrI = RNIL;
+ }
+ }
+
+ getSection(handle.m_ptr[0], keyInfoPtrI);
+ getSection(handle.m_ptr[1], attrInfoPtrI);
+ handle.m_cnt = 2;
+
+ /**
+ * Inject error to test LQHKEYREF handling:
+ * Tampering with tableSchemaVersion such that LQH will
+ * return LQHKEYREF('1227: Invalid schema version')
+ * May happen for different treeNodes in the request:
+ * - 17030: Fail on any lookup_send()
+ * - 17031: Fail on lookup_send() if 'isLeaf'
+ * - 17032: Fail on lookup_send() if treeNode not root
+ */
+ if (ERROR_INSERTED_CLEAR(17030) ||
+ (treeNodePtr.p->isLeaf() && ERROR_INSERTED_CLEAR(17031)) ||
+ (treeNodePtr.p->m_parentPtrI != RNIL && ERROR_INSERTED_CLEAR(17032)))
+ {
+ jam();
+ req->tableSchemaVersion += (1 << 16); // Provoke 'Invalid schema version'
+ }
+
+#if defined DEBUG_LQHKEYREQ
+ ndbout_c("LQHKEYREQ to %x", ref);
+ printLQHKEYREQ(stdout, signal->getDataPtrSend(),
+ NDB_ARRAY_SIZE(treeNodePtr.p->m_lookup_data.m_lqhKeyReq),
+ DBLQH);
+ printf("KEYINFO: ");
+ print(handle.m_ptr[0], stdout);
+ printf("ATTRINFO: ");
+ print(handle.m_ptr[1], stdout);
+#endif
+
+ Uint32 Tnode = refToNode(ref);
+ if (Tnode == getOwnNodeId())
+ {
+ c_Counters.incr_counter(CI_LOCAL_READS_SENT, 1);
+ }
+ else
+ {
+ c_Counters.incr_counter(CI_REMOTE_READS_SENT, 1);
+ }
- treeNodePtr.p->m_lookup_data.m_outstanding += cnt;
- if (requestPtr.p->isLookup() && treeNodePtr.p->isLeaf())
- {
- jam();
/**
- * Send TCKEYCONF with DirtyReadBit + Tnode,
- * so that API can discover if Tnode while waiting for result
+ * Test execution terminated due to 'NodeFailure' which
+ * may happen for different treeNodes in the request:
+ * - 17020: Fail on any lookup_send()
+ * - 17021: Fail on lookup_send() if 'isLeaf'
+ * - 17022: Fail on lookup_send() if treeNode not root
*/
- Uint32 resultRef = req->variableData[0];
- Uint32 resultData = req->variableData[1];
-
- TcKeyConf* conf = (TcKeyConf*)signal->getDataPtrSend();
- conf->apiConnectPtr = RNIL; // lookup transaction from operations...
- conf->confInfo = 0;
- TcKeyConf::setNoOfOperations(conf->confInfo, 1);
- conf->transId1 = requestPtr.p->m_transId[0];
- conf->transId2 = requestPtr.p->m_transId[1];
- conf->operations[0].apiOperationPtr = resultData;
- conf->operations[0].attrInfoLen = TcKeyConf::DirtyReadBit | Tnode;
- Uint32 sigLen = TcKeyConf::StaticLength + TcKeyConf::OperationLength;
- sendTCKEYCONF(signal, sigLen, resultRef, requestPtr.p->m_senderRef);
+ if (ERROR_INSERTED_CLEAR(17020) ||
+ (treeNodePtr.p->isLeaf() && ERROR_INSERTED_CLEAR(17021)) ||
+ (treeNodePtr.p->m_parentPtrI != RNIL && ERROR_INSERTED_CLEAR(17022)))
+ {
+ jam();
+ releaseSections(handle);
+ err = DbspjErr::NodeFailure;
+ break;
+ }
+ // Test for online downgrade.
+ if (unlikely(!ndb_join_pushdown(getNodeInfo(Tnode).m_version)))
+ {
+ jam();
+ releaseSections(handle);
+ err = 4003; // Function not implemented.
+ break;
+ }
+
+ if (unlikely(!c_alive_nodes.get(Tnode)))
+ {
+ jam();
+ releaseSections(handle);
+ err = DbspjErr::NodeFailure;
+ break;
+ }
+ else if (! (treeNodePtr.p->isLeaf() && requestPtr.p->isLookup()))
+ {
+ jam();
+ ndbassert(Tnode < NDB_ARRAY_SIZE(requestPtr.p->m_lookup_node_data));
+ requestPtr.p->m_outstanding += cnt;
+ requestPtr.p->m_lookup_node_data[Tnode] += cnt;
+ // number wrapped
+ ndbrequire(! (requestPtr.p->m_lookup_node_data[Tnode] == 0));
+ }
+
+ sendSignal(ref, GSN_LQHKEYREQ, signal,
+ NDB_ARRAY_SIZE(treeNodePtr.p->m_lookup_data.m_lqhKeyReq),
+ JBB, &handle);
+
+ treeNodePtr.p->m_lookup_data.m_outstanding += cnt;
+ if (requestPtr.p->isLookup() && treeNodePtr.p->isLeaf())
+ {
+ jam();
+ /**
+ * Send TCKEYCONF with DirtyReadBit + Tnode,
+ * so that API can discover if Tnode while waiting for result
+ */
+ Uint32 resultRef = req->variableData[0];
+ Uint32 resultData = req->variableData[1];
+
+ TcKeyConf* conf = (TcKeyConf*)signal->getDataPtrSend();
+ conf->apiConnectPtr = RNIL; // lookup transaction from operations...
+ conf->confInfo = 0;
+ TcKeyConf::setNoOfOperations(conf->confInfo, 1);
+ conf->transId1 = requestPtr.p->m_transId[0];
+ conf->transId2 = requestPtr.p->m_transId[1];
+ conf->operations[0].apiOperationPtr = resultData;
+ conf->operations[0].attrInfoLen = TcKeyConf::DirtyReadBit | Tnode;
+ Uint32 sigLen = TcKeyConf::StaticLength + TcKeyConf::OperationLength;
+ sendTCKEYCONF(signal, sigLen, resultRef, requestPtr.p->m_senderRef);
+ }
+ return;
}
+ while (0);
+
+ ndbrequire(err);
+ jam();
+ abort(signal, requestPtr, err);
}
void
@@ -3099,14 +3318,18 @@ Dbspj::lookup_execTRANSID_AI(Signal* sig
LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
Local_dependency_map list(pool, treeNodePtr.p->m_dependent_nodes);
Dependency_map::ConstDataBufferIterator it;
+
for (list.first(it); !it.isNull(); list.next(it))
{
- jam();
- Ptr<TreeNode> childPtr;
- m_treenode_pool.getPtr(childPtr, * it.data);
- ndbrequire(childPtr.p->m_info != 0&&childPtr.p->m_info->m_parent_row!=0);
- (this->*(childPtr.p->m_info->m_parent_row))(signal,
- requestPtr, childPtr,rowRef);
+ if (likely((requestPtr.p->m_state & Request::RS_ABORTING) == 0))
+ {
+ jam();
+ Ptr<TreeNode> childPtr;
+ m_treenode_pool.getPtr(childPtr, * it.data);
+ ndbrequire(childPtr.p->m_info!=0 && childPtr.p->m_info->m_parent_row!=0);
+ (this->*(childPtr.p->m_info->m_parent_row))(signal,
+ requestPtr, childPtr,rowRef);
+ }
}
}
ndbrequire(!(requestPtr.p->isLookup() && treeNodePtr.p->isLeaf()));
@@ -3143,85 +3366,89 @@ Dbspj::lookup_execLQHKEYREF(Signal* sign
c_Counters.incr_counter(CI_READS_NOT_FOUND, 1);
- if (requestPtr.p->isLookup())
+ DEBUG("lookup_execLQHKEYREF, errorCode:" << errCode);
+
+ /**
+ * If Request is still actively running: API need to
+ * be informed about error.
+ * Error code may either indicate a 'hard error' which should
+ * terminate the query execution, or a 'soft error' which
+ * should be signaled NDBAPI, and execution continued.
+ */
+ if (likely((requestPtr.p->m_state & Request::RS_ABORTING) == 0))
{
- jam();
+ switch(errCode){
+ case 626: // 'Soft error' : Row not found
+ case 899: // 'Soft error' : Interpreter_exit_nok
- /* CONF/REF not requested for lookup-Leaf: */
- ndbrequire(!treeNodePtr.p->isLeaf());
+ jam();
+ /**
+ * Only Lookup-request need to send TCKEYREF...
+ */
+ if (requestPtr.p->isLookup())
+ {
+ jam();
- /**
- * Scan-request does not need to
- * send TCKEYREF...
- */
- /**
- * Return back to api...
- * NOTE: assume that signal is tampered with
- */
- Uint32 resultRef = treeNodePtr.p->m_lookup_data.m_api_resultRef;
- Uint32 resultData = treeNodePtr.p->m_lookup_data.m_api_resultData;
- TcKeyRef* ref = (TcKeyRef*)signal->getDataPtr();
- ref->connectPtr = resultData;
- ref->transId[0] = requestPtr.p->m_transId[0];
- ref->transId[1] = requestPtr.p->m_transId[1];
- ref->errorCode = errCode;
- ref->errorData = 0;
+ /* CONF/REF not requested for lookup-Leaf: */
+ ndbrequire(!treeNodePtr.p->isLeaf());
- DEBUG("lookup_execLQHKEYREF, errorCode:" << errCode);
+ /**
+ * Return back to api...
+ * NOTE: assume that signal is tampered with
+ */
+ Uint32 resultRef = treeNodePtr.p->m_lookup_data.m_api_resultRef;
+ Uint32 resultData = treeNodePtr.p->m_lookup_data.m_api_resultData;
+ TcKeyRef* ref = (TcKeyRef*)signal->getDataPtr();
+ ref->connectPtr = resultData;
+ ref->transId[0] = requestPtr.p->m_transId[0];
+ ref->transId[1] = requestPtr.p->m_transId[1];
+ ref->errorCode = errCode;
+ ref->errorData = 0;
- sendTCKEYREF(signal, resultRef, requestPtr.p->m_senderRef);
+ sendTCKEYREF(signal, resultRef, requestPtr.p->m_senderRef);
- if (treeNodePtr.p->m_bits & TreeNode::T_UNIQUE_INDEX_LOOKUP)
- {
- /**
- * If this is a "leaf" unique index lookup
- * emit extra TCKEYCONF as would have been done with ordinary
- * operation
- */
- LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
- Local_dependency_map list(pool, treeNodePtr.p->m_dependent_nodes);
- Dependency_map::ConstDataBufferIterator it;
- ndbrequire(list.first(it));
- ndbrequire(list.getSize() == 1); // should only be 1 child
- Ptr<TreeNode> childPtr;
- m_treenode_pool.getPtr(childPtr, * it.data);
- if (childPtr.p->m_bits & TreeNode::T_LEAF)
- {
- jam();
- Uint32 resultRef = childPtr.p->m_lookup_data.m_api_resultRef;
- Uint32 resultData = childPtr.p->m_lookup_data.m_api_resultData;
- TcKeyConf* conf = (TcKeyConf*)signal->getDataPtr();
- conf->apiConnectPtr = RNIL;
- conf->confInfo = 0;
- conf->gci_hi = 0;
- TcKeyConf::setNoOfOperations(conf->confInfo, 1);
- conf->transId1 = requestPtr.p->m_transId[0];
- conf->transId2 = requestPtr.p->m_transId[1];
- conf->operations[0].apiOperationPtr = resultData;
- conf->operations[0].attrInfoLen =
- TcKeyConf::DirtyReadBit |getOwnNodeId();
- sendTCKEYCONF(signal, TcKeyConf::StaticLength + 2, resultRef, requestPtr.p->m_senderRef);
- }
- }
- }
- else
- {
- jam();
- switch(errCode){
- case 626: // Row not found
- case 899: // Interpreter_exit_nok
- jam();
+ if (treeNodePtr.p->m_bits & TreeNode::T_UNIQUE_INDEX_LOOKUP)
+ {
+ /**
+ * If this is a "leaf" unique index lookup
+ * emit extra TCKEYCONF as would have been done with ordinary
+ * operation
+ */
+ LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
+ Local_dependency_map list(pool, treeNodePtr.p->m_dependent_nodes);
+ Dependency_map::ConstDataBufferIterator it;
+ ndbrequire(list.first(it));
+ ndbrequire(list.getSize() == 1); // should only be 1 child
+ Ptr<TreeNode> childPtr;
+ m_treenode_pool.getPtr(childPtr, * it.data);
+ if (childPtr.p->m_bits & TreeNode::T_LEAF)
+ {
+ jam();
+ Uint32 resultRef = childPtr.p->m_lookup_data.m_api_resultRef;
+ Uint32 resultData = childPtr.p->m_lookup_data.m_api_resultData;
+ TcKeyConf* conf = (TcKeyConf*)signal->getDataPtr();
+ conf->apiConnectPtr = RNIL;
+ conf->confInfo = 0;
+ conf->gci_hi = 0;
+ TcKeyConf::setNoOfOperations(conf->confInfo, 1);
+ conf->transId1 = requestPtr.p->m_transId[0];
+ conf->transId2 = requestPtr.p->m_transId[1];
+ conf->operations[0].apiOperationPtr = resultData;
+ conf->operations[0].attrInfoLen =
+ TcKeyConf::DirtyReadBit |getOwnNodeId();
+ sendTCKEYCONF(signal, TcKeyConf::StaticLength + 2, resultRef, requestPtr.p->m_senderRef);
+ }
+ }
+ } // isLookup()
break;
- default:
+
+ default: // 'Hard error' : abort query
jam();
abort(signal, requestPtr, errCode);
}
}
- Uint32 cnt = 2;
- if (treeNodePtr.p->isLeaf()) // Can't be a lookup-Leaf, asserted above
- cnt = 1;
-
+ Uint32 cnt = (treeNodePtr.p->isLeaf()) ? 1 : 2;
ndbassert(requestPtr.p->m_lookup_node_data[Tnode] >= cnt);
requestPtr.p->m_lookup_node_data[Tnode] -= cnt;
@@ -3291,15 +3518,32 @@ Dbspj::lookup_parent_row(Signal* signal,
* 2) compute hash (normally TC)
* 3) get node for row (normally TC)
*/
- Uint32 err;
+ Uint32 err = 0;
const LqhKeyReq* src = (LqhKeyReq*)treeNodePtr.p->m_lookup_data.m_lqhKeyReq;
const Uint32 tableId = LqhKeyReq::getTableId(src->tableSchemaVersion);
const Uint32 corrVal = rowRef.m_src_correlation;
- DEBUG("::lookup_parent_row");
+ DEBUG("::lookup_parent_row"
+ << ", node: " << treeNodePtr.p->m_node_no);
do
{
+ /**
+ * Test execution terminated due to 'OutOfQueryMemory' which
+ * may happen multiple places below:
+ * - 17040: Fail on any lookup_parent_row()
+ * - 17041: Fail on lookup_parent_row() if 'isLeaf'
+ * - 17042: Fail on lookup_parent_row() if treeNode not root
+ */
+ if (ERROR_INSERTED_CLEAR(17040) ||
+ (treeNodePtr.p->isLeaf() && ERROR_INSERTED_CLEAR(17041)) ||
+ (treeNodePtr.p->m_parentPtrI != RNIL && ERROR_INSERTED_CLEAR(17042)))
+ {
+ jam();
+ err = DbspjErr::OutOfQueryMemory;
+ break;
+ }
+
Uint32 ptrI = RNIL;
if (treeNodePtr.p->m_bits & TreeNode::T_KEYINFO_CONSTRUCTED)
{
@@ -3314,7 +3558,11 @@ Dbspj::lookup_parent_row(Signal* signal,
bool keyIsNull;
err = expand(ptrI, pattern, rowRef, keyIsNull);
if (unlikely(err != 0))
+ {
+ jam();
+ releaseSection(ptrI);
break;
+ }
if (keyIsNull)
{
@@ -3336,10 +3584,7 @@ Dbspj::lookup_parent_row(Signal* signal,
*/
jam();
DEBUG("..Ignore impossible KEYREQ");
- if (ptrI != RNIL)
- {
- releaseSection(ptrI);
- }
+ releaseSection(ptrI);
return; // Bailout, KEYREQ would have returned KEYREF(626) anyway
}
else // isLookup()
@@ -3401,7 +3646,33 @@ Dbspj::lookup_parent_row(Signal* signal,
{
jam();
Uint32 tmp = RNIL;
- ndbrequire(dupSection(tmp, attrInfoPtrI)); // TODO handle error
+
+ /**
+ * Test execution terminated due to 'OutOfSectionMemory' which
+ * may happen for different treeNodes in the request:
+ * - 17080: Fail on lookup_parent_row
+ * - 17081: Fail on lookup_parent_row: if 'isLeaf'
+ * - 17082: Fail on lookup_parent_row: if treeNode not root
+ */
+
+ if (ERROR_INSERTED_CLEAR(17080) ||
+ (treeNodePtr.p->isLeaf() && ERROR_INSERTED_CLEAR(17081)) ||
+ (treeNodePtr.p->m_parentPtrI != RNIL && ERROR_INSERTED_CLEAR(17082)))
+ {
+ jam();
+ ndbout_c("Injecting OutOfSectionMemory error at line %d file %s",
+ __LINE__, __FILE__);
+ err = DbspjErr::OutOfSectionMemory;
+ break;
+ }
+
+ if (!dupSection(tmp, attrInfoPtrI))
+ {
+ jam();
+ ndbassert(tmp == RNIL); // Guard for memleak
+ err = DbspjErr::OutOfSectionMemory;
+ break;
+ }
Uint32 org_size;
{
@@ -3415,7 +3686,11 @@ Dbspj::lookup_parent_row(Signal* signal,
Local_pattern_store pattern(pool, treeNodePtr.p->m_attrParamPattern);
err = expand(tmp, pattern, rowRef, hasNull);
if (unlikely(err != 0))
+ {
+ jam();
+ releaseSection(tmp);
break;
+ }
// ndbrequire(!hasNull);
/**
@@ -3471,7 +3746,10 @@ Dbspj::lookup_parent_row(Signal* signal,
return;
} while (0);
- ndbrequire(false);
+ // If we fail it will always be a 'hard error' -> abort
+ ndbrequire(err);
+ jam();
+ abort(signal, requestPtr, err);
}
void
@@ -3691,9 +3969,15 @@ Dbspj::computePartitionHash(Signal* sign
const KeyDescriptor::KeyAttr& keyAttr = desc->keyAttr[i];
if (AttributeDescriptor::getDKey(keyAttr.attributeDescriptor))
{
+ Uint32 attrLen =
xfrm_attr(keyAttr.attributeDescriptor, keyAttr.charsetInfo,
src, srcPos, dst, dstPos,
NDB_ARRAY_SIZE(signal->theData) - 24);
+ if (unlikely(attrLen == 0))
+ {
+ DEBUG_CRASH();
+ return 290; // 'Corrupt key in TC, unable to xfrm'
+ }
}
}
tmp64 = (Uint64*)dst;
@@ -3734,8 +4018,10 @@ Dbspj::getNodes(Signal* signal, BuildKey
jamEntry();
if (unlikely(err != 0))
+ {
+ jam();
goto error;
-
+ }
dst.fragId = conf->fragId;
dst.fragDistKey = (Tdata2 >> 16) & 255;
dst.receiverRef = numberToRef(DBLQH, instanceKey, nodeId);
@@ -3743,10 +4029,6 @@ Dbspj::getNodes(Signal* signal, BuildKey
return 0;
error:
- /**
- * TODO handle error
- */
- ndbrequire(false);
return err;
}
@@ -3799,7 +4081,6 @@ Dbspj::scanFrag_build(Build_context& ctx
if (unlikely(node->len < QN_ScanFragNode::NodeSize))
{
jam();
- DEBUG_CRASH();
break;
}
@@ -3808,20 +4089,32 @@ Dbspj::scanFrag_build(Build_context& ctx
if (unlikely(param->len < QN_ScanFragParameters::NodeSize))
{
jam();
- DEBUG_CRASH();
break;
}
err = createNode(ctx, requestPtr, treeNodePtr);
if (unlikely(err != 0))
+ {
+ jam();
break;
+ }
+ treeNodePtr.p->m_info = &g_ScanFragOpInfo;
treeNodePtr.p->m_scanfrag_data.m_scanFragHandlePtrI = RNIL;
Ptr<ScanFragHandle> scanFragHandlePtr;
+ if (ERROR_INSERTED_CLEAR(17004))
+ {
+ ndbout_c("Injecting OutOfQueryMemory error 17004 at line %d file %s",
+ __LINE__, __FILE__);
+ jam();
+ err = DbspjErr::OutOfQueryMemory;
+ break;
+ }
if (unlikely(m_scanfraghandle_pool.seize(requestPtr.p->m_arena,
scanFragHandlePtr) != true))
{
err = DbspjErr::OutOfQueryMemory;
+ jam();
break;
}
@@ -3830,7 +4123,6 @@ Dbspj::scanFrag_build(Build_context& ctx
treeNodePtr.p->m_scanfrag_data.m_scanFragHandlePtrI = scanFragHandlePtr.i;
requestPtr.p->m_bits |= Request::RT_SCAN;
- treeNodePtr.p->m_info = &g_ScanFragOpInfo;
treeNodePtr.p->m_bits |= TreeNode::T_ATTR_INTERPRETED;
treeNodePtr.p->m_batch_size = ctx.m_batch_size_rows;
@@ -3875,7 +4167,6 @@ Dbspj::scanFrag_build(Build_context& ctx
if (unlikely(err != 0))
{
jam();
- DEBUG_CRASH();
break;
}
@@ -3951,7 +4242,6 @@ Dbspj::scanFrag_build(Build_context& ctx
ndbassert(dst->transId2 == transId2);
#endif
- treeNodePtr.p->m_send.m_keyInfoPtrI = ctx.m_keyPtr.i;
treeNodePtr.p->m_bits |= TreeNode::T_ONE_SHOT;
if (rangeScanFlag)
@@ -3989,9 +4279,6 @@ Dbspj::scanFrag_send(Signal* signal,
{
jam();
- requestPtr.p->m_outstanding++;
- requestPtr.p->m_cnt_active++;
- treeNodePtr.p->m_state = TreeNode::TN_ACTIVE;
Ptr<ScanFragHandle> scanFragHandlePtr;
m_scanfraghandle_pool.getPtr(scanFragHandlePtr, treeNodePtr.p->
m_scanfrag_data.m_scanFragHandlePtrI);
@@ -4053,11 +4340,24 @@ Dbspj::scanFrag_send(Signal* signal,
c_Counters.incr_counter(CI_LOCAL_TABLE_SCANS_SENT, 1);
}
+ if (ERROR_INSERTED_CLEAR(17100))
+ {
+ jam();
+ ndbout_c("Injecting invalid schema version error at line %d file %s",
+ __LINE__, __FILE__);
+ // Provoke 'Invalid schema version' in order to receive SCAN_FRAGREF
+ req->schemaVersion++;
+ }
+
ndbrequire(refToNode(ref) == getOwnNodeId());
sendSignal(ref, GSN_SCAN_FRAGREQ, signal,
NDB_ARRAY_SIZE(treeNodePtr.p->m_scanfrag_data.m_scanFragReq),
JBB, &handle);
+ requestPtr.p->m_outstanding++;
+ requestPtr.p->m_cnt_active++;
+ treeNodePtr.p->m_state = TreeNode::TN_ACTIVE;
+
scanFragHandlePtr.p->m_state = ScanFragHandle::SFH_SCANNING;
treeNodePtr.p->m_scanfrag_data.m_rows_received = 0;
treeNodePtr.p->m_scanfrag_data.m_rows_expecting = ~Uint32(0);
@@ -4072,19 +4372,22 @@ Dbspj::scanFrag_execTRANSID_AI(Signal* s
jam();
treeNodePtr.p->m_scanfrag_data.m_rows_received++;
- LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
- Local_dependency_map list(pool, treeNodePtr.p->m_dependent_nodes);
- Dependency_map::ConstDataBufferIterator it;
-
{
+ LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
+ Local_dependency_map list(pool, treeNodePtr.p->m_dependent_nodes);
+ Dependency_map::ConstDataBufferIterator it;
+
for (list.first(it); !it.isNull(); list.next(it))
{
- jam();
- Ptr<TreeNode> childPtr;
- m_treenode_pool.getPtr(childPtr, * it.data);
- ndbrequire(childPtr.p->m_info != 0&&childPtr.p->m_info->m_parent_row!=0);
- (this->*(childPtr.p->m_info->m_parent_row))(signal,
- requestPtr, childPtr,rowRef);
+ if (likely((requestPtr.p->m_state & Request::RS_ABORTING) == 0))
+ {
+ jam();
+ Ptr<TreeNode> childPtr;
+ m_treenode_pool.getPtr(childPtr, * it.data);
+ ndbrequire(childPtr.p->m_info!=0 && childPtr.p->m_info->m_parent_row!=0);
+ (this->*(childPtr.p->m_info->m_parent_row))(signal,
+ requestPtr, childPtr,rowRef);
+ }
}
}
@@ -4110,6 +4413,8 @@ Dbspj::scanFrag_execSCAN_FRAGREF(Signal*
Ptr<TreeNode> treeNodePtr,
Ptr<ScanFragHandle> scanFragHandlePtr)
{
+ jam();
+
const ScanFragRef* rep =
reinterpret_cast<const ScanFragRef*>(signal->getDataPtr());
Uint32 errCode = rep->errorCode;
@@ -4352,7 +4657,6 @@ Dbspj::scanIndex_build(Build_context& ct
if (unlikely(node->len < QN_ScanIndexNode::NodeSize))
{
jam();
- DEBUG_CRASH();
break;
}
@@ -4361,13 +4665,15 @@ Dbspj::scanIndex_build(Build_context& ct
if (unlikely(param->len < QN_ScanIndexParameters::NodeSize))
{
jam();
- DEBUG_CRASH();
break;
}
err = createNode(ctx, requestPtr, treeNodePtr);
if (unlikely(err != 0))
+ {
+ jam();
break;
+ }
Uint32 batchSize = param->batchSize;
@@ -4425,7 +4731,6 @@ Dbspj::scanIndex_build(Build_context& ct
if (unlikely(err != 0))
{
jam();
- DEBUG_CRASH();
break;
}
@@ -4527,8 +4832,10 @@ Dbspj::parseScanIndex(Build_context& ctx
*/
err = expand(pattern, treeNodePtr, tree, len, origParam, cnt);
if (unlikely(err != 0))
+ {
+ jam();
break;
-
+ }
treeNodePtr.p->m_bits |= TreeNode::T_PRUNE_PATTERN;
c_Counters.incr_counter(CI_PRUNED_RANGE_SCANS_RECEIVED, 1);
}
@@ -4546,13 +4853,18 @@ Dbspj::parseScanIndex(Build_context& ctx
bool hasNull;
err = expand(prunePtrI, tree, len, origParam, cnt, hasNull);
if (unlikely(err != 0))
+ {
+ jam();
+ releaseSection(prunePtrI);
break;
+ }
if (unlikely(hasNull))
{
/* API should have elliminated requests w/ const-NULL keys */
jam();
DEBUG("BEWARE: T_CONST_PRUNE-key contain NULL values");
+ releaseSection(prunePtrI);
// treeNodePtr.p->m_bits |= TreeNode::T_NULL_PRUNE;
// break;
ndbrequire(false);
@@ -4580,7 +4892,7 @@ Dbspj::parseScanIndex(Build_context& ctx
return 0;
} while(0);
- DEBUG_CRASH();
+ jam();
return err;
}
@@ -4632,7 +4944,11 @@ Dbspj::execDIH_SCAN_TAB_CONF(Signal* sig
jam();
ScanFragReq::setReorgFlag(dst->requestInfo, 1);
}
-
+ if (treeNodePtr.p->m_bits & TreeNode::T_CONST_PRUNE)
+ {
+ jam();
+ fragCount = 1;
+ }
data.m_fragCount = fragCount;
data.m_scanCookie = cookie;
@@ -4646,128 +4962,139 @@ Dbspj::execDIH_SCAN_TAB_CONF(Signal* sig
// the same subset of frags fram all SPJ requests in case of
// the scan not being ' T_SCAN_PARALLEL'
Uint16 fragNoOffs = requestPtr.p->m_rootFragId % fragCount;
+ Uint32 err = 0;
- Ptr<ScanFragHandle> fragPtr;
- Local_ScanFragHandle_list list(m_scanfraghandle_pool, data.m_fragments);
- if (likely(m_scanfraghandle_pool.seize(requestPtr.p->m_arena, fragPtr)))
- {
- jam();
- fragPtr.p->init(fragNoOffs);
- fragPtr.p->m_treeNodePtrI = treeNodePtr.i;
- list.addLast(fragPtr);
- }
- else
+ do
{
- jam();
- goto error1;
- }
+ Ptr<ScanFragHandle> fragPtr;
- if (treeNodePtr.p->m_bits & TreeNode::T_CONST_PRUNE)
- {
- jam();
+ /** Allocate & init all 'fragCnt' fragment desriptors */
+ {
+ Local_ScanFragHandle_list list(m_scanfraghandle_pool, data.m_fragments);
- // TODO we need a different variant of computeHash here,
- // since m_constPrunePtrI does not contain full primary key
- // but only parts in distribution key
+ for (Uint32 i = 0; i<fragCount; i++)
+ {
+ jam();
+ Ptr<ScanFragHandle> fragPtr;
+ Uint16 fragNo = (fragNoOffs+i) % fragCount;
- BuildKeyReq tmp;
- Uint32 indexId = dst->tableId;
- Uint32 tableId = g_key_descriptor_pool.getPtr(indexId)->primaryTableId;
- Uint32 err = computePartitionHash(signal, tmp, tableId, data.m_constPrunePtrI);
- if (unlikely(err != 0))
- goto error;
+ if (!ERROR_INSERTED_CLEAR(17012) &&
+ likely(m_scanfraghandle_pool.seize(requestPtr.p->m_arena, fragPtr)))
+ {
+ jam();
+ fragPtr.p->init(fragNo);
+ fragPtr.p->m_treeNodePtrI = treeNodePtr.i;
+ list.addLast(fragPtr);
+ }
+ else
+ {
+ jam();
+ err = DbspjErr::OutOfQueryMemory;
+ goto error;
+ }
+ }
+ list.first(fragPtr); // Needed if T_CONST_PRUNE
+ } // end 'Alloc scope'
- releaseSection(data.m_constPrunePtrI);
- data.m_constPrunePtrI = RNIL;
+ if (treeNodePtr.p->m_bits & TreeNode::T_CONST_PRUNE)
+ {
+ jam();
- err = getNodes(signal, tmp, tableId);
- if (unlikely(err != 0))
- goto error;
+ // TODO we need a different variant of computeHash here,
+ // since m_constPrunePtrI does not contain full primary key
+ // but only parts in distribution key
- fragPtr.p->m_fragId = tmp.fragId;
- fragPtr.p->m_ref = tmp.receiverRef;
- data.m_fragCount = 1;
- }
- else if (fragCount == 1)
- {
- jam();
- /**
- * This is roughly equivalent to T_CONST_PRUNE
- * pretend that it is const-pruned
- */
- if (treeNodePtr.p->m_bits & TreeNode::T_PRUNE_PATTERN)
+ BuildKeyReq tmp;
+ Uint32 indexId = dst->tableId;
+ Uint32 tableId = g_key_descriptor_pool.getPtr(indexId)->primaryTableId;
+ err = computePartitionHash(signal, tmp, tableId, data.m_constPrunePtrI);
+ if (unlikely(err != 0))
+ {
+ jam();
+ break;
+ }
+
+ releaseSection(data.m_constPrunePtrI);
+ data.m_constPrunePtrI = RNIL;
+
+ err = getNodes(signal, tmp, tableId);
+ if (unlikely(err != 0))
+ {
+ jam();
+ break;
+ }
+
+ fragPtr.p->m_fragId = tmp.fragId;
+ fragPtr.p->m_ref = tmp.receiverRef;
+ ndbassert(data.m_fragCount == 1);
+ }
+ else if (fragCount == 1)
{
jam();
- LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
- Local_pattern_store pattern(pool, data.m_prunePattern);
- pattern.release();
+ /**
+ * This is roughly equivalent to T_CONST_PRUNE
+ * pretend that it is const-pruned
+ */
+ if (treeNodePtr.p->m_bits & TreeNode::T_PRUNE_PATTERN)
+ {
+ jam();
+ LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
+ Local_pattern_store pattern(pool, data.m_prunePattern);
+ pattern.release();
+ }
+ data.m_constPrunePtrI = RNIL;
+ Uint32 clear = TreeNode::T_PRUNE_PATTERN | TreeNode::T_SCAN_PARALLEL;
+ treeNodePtr.p->m_bits &= ~clear;
+ treeNodePtr.p->m_bits |= TreeNode::T_CONST_PRUNE;
+
+ /**
+ * We must get fragPtr.p->m_ref...so set pruned=false
+ */
+ pruned = false;
}
- data.m_constPrunePtrI = RNIL;
- Uint32 clear = TreeNode::T_PRUNE_PATTERN | TreeNode::T_SCAN_PARALLEL;
- treeNodePtr.p->m_bits &= ~clear;
- treeNodePtr.p->m_bits |= TreeNode::T_CONST_PRUNE;
+ data.m_frags_complete = data.m_fragCount;
- /**
- * We must get fragPtr.p->m_ref...so set pruned=false
- */
- pruned = false;
- }
- else
- {
- for (Uint32 i = 1; i<fragCount; i++)
+ if (!pruned)
{
jam();
- Ptr<ScanFragHandle> fragPtr;
- Uint16 fragNo = (fragNoOffs+i) % fragCount;
- if (likely(m_scanfraghandle_pool.seize(requestPtr.p->m_arena, fragPtr)))
+ Uint32 tableId = ((ScanFragReq*)data.m_scanFragReq)->tableId;
+ DihScanGetNodesReq * req = (DihScanGetNodesReq*)signal->getDataPtrSend();
+ req->senderRef = reference();
+ req->tableId = tableId;
+ req->scanCookie = cookie;
+
+ Uint32 cnt = 0;
+ Local_ScanFragHandle_list list(m_scanfraghandle_pool, data.m_fragments);
+ for (list.first(fragPtr); !fragPtr.isNull(); list.next(fragPtr))
{
jam();
- fragPtr.p->init(fragNo);
- fragPtr.p->m_treeNodePtrI = treeNodePtr.i;
- list.addLast(fragPtr);
- }
- else
- {
- goto error1;
+ req->senderData = fragPtr.i;
+ req->fragId = fragPtr.p->m_fragId;
+ sendSignal(DBDIH_REF, GSN_DIH_SCAN_GET_NODES_REQ, signal,
+ DihScanGetNodesReq::SignalLength, JBB);
+ cnt++;
}
+ data.m_frags_outstanding = cnt;
+ requestPtr.p->m_outstanding++;
}
- }
- data.m_frags_complete = data.m_fragCount;
-
- if (!pruned)
- {
- jam();
- Uint32 tableId = ((ScanFragReq*)data.m_scanFragReq)->tableId;
- DihScanGetNodesReq * req = (DihScanGetNodesReq*)signal->getDataPtrSend();
- req->senderRef = reference();
- req->tableId = tableId;
- req->scanCookie = cookie;
-
- Uint32 cnt = 0;
- for (list.first(fragPtr); !fragPtr.isNull(); list.next(fragPtr))
+ else
{
jam();
- req->senderData = fragPtr.i;
- req->fragId = fragPtr.p->m_fragId;
- sendSignal(DBDIH_REF, GSN_DIH_SCAN_GET_NODES_REQ, signal,
- DihScanGetNodesReq::SignalLength, JBB);
- cnt++;
+ treeNodePtr.p->m_state = TreeNode::TN_INACTIVE;
}
- data.m_frags_outstanding = cnt;
- requestPtr.p->m_outstanding++;
- }
- else
+ } while (0);
+
+ if (likely(err==0))
{
jam();
- treeNodePtr.p->m_state = TreeNode::TN_INACTIVE;
+ checkPrepareComplete(signal, requestPtr, 1);
+ return;
}
- checkPrepareComplete(signal, requestPtr, 1);
-
- return;
-
-error1:
error:
- ndbrequire(false);
+ ndbrequire(requestPtr.p->isScan());
+ ndbrequire(requestPtr.p->m_outstanding >= 1);
+ requestPtr.p->m_outstanding -= 1;
+ abort(signal, requestPtr, err);
}
void
@@ -4825,7 +5152,7 @@ Dbspj::scanIndex_findFrag(Local_ScanFrag
}
}
- return 99; // TODO
+ return DbspjErr::IndexFragNotFound;
}
void
@@ -4835,6 +5162,8 @@ Dbspj::scanIndex_parent_row(Signal* sign
const RowPtr & rowRef)
{
jam();
+ DEBUG("::scanIndex_parent_row"
+ << ", node: " << treeNodePtr.p->m_node_no);
Uint32 err;
ScanIndexData& data = treeNodePtr.p->m_scanindex_data;
@@ -4864,7 +5193,8 @@ Dbspj::scanIndex_parent_row(Signal* sign
err = expand(pruneKeyPtrI, pattern, rowRef, hasNull);
if (unlikely(err != 0))
{
- DEBUG_CRASH();
+ jam();
+ releaseSection(pruneKeyPtrI);
break;
}
@@ -4874,33 +5204,26 @@ Dbspj::scanIndex_parent_row(Signal* sign
DEBUG("T_PRUNE_PATTERN-key contain NULL values");
// Ignore this request as 'NULL == <column>' will never give a match
- if (pruneKeyPtrI != RNIL)
- {
- releaseSection(pruneKeyPtrI);
- }
+ releaseSection(pruneKeyPtrI);
return; // Bailout, SCANREQ would have returned 0 rows anyway
}
- // TODO we need a different variant of computeHash here,
- // since pruneKeyPtrI does not contain full primary key
- // but only parts in distribution key
-
BuildKeyReq tmp;
ScanFragReq * dst = (ScanFragReq*)data.m_scanFragReq;
Uint32 indexId = dst->tableId;
Uint32 tableId = g_key_descriptor_pool.getPtr(indexId)->primaryTableId;
err = computePartitionHash(signal, tmp, tableId, pruneKeyPtrI);
- releaseSection(pruneKeyPtrI); // see ^ TODO
+ releaseSection(pruneKeyPtrI);
if (unlikely(err != 0))
{
- DEBUG_CRASH();
+ jam();
break;
}
err = getNodes(signal, tmp, tableId);
if (unlikely(err != 0))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -4932,16 +5255,34 @@ Dbspj::scanIndex_parent_row(Signal* sign
list.first(fragPtr);
}
- Uint32 ptrI = fragPtr.p->m_rangePtrI;
bool hasNull;
if (treeNodePtr.p->m_bits & TreeNode::T_KEYINFO_CONSTRUCTED)
{
jam();
Local_pattern_store pattern(pool, treeNodePtr.p->m_keyPattern);
- err = expand(ptrI, pattern, rowRef, hasNull);
+
+ /**
+ * Test execution terminated due to 'OutOfSectionMemory':
+ * - 17060: Fail on scanIndex_parent_row at first call
+ * - 17061: Fail on scanIndex_parent_row if 'isLeaf'
+ * - 17062: Fail on scanIndex_parent_row if treeNode not root
+ * - 17063: Fail on scanIndex_parent_row at a random node of the query tree
+ */
+ if (ERROR_INSERTED_CLEAR(17060) ||
+ ((rand() % 7) == 0 && ERROR_INSERTED_CLEAR(17061)) ||
+ ((treeNodePtr.p->isLeaf() && ERROR_INSERTED_CLEAR(17062))) ||
+ ((treeNodePtr.p->m_parentPtrI != RNIL && ERROR_INSERTED_CLEAR(17063))))
+ {
+ ndbout_c("Injecting OutOfSectionMemory error at line %d file %s",
+ __LINE__, __FILE__);
+ err = DbspjErr::OutOfSectionMemory;
+ break;
+ }
+
+ err = expand(fragPtr.p->m_rangePtrI, pattern, rowRef, hasNull);
if (unlikely(err != 0))
{
- DEBUG_CRASH();
+ jam();
break;
}
}
@@ -4952,8 +5293,7 @@ Dbspj::scanIndex_parent_row(Signal* sign
ndbrequire(false);
}
// ndbrequire(!hasNull); // FIXME, can't ignore request as we already added it to keyPattern
- fragPtr.p->m_rangePtrI = ptrI;
- scanIndex_fixupBound(fragPtr, ptrI, rowRef.m_src_correlation);
+ scanIndex_fixupBound(fragPtr, fragPtr.p->m_rangePtrI, rowRef.m_src_correlation);
if (treeNodePtr.p->m_bits & TreeNode::T_ONE_SHOT)
{
@@ -4968,7 +5308,9 @@ Dbspj::scanIndex_parent_row(Signal* sign
return;
} while (0);
- ndbrequire(false);
+ ndbrequire(err);
+ jam();
+ abort(signal, requestPtr, err);
}
@@ -5132,7 +5474,7 @@ Dbspj::scanIndex_parent_batch_complete(S
data.m_parallelism = static_cast<Uint32>(parallelism);
#ifdef DEBUG_SCAN_FRAGREQ
- DEBUG("::scanIndex_send() starting index scan with parallelism="
+ DEBUG("::scanIndex_parent_batch_complete() starting index scan with parallelism="
<< data.m_parallelism);
#endif
}
@@ -5163,24 +5505,34 @@ Dbspj::scanIndex_parent_batch_complete(S
}
Uint32 batchRange = 0;
- scanIndex_send(signal,
- requestPtr,
- treeNodePtr,
- data.m_parallelism,
- bs_bytes,
- bs_rows,
- batchRange);
-
- data.m_firstExecution = false;
-
- ndbrequire(static_cast<Uint32>(data.m_frags_outstanding +
- data.m_frags_complete) <=
- data.m_fragCount);
+ Uint32 frags_started =
+ scanIndex_send(signal,
+ requestPtr,
+ treeNodePtr,
+ data.m_parallelism,
+ bs_bytes,
+ bs_rows,
+ batchRange);
- data.m_batch_chunks = 1;
- requestPtr.p->m_cnt_active++;
- requestPtr.p->m_outstanding++;
- treeNodePtr.p->m_state = TreeNode::TN_ACTIVE;
+ /**
+ * scanIndex_send might fail to send (errors?):
+ * Check that we really did send something before
+ * updating outstanding & active.
+ */
+ if (likely(frags_started > 0))
+ {
+ jam();
+ data.m_firstExecution = false;
+
+ ndbrequire(static_cast<Uint32>(data.m_frags_outstanding +
+ data.m_frags_complete) <=
+ data.m_fragCount);
+
+ data.m_batch_chunks = 1;
+ requestPtr.p->m_cnt_active++;
+ requestPtr.p->m_outstanding++;
+ treeNodePtr.p->m_state = TreeNode::TN_ACTIVE;
+ }
}
void
@@ -5212,8 +5564,11 @@ Dbspj::scanIndex_parent_batch_repeat(Sig
/**
* Ask for the first batch for a number of fragments.
+ *
+ * Returns how many fragments we did request the
+ * 'first batch' from. (<= noOfFrags)
*/
-void
+Uint32
Dbspj::scanIndex_send(Signal* signal,
Ptr<Request> requestPtr,
Ptr<TreeNode> treeNodePtr,
@@ -5254,147 +5609,206 @@ Dbspj::scanIndex_send(Signal* signal,
req->batch_size_bytes = bs_bytes;
req->batch_size_rows = bs_rows;
+ Uint32 err = 0;
Uint32 requestsSent = 0;
- Local_ScanFragHandle_list list(m_scanfraghandle_pool, data.m_fragments);
- Ptr<ScanFragHandle> fragPtr;
- list.first(fragPtr);
- Uint32 keyInfoPtrI = fragPtr.p->m_rangePtrI;
- ndbrequire(prune || keyInfoPtrI != RNIL);
- /**
- * Iterate over the list of fragments until we have sent as many
- * SCAN_FRAGREQs as we should.
- */
- while (requestsSent < noOfFrags)
{
- jam();
- ndbassert(!fragPtr.isNull());
-
- if (fragPtr.p->m_state != ScanFragHandle::SFH_NOT_STARTED)
+ Local_ScanFragHandle_list list(m_scanfraghandle_pool, data.m_fragments);
+ Ptr<ScanFragHandle> fragPtr;
+ list.first(fragPtr);
+ Uint32 keyInfoPtrI = fragPtr.p->m_rangePtrI;
+ ndbrequire(prune || keyInfoPtrI != RNIL);
+ /**
+ * Iterate over the list of fragments until we have sent as many
+ * SCAN_FRAGREQs as we should.
+ */
+ while (requestsSent < noOfFrags)
{
- // Skip forward to the frags that we should send.
jam();
- list.next(fragPtr);
- continue;
- }
+ ndbassert(!fragPtr.isNull());
- const Uint32 ref = fragPtr.p->m_ref;
+ if (fragPtr.p->m_state != ScanFragHandle::SFH_NOT_STARTED)
+ {
+ // Skip forward to the frags that we should send.
+ jam();
+ list.next(fragPtr);
+ continue;
+ }
+
+ const Uint32 ref = fragPtr.p->m_ref;
+
+ if (noOfFrags==1 && !prune &&
+ data.m_frags_not_started == data.m_fragCount &&
+ refToNode(ref) != getOwnNodeId() &&
+ list.hasNext(fragPtr))
+ {
+ /**
+ * If we are doing a scan with adaptive parallelism and start with
+ * parallelism=1 then it makes sense to fetch a batch from a fragment on
+ * the local data node. The reason for this is that if that fragment
+ * contains few rows, we may be able to read from several fragments in
+ * parallel. Then we minimize the total number of round trips (to remote
+ * data nodes) if we fetch the first fragment batch locally.
+ */
+ jam();
+ list.next(fragPtr);
+ continue;
+ }
+
+ SectionHandle handle(this);
+
+ Uint32 attrInfoPtrI = treeNodePtr.p->m_send.m_attrInfoPtrI;
- if (noOfFrags==1 && !prune &&
- data.m_frags_not_started == data.m_fragCount &&
- refToNode(ref) != getOwnNodeId() &&
- list.hasNext(fragPtr))
- {
/**
- * If we are doing a scan with adaptive parallelism and start with
- * parallelism=1 then it makes sense to fetch a batch from a fragment on
- * the local data node. The reason for this is that if that fragment
- * contains few rows, we may be able to read from several fragments in
- * parallel. Then we minimize the total number of round trips (to remote
- * data nodes) if we fetch the first fragment batch locally.
+ * Set data specific for this fragment
*/
- jam();
- list.next(fragPtr);
- continue;
- }
+ req->senderData = fragPtr.i;
+ req->fragmentNoKeyLen = fragPtr.p->m_fragId;
- SectionHandle handle(this);
+ // Test for online downgrade.
+ if (unlikely(ref != 0 &&
+ !ndb_join_pushdown(getNodeInfo(refToNode(ref)).m_version)))
+ {
+ jam();
+ err = 4003; // Function not implemented.
+ break;
+ }
- Uint32 attrInfoPtrI = treeNodePtr.p->m_send.m_attrInfoPtrI;
+ if (prune)
+ {
+ jam();
+ keyInfoPtrI = fragPtr.p->m_rangePtrI;
+ if (keyInfoPtrI == RNIL)
+ {
+ /**
+ * Since we use pruning, we can see that no parent rows would hash
+ * to this fragment.
+ */
+ jam();
+ fragPtr.p->m_state = ScanFragHandle::SFH_COMPLETE;
+ list.next(fragPtr);
+ continue;
+ }
- /**
- * Set data specific for this fragment
- */
- req->senderData = fragPtr.i;
- req->fragmentNoKeyLen = fragPtr.p->m_fragId;
+ if (!repeatable)
+ {
+ /**
+ * If we'll use sendSignal() and we need to send the attrInfo several
+ * times, we need to copy them. (For repeatable or unpruned scans
+ * we use sendSignalNoRelease(), so then we do not need to copy.)
+ */
+ jam();
+ Uint32 tmp = RNIL;
- if (prune)
- {
- jam();
- keyInfoPtrI = fragPtr.p->m_rangePtrI;
- if (keyInfoPtrI == RNIL)
+ /**
+ * Test execution terminated due to 'OutOfSectionMemory' which
+ * may happen for different treeNodes in the request:
+ * - 17090: Fail on any scanIndex_send()
+ * - 17091: Fail after sending SCAN_FRAGREQ to some fragments
+ * - 17092: Fail on scanIndex_send() if 'isLeaf'
+ * - 17093: Fail on scanIndex_send() if treeNode not root
+ */
+
+ if (ERROR_INSERTED_CLEAR(17090) ||
+ (requestsSent > 1 && ERROR_INSERTED_CLEAR(17091)) ||
+ (treeNodePtr.p->isLeaf() && ERROR_INSERTED_CLEAR(17092)) ||
+ (treeNodePtr.p->m_parentPtrI != RNIL && ERROR_INSERTED_CLEAR(17093)))
+ {
+ jam();
+ ndbout_c("Injecting OutOfSectionMemory error at line %d file %s",
+ __LINE__, __FILE__);
+ err = DbspjErr::OutOfSectionMemory;
+ break;
+ }
+
+ if (!dupSection(tmp, attrInfoPtrI))
+ {
+ jam();
+ ndbassert(tmp == RNIL); // Guard for memleak
+ err = DbspjErr::OutOfSectionMemory;
+ break;
+ }
+
+ attrInfoPtrI = tmp;
+ }
+ }
+
+ req->variableData[0] = batchRange;
+ getSection(handle.m_ptr[0], attrInfoPtrI);
+ getSection(handle.m_ptr[1], keyInfoPtrI);
+ handle.m_cnt = 2;
+
+#if defined DEBUG_SCAN_FRAGREQ
+ ndbout_c("SCAN_FRAGREQ to %x", ref);
+ printSCAN_FRAGREQ(stdout, signal->getDataPtrSend(),
+ NDB_ARRAY_SIZE(treeNodePtr.p->m_scanfrag_data.m_scanFragReq),
+ DBLQH);
+ printf("ATTRINFO: ");
+ print(handle.m_ptr[0], stdout);
+ printf("KEYINFO: ");
+ print(handle.m_ptr[1], stdout);
+#endif
+
+ if (refToNode(ref) == getOwnNodeId())
+ {
+ c_Counters.incr_counter(CI_LOCAL_RANGE_SCANS_SENT, 1);
+ }
+ else
+ {
+ c_Counters.incr_counter(CI_REMOTE_RANGE_SCANS_SENT, 1);
+ }
+
+ if (prune && !repeatable)
{
/**
- * Since we use pruning, we can see that no parent rows would hash
- * to this fragment.
+ * For a non-repeatable pruned scan, key info is unique for each
+ * fragment and therefore cannot be reused, so we release key info
+ * right away.
*/
jam();
- fragPtr.p->m_state = ScanFragHandle::SFH_COMPLETE;
- list.next(fragPtr);
- continue;
- }
- if (!repeatable)
+ if (ERROR_INSERTED_CLEAR(17110) ||
+ (treeNodePtr.p->isLeaf() && ERROR_INSERTED_CLEAR(17111)) ||
+ (treeNodePtr.p->m_parentPtrI != RNIL && ERROR_INSERTED_CLEAR(17112)))
+ {
+ jam();
+ ndbout_c("Injecting invalid schema version error at line %d file %s",
+ __LINE__, __FILE__);
+ // Provoke 'Invalid schema version' in order to receive SCAN_FRAGREF
+ req->schemaVersion++;
+ }
+
+ sendSignal(ref, GSN_SCAN_FRAGREQ, signal,
+ NDB_ARRAY_SIZE(data.m_scanFragReq), JBB, &handle);
+ fragPtr.p->m_rangePtrI = RNIL;
+ fragPtr.p->reset_ranges();
+ }
+ else
{
/**
- * If we'll use sendSignal() and we need to send the attrInfo several
- * times, we need to copy them. (For repeatable or unpruned scans
- * we use sendSignalNoRelease(), so then we do not need to copy.)
+ * Reuse key info for multiple fragments and/or multiple repetitions
+ * of the scan.
*/
jam();
- Uint32 tmp = RNIL;
- ndbrequire(dupSection(tmp, attrInfoPtrI)); // TODO handle error
- attrInfoPtrI = tmp;
+ sendSignalNoRelease(ref, GSN_SCAN_FRAGREQ, signal,
+ NDB_ARRAY_SIZE(data.m_scanFragReq), JBB, &handle);
}
- }
-
- req->variableData[0] = batchRange;
- getSection(handle.m_ptr[0], attrInfoPtrI);
- getSection(handle.m_ptr[1], keyInfoPtrI);
- handle.m_cnt = 2;
-
-#if defined DEBUG_SCAN_FRAGREQ
- ndbout_c("SCAN_FRAGREQ to %x", ref);
- printSCAN_FRAGREQ(stdout, signal->getDataPtrSend(),
- NDB_ARRAY_SIZE(treeNodePtr.p->m_scanfrag_data.m_scanFragReq),
- DBLQH);
- printf("ATTRINFO: ");
- print(handle.m_ptr[0], stdout);
- printf("KEYINFO: ");
- print(handle.m_ptr[1], stdout);
-#endif
-
- if (refToNode(ref) == getOwnNodeId())
- {
- c_Counters.incr_counter(CI_LOCAL_RANGE_SCANS_SENT, 1);
- }
- else
- {
- c_Counters.incr_counter(CI_REMOTE_RANGE_SCANS_SENT, 1);
- }
-
- if (prune && !repeatable)
- {
- /**
- * For a non-repeatable pruned scan, key info is unique for each
- * fragment and therefore cannot be reused, so we release key info
- * right away.
- */
- jam();
- sendSignal(ref, GSN_SCAN_FRAGREQ, signal,
- NDB_ARRAY_SIZE(data.m_scanFragReq), JBB, &handle);
- fragPtr.p->m_rangePtrI = RNIL;
- fragPtr.p->reset_ranges();
- }
- else
- {
- /**
- * Reuse key info for multiple fragments and/or multiple repetitions
- * of the scan.
- */
- jam();
- sendSignalNoRelease(ref, GSN_SCAN_FRAGREQ, signal,
- NDB_ARRAY_SIZE(data.m_scanFragReq), JBB, &handle);
- }
- handle.clear();
+ handle.clear();
- fragPtr.p->m_state = ScanFragHandle::SFH_SCANNING; // running
- data.m_frags_outstanding++;
- batchRange += bs_rows;
- requestsSent++;
- list.next(fragPtr);
- } // while (requestsSent < noOfFrags)
+ fragPtr.p->m_state = ScanFragHandle::SFH_SCANNING; // running
+ data.m_frags_outstanding++;
+ data.m_frags_not_started--;
+ batchRange += bs_rows;
+ requestsSent++;
+ list.next(fragPtr);
+ } // while (requestsSent < noOfFrags)
+ }
+ if (err)
+ {
+ jam();
+ abort(signal, requestPtr, err);
+ }
- data.m_frags_not_started -= requestsSent;
+ return requestsSent;
}
void
@@ -5405,19 +5819,22 @@ Dbspj::scanIndex_execTRANSID_AI(Signal*
{
jam();
- LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
- Local_dependency_map list(pool, treeNodePtr.p->m_dependent_nodes);
- Dependency_map::ConstDataBufferIterator it;
-
{
+ LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
+ Local_dependency_map list(pool, treeNodePtr.p->m_dependent_nodes);
+ Dependency_map::ConstDataBufferIterator it;
+
for (list.first(it); !it.isNull(); list.next(it))
{
- jam();
- Ptr<TreeNode> childPtr;
- m_treenode_pool.getPtr(childPtr, * it.data);
- ndbrequire(childPtr.p->m_info != 0&&childPtr.p->m_info->m_parent_row!=0);
- (this->*(childPtr.p->m_info->m_parent_row))(signal,
- requestPtr, childPtr,rowRef);
+ if (likely((requestPtr.p->m_state & Request::RS_ABORTING) == 0))
+ {
+ jam();
+ Ptr<TreeNode> childPtr;
+ m_treenode_pool.getPtr(childPtr, * it.data);
+ ndbrequire(childPtr.p->m_info != 0&&childPtr.p->m_info->m_parent_row!=0);
+ (this->*(childPtr.p->m_info->m_parent_row))(signal,
+ requestPtr, childPtr,rowRef);
+ }
}
}
@@ -5598,16 +6015,23 @@ Dbspj::scanIndex_execSCAN_FRAGCONF(Signa
if (unlikely(bs_rows > bs_bytes))
bs_rows = bs_bytes;
- scanIndex_send(signal,
- requestPtr,
- treeNodePtr,
- data.m_frags_not_started,
- bs_bytes,
- bs_rows,
- batchRange);
- return;
+ Uint32 frags_started =
+ scanIndex_send(signal,
+ requestPtr,
+ treeNodePtr,
+ data.m_frags_not_started,
+ bs_bytes,
+ bs_rows,
+ batchRange);
+
+ if (likely(frags_started > 0))
+ return;
+
+ // Else: scanIndex_send() didn't send anything for some reason.
+ // Need to continue into 'completion detection' below.
+ jam();
}
- }
+ } // (data.m_frags_outstanding == 0)
if (data.m_rows_received != data.m_rows_expecting)
{
@@ -5765,43 +6189,44 @@ Dbspj::scanIndex_execSCAN_NEXTREQ(Signal
/**
* First, ask for more data from fragments that are already started.
*/
- Local_ScanFragHandle_list list(m_scanfraghandle_pool, data.m_fragments);
- list.first(fragPtr);
+ Local_ScanFragHandle_list list(m_scanfraghandle_pool, data.m_fragments);
+ list.first(fragPtr);
while (sentFragCount < data.m_parallelism && !fragPtr.isNull())
- {
- jam();
+ {
+ jam();
ndbassert(fragPtr.p->m_state == ScanFragHandle::SFH_WAIT_NEXTREQ ||
fragPtr.p->m_state == ScanFragHandle::SFH_COMPLETE ||
fragPtr.p->m_state == ScanFragHandle::SFH_NOT_STARTED);
- if (fragPtr.p->m_state == ScanFragHandle::SFH_WAIT_NEXTREQ)
- {
- jam();
+ if (fragPtr.p->m_state == ScanFragHandle::SFH_WAIT_NEXTREQ)
+ {
+ jam();
- data.m_frags_outstanding++;
- req->variableData[0] = batchRange;
- fragPtr.p->m_state = ScanFragHandle::SFH_SCANNING;
- batchRange += bs_rows;
+ data.m_frags_outstanding++;
+ req->variableData[0] = batchRange;
+ fragPtr.p->m_state = ScanFragHandle::SFH_SCANNING;
+ batchRange += bs_rows;
- DEBUG("scanIndex_execSCAN_NEXTREQ to: " << hex
- << treeNodePtr.p->m_send.m_ref
- << ", m_node_no=" << treeNodePtr.p->m_node_no
- << ", senderData: " << req->senderData);
+ DEBUG("scanIndex_execSCAN_NEXTREQ to: " << hex
+ << treeNodePtr.p->m_send.m_ref
+ << ", m_node_no=" << treeNodePtr.p->m_node_no
+ << ", senderData: " << req->senderData);
#ifdef DEBUG_SCAN_FRAGREQ
- printSCANFRAGNEXTREQ(stdout, &signal->theData[0],
- ScanFragNextReq:: SignalLength + 1, DBLQH);
+ printSCANFRAGNEXTREQ(stdout, &signal->theData[0],
+ ScanFragNextReq:: SignalLength + 1, DBLQH);
#endif
- req->senderData = fragPtr.i;
- sendSignal(fragPtr.p->m_ref, GSN_SCAN_NEXTREQ, signal,
- ScanFragNextReq::SignalLength + 1,
- JBB);
+ req->senderData = fragPtr.i;
+ sendSignal(fragPtr.p->m_ref, GSN_SCAN_NEXTREQ, signal,
+ ScanFragNextReq::SignalLength + 1,
+ JBB);
sentFragCount++;
}
list.next(fragPtr);
}
}
+ Uint32 frags_started = 0;
if (sentFragCount < data.m_parallelism)
{
/**
@@ -5809,25 +6234,29 @@ Dbspj::scanIndex_execSCAN_NEXTREQ(Signal
*/
jam();
ndbassert(data.m_frags_not_started != 0);
- scanIndex_send(signal,
- requestPtr,
- treeNodePtr,
- data.m_parallelism - sentFragCount,
- org->batch_size_bytes/data.m_parallelism,
- bs_rows,
- batchRange);
+ frags_started =
+ scanIndex_send(signal,
+ requestPtr,
+ treeNodePtr,
+ data.m_parallelism - sentFragCount,
+ org->batch_size_bytes/data.m_parallelism,
+ bs_rows,
+ batchRange);
}
/**
- * cursor should not have been positioned here...
- * unless we actually had something more to send.
- * so require that we did actually send something
+ * sendSignal() or scanIndex_send() might have failed to send:
+ * Check that we really did send something before
+ * updating outstanding & active.
*/
- ndbrequire(data.m_frags_outstanding > 0);
- ndbrequire(data.m_batch_chunks > 0);
- data.m_batch_chunks++;
+ if (likely(sentFragCount+frags_started > 0))
+ {
+ jam();
+ ndbrequire(data.m_batch_chunks > 0);
+ data.m_batch_chunks++;
- requestPtr.p->m_outstanding++;
- ndbassert(treeNodePtr.p->m_state == TreeNode::TN_ACTIVE);
+ requestPtr.p->m_outstanding++;
+ ndbassert(treeNodePtr.p->m_state == TreeNode::TN_ACTIVE);
+ }
}
void
@@ -6062,7 +6491,8 @@ Dbspj::scanIndex_release_rangekeys(Ptr<R
else
{
jam();
- list.first(fragPtr);
+ if (!list.first(fragPtr))
+ return;
if (fragPtr.p->m_rangePtrI != RNIL)
{
releaseSection(fragPtr.p->m_rangePtrI);
@@ -6251,8 +6681,15 @@ Dbspj::appendToPattern(Local_pattern_sto
if (unlikely(tree.ptr + len > tree.end))
return DbspjErr::InvalidTreeNodeSpecification;
+ if (ERROR_INSERTED_CLEAR(17008))
+ {
+ ndbout_c("Injecting OutOfQueryMemory error 17008 at line %d file %s",
+ __LINE__, __FILE__);
+ jam();
+ return DbspjErr::OutOfQueryMemory;
+ }
if (unlikely(pattern.append(tree.ptr, len)==0))
- return DbspjErr::OutOfQueryMemory;
+ return DbspjErr::OutOfQueryMemory;
tree.ptr += len;
return 0;
@@ -6263,30 +6700,62 @@ Dbspj::appendParamToPattern(Local_patter
const RowPtr::Linear & row, Uint32 col)
{
jam();
- /**
- * TODO handle errors
- */
Uint32 offset = row.m_header->m_offset[col];
const Uint32 * ptr = row.m_data + offset;
Uint32 len = AttributeHeader::getDataSize(* ptr ++);
/* Param COL's converted to DATA when appended to pattern */
Uint32 info = QueryPattern::data(len);
+
+ if (ERROR_INSERTED_CLEAR(17009))
+ {
+ ndbout_c("Injecting OutOfQueryMemory error 17009 at line %d file %s",
+ __LINE__, __FILE__);
+ jam();
+ return DbspjErr::OutOfQueryMemory;
+ }
+
return dst.append(&info,1) && dst.append(ptr,len) ? 0 : DbspjErr::OutOfQueryMemory;
}
+#ifdef ERROR_INSERT
+static int fi_cnt = 0;
+bool
+Dbspj::appendToSection(Uint32& firstSegmentIVal,
+ const Uint32* src, Uint32 len)
+{
+ if (fi_cnt++ % 13 == 0 && ERROR_INSERTED(17510))
+ {
+ jam();
+ ndbout_c("Injecting appendToSection error 17510 at line %d file %s",
+ __LINE__, __FILE__);
+ return false;
+ }
+ else
+ {
+ return SimulatedBlock::appendToSection(firstSegmentIVal, src, len);
+ }
+}
+#endif
+
Uint32
Dbspj::appendParamHeadToPattern(Local_pattern_store& dst,
const RowPtr::Linear & row, Uint32 col)
{
jam();
- /**
- * TODO handle errors
- */
Uint32 offset = row.m_header->m_offset[col];
const Uint32 * ptr = row.m_data + offset;
Uint32 len = AttributeHeader::getDataSize(*ptr);
/* Param COL's converted to DATA when appended to pattern */
Uint32 info = QueryPattern::data(len+1);
+
+ if (ERROR_INSERTED_CLEAR(17010))
+ {
+ ndbout_c("Injecting OutOfQueryMemory error 17010 at line %d file %s",
+ __LINE__, __FILE__);
+ jam();
+ return DbspjErr::OutOfQueryMemory;
+ }
+
return dst.append(&info,1) && dst.append(ptr,len+1) ? 0 : DbspjErr::OutOfQueryMemory;
}
@@ -6303,16 +6772,16 @@ Dbspj::appendTreeToSection(Uint32 & ptrI
{
jam();
tree.getWords(tmp, SZ);
- ndbrequire(appendToSection(ptrI, tmp, SZ));
+ if (!appendToSection(ptrI, tmp, SZ))
+ return DbspjErr::OutOfSectionMemory;
len -= SZ;
}
tree.getWords(tmp, len);
- return appendToSection(ptrI, tmp, len) ? 0 : /** todo error code */ 1;
-#if TODO
-err:
- return 1;
-#endif
+ if (!appendToSection(ptrI, tmp, len))
+ return DbspjErr::OutOfSectionMemory;
+
+ return 0;
}
void
@@ -6380,9 +6849,6 @@ Dbspj::appendColToSection(Uint32 & dst,
Uint32 col, bool& hasNull)
{
jam();
- /**
- * TODO handle errors
- */
Uint32 offset = row.m_header->m_offset[col];
const Uint32 * ptr = row.m_data + offset;
Uint32 len = AttributeHeader::getDataSize(* ptr ++);
@@ -6392,7 +6858,7 @@ Dbspj::appendColToSection(Uint32 & dst,
hasNull = true; // NULL-value in key
return 0;
}
- return appendToSection(dst, ptr, len) ? 0 : DbspjErr::InvalidPattern;
+ return appendToSection(dst, ptr, len) ? 0 : DbspjErr::OutOfSectionMemory;
}
Uint32
@@ -6400,9 +6866,6 @@ Dbspj::appendAttrinfoToSection(Uint32 &
Uint32 col, bool& hasNull)
{
jam();
- /**
- * TODO handle errors
- */
Uint32 offset = row.m_header->m_offset[col];
const Uint32 * ptr = row.m_data + offset;
Uint32 len = AttributeHeader::getDataSize(* ptr);
@@ -6411,7 +6874,7 @@ Dbspj::appendAttrinfoToSection(Uint32 &
jam();
hasNull = true; // NULL-value in key
}
- return appendToSection(dst, ptr, 1 + len) ? 0 : DbspjErr::InvalidPattern;
+ return appendToSection(dst, ptr, 1 + len) ? 0 : DbspjErr::OutOfSectionMemory;
}
Uint32
@@ -6472,7 +6935,7 @@ Dbspj::appendPkColToSection(Uint32 & dst
Uint32 tmp = row.m_data[offset];
Uint32 len = AttributeHeader::getDataSize(tmp);
ndbrequire(len>1); // NULL-value in PkKey is an error
- return appendToSection(dst, row.m_data+offset+2, len - 1) ? 0 : /** todo error code */ 1;
+ return appendToSection(dst, row.m_data+offset+2, len - 1) ? 0 : DbspjErr::OutOfSectionMemory;
}
Uint32
@@ -6486,6 +6949,8 @@ Dbspj::appendFromParent(Uint32 & dst, Lo
m_treenode_pool.getPtr(treeNodePtr, rowptr.m_src_node_ptrI);
Uint32 corrVal = rowptr.m_src_correlation;
RowPtr targetRow;
+ DEBUG("appendFromParent-of"
+ << " node: " << treeNodePtr.p->m_node_no);
while (levels--)
{
jam();
@@ -6495,6 +6960,8 @@ Dbspj::appendFromParent(Uint32 & dst, Lo
return DbspjErr::InvalidPattern;
}
m_treenode_pool.getPtr(treeNodePtr, treeNodePtr.p->m_parentPtrI);
+ DEBUG("appendFromParent"
+ << ", node: " << treeNodePtr.p->m_node_no);
if (unlikely((treeNodePtr.p->m_bits & TreeNode::T_ROW_BUFFER_MAP) == 0))
{
DEBUG_CRASH();
@@ -6562,32 +7029,33 @@ Dbspj::appendFromParent(Uint32 & dst, Lo
case QueryPattern::P_COL:
jam();
return appendColToSection(dst, targetRow.m_row_data.m_linear, val, hasNull);
- break;
case QueryPattern::P_UNQ_PK:
jam();
return appendPkColToSection(dst, targetRow.m_row_data.m_linear, val);
- break;
case QueryPattern::P_ATTRINFO:
jam();
return appendAttrinfoToSection(dst, targetRow.m_row_data.m_linear, val, hasNull);
- break;
case QueryPattern::P_DATA:
jam();
// retreiving DATA from parent...is...an error
- break;
+ DEBUG_CRASH();
+ return DbspjErr::InvalidPattern;
case QueryPattern::P_PARENT:
jam();
// no point in nesting P_PARENT...an error
- break;
+ DEBUG_CRASH();
+ return DbspjErr::InvalidPattern;
case QueryPattern::P_PARAM:
case QueryPattern::P_PARAM_HEADER:
jam();
// should have been expanded during build
- break;
+ DEBUG_CRASH();
+ return DbspjErr::InvalidPattern;
+ default:
+ jam();
+ DEBUG_CRASH();
+ return DbspjErr::InvalidPattern;
}
-
- DEBUG_CRASH();
- return DbspjErr::InvalidPattern;
}
Uint32
@@ -6634,8 +7102,8 @@ Dbspj::appendDataToSection(Uint32 & ptrI
{
if (!appendToSection(ptrI, tmp, dstIdx))
{
- DEBUG_CRASH();
- return DbspjErr::InvalidPattern;
+ jam();
+ return DbspjErr::OutOfSectionMemory;
}
dstIdx = 0;
}
@@ -6721,16 +7189,13 @@ Dbspj::expandS(Uint32 & _dst, Local_patt
if (unlikely(err != 0))
{
jam();
- DEBUG_CRASH();
- goto error;
+ _dst = dst;
+ return err;
}
}
_dst = dst;
return 0;
-error:
- jam();
- return err;
}
/**
@@ -6786,18 +7251,16 @@ Dbspj::expandL(Uint32 & _dst, Local_patt
if (unlikely(err != 0))
{
jam();
- DEBUG_CRASH();
- goto error;
+ _dst = dst;
+ return err;
}
}
_dst = dst;
return 0;
-error:
- jam();
- return err;
}
+/* ::expand() used during initial 'build' phase on 'tree' + 'param' from API */
Uint32
Dbspj::expand(Uint32 & ptrI, DABuffer& pattern, Uint32 len,
DABuffer& param, Uint32 paramCnt, bool& hasNull)
@@ -6806,7 +7269,7 @@ Dbspj::expand(Uint32 & ptrI, DABuffer& p
/**
* TODO handle error
*/
- Uint32 err;
+ Uint32 err = 0;
Uint32 tmp[1+MAX_ATTRIBUTES_IN_TABLE];
struct RowPtr::Linear row;
row.m_data = param.ptr;
@@ -6839,19 +7302,17 @@ Dbspj::expand(Uint32 & ptrI, DABuffer& p
{
jam();
hasNull = true;
- err = 0;
}
else if (likely(appendToSection(dst, ptr, val)))
{
jam();
- err = 0;
+ ptr += val;
}
else
{
jam();
- err = DbspjErr::InvalidPattern;
+ err = DbspjErr::OutOfSectionMemory;
}
- ptr += val;
break;
case QueryPattern::P_COL: // (linked) COL's not expected here
case QueryPattern::P_PARENT: // Prefix to P_COL
@@ -6861,13 +7322,12 @@ Dbspj::expand(Uint32 & ptrI, DABuffer& p
jam();
jamLine(type);
err = DbspjErr::InvalidPattern;
- DEBUG_CRASH();
}
if (unlikely(err != 0))
{
jam();
- DEBUG_CRASH();
- goto error;
+ ptrI = dst;
+ return err;
}
}
@@ -6875,13 +7335,11 @@ Dbspj::expand(Uint32 & ptrI, DABuffer& p
* Iterate forward
*/
pattern.ptr = end;
-
-error:
- jam();
ptrI = dst;
- return err;
+ return 0;
}
+/* ::expand() used during initial 'build' phase on 'tree' + 'param' from API */
Uint32
Dbspj::expand(Local_pattern_store& dst, Ptr<TreeNode> treeNodePtr,
DABuffer& pattern, Uint32 len,
@@ -6933,7 +7391,11 @@ Dbspj::expand(Local_pattern_store& dst,
{
jam();
err = appendToPattern(dst, pattern, 1);
-
+ if (unlikely(err))
+ {
+ jam();
+ break;
+ }
// Locate requested grandparent and request it to
// T_ROW_BUFFER its result rows
Ptr<TreeNode> parentPtr;
@@ -6952,22 +7414,17 @@ Dbspj::expand(Local_pattern_store& dst,
break;
}
default:
- jam();
err = DbspjErr::InvalidPattern;
- DEBUG_CRASH();
+ jam();
}
if (unlikely(err != 0))
{
- DEBUG_CRASH();
- goto error;
+ jam();
+ return err;
}
}
return 0;
-
-error:
- jam();
- return err;
}
Uint32
@@ -6983,6 +7440,26 @@ Dbspj::parseDA(Build_context& ctx,
do
{
+ /**
+ * Test execution terminated due to 'OutOfSectionMemory' which
+ * may happen multiple places (eg. appendtosection, expand) below:
+ * - 17050: Fail on parseDA at first call
+ * - 17051: Fail on parseDA if 'isLeaf'
+ * - 17052: Fail on parseDA if treeNode not root
+ * - 17053: Fail on parseDA at a random node of the query tree
+ */
+ if (ERROR_INSERTED_CLEAR(17050) ||
+ ((treeNodePtr.p->isLeaf() && ERROR_INSERTED_CLEAR(17051))) ||
+ ((treeNodePtr.p->m_parentPtrI != RNIL && ERROR_INSERTED_CLEAR(17052)))||
+ ((rand() % 7) == 0 && ERROR_INSERTED_CLEAR(17053)))
+ {
+ ndbout_c("Injecting OutOfSectionMemory error at line %d file %s",
+ __LINE__, __FILE__);
+ jam();
+ err = DbspjErr::OutOfSectionMemory;
+ break;
+ }
+
if (treeBits & DABits::NI_REPEAT_SCAN_RESULT)
{
jam();
@@ -7007,20 +7484,20 @@ Dbspj::parseDA(Build_context& ctx,
Uint32 cnt = unpackList(NDB_ARRAY_SIZE(dst), dst, tree);
if (unlikely(cnt > NDB_ARRAY_SIZE(dst)))
{
- DEBUG_CRASH();
+ jam();
break;
}
- err = 0;
-
if (unlikely(cnt!=1))
{
/**
* Only a single parent supported for now, i.e only trees
*/
- DEBUG_CRASH();
+ jam();
+ break;
}
+ err = 0;
for (Uint32 i = 0; i<cnt; i++)
{
DEBUG("adding " << dst[i] << " as parent");
@@ -7030,7 +7507,7 @@ Dbspj::parseDA(Build_context& ctx,
if (unlikely(!map.append(&treeNodePtr.i, 1)))
{
err = DbspjErr::OutOfQueryMemory;
- DEBUG_CRASH();
+ jam();
break;
}
parentPtr.p->m_bits &= ~(Uint32)TreeNode::T_LEAF;
@@ -7049,7 +7526,7 @@ Dbspj::parseDA(Build_context& ctx,
if (unlikely( ((treeBits & DABits::NI_KEY_PARAMS)==0) !=
((paramBits & DABits::PI_KEY_PARAMS)==0)))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -7077,7 +7554,7 @@ Dbspj::parseDA(Build_context& ctx,
if (unlikely( ((cnt==0) != ((treeBits & DABits::NI_KEY_PARAMS) == 0)) ||
((cnt==0) != ((paramBits & DABits::PI_KEY_PARAMS) == 0))))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -7089,7 +7566,11 @@ Dbspj::parseDA(Build_context& ctx,
* Expand pattern into a new pattern (with linked values)
*/
err = expand(pattern, treeNodePtr, tree, len, param, cnt);
-
+ if (unlikely(err != 0))
+ {
+ jam();
+ break;
+ }
/**
* This node constructs a new key for each send
*/
@@ -7106,23 +7587,25 @@ Dbspj::parseDA(Build_context& ctx,
bool hasNull;
Uint32 keyInfoPtrI = RNIL;
err = expand(keyInfoPtrI, tree, len, param, cnt, hasNull);
+ if (unlikely(err != 0))
+ {
+ jam();
+ releaseSection(keyInfoPtrI);
+ break;
+ }
if (unlikely(hasNull))
{
/* API should have elliminated requests w/ const-NULL keys */
jam();
DEBUG("BEWARE: FIXED-key contain NULL values");
+ releaseSection(keyInfoPtrI);
// treeNodePtr.p->m_bits |= TreeNode::T_NULL_PRUNE;
// break;
ndbrequire(false);
}
treeNodePtr.p->m_send.m_keyInfoPtrI = keyInfoPtrI;
}
-
- if (unlikely(err != 0))
- {
- DEBUG_CRASH();
- break;
- }
+ ndbassert(err == 0); // All errors should have been handled
} // DABits::NI_KEY_...
const Uint32 mask =
@@ -7177,7 +7660,7 @@ Dbspj::parseDA(Build_context& ctx,
err = DbspjErr::OutOfSectionMemory;
if (unlikely(!appendToSection(attrInfoPtrI, sections, 5)))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -7195,7 +7678,7 @@ Dbspj::parseDA(Build_context& ctx,
err = DbspjErr::BothTreeAndParametersContainInterpretedProgram;
if (unlikely(paramBits & DABits::PI_ATTR_INTERPRET))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -7206,7 +7689,7 @@ Dbspj::parseDA(Build_context& ctx,
err = DbspjErr::OutOfSectionMemory;
if (unlikely(!appendToSection(attrInfoPtrI, tree.ptr, len_prg)))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -7228,7 +7711,7 @@ Dbspj::parseDA(Build_context& ctx,
err = expand(pattern, treeNodePtr, tree, len_pattern, param, cnt);
if (unlikely(err))
{
- DEBUG_CRASH();
+ jam();
break;
}
/**
@@ -7247,7 +7730,7 @@ Dbspj::parseDA(Build_context& ctx,
err = expand(attrParamPtrI, tree, len_pattern, param, cnt, hasNull);
if (unlikely(err))
{
- DEBUG_CRASH();
+ jam();
break;
}
// ndbrequire(!hasNull);
@@ -7278,7 +7761,7 @@ Dbspj::parseDA(Build_context& ctx,
err = DbspjErr::OutOfSectionMemory;
if (unlikely(!appendToSection(attrInfoPtrI, &tmp, 1)))
{
- DEBUG_CRASH();
+ jam();
break;
}
sectionptrs[1] = 1;
@@ -7299,7 +7782,7 @@ Dbspj::parseDA(Build_context& ctx,
err = DbspjErr::OutOfSectionMemory;
if (unlikely(!appendToSection(attrInfoPtrI, param.ptr, program_len)))
{
- DEBUG_CRASH();
+ jam();
break;
}
/**
@@ -7316,7 +7799,7 @@ Dbspj::parseDA(Build_context& ctx,
if (unlikely(!appendToSection(attrParamPtrI,
param.ptr, subroutine_len)))
{
- DEBUG_CRASH();
+ jam();
break;
}
sectionptrs[4] = subroutine_len;
@@ -7338,7 +7821,7 @@ Dbspj::parseDA(Build_context& ctx,
err = DbspjErr::OutOfSectionMemory;
if (!appendToSection(attrInfoPtrI, param.ptr, len))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -7354,7 +7837,7 @@ Dbspj::parseDA(Build_context& ctx,
flush[3] = ctx.m_senderRef; // RouteRef
if (!appendToSection(attrInfoPtrI, flush, 4))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -7369,7 +7852,7 @@ Dbspj::parseDA(Build_context& ctx,
Uint32 cnt = unpackList(MAX_ATTRIBUTES_IN_TABLE, dst, tree);
if (unlikely(cnt > MAX_ATTRIBUTES_IN_TABLE))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -7387,7 +7870,7 @@ Dbspj::parseDA(Build_context& ctx,
err = DbspjErr::OutOfSectionMemory;
if (!appendToSection(attrInfoPtrI, dst, cnt))
{
- DEBUG_CRASH();
+ jam();
break;
}
@@ -7413,18 +7896,20 @@ Dbspj::parseDA(Build_context& ctx,
{
SectionReader r0(ptr, getSectionSegmentPool());
err = appendTreeToSection(attrInfoPtrI, r0, ptr.sz);
- sectionptrs[4] = ptr.sz;
if (unlikely(err != 0))
{
- DEBUG_CRASH();
+ jam();
break;
}
+ sectionptrs[4] = ptr.sz;
}
releaseSection(attrParamPtrI);
+ attrParamPtrI = RNIL;
}
}
treeNodePtr.p->m_send.m_attrInfoPtrI = attrInfoPtrI;
+ attrInfoPtrI = RNIL;
} // if (((treeBits & mask) | (paramBits & DABits::PI_ATTR_LIST)) != 0)
// Empty attrinfo would cause node crash.
@@ -7437,7 +7922,7 @@ Dbspj::parseDA(Build_context& ctx,
err = DbspjErr::OutOfSectionMemory;
if (unlikely(!appendToSection(treeNodePtr.p->m_send.m_attrInfoPtrI, &tmp, 1)))
{
- DEBUG_CRASH();
+ jam();
break;
}
}
@@ -7445,6 +7930,18 @@ Dbspj::parseDA(Build_context& ctx,
return 0;
} while (0);
+ if (attrInfoPtrI != RNIL)
+ {
+ jam();
+ releaseSection(attrInfoPtrI);
+ }
+
+ if (attrParamPtrI != RNIL)
+ {
+ jam();
+ releaseSection(attrParamPtrI);
+ }
+
return err;
}
=== modified file 'storage/ndb/src/kernel/blocks/dbspj/DbspjProxy.hpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/DbspjProxy.hpp 2011-10-07 08:07:21 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/DbspjProxy.hpp 2012-08-24 11:46:00 +0000
@@ -11,7 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef NDB_DBSPJ_PROXY_HPP
#define NDB_DBSPJ_PROXY_HPP
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-5.1-telco-7.1 branch (ole.john.aske:4595 to 4596) | Ole John Aske | 27 Aug |