void Pipeline::Optimizations::Local::coalesceAdjacent(Pipeline* pipeline) { SourceContainer& sources = pipeline->sources; if (sources.empty()) return; // move all sources to a temporary list SourceContainer tempSources; sources.swap(tempSources); // move the first one to the final list sources.push_back(tempSources[0]); // run through the sources, coalescing them or keeping them for (size_t tempn = tempSources.size(), tempi = 1; tempi < tempn; ++tempi) { // If we can't coalesce the source with the last, then move it // to the final list, and make it the new last. (If we succeeded, // then we're still on the same last, and there's no need to move // or do anything with the source -- the destruction of tempSources // will take care of the rest.) intrusive_ptr<DocumentSource> &pLastSource = sources.back(); intrusive_ptr<DocumentSource> &pTemp = tempSources[tempi]; verify(pTemp && pLastSource); if (!pLastSource->coalesce(pTemp)) sources.push_back(pTemp); } }
void Pipeline::Optimizations::Local::optimizeEachDocumentSource(Pipeline* pipeline) { SourceContainer& sources = pipeline->sources; SourceContainer newSources; for (SourceContainer::iterator it(sources.begin()); it != sources.end(); ++it) { if (auto out = (*it)->optimize()) { newSources.push_back(std::move(out)); } } pipeline->sources = std::move(newSources); }
static void split( const SourceContainer &from, openmp_state< typename SourceContainer::value_type > &to ) { if(to.size() == 0) to.resize( omp_get_max_threads() ); const size_t part = from.size() / to.size(); # pragma omp parallel for schedule(dynamic) for(size_t i = 0 ; i < to.size() ; i++) { typedef typename SourceContainer::const_iterator it_t; const it_t begin = from.begin() + i * part; it_t end = begin + part; // for cases where from.size() % to.size() > 0 if(i + 1 == to.size() || end > from.end()) end = from.end(); to[i].resize(end - begin); std::copy(begin, end, to[i].begin()); } }
void push_back_right(TargetContainer& x, const SourceContainer& y) { // x.insert( x.end(), y.begin(), y.end() ); int n = y.size(); for (int i = 0; i < n; i++) { x.push_back(-y[i] - 1); } }
void Pipeline::optimizePipeline() { SourceContainer optimizedSources; SourceContainer::iterator itr = sources.begin(); while (itr != sources.end() && std::next(itr) != sources.end()) { invariant((*itr).get()); itr = (*itr).get()->optimizeAt(itr, &sources); } // Once we have reached our final number of stages, optimize each individually. for (auto&& source : sources) { if (auto out = source->optimize()) { optimizedSources.push_back(out); } } sources.swap(optimizedSources); }
TargetContainer traits::convert( SourceContainer const & source ) { return std::move( to_ucs2( &source[0], &source[0] + source.size() ) ); }
intrusive_ptr<Pipeline> Pipeline::parseCommand( string &errmsg, BSONObj &cmdObj, const intrusive_ptr<ExpressionContext> &pCtx) { intrusive_ptr<Pipeline> pPipeline(new Pipeline(pCtx)); vector<BSONElement> pipeline; /* gather the specification for the aggregation */ for(BSONObj::iterator cmdIterator = cmdObj.begin(); cmdIterator.more(); ) { BSONElement cmdElement(cmdIterator.next()); const char *pFieldName = cmdElement.fieldName(); // ignore top-level fields prefixed with $. They are for the command processor, not us. if (pFieldName[0] == '$') { continue; } /* look for the aggregation command */ if (!strcmp(pFieldName, commandName)) { pPipeline->collectionName = cmdElement.String(); continue; } /* check for the collection name */ if (!strcmp(pFieldName, pipelineName)) { pipeline = cmdElement.Array(); continue; } /* check for explain option */ if (!strcmp(pFieldName, explainName)) { pPipeline->explain = cmdElement.Bool(); continue; } /* if the request came from the router, we're in a shard */ if (!strcmp(pFieldName, fromRouterName)) { pCtx->setInShard(cmdElement.Bool()); continue; } /* check for debug options */ if (!strcmp(pFieldName, splitMongodPipelineName)) { pPipeline->splitMongodPipeline = true; continue; } /* we didn't recognize a field in the command */ ostringstream sb; sb << "unrecognized field \"" << cmdElement.fieldName(); errmsg = sb.str(); return intrusive_ptr<Pipeline>(); } /* If we get here, we've harvested the fields we expect for a pipeline. Set up the specified document source pipeline. */ SourceContainer& sources = pPipeline->sources; // shorthand /* iterate over the steps in the pipeline */ const size_t nSteps = pipeline.size(); for(size_t iStep = 0; iStep < nSteps; ++iStep) { /* pull out the pipeline element as an object */ BSONElement pipeElement(pipeline[iStep]); uassert(15942, str::stream() << "pipeline element " << iStep << " is not an object", pipeElement.type() == Object); BSONObj bsonObj(pipeElement.Obj()); // Parse a pipeline stage from 'bsonObj'. uassert(16435, "A pipeline stage specification object must contain exactly one field.", bsonObj.nFields() == 1); BSONElement stageSpec = bsonObj.firstElement(); const char* stageName = stageSpec.fieldName(); // Create a DocumentSource pipeline stage from 'stageSpec'. StageDesc key; key.pName = stageName; const StageDesc* pDesc = (const StageDesc*) bsearch(&key, stageDesc, nStageDesc, sizeof(StageDesc), stageDescCmp); uassert(16436, str::stream() << "Unrecognized pipeline stage name: '" << stageName << "'", pDesc); intrusive_ptr<DocumentSource> stage = (*pDesc->pFactory)(&stageSpec, pCtx); verify(stage); stage->setPipelineStep(iStep); sources.push_back(stage); } /* if there aren't any pipeline stages, there's nothing more to do */ if (sources.empty()) return pPipeline; /* Move filters up where possible. CW TODO -- move filter past projections where possible, and noting corresponding field renaming. */ /* Wherever there is a match immediately following a sort, swap them. This means we sort fewer items. Neither changes the documents in the stream, so this transformation shouldn't affect the result. We do this first, because then when we coalesce operators below, any adjacent matches will be combined. */ for (size_t srcn = sources.size(), srci = 1; srci < srcn; ++srci) { intrusive_ptr<DocumentSource> &pSource = sources[srci]; if (dynamic_cast<DocumentSourceMatch *>(pSource.get())) { intrusive_ptr<DocumentSource> &pPrevious = sources[srci - 1]; if (dynamic_cast<DocumentSourceSort *>(pPrevious.get())) { /* swap this item with the previous */ intrusive_ptr<DocumentSource> pTemp(pPrevious); pPrevious = pSource; pSource = pTemp; } } } /* Move limits in front of skips. This is more optimal for sharding * since currently, we can only split the pipeline at a single source * and it is better to limit the results coming from each shard */ for(int i = sources.size() - 1; i >= 1 /* not looking at 0 */; i--) { DocumentSourceLimit* limit = dynamic_cast<DocumentSourceLimit*>(sources[i].get()); DocumentSourceSkip* skip = dynamic_cast<DocumentSourceSkip*>(sources[i-1].get()); if (limit && skip) { // Increase limit by skip since the skipped docs now pass through the $limit limit->setLimit(limit->getLimit() + skip->getSkip()); swap(sources[i], sources[i-1]); // Start at back again. This is needed to handle cases with more than 1 $limit // (S means skip, L means limit) // // These two would work without second pass (assuming back to front ordering) // SL -> LS // SSL -> LSS // // The following cases need a second pass to handle the second limit // SLL -> LLS // SSLL -> LLSS // SLSL -> LLSS i = sources.size(); // decremented before next pass } } /* Coalesce adjacent filters where possible. Two adjacent filters are equivalent to one filter whose predicate is the conjunction of the two original filters' predicates. For now, capture this by giving any DocumentSource the option to absorb it's successor; this will also allow adjacent projections to coalesce when possible. Run through the DocumentSources, and give each one the opportunity to coalesce with its successor. If successful, remove the successor. Move all document sources to a temporary list. */ SourceContainer tempSources; sources.swap(tempSources); /* move the first one to the final list */ sources.push_back(tempSources[0]); /* run through the sources, coalescing them or keeping them */ for (size_t tempn = tempSources.size(), tempi = 1; tempi < tempn; ++tempi) { /* If we can't coalesce the source with the last, then move it to the final list, and make it the new last. (If we succeeded, then we're still on the same last, and there's no need to move or do anything with the source -- the destruction of tempSources will take care of the rest.) */ intrusive_ptr<DocumentSource> &pLastSource = sources.back(); intrusive_ptr<DocumentSource> &pTemp = tempSources[tempi]; verify(pTemp && pLastSource); if (!pLastSource->coalesce(pTemp)) sources.push_back(pTemp); } /* optimize the elements in the pipeline */ for(SourceContainer::iterator iter(sources.begin()), listEnd(sources.end()); iter != listEnd; ++iter) { if (!*iter) { errmsg = "Pipeline received empty document as argument"; return intrusive_ptr<Pipeline>(); } (*iter)->optimize(); } return pPipeline; }
void push_back( TargetContainer& x, const SourceContainer& y ){ x.insert( x.end(), y.begin(), y.end() ) ; }
/* * IHXBroadcastMapperResponse */ STDMETHODIMP BasicSourceFinder::BroadcastTypeFound(HX_RESULT status, const char* pType) { if (SF_CLOSED == m_findState) { return HXR_OK; } m_CurrentSourceType = pType; HX_ASSERT(m_pBroadcastMapper); HX_RELEASE(m_pBroadcastMapper); PluginHandler::BroadcastFormat* broadcast_handler; PluginHandler::Errors plugin_result; PluginHandler::Plugin* plugin; broadcast_handler = m_pProc->pc->plugin_handler->m_broadcast_handler; plugin_result = broadcast_handler->Find(pType, plugin); if(PluginHandler::NO_ERRORS != plugin_result) { ERRMSG(m_pProc->pc->error_handler, "No live handler for %s\n", pType?pType:"(null)"); return HXR_FAIL; } /* * Depending on a request */ HX_RESULT theErr = HXR_FAIL; IHXPSourceControl* pSource = NULL; IHXValues* pVal = NULL; IHXBuffer* pBuf = NULL; const char* pFileName = m_pURL->name + m_pFSManager->m_mount_point_len - 1; UINT32 bUseSourceContainer = FALSE; BOOL bUseMediaDeliveryPipeline = FALSE; /* XXDWL * For live (broadcast) sessions, the media delivery pipeline needs to be turned off. * This is a temporary solution until a number of issues dealing with timestamp * dependent media, and ASM rule handling are worked out. * See also: server/engine/session/player.cpp:1947 bUseMediaDeliveryPipeline = m_pPlayerSession->m_bUseMediaDeliveryPipeline; */ #if NOTYET /* XXTDM * According to ghori, this was an attempt to merge the various source * finding code into one place. Due to time constraints, it was never * finished. Therefore, this code is currently unused and untested. */ theErr = m_pRequest->GetRequestHeaders(FS_HEADERS, pVal); if (HXR_OK == theErr) { theErr = pVal->GetPropertyULONG32("UseSourceContainer", bUseSourceContainer); if (HXR_OK != theErr) { bUseSourceContainer = FALSE; } theErr = pVal->GetPropertyCString("BroadcastAlias", pBuf); if (HXR_OK == theErr) { pFileName = (const char*)pBuf->GetBuffer(); } } #endif /* NOTYET */ HX_ASSERT(pFileName); theErr = m_pProc->pc->broadcast_manager->GetStream(pType, pFileName, pSource, m_pProc, bUseMediaDeliveryPipeline, m_pPlayerSession ? m_pPlayerSession->GetSessionStats() : NULL); if (HXR_OK == theErr) { if (bUseSourceContainer) { SourceContainer* pContainer = new SourceContainer(m_pProc->pc->server_context, pSource); if (pContainer) { pContainer->AddRef(); FindSourceDone(HXR_OK, (IUnknown*)(IHXPSinkPackets*)pContainer); pContainer->Release(); } else { theErr = HXR_OUTOFMEMORY; HX_RELEASE(pSource); } } } FindSourceDone(theErr, pSource); HX_RELEASE(pSource); HX_RELEASE(pVal); HX_RELEASE(pBuf); return HXR_OK; }