From: Ole John Aske Date: November 9 2010 2:55pm Subject: bzr commit into mysql-5.1-telco-7.0-spj-scan-vs-scan branch (ole.john.aske:3355) List-Archive: http://lists.mysql.com/commits/123287 Message-Id: <20101109145505.66444222@fimafeng09.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============3658799939275237387==" --===============3658799939275237387== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///net/fimafeng09/export/home/tmp/oleja/mysql/mysql-5.1-telco-7.0-spj-scan-scan/ based on revid:jonas@stripped 3355 Ole John Aske 2010-11-09 sps-svs: refactoring, no functional changes. - recommit after merge conflicts Cleaned up and removed duplicated code in receiving result related to ::handleBatchComplete(). - More logic related to counting of 'm_pendingFrags' and 'm_finalBatchFrags' which was duplicated in several signal ::execFOO methods has been moved into ::handleBatchComplete() - ::incrementPendingFrags() has been removed, and its logic integrated into ::handleBatchComplete - ::closeSingletonScans() (Which was not a 'close' at all) has been removed by making receive of lookup queries more similar to scans. - Introduced ::findResultStream(Uint32 receiverId) which contains functionality previously duplicated in ::execTRANSID_AI() and ::execSCAN_TABCONF(). - modified: storage/ndb/src/ndbapi/NdbQueryOperation.cpp storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp === modified file 'storage/ndb/src/ndbapi/NdbQueryOperation.cpp' --- a/storage/ndb/src/ndbapi/NdbQueryOperation.cpp 2010-11-08 15:18:22 +0000 +++ b/storage/ndb/src/ndbapi/NdbQueryOperation.cpp 2010-11-09 14:55:01 +0000 @@ -1867,60 +1867,94 @@ NdbQueryImpl::awaitMoreResults(bool forc * the lock, because we know that the signal receiver thread will not * be accessing m_fullFrags at this time. */ - NdbRootFragment* frag = m_fullFrags.pop(); - if (frag==NULL) + NdbRootFragment* frag; + if ((frag=m_fullFrags.pop()) != NULL) { - /* Getting here means that either: - * - No results was returned (TCKEYREF) - * - There was no matching row for an inner join. - * - or, the application called nextResult() twice for a lookup query. - */ - assert(m_finalBatchFrags == getRootFragCount()); - return FetchResult_noMoreData; + m_applFrags.add(*frag); } - else + assert(m_fullFrags.pop()==NULL); // Only one stream for lookups. + + if (m_applFrags.getCurrent() != NULL) { - /* Move fragment from receiver thread's container to application - * thread's container.*/ - assert(!frag->isEmpty()); - m_applFrags.add(*frag); - assert(m_fullFrags.pop()==NULL); // Only one stream for lookups. return FetchResult_ok; } + + /* Getting here means that either: + * - No results was returned (TCKEYREF) + * - There was no matching row for an inner join. + * - or, the application called nextResult() twice for a lookup query. + */ + assert(m_pendingFrags == 0); + assert(m_finalBatchFrags == getRootFragCount()); + return FetchResult_noMoreData; } // if(m_queryDef.isScanQuery()) + } //NdbQueryImpl::awaitMoreResults -void + +/* + ::handleBatchComplete() is intended to be called when receiving signals only. + The PollGuard mutex is then set and the shared 'm_pendingFrags', + 'm_finalBatchFrags' and 'm_fullFrags' can safely be updated. + + returns: 'true' when application thread should be resumed. +*/ +bool NdbQueryImpl::handleBatchComplete(Uint32 fragNo) { - assert(m_rootFrags[fragNo].isFragBatchComplete()); - getRoot().handleBatchComplete(fragNo); + if (traceSignals) { + ndbout << "NdbQueryImpl::handleBatchComplete, fragNo=" << fragNo + << ", pendingFrags=" << (m_pendingFrags-1) + << ", finalBatchFrags=" << m_finalBatchFrags + << endl; + } + bool resume = false; + + /* May received fragment data after a SCANREF() (timeout?) + * terminated the scan. We are about to close this query, + * and didn't expect any more data - ignore it! + */ + if (likely(m_fullFrags.m_errorCode == 0)) + { + NdbQueryOperationImpl& root = getRoot(); + NdbRootFragment& rootFrag = m_rootFrags[fragNo]; + assert(rootFrag.isFragBatchComplete()); - // Position at the first (sorted?) row available from this fragments. - getRoot().m_resultStreams[fragNo]->firstResult(); -} + assert(m_pendingFrags > 0); // Check against underflow. + assert(m_pendingFrags <= m_rootFragCount); // .... and overflow + m_pendingFrags--; -void -NdbQueryImpl::closeSingletonScans() -{ - assert(!getQueryDef().isScanQuery()); - for(Uint32 i = 0; igetReceiver().m_tcPtrI==RNIL); + assert(m_finalBatchFrags==1); + assert(m_pendingFrags==0); // Lookup query should be complete now. + resume = true; + } + + /* Position at the first (sorted?) row available from this fragments. */ - resultStream.getReceiver() - .execSCANOPCONF(RNIL, 0, resultStream.getRowCount()); - } - /* nextResult() will later move it from m_fullFrags to m_applFrags - * under mutex protection. - */ - if (getRoot().m_resultStreams[0]->firstResult() != tupleNotFound) { - m_fullFrags.push(m_rootFrags[0]); + root.m_resultStreams[fragNo]->firstResult(); + + /* When application thread ::awaitMoreResults() it will later be moved + * from m_fullFrags to m_applFrags under mutex protection. + */ + m_fullFrags.push(rootFrag); } - m_finalBatchFrags++; -} //NdbQueryImpl::closeSingletonScans + + return resume; +} // NdbQueryImpl::handleBatchComplete int NdbQueryImpl::close(bool forceSend) @@ -2042,12 +2076,9 @@ NdbQueryImpl::execTCKEYCONF() m_rootFrags[0].incrOutstandingResults(-1); bool ret = false; - if (m_rootFrags[0].isFragBatchComplete()) { - /* If this root fragment is complete, verify that the query is also - * complete for this batch. - */ - ret = incrementPendingFrags(-1); - assert(ret); + if (m_rootFrags[0].isFragBatchComplete()) + { + ret = handleBatchComplete(0); } if (traceSignals) { @@ -2058,7 +2089,7 @@ NdbQueryImpl::execTCKEYCONF() << endl; } return ret; -} +} // NdbQueryImpl::execTCKEYCONF void NdbQueryImpl::execCLOSE_SCAN_REP(int errorCode, bool needClose) @@ -2070,41 +2101,6 @@ NdbQueryImpl::execCLOSE_SCAN_REP(int err setFetchTerminated(errorCode,needClose); } -/* - ::incrementPendingFrags() is intended to be called when receiving signals only. - The PollGuard mutex is then set and the shared 'm_pendingFrags' can safely be updated. -*/ -bool -NdbQueryImpl::incrementPendingFrags(int increment) -{ - if (unlikely(m_fullFrags.m_errorCode != 0)) - { - /* Received fragment data after a SCANREF() (timeout?) has terminated the scan. - * We are about to close this query, and didn't expect there to be anything 'pending'. - */ - assert (m_pendingFrags==0); - return (m_pendingFrags==0); - } - - m_pendingFrags += increment; - assert(m_pendingFrags < 1<<15); // Check against underflow. - assert(m_pendingFrags <= m_rootFragCount); // .... and overflow - - if (traceSignals) { - ndbout << "NdbQueryImpl::incrementPendingFrags(" << increment << "): " - << ", pendingFrags=" << m_pendingFrags << endl; - } - - if (m_pendingFrags==0) { - if (!getQueryDef().isScanQuery()) { - closeSingletonScans(); - } - return true; - } else { - return false; - } -} - int NdbQueryImpl::prepareSend() { @@ -3506,9 +3502,9 @@ NdbQueryOperationImpl::handleBatchComple NdbQueryOperationImpl& child = getChildOperation(i); child.handleBatchComplete(fragNo); } - m_resultStreams[fragNo]->handleBatchComplete(); -} + +} // NdbQueryOperationImpl::handleBatchComplete void @@ -4321,7 +4317,6 @@ NdbQueryOperationImpl::prepareLookupKeyI default: assert(false); } - } if (unlikely(keyInfo.isMemoryExhausted())) { @@ -4332,17 +4327,29 @@ NdbQueryOperationImpl::prepareLookupKeyI } // NdbQueryOperationImpl::prepareLookupKeyInfo -bool -NdbQueryOperationImpl::execTRANSID_AI(const Uint32* ptr, Uint32 len){ - if (traceSignals) { - ndbout << "NdbQueryOperationImpl::execTRANSID_AI()" - << " operation no: " - << getQueryOperationDef().getQueryOperationIx() << endl; +Uint32 +NdbQueryOperationImpl::findResultStream(Uint32 receiverId) const +{ + Uint32 rootFragNo; + Uint32 rootFragCount = getQuery().getRootFragCount(); + assert(&getRoot() == this); + + for (rootFragNo = 0; rootFragNogetReceiver().getId() == receiverId) + return rootFragNo; } - bool ret = false; - NdbRootFragment* rootFrag = NULL; - if(getQueryDef().isScanQuery()) + assert(false); + return rootFragCount; +} // NdbQueryOperationImpl::findResultStream + + +bool +NdbQueryOperationImpl::execTRANSID_AI(const Uint32* ptr, Uint32 len) +{ + Uint32 rootFragNo = 0; + if (getQueryDef().isScanQuery()) { const Uint32 receiverId = CorrelationData(ptr, len).getRootReceiverId(); @@ -4350,50 +4357,26 @@ NdbQueryOperationImpl::execTRANSID_AI(co * of the root operation. We can thus find the correct root fragment * number. */ - Uint32 rootFragNo; - for(rootFragNo = 0; - rootFragNogetReceiver().getId() - != receiverId; - rootFragNo++); - assert(rootFragNoexecTRANSID_AI(ptr, len); - - rootFrag = &getQuery().m_rootFrags[rootFragNo]; - rootFrag->incrOutstandingResults(-1); - - if (rootFrag->isFragBatchComplete()) { - m_queryImpl.incrementPendingFrags(-1); - m_queryImpl.handleBatchComplete(rootFragNo); - - /* nextResult() will later move it from m_fullFrags to m_applFrags - * under mutex protection.*/ - m_queryImpl.m_fullFrags.push(*rootFrag); - // Wake up appl thread when we have data, or entire query batch completed. - ret = true; - } + rootFragNo = getRoot().findResultStream(receiverId); + } + if (traceSignals) { + ndbout << "NdbQueryOperationImpl::execTRANSID_AI()" + << ", operation no: " << getQueryOperationDef().getQueryOperationIx() + << ", fragment no: " << rootFragNo + << endl; + } + + // Process result values. + m_resultStreams[rootFragNo]->execTRANSID_AI(ptr, len); + + NdbRootFragment& rootFrag = m_queryImpl.m_rootFrags[rootFragNo]; + rootFrag.incrOutstandingResults(-1); + + bool ret = false; + if (rootFrag.isFragBatchComplete()) + { + ret = m_queryImpl.handleBatchComplete(rootFragNo); } - else - { // Lookup query - // The root operation is a lookup. - m_resultStreams[0]->execTRANSID_AI(ptr, len); - - rootFrag = &getQuery().m_rootFrags[0]; - rootFrag->incrOutstandingResults(-1); - - if (rootFrag->isFragBatchComplete()) { - ret = m_queryImpl.incrementPendingFrags(-1); - assert(ret); // The query should be complete now. - } - } // end lookup if (traceSignals) { ndbout << "NdbQueryOperationImpl::execTRANSID_AI(): returns:" << ret @@ -4404,7 +4387,8 @@ NdbQueryOperationImpl::execTRANSID_AI(co bool -NdbQueryOperationImpl::execTCKEYREF(const NdbApiSignal* aSignal){ +NdbQueryOperationImpl::execTCKEYREF(const NdbApiSignal* aSignal) +{ if (traceSignals) { ndbout << "NdbQueryOperationImpl::execTCKEYREF()" << endl; } @@ -4432,6 +4416,9 @@ NdbQueryOperationImpl::execTCKEYREF(cons } } + Uint32 rootFragNo = 0; + NdbRootFragment& rootFrag = getQuery().m_rootFrags[0]; + if (ref->errorCode != DbspjErr::NodeFailure) { // Compensate for children results not produced. @@ -4443,18 +4430,18 @@ NdbQueryOperationImpl::execTCKEYREF(cons { cnt += getNoOfLeafOperations(); } - getQuery().m_rootFrags[0].incrOutstandingResults(- Int32(cnt)); + rootFrag.incrOutstandingResults(- Int32(cnt)); } else { // consider frag-batch complete - getQuery().m_rootFrags[0].clearOutstandingResults(); + rootFrag.clearOutstandingResults(); } bool ret = false; - if (getQuery().m_rootFrags[0].isFragBatchComplete()) { - ret = m_queryImpl.incrementPendingFrags(-1); - assert(ret); // The query should be complete now. + if (rootFrag.isFragBatchComplete()) + { + ret = m_queryImpl.handleBatchComplete(rootFragNo); } if (traceSignals) { @@ -4482,14 +4469,9 @@ NdbQueryOperationImpl::execSCAN_TABCONF( // For now, only the root operation may be a scan. assert(&getRoot() == this); assert(m_operationDef.isScanOperation()); - Uint32 fragNo; + // Find root fragment number. - for(fragNo = 0; - fragNogetReceiver() != receiver; - fragNo++); - assert(fragNogetId()); NdbRootFragment& rootFrag = getQuery().m_rootFrags[fragNo]; rootFrag.setConfReceived(); @@ -4499,10 +4481,6 @@ NdbQueryOperationImpl::execSCAN_TABCONF( NdbResultStream& resultStream = *m_resultStreams[fragNo]; resultStream.getReceiver().m_tcPtrI = tcPtrI; - if (rootFrag.finalBatchReceived()) - { - m_queryImpl.m_finalBatchFrags++; - } if(traceSignals){ ndbout << " resultStream(root) {" << resultStream << "} fragNo=" << fragNo << endl; @@ -4536,17 +4514,12 @@ NdbQueryOperationImpl::execSCAN_TABCONF( // Check that nodeMask does not have more bits than we have operations. UNUSED(finalOpDef); assert(nodeMask >> (1+finalOpDef.getQueryOperationId()) == 0); + bool ret = false; - if (rootFrag.isFragBatchComplete()) { - /* This fragment is now complete*/ - m_queryImpl.incrementPendingFrags(-1); - m_queryImpl.handleBatchComplete(fragNo); - - /* nextResult() will later move it from m_fullFrags to m_applFrags - * under mutex protection.*/ - m_queryImpl.m_fullFrags.push(rootFrag); - // Wake up now. - ret = true; + if (rootFrag.isFragBatchComplete()) + { + /* This fragment is now complete */ + ret = m_queryImpl.handleBatchComplete(fragNo); } if (traceSignals) { ndbout << "NdbQueryOperationImpl::execSCAN_TABCONF():, returns:" << ret === modified file 'storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp' --- a/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp 2010-11-08 15:18:22 +0000 +++ b/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp 2010-11-09 14:55:01 +0000 @@ -487,28 +487,18 @@ private: */ int sendClose(int nodeId); - /** Close scan receivers used for lookups. (Since scans and lookups should - * have the same semantics for nextResult(), lookups use scan-type - * NdbReceiver objects.) - */ - void closeSingletonScans(); - const NdbQuery& getInterface() const { return m_interface; } NdbQueryOperationImpl& getRoot() const { return getQueryOperation(0U); } - /** Count number of completed root fragments within this batch. - * @param increment Change in count of completed root frgaments. - * @return True if batch is complete. - */ - bool incrementPendingFrags(int increment); - /** A complete batch has been received for a given root fragment - * Update whatever required before the appl. is allowed to navigate the result. + * Update whatever required before the appl. is allowed to navigate + * the result. + * @return: 'true' if its time to resume appl. threads */ - void handleBatchComplete(Uint32 rootFragNo); + bool handleBatchComplete(Uint32 rootFragNo); }; // class NdbQueryImpl @@ -779,6 +769,8 @@ private: * NdbReceiver::m_query_operation_impl here.*/ Uint32 getIdOfReceiver() const; + Uint32 findResultStream(Uint32 receiverId) const; + /** * If the operation has a scan filter, append the corresponding * interpreter code to a buffer. --===============3658799939275237387== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/ole.john.aske@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: ole.john.aske@stripped\ # jx79t4i5bpyi731q # target_branch: file:///net/fimafeng09/export/home/tmp/oleja/mysql\ # /mysql-5.1-telco-7.0-spj-scan-scan/ # testament_sha1: d0fa146fbf4882c44321a2662493394700f4dc99 # timestamp: 2010-11-09 15:55:05 +0100 # source_branch: bzr+ssh://oaske@stripped/bzrroot/server\ # /mysql-5.1-telco-7.0-spj/ # base_revision_id: jonas@stripped # # Begin bundle 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 fp0GmOgf8XckU4UJAZy64qA= --===============3658799939275237387==--