From: Ole John Aske Date: November 9 2010 2:50pm Subject: bzr commit into mysql-5.1-telco-7.0-spj-scan-vs-scan branch (ole.john.aske:3349) List-Archive: http://lists.mysql.com/commits/123283 Message-Id: <20101109145004.C6A77222@fimafeng09.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============4307333579463224491==" --===============4307333579463224491== 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:jan.wedvik@stripped 3349 Ole John Aske 2010-11-09 sps-svs: refactoring, no functional changes. 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:50:00 +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:50:00 +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. --===============4307333579463224491== 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\ # dh3gh32h1lnrk4w3 # target_branch: file:///net/fimafeng09/export/home/tmp/oleja/mysql\ # /mysql-5.1-telco-7.0-spj-scan-scan/ # testament_sha1: a07fc9cc6fe7f98ab7e81df97b4247106dddae6e # timestamp: 2010-11-09 15:50:04 +0100 # source_branch: bzr+ssh://oaske@stripped/bzrroot/server\ # /mysql-5.1-telco-7.0-spj/ # base_revision_id: jan.wedvik@stripped # # Begin bundle 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 --===============4307333579463224491==--