static int handle_system_collection_insert(const char *ns, const BSONObj &obj, bool logop) { // Trying to insert into a system collection. Fancy side-effects go here: // TODO: see insert_checkSys if (mongoutils::str::endsWith(ns, ".system.indexes")) { // obj is something like this: // { _id: ObjectId('511d34f6d3080c48017a14d0'), ns: "test.leif", key: { a: -1.0 }, name: "a_-1", unique: true } const string &coll = obj["ns"].String(); NamespaceDetails *details = getAndMaybeCreateNS(coll.c_str(), logop); BSONObj key = obj["key"].Obj(); int i = details->findIndexByKeyPattern(key); if (i >= 0) { return ASSERT_ID_DUPKEY; } else { details->createIndex(obj); } } else if (legalClientSystemNS(ns, true)) { if (mongoutils::str::endsWith(ns, ".system.users")) { uassert( 14051 , "system.users entry needs 'user' field to be a string", obj["user"].type() == String ); uassert( 14052 , "system.users entry needs 'pwd' field to be a string", obj["pwd"].type() == String ); uassert( 14053 , "system.users entry needs 'user' field to be non-empty", obj["user"].String().size() ); uassert( 14054 , "system.users entry needs 'pwd' field to be non-empty", obj["pwd"].String().size() ); } } else { uasserted(16459, str::stream() << "attempt to insert in system namespace '" << ns << "'"); } return 0; }
IndexDescriptor* getIndex(const BSONObj& obj) { Client::ReadContext ctx(ns()); Collection* collection = ctx.ctx().db()->getCollection( ns() ); NamespaceDetails* nsd = collection->details(); int idxNo = nsd->findIndexByKeyPattern(obj); return collection->getIndexCatalog()->getDescriptor( idxNo ); }
long long Helpers::removeRange( const string& ns , const BSONObj& min , const BSONObj& max , bool yield , bool maxInclusive , RemoveCallback * callback, bool fromMigrate ) { BSONObj keya , keyb; BSONObj minClean = toKeyFormat( min , keya ); BSONObj maxClean = toKeyFormat( max , keyb ); verify( keya == keyb ); Client::Context ctx(ns); shared_ptr<Cursor> c; auto_ptr<ClientCursor> cc; { NamespaceDetails* nsd = nsdetails( ns.c_str() ); if ( ! nsd ) return 0; int ii = nsd->findIndexByKeyPattern( keya ); verify( ii >= 0 ); IndexDetails& i = nsd->idx( ii ); c.reset( BtreeCursor::make( nsd , ii , i , minClean , maxClean , maxInclusive, 1 ) ); cc.reset( new ClientCursor( QueryOption_NoCursorTimeout , c , ns ) ); cc->setDoingDeletes( true ); } long long num = 0; while ( cc->ok() ) { if ( yield && ! cc->yieldSometimes( ClientCursor::WillNeed) ) { // cursor got finished by someone else, so we're done cc.release(); // if the collection/db is dropped, cc may be deleted break; } if ( ! cc->ok() ) break; DiskLoc rloc = cc->currLoc(); if ( callback ) callback->goingToDelete( cc->current() ); cc->advance(); c->prepareToTouchEarlierIterate(); logOp( "d" , ns.c_str() , rloc.obj()["_id"].wrap() , 0 , 0 , fromMigrate ); theDataFileMgr.deleteRecord(ns.c_str() , rloc.rec(), rloc); num++; c->recoverFromTouchingEarlierIterate(); getDur().commitIfNeeded(); } return num; }
long long Helpers::removeRange( const string& ns , const BSONObj& min , const BSONObj& max , bool yield , bool maxInclusive , RemoveCallback * callback ) { BSONObj keya , keyb; BSONObj minClean = toKeyFormat( min , keya ); BSONObj maxClean = toKeyFormat( max , keyb ); assert( keya == keyb ); Client::Context ctx(ns); NamespaceDetails* nsd = nsdetails( ns.c_str() ); if ( ! nsd ) return 0; int ii = nsd->findIndexByKeyPattern( keya ); assert( ii >= 0 ); long long num = 0; IndexDetails& i = nsd->idx( ii ); shared_ptr<Cursor> c( new BtreeCursor( nsd , ii , i , minClean , maxClean , maxInclusive, 1 ) ); auto_ptr<ClientCursor> cc( new ClientCursor( QueryOption_NoCursorTimeout , c , ns ) ); cc->setDoingDeletes( true ); while ( c->ok() ) { DiskLoc rloc = c->currLoc(); BSONObj key = c->currKey(); if ( callback ) callback->goingToDelete( c->current() ); c->advance(); c->noteLocation(); logOp( "d" , ns.c_str() , rloc.obj()["_id"].wrap() ); theDataFileMgr.deleteRecord(ns.c_str() , rloc.rec(), rloc); num++; c->checkLocation(); if ( yield && ! cc->yieldSometimes() ) { // cursor got finished by someone else, so we're done cc.release(); // if the collection/db is dropped, cc may be deleted break; } } return num; }
IndexDescriptor* getIndex(const BSONObj& obj, Collection* coll) { NamespaceDetails* nsd = coll->details(); int idxNo = nsd->findIndexByKeyPattern(obj); return coll->getIndexCatalog()->getDescriptor( idxNo ); }
PlanStage* buildStages(const QuerySolution& qsol, const QuerySolutionNode* root, WorkingSet* ws, bool use_chronos = false) { if (STAGE_COLLSCAN == root->getType()) { const CollectionScanNode* csn = static_cast<const CollectionScanNode*>(root); CollectionScanParams params; params.ns = csn->name; params.tailable = csn->tailable; params.direction = (csn->direction == 1) ? CollectionScanParams::FORWARD : CollectionScanParams::BACKWARD; params.maxScan = csn->maxScan; return new CollectionScan(params, ws, csn->filter.get(), use_chronos); } else if (STAGE_IXSCAN == root->getType()) { const IndexScanNode* ixn = static_cast<const IndexScanNode*>(root); // // XXX XXX // Given that this grabs data from the catalog, we must do this inside of a lock. // We should change this to take a (ns, index key pattern) pair so that the params // don't involve any on-disk data, just descriptions thereof. // XXX XXX // Database* db = cc().database(); Collection* collection = db ? db->getCollection(qsol.ns) : NULL; if (NULL == collection) { warning() << "Can't ixscan null ns " << qsol.ns << endl; return NULL; } NamespaceDetails* nsd = collection->details(); int idxNo = nsd->findIndexByKeyPattern(ixn->indexKeyPattern); if (-1 == idxNo) { warning() << "Can't find idx " << ixn->indexKeyPattern.toString() << "in ns " << qsol.ns << endl; return NULL; } IndexScanParams params; params.descriptor = collection->getIndexCatalog()->getDescriptor( idxNo ); params.bounds = ixn->bounds; params.direction = ixn->direction; params.limit = ixn->limit; params.maxScan = ixn->maxScan; params.addKeyMetadata = ixn->addKeyMetadata; params.ns = qsol.ns; return new IndexScan(params, ws, ixn->filter.get(), use_chronos); } else if (STAGE_FETCH == root->getType()) { const FetchNode* fn = static_cast<const FetchNode*>(root); PlanStage* childStage = buildStages(qsol, fn->children[0], ws); if (NULL == childStage) { return NULL; } return new FetchStage(ws, childStage, fn->filter.get()); } else if (STAGE_SORT == root->getType()) { const SortNode* sn = static_cast<const SortNode*>(root); PlanStage* childStage = buildStages(qsol, sn->children[0], ws); if (NULL == childStage) { return NULL; } SortStageParams params; params.pattern = sn->pattern; params.query = sn->query; params.limit = sn->limit; return new SortStage(params, ws, childStage); } else if (STAGE_PROJECTION == root->getType()) { const ProjectionNode* pn = static_cast<const ProjectionNode*>(root); PlanStage* childStage = buildStages(qsol, pn->children[0], ws); if (NULL == childStage) { return NULL; } return new ProjectionStage(pn->projection, pn->fullExpression, ws, childStage); } else if (STAGE_LIMIT == root->getType()) { const LimitNode* ln = static_cast<const LimitNode*>(root); PlanStage* childStage = buildStages(qsol, ln->children[0], ws); if (NULL == childStage) { return NULL; } return new LimitStage(ln->limit, ws, childStage); } else if (STAGE_SKIP == root->getType()) { const SkipNode* sn = static_cast<const SkipNode*>(root); PlanStage* childStage = buildStages(qsol, sn->children[0], ws); if (NULL == childStage) { return NULL; } return new SkipStage(sn->skip, ws, childStage); } else if (STAGE_AND_HASH == root->getType()) { const AndHashNode* ahn = static_cast<const AndHashNode*>(root); auto_ptr<AndHashStage> ret(new AndHashStage(ws, ahn->filter.get())); for (size_t i = 0; i < ahn->children.size(); ++i) { PlanStage* childStage = buildStages(qsol, ahn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_OR == root->getType()) { const OrNode * orn = static_cast<const OrNode*>(root); auto_ptr<OrStage> ret(new OrStage(ws, orn->dedup, orn->filter.get())); for (size_t i = 0; i < orn->children.size(); ++i) { PlanStage* childStage = buildStages(qsol, orn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_AND_SORTED == root->getType()) { const AndSortedNode* asn = static_cast<const AndSortedNode*>(root); auto_ptr<AndSortedStage> ret(new AndSortedStage(ws, asn->filter.get())); for (size_t i = 0; i < asn->children.size(); ++i) { PlanStage* childStage = buildStages(qsol, asn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_SORT_MERGE == root->getType()) { const MergeSortNode* msn = static_cast<const MergeSortNode*>(root); MergeSortStageParams params; params.dedup = msn->dedup; params.pattern = msn->sort; auto_ptr<MergeSortStage> ret(new MergeSortStage(params, ws)); for (size_t i = 0; i < msn->children.size(); ++i) { PlanStage* childStage = buildStages(qsol, msn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_GEO_2D == root->getType()) { const Geo2DNode* node = static_cast<const Geo2DNode*>(root); TwoDParams params; params.gq = node->gq; params.filter = node->filter.get(); params.indexKeyPattern = node->indexKeyPattern; params.ns = qsol.ns; return new TwoD(params, ws); } else if (STAGE_GEO_NEAR_2D == root->getType()) { const GeoNear2DNode* node = static_cast<const GeoNear2DNode*>(root); TwoDNearParams params; params.nearQuery = node->nq; params.ns = qsol.ns; params.indexKeyPattern = node->indexKeyPattern; params.filter = node->filter.get(); params.numWanted = node->numWanted; params.addPointMeta = node->addPointMeta; params.addDistMeta = node->addDistMeta; return new TwoDNear(params, ws); } else if (STAGE_GEO_NEAR_2DSPHERE == root->getType()) { const GeoNear2DSphereNode* node = static_cast<const GeoNear2DSphereNode*>(root); S2NearParams params; params.ns = qsol.ns; params.indexKeyPattern = node->indexKeyPattern; params.nearQuery = node->nq; params.baseBounds = node->baseBounds; params.filter = node->filter.get(); params.addPointMeta = node->addPointMeta; params.addDistMeta = node->addDistMeta; return new S2NearStage(params, ws); } else if (STAGE_TEXT == root->getType()) { const TextNode* node = static_cast<const TextNode*>(root); Database* db = cc().database(); Collection* collection = db ? db->getCollection(qsol.ns) : NULL; if (NULL == collection) { warning() << "null collection for text?"; return NULL; } vector<int> idxMatches; collection->details()->findIndexByType("text", idxMatches); if (1 != idxMatches.size()) { warning() << "more than one text idx?"; return NULL; } IndexDescriptor* index = collection->getIndexCatalog()->getDescriptor(idxMatches[0]); const FTSAccessMethod* fam = static_cast<FTSAccessMethod*>( collection->getIndexCatalog()->getIndex( index ) ); TextStageParams params(fam->getSpec()); params.ns = qsol.ns; params.index = index; params.spec = fam->getSpec(); // XXX change getIndexPrefix to not look at BSONObj Status s = fam->getSpec().getIndexPrefix(qsol.filterData, ¶ms.indexPrefix); if (!s.isOK()) { warning() << "can't get text index prefix??"; return NULL; } string language = ("" == node->_language ? fam->getSpec().defaultLanguage().str() : node->_language); FTSQuery ftsq; Status parseStatus = ftsq.parse(node->_query, language); if (!parseStatus.isOK()) { warning() << "cant parse fts query"; return NULL; } params.query = ftsq; return new TextStage(params, ws, node->filter.get()); } else if (STAGE_SHARDING_FILTER == root->getType()) { const ShardingFilterNode* fn = static_cast<const ShardingFilterNode*>(root); PlanStage* childStage = buildStages(qsol, fn->children[0], ws); if (NULL == childStage) { return NULL; } return new ShardFilterStage(shardingState.getCollectionMetadata(qsol.ns), ws, childStage); } else { stringstream ss; root->appendToString(&ss, 0); warning() << "Could not build exec tree for node " << ss.str() << endl; return NULL; } }
IndexDescriptor* getIndex(const BSONObj& obj) { Client::ReadContext ctx(ns()); NamespaceDetails* nsd = nsdetails(ns()); int idxNo = nsd->findIndexByKeyPattern(obj); return CatalogHack::getDescriptor(nsd, idxNo); }
PlanStage* parseQuery(const string& dbname, BSONObj obj, WorkingSet* workingSet, OwnedPointerVector<MatchExpression>* exprs) { BSONElement firstElt = obj.firstElement(); if (!firstElt.isABSONObj()) { return NULL; } BSONObj paramObj = firstElt.Obj(); MatchExpression* matcher = NULL; BSONObj nodeArgs; // Every node has these two fields. const string filterTag = "filter"; const string argsTag = "args"; BSONObjIterator it(paramObj); while (it.more()) { BSONElement e = it.next(); if (!e.isABSONObj()) { return NULL; } BSONObj argObj = e.Obj(); if (filterTag == e.fieldName()) { StatusWithMatchExpression swme = MatchExpressionParser::parse(argObj); if (!swme.isOK()) { return NULL; } // exprs is what will wind up deleting this. matcher = swme.getValue(); verify(NULL != matcher); exprs->mutableVector().push_back(matcher); } else if (argsTag == e.fieldName()) { nodeArgs = argObj; } else { uasserted(16910, "Unknown fieldname " + string(e.fieldName()) + " in query node " + obj.toString()); return NULL; } } string nodeName = firstElt.fieldName(); if ("ixscan" == nodeName) { NamespaceDetails* nsd = nsdetails(dbname + "." + nodeArgs["name"].String()); uassert(16913, "Can't find collection " + nodeArgs["name"].String(), nsd); int idxNo = nsd->findIndexByKeyPattern(nodeArgs["keyPattern"].Obj()); uassert(16890, "Can't find index: " + nodeArgs["keyPattern"].Obj().toString(), idxNo != -1); IndexScanParams params; params.descriptor = CatalogHack::getDescriptor(nsd, idxNo); params.startKey = nodeArgs["startKey"].Obj(); params.endKey = nodeArgs["endKey"].Obj(); params.endKeyInclusive = nodeArgs["endKeyInclusive"].Bool(); params.direction = nodeArgs["direction"].numberInt(); params.limit = nodeArgs["limit"].numberInt(); params.forceBtreeAccessMethod = false; return new IndexScan(params, workingSet, matcher); } else if ("andHash" == nodeName) { uassert(16921, "Nodes argument must be provided to AND", nodeArgs["nodes"].isABSONObj()); auto_ptr<AndHashStage> andStage(new AndHashStage(workingSet, matcher)); int nodesAdded = 0; BSONObjIterator it(nodeArgs["nodes"].Obj()); while (it.more()) { BSONElement e = it.next(); uassert(16922, "node of AND isn't an obj?: " + e.toString(), e.isABSONObj()); PlanStage* subNode = parseQuery(dbname, e.Obj(), workingSet, exprs); uassert(16923, "Can't parse sub-node of AND: " + e.Obj().toString(), NULL != subNode); // takes ownership andStage->addChild(subNode); ++nodesAdded; } uassert(16927, "AND requires more than one child", nodesAdded >= 2); return andStage.release(); } else if ("andSorted" == nodeName) { uassert(16924, "Nodes argument must be provided to AND", nodeArgs["nodes"].isABSONObj()); auto_ptr<AndSortedStage> andStage(new AndSortedStage(workingSet, matcher)); int nodesAdded = 0; BSONObjIterator it(nodeArgs["nodes"].Obj()); while (it.more()) { BSONElement e = it.next(); uassert(16925, "node of AND isn't an obj?: " + e.toString(), e.isABSONObj()); PlanStage* subNode = parseQuery(dbname, e.Obj(), workingSet, exprs); uassert(16926, "Can't parse sub-node of AND: " + e.Obj().toString(), NULL != subNode); // takes ownership andStage->addChild(subNode); ++nodesAdded; } uassert(16928, "AND requires more than one child", nodesAdded >= 2); return andStage.release(); } else if ("or" == nodeName) { uassert(16934, "Nodes argument must be provided to AND", nodeArgs["nodes"].isABSONObj()); uassert(16935, "Dedup argument must be provided to OR", !nodeArgs["dedup"].eoo()); BSONObjIterator it(nodeArgs["nodes"].Obj()); auto_ptr<OrStage> orStage(new OrStage(workingSet, nodeArgs["dedup"].Bool(), matcher)); while (it.more()) { BSONElement e = it.next(); if (!e.isABSONObj()) { return NULL; } PlanStage* subNode = parseQuery(dbname, e.Obj(), workingSet, exprs); uassert(16936, "Can't parse sub-node of OR: " + e.Obj().toString(), NULL != subNode); // takes ownership orStage->addChild(subNode); } return orStage.release(); } else if ("fetch" == nodeName) { uassert(16929, "Node argument must be provided to fetch", nodeArgs["node"].isABSONObj()); PlanStage* subNode = parseQuery(dbname, nodeArgs["node"].Obj(), workingSet, exprs); return new FetchStage(workingSet, subNode, matcher); } else if ("limit" == nodeName) { uassert(16937, "Limit stage doesn't have a filter (put it on the child)", NULL == matcher); uassert(16930, "Node argument must be provided to limit", nodeArgs["node"].isABSONObj()); uassert(16931, "Num argument must be provided to limit", nodeArgs["num"].isNumber()); PlanStage* subNode = parseQuery(dbname, nodeArgs["node"].Obj(), workingSet, exprs); return new LimitStage(nodeArgs["num"].numberInt(), workingSet, subNode); } else if ("skip" == nodeName) { uassert(16938, "Skip stage doesn't have a filter (put it on the child)", NULL == matcher); uassert(16932, "Node argument must be provided to skip", nodeArgs["node"].isABSONObj()); uassert(16933, "Num argument must be provided to skip", nodeArgs["num"].isNumber()); PlanStage* subNode = parseQuery(dbname, nodeArgs["node"].Obj(), workingSet, exprs); return new SkipStage(nodeArgs["num"].numberInt(), workingSet, subNode); } else if ("cscan" == nodeName) { CollectionScanParams params; // What collection? params.ns = dbname + "." + nodeArgs["name"].String(); uassert(16962, "Can't find collection " + nodeArgs["name"].String(), NULL != nsdetails(params.ns)); // What direction? uassert(16963, "Direction argument must be specified and be a number", nodeArgs["direction"].isNumber()); if (1 == nodeArgs["direction"].numberInt()) { params.direction = CollectionScanParams::FORWARD; } else { params.direction = CollectionScanParams::BACKWARD; } return new CollectionScan(params, workingSet, matcher); } else if ("sort" == nodeName) { uassert(16969, "Node argument must be provided to sort", nodeArgs["node"].isABSONObj()); uassert(16970, "Pattern argument must be provided to sort", nodeArgs["pattern"].isABSONObj()); PlanStage* subNode = parseQuery(dbname, nodeArgs["node"].Obj(), workingSet, exprs); SortStageParams params; params.pattern = nodeArgs["pattern"].Obj(); return new SortStage(params, workingSet, subNode); } else if ("mergeSort" == nodeName) { uassert(16971, "Nodes argument must be provided to sort", nodeArgs["nodes"].isABSONObj()); uassert(16972, "Pattern argument must be provided to sort", nodeArgs["pattern"].isABSONObj()); MergeSortStageParams params; params.pattern = nodeArgs["pattern"].Obj(); // Dedup is true by default. auto_ptr<MergeSortStage> mergeStage(new MergeSortStage(params, workingSet)); BSONObjIterator it(nodeArgs["nodes"].Obj()); while (it.more()) { BSONElement e = it.next(); uassert(16973, "node of mergeSort isn't an obj?: " + e.toString(), e.isABSONObj()); PlanStage* subNode = parseQuery(dbname, e.Obj(), workingSet, exprs); uassert(16974, "Can't parse sub-node of mergeSort: " + e.Obj().toString(), NULL != subNode); // takes ownership mergeStage->addChild(subNode); } return mergeStage.release(); } else { return NULL; } }
PlanStage* buildStages(const string& ns, const QuerySolutionNode* root, WorkingSet* ws) { if (STAGE_COLLSCAN == root->getType()) { const CollectionScanNode* csn = static_cast<const CollectionScanNode*>(root); CollectionScanParams params; params.ns = csn->name; params.tailable = csn->tailable; params.direction = (csn->direction == 1) ? CollectionScanParams::FORWARD : CollectionScanParams::BACKWARD; return new CollectionScan(params, ws, csn->filter.get()); } else if (STAGE_IXSCAN == root->getType()) { const IndexScanNode* ixn = static_cast<const IndexScanNode*>(root); // // XXX XXX // Given that this grabs data from the catalog, we must do this inside of a lock. // We should change this to take a (ns, index key pattern) pair so that the params // don't involve any on-disk data, just descriptions thereof. // XXX XXX // IndexScanParams params; NamespaceDetails* nsd = nsdetails(ns.c_str()); if (NULL == nsd) { warning() << "Can't ixscan null ns " << ns << endl; return NULL; } int idxNo = nsd->findIndexByKeyPattern(ixn->indexKeyPattern); if (-1 == idxNo) { warning() << "Can't find idx " << ixn->indexKeyPattern.toString() << "in ns " << ns << endl; return NULL; } params.descriptor = CatalogHack::getDescriptor(nsd, idxNo); params.bounds = ixn->bounds; params.direction = ixn->direction; params.limit = ixn->limit; return new IndexScan(params, ws, ixn->filter.get()); } else if (STAGE_FETCH == root->getType()) { const FetchNode* fn = static_cast<const FetchNode*>(root); PlanStage* childStage = buildStages(ns, fn->child.get(), ws); if (NULL == childStage) { return NULL; } return new FetchStage(ws, childStage, fn->filter.get()); } else if (STAGE_SORT == root->getType()) { const SortNode* sn = static_cast<const SortNode*>(root); PlanStage* childStage = buildStages(ns, sn->child.get(), ws); if (NULL == childStage) { return NULL; } SortStageParams params; params.pattern = sn->pattern; return new SortStage(params, ws, childStage); } else if (STAGE_PROJECTION == root->getType()) { const ProjectionNode* pn = static_cast<const ProjectionNode*>(root); PlanStage* childStage = buildStages(ns, pn->child.get(), ws); if (NULL == childStage) { return NULL; } return new ProjectionStage(pn->projection, ws, childStage, NULL); } else if (STAGE_LIMIT == root->getType()) { const LimitNode* ln = static_cast<const LimitNode*>(root); PlanStage* childStage = buildStages(ns, ln->child.get(), ws); if (NULL == childStage) { return NULL; } return new LimitStage(ln->limit, ws, childStage); } else if (STAGE_SKIP == root->getType()) { const SkipNode* sn = static_cast<const SkipNode*>(root); PlanStage* childStage = buildStages(ns, sn->child.get(), ws); if (NULL == childStage) { return NULL; } return new SkipStage(sn->skip, ws, childStage); } else if (STAGE_AND_HASH == root->getType()) { const AndHashNode* ahn = static_cast<const AndHashNode*>(root); auto_ptr<AndHashStage> ret(new AndHashStage(ws, ahn->filter.get())); for (size_t i = 0; i < ahn->children.size(); ++i) { PlanStage* childStage = buildStages(ns, ahn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_OR == root->getType()) { const OrNode * orn = static_cast<const OrNode*>(root); auto_ptr<OrStage> ret(new OrStage(ws, orn->dedup, orn->filter.get())); for (size_t i = 0; i < orn->children.size(); ++i) { PlanStage* childStage = buildStages(ns, orn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_AND_SORTED == root->getType()) { const AndSortedNode* asn = static_cast<const AndSortedNode*>(root); auto_ptr<AndSortedStage> ret(new AndSortedStage(ws, asn->filter.get())); for (size_t i = 0; i < asn->children.size(); ++i) { PlanStage* childStage = buildStages(ns, asn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_SORT_MERGE == root->getType()) { const MergeSortNode* msn = static_cast<const MergeSortNode*>(root); MergeSortStageParams params; params.dedup = msn->dedup; params.pattern = msn->sort; auto_ptr<MergeSortStage> ret(new MergeSortStage(params, ws)); for (size_t i = 0; i < msn->children.size(); ++i) { PlanStage* childStage = buildStages(ns, msn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } return ret.release(); } else if (STAGE_GEO_2D == root->getType()) { const Geo2DNode* node = static_cast<const Geo2DNode*>(root); TwoDParams params; params.gq = node->gq; params.filter = node->filter.get(); params.indexKeyPattern = node->indexKeyPattern; params.ns = ns; return new TwoD(params, ws); } else if (STAGE_GEO_NEAR_2D == root->getType()) { const GeoNear2DNode* node = static_cast<const GeoNear2DNode*>(root); TwoDNearParams params; params.nearQuery = node->nq; params.ns = ns; params.indexKeyPattern = node->indexKeyPattern; params.filter = node->filter.get(); params.numWanted = node->numWanted; // XXX XXX where do we grab this from?? the near query...modify geo parser... :( params.uniqueDocs = false; // XXX XXX where do we grab this from?? the near query...modify geo parser... :( return new TwoDNear(params, ws); } else if (STAGE_GEO_NEAR_2DSPHERE == root->getType()) { const GeoNear2DSphereNode* node = static_cast<const GeoNear2DSphereNode*>(root); return new S2NearStage(ns, node->indexKeyPattern, node->nq, node->baseBounds, node->filter.get(), ws); } else if (STAGE_TEXT == root->getType()) { const TextNode* node = static_cast<const TextNode*>(root); NamespaceDetails* nsd = nsdetails(ns.c_str()); if (NULL == nsd) { return NULL; } vector<int> idxMatches; nsd->findIndexByType("text", idxMatches); if (1 != idxMatches.size()) { return NULL; } IndexDescriptor* index = CatalogHack::getDescriptor(nsd, idxMatches[0]); auto_ptr<FTSAccessMethod> fam(new FTSAccessMethod(index)); TextStageParams params(fam->getSpec()); params.ns = ns; params.index = index; params.spec = fam->getSpec(); params.limit = node->_numWanted; Status s = fam->getSpec().getIndexPrefix(BSONObj(), ¶ms.indexPrefix); if (!s.isOK()) { return NULL; } string language = ("" == node->_language ? fam->getSpec().defaultLanguage() : node->_language); FTSQuery ftsq; Status parseStatus = ftsq.parse(node->_query, language); if (!parseStatus.isOK()) { return NULL; } params.query = ftsq; return new TextStage(params, ws, node->_filter.get()); } else { stringstream ss; root->appendToString(&ss, 0); warning() << "Could not build exec tree for node " << ss.str() << endl; return NULL; } }
long long Helpers::removeRange( const string& ns , const BSONObj& min , const BSONObj& max , const BSONObj& keyPattern , bool maxInclusive , bool secondaryThrottle , RemoveCallback * callback, bool fromMigrate ) { Client& c = cc(); long long numDeleted = 0; PageFaultRetryableSection pgrs; long long millisWaitingForReplication = 0; while ( 1 ) { try { Client::WriteContext ctx(ns); scoped_ptr<Cursor> c; { NamespaceDetails* nsd = nsdetails( ns.c_str() ); if ( ! nsd ) break; int ii = nsd->findIndexByKeyPattern( keyPattern ); verify( ii >= 0 ); IndexDetails& i = nsd->idx( ii ); // Extend min to get (min, MinKey, MinKey, ....) BSONObj newMin = Helpers::modifiedRangeBound( min , keyPattern , -1 ); // If upper bound is included, extend max to get (max, MaxKey, MaxKey, ...) // If not included, extend max to get (max, MinKey, MinKey, ....) int minOrMax = maxInclusive ? 1 : -1; BSONObj newMax = Helpers::modifiedRangeBound( max , keyPattern , minOrMax ); c.reset( BtreeCursor::make( nsd , ii , i , newMin , newMax , maxInclusive , 1 ) ); } if ( ! c->ok() ) { // we're done break; } DiskLoc rloc = c->currLoc(); BSONObj obj = c->current(); // this is so that we don't have to handle this cursor in the delete code c.reset(0); if ( callback ) callback->goingToDelete( obj ); logOp( "d" , ns.c_str() , rloc.obj()["_id"].wrap() , 0 , 0 , fromMigrate ); theDataFileMgr.deleteRecord(ns.c_str() , rloc.rec(), rloc); numDeleted++; } catch( PageFaultException& e ) { e.touch(); continue; } Timer secondaryThrottleTime; if ( secondaryThrottle ) { if ( ! waitForReplication( c.getLastOp(), 2, 60 /* seconds to wait */ ) ) { warning() << "replication to secondaries for removeRange at least 60 seconds behind" << endl; } millisWaitingForReplication += secondaryThrottleTime.millis(); } if ( ! Lock::isLocked() ) { int micros = ( 2 * Client::recommendedYieldMicros() ) - secondaryThrottleTime.micros(); if ( micros > 0 ) { LOG(1) << "Helpers::removeRangeUnlocked going to sleep for " << micros << " micros" << endl; sleepmicros( micros ); } } } if ( secondaryThrottle ) log() << "Helpers::removeRangeUnlocked time spent waiting for replication: " << millisWaitingForReplication << "ms" << endl; return numDeleted; }