summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/SConscript2
-rw-r--r--src/mongo/db/fts/fts_index.cpp8
-rw-r--r--src/mongo/db/fts/fts_index.h5
-rw-r--r--src/mongo/db/geo/2d.cpp49
-rw-r--r--src/mongo/db/geo/geonear.cpp20
-rw-r--r--src/mongo/db/geo/haystack.cpp8
-rw-r--r--src/mongo/db/geo/s2index.cpp44
-rw-r--r--src/mongo/db/hashindex.cpp14
-rw-r--r--src/mongo/db/hashindex.h22
-rw-r--r--src/mongo/db/index/2d_access_method.cpp5
-rw-r--r--src/mongo/db/index/2d_common.h1
-rw-r--r--src/mongo/db/index/2d_index_cursor.cpp2
-rw-r--r--src/mongo/db/index/catalog_hack.h21
-rw-r--r--src/mongo/db/index/emulated_cursor.h29
-rw-r--r--src/mongo/db/index/s2_access_method.cpp7
-rw-r--r--src/mongo/db/index/s2_common.h2
-rw-r--r--src/mongo/db/index/s2_index_cursor.cpp3
-rw-r--r--src/mongo/db/index_names.cpp26
-rw-r--r--src/mongo/db/index_names.h39
-rw-r--r--src/mongo/db/index_selection.cpp170
-rw-r--r--src/mongo/db/index_selection.h42
-rw-r--r--src/mongo/db/indexkey.cpp35
-rw-r--r--src/mongo/db/indexkey.h39
-rw-r--r--src/mongo/db/query_optimizer_internal.cpp9
-rw-r--r--src/mongo/db/query_plan.cpp5
-rw-r--r--src/mongo/db/queryutil.cpp11
-rw-r--r--src/mongo/dbtests/namespacetests.cpp87
27 files changed, 393 insertions, 312 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index c6e4f35e8ee..fac782eadc4 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -238,6 +238,7 @@ env.StaticLibrary("coredb", [
"db/pipeline/pipeline.cpp",
"db/dbcommands_generic.cpp",
"db/dbwebserver.cpp",
+ "db/index_names.cpp",
"db/keypattern.cpp",
"db/matcher.cpp",
"db/pipeline/accumulator.cpp",
@@ -287,6 +288,7 @@ env.StaticLibrary("coredb", [
coreServerFiles = [ "db/client_basic.cpp",
"util/net/miniwebserver.cpp",
"db/indexkey.cpp",
+ "db/index_selection.cpp",
"db/stats/counters.cpp",
"db/stats/service_stats.cpp",
]
diff --git a/src/mongo/db/fts/fts_index.cpp b/src/mongo/db/fts/fts_index.cpp
index 2e667d0d1f7..0f6c3995fce 100644
--- a/src/mongo/db/fts/fts_index.cpp
+++ b/src/mongo/db/fts/fts_index.cpp
@@ -48,14 +48,6 @@ namespace mongo {
FTSIndexFormat::getKeys( _ftsSpec, obj, &keys );
}
- shared_ptr<Cursor> FTSIndex::newCursor( const BSONObj& query,
- const BSONObj& order,
- int numWanted ) const {
- shared_ptr<Cursor> c;
- verify(0);
- return c;
- }
-
FTSIndexPlugin::FTSIndexPlugin() : IndexPlugin( INDEX_NAME ) {}
diff --git a/src/mongo/db/fts/fts_index.h b/src/mongo/db/fts/fts_index.h
index 2eff9207ab1..a6a1378672f 100644
--- a/src/mongo/db/fts/fts_index.h
+++ b/src/mongo/db/fts/fts_index.h
@@ -40,11 +40,6 @@ namespace mongo {
void getKeys( const BSONObj& obj, BSONObjSet& keys) const;
- /* newCursor is pure Virtual in IndexType so it has to be redefined in FTSIndex */
- shared_ptr<Cursor> newCursor( const BSONObj& query,
- const BSONObj& order,
- int numWanted ) const;
-
const FTSSpec& getFtsSpec() const { return _ftsSpec; }
private:
diff --git a/src/mongo/db/geo/2d.cpp b/src/mongo/db/geo/2d.cpp
index 487df2c846b..21ecfac92ae 100644
--- a/src/mongo/db/geo/2d.cpp
+++ b/src/mongo/db/geo/2d.cpp
@@ -214,55 +214,6 @@ namespace mongo {
const IndexDetails* getDetails() const { return _spec->getDetails(); }
- virtual shared_ptr<Cursor> newCursor(const BSONObj& query, const BSONObj& order,
- int numWanted) const {
- shared_ptr<Cursor> c;
- verify(0);
- return c;
- }
-
- virtual IndexSuitability suitability( const FieldRangeSet& queryConstraints ,
- const BSONObj& order ) const {
- BSONObj query = queryConstraints.originalQuery();
-
- BSONElement e = query.getFieldDotted(_geo.c_str());
- switch (e.type()) {
- case Object: {
- BSONObj sub = e.embeddedObject();
- switch (sub.firstElement().getGtLtOp()) {
- case BSONObj::opNEAR:
- return OPTIMAL;
- case BSONObj::opWITHIN: {
- // Don't return optimal if it's $within: {$geometry: ... }
- // because we will error out in that case, but the matcher
- // or 2dsphere index may handle it.
- BSONElement elt = sub.firstElement();
- if (Object == elt.type()) {
- BSONObjIterator it(elt.embeddedObject());
- while (it.more()) {
- BSONElement elt = it.next();
- if (mongoutils::str::equals("$geometry", elt.fieldName())) {
- return USELESS;
- }
- }
- }
- return OPTIMAL;
- }
- default:
- // We can try to match if there's no other indexing defined,
- // this is assumed a point
- return HELPFUL;
- }
- }
- case Array:
- // We can try to match if there's no other indexing defined,
- // this is assumed a point
- return HELPFUL;
- default:
- return USELESS;
- }
- }
-
const GeoHashConverter& getConverter() const { return *_geoHashConverter; }
// XXX: make private with a getter
diff --git a/src/mongo/db/geo/geonear.cpp b/src/mongo/db/geo/geonear.cpp
index 83d2600c753..c262912c4c8 100644
--- a/src/mongo/db/geo/geonear.cpp
+++ b/src/mongo/db/geo/geonear.cpp
@@ -23,6 +23,7 @@
#include "mongo/db/auth/privilege.h"
#include "mongo/db/commands.h"
#include "mongo/db/curop.h"
+#include "mongo/db/index_names.h"
#include "mongo/db/index/2d_index_cursor.h"
#include "mongo/db/index/catalog_hack.h"
#include "mongo/db/index/index_descriptor.h"
@@ -106,7 +107,7 @@ namespace mongo {
vector<int> idxs;
- d->findIndexByType("2d", idxs);
+ d->findIndexByType(IndexNames::GEO_2D, idxs);
if (idxs.size() > 1) {
errmsg = "more than one 2d index, not sure which to run geoNear on";
return false;
@@ -114,10 +115,14 @@ namespace mongo {
if (1 == idxs.size()) {
result.append("ns", ns);
- return twod_internal::TwoDGeoNearRunner::run2DGeoNear(d, idxs[0], cmdObj, commonArgs, errmsg, result);
+ twod_internal::TwoDGeoNearRunner::run2DGeoNear(d, idxs[0], cmdObj, commonArgs, errmsg, result);
+ BSONObjBuilder stats(result.subobjStart("stats"));
+ stats.append("time", cc().curop()->elapsedMillis());
+ stats.done();
+ return true;
}
- d->findIndexByType("2dsphere", idxs);
+ d->findIndexByType(IndexNames::GEO_2DSPHERE, idxs);
if (idxs.size() > 1) {
errmsg = "more than one 2dsphere index, not sure which to run geoNear on";
return false;
@@ -125,7 +130,11 @@ namespace mongo {
if (1 == idxs.size()) {
result.append("ns", ns);
- return run2DSphereGeoNear(d, idxs[0], cmdObj, commonArgs, errmsg, result);
+ run2DSphereGeoNear(d, idxs[0], cmdObj, commonArgs, errmsg, result);
+ BSONObjBuilder stats(result.subobjStart("stats"));
+ stats.append("time", cc().curop()->elapsedMillis());
+ stats.done();
+ return true;
}
errmsg = "no geo indices for geoNear";
@@ -146,7 +155,7 @@ namespace mongo {
BSONObjIterator i(descriptor->keyPattern());
while (i.more()) {
BSONElement e = i.next();
- if (e.type() == String && S2IndexingParams::SPHERE_2D_NAME == e.valuestr()) {
+ if (e.type() == String && IndexNames::GEO_2DSPHERE == e.valuestr()) {
geoFieldNames.push_back(e.fieldName());
}
}
@@ -213,7 +222,6 @@ namespace mongo {
resultBuilder.done();
BSONObjBuilder stats(result.subobjStart("stats"));
- stats.append("time", cc().curop()->elapsedMillis());
stats.appendNumber("nscanned", nic->nscanned());
stats.append("avgDistance", totalDistance / results);
stats.append("maxDistance", farthestDist);
diff --git a/src/mongo/db/geo/haystack.cpp b/src/mongo/db/geo/haystack.cpp
index 0d77876a68a..6088d7c8f1e 100644
--- a/src/mongo/db/geo/haystack.cpp
+++ b/src/mongo/db/geo/haystack.cpp
@@ -176,14 +176,6 @@ namespace mongo {
}
}
- // XXX: Who could call this and how do they know not to actually do so?
- shared_ptr<Cursor> newCursor(const BSONObj& query, const BSONObj& order,
- int numWanted) const {
- shared_ptr<Cursor> c;
- verify(0);
- return c;
- }
-
void searchCommand(NamespaceDetails* nsd,
const BSONObj& n /*near*/, double maxDistance, const BSONObj& search,
BSONObjBuilder& result, unsigned limit) {
diff --git a/src/mongo/db/geo/s2index.cpp b/src/mongo/db/geo/s2index.cpp
index 5b024104a22..568a8db6145 100644
--- a/src/mongo/db/geo/s2index.cpp
+++ b/src/mongo/db/geo/s2index.cpp
@@ -138,50 +138,6 @@ namespace mongo {
}
}
- // Entry point for a search.
- virtual shared_ptr<Cursor> newCursor(const BSONObj& query, const BSONObj& order,
- int numWanted) const {
- shared_ptr<Cursor> c;
- verify(0);
- return c;
- }
-
- virtual IndexSuitability suitability(const FieldRangeSet& queryConstraints,
- const BSONObj& order) const {
- BSONObj query = queryConstraints.originalQuery();
-
- for (size_t i = 0; i < _fields.size(); ++i) {
- const IndexedField &field = _fields[i];
- if (IndexedField::GEO != field.type) { continue; }
-
- BSONElement e = query.getFieldDotted(field.name);
- // Some locations are given to us as arrays. Sigh.
- if (Array == e.type()) { return HELPFUL; }
- if (Object != e.type()) { continue; }
- // getGtLtOp is horribly misnamed and really means get the operation.
- switch (e.embeddedObject().firstElement().getGtLtOp()) {
- case BSONObj::opNEAR:
- return OPTIMAL;
- case BSONObj::opWITHIN: {
- BSONElement elt = e.embeddedObject().firstElement();
- if (Object != elt.type()) { continue; }
- const char* fname = elt.embeddedObject().firstElement().fieldName();
- if (mongoutils::str::equals("$geometry", fname)
- || mongoutils::str::equals("$centerSphere", fname)) {
- return OPTIMAL;
- } else {
- return USELESS;
- }
- }
- case BSONObj::opGEO_INTERSECTS:
- return OPTIMAL;
- default:
- return USELESS;
- }
- }
- return USELESS;
- }
-
const IndexDetails* getDetails() const { return _spec->getDetails(); }
// These are used by the geoNear command. geoNear constructs its own cursor.
diff --git a/src/mongo/db/hashindex.cpp b/src/mongo/db/hashindex.cpp
index 61c8f394af5..a658ba1467f 100644
--- a/src/mongo/db/hashindex.cpp
+++ b/src/mongo/db/hashindex.cpp
@@ -69,13 +69,6 @@ namespace mongo {
HashedIndexType::~HashedIndexType() { }
- IndexSuitability HashedIndexType::suitability( const FieldRangeSet& queryConstraints ,
- const BSONObj& order ) const {
- if ( queryConstraints.isPointIntervalSet( _hashedField ) )
- return HELPFUL;
- return USELESS;
- }
-
void HashedIndexType::getKeys( const BSONObj &obj, BSONObjSet &keys ) const {
string hashedFieldCopy = string( _hashedField );
const char* hashedFieldCopyPtr = hashedFieldCopy.c_str();
@@ -92,13 +85,6 @@ namespace mongo {
}
}
- shared_ptr<Cursor> HashedIndexType::newCursor(const BSONObj& query, const BSONObj& order,
- int numWanted) const {
- shared_ptr<Cursor> c;
- verify(0);
- return c;
- }
-
/* This class registers HASHED_INDEX_NAME in a global map of special index types
* Using this pattern, any index with the pattern, {fieldname : HASHED_INDEX_NAME}
* will be recognized as a HashedIndexType and the associated methods will be used.
diff --git a/src/mongo/db/hashindex.h b/src/mongo/db/hashindex.h
index 7451ba307f1..f7bfa4b4552 100644
--- a/src/mongo/db/hashindex.h
+++ b/src/mongo/db/hashindex.h
@@ -64,21 +64,6 @@ namespace mongo {
HashedIndexType( const IndexPlugin* plugin , const IndexSpec* spec );
virtual ~HashedIndexType();
- /* This index is only considered "HELPFUL" for a query
- * if it's the union of at least one equality constraint on the
- * hashed field. Otherwise it's considered USELESS.
- * Example queries (supposing the indexKey is {a : "hashed"}):
- * {a : 3} HELPFUL
- * {a : 3 , b : 3} HELPFUL
- * {a : {$in : [3,4]}} HELPFUL
- * {a : {$gte : 3, $lte : 3}} HELPFUL
- * {} USELESS
- * {b : 3} USELESS
- * {a : {$gt : 3}} USELESS
- */
- IndexSuitability suitability( const FieldRangeSet& queryConstraints ,
- const BSONObj& order ) const;
-
/* The input is "obj" which should have a field corresponding to the hashedfield.
* The output is a BSONObj with a single BSONElement whose value is the hash
* Eg if this is an index on "a" we have
@@ -93,13 +78,6 @@ namespace mongo {
*/
BSONElement missingField() const { return _missingKey.firstElement(); }
- /* The newCursor method works for suitable queries by generating a BtreeCursor
- * using the hash of point-intervals parsed by FieldRangeSet.
- * For unsuitable queries it just instantiates a btree cursor over the whole tree
- */
- shared_ptr<Cursor> newCursor( const BSONObj& query ,
- const BSONObj& order , int numWanted ) const;
-
/* Takes a BSONElement, seed and hashVersion, and outputs the
* 64-bit hash used for this index
* E.g. if the element is {a : 3} this outputs v1-hash(3)
diff --git a/src/mongo/db/index/2d_access_method.cpp b/src/mongo/db/index/2d_access_method.cpp
index 33e7c8aede8..1d69796833f 100644
--- a/src/mongo/db/index/2d_access_method.cpp
+++ b/src/mongo/db/index/2d_access_method.cpp
@@ -20,6 +20,7 @@
#include <vector>
#include "mongo/db/geo/core.h"
+#include "mongo/db/index_names.h"
#include "mongo/db/index/2d_common.h"
#include "mongo/db/index/2d_index_cursor.h"
#include "mongo/db/jsobj.h"
@@ -27,8 +28,6 @@
namespace mongo {
- const string TwoDIndexingParams::TWOD_NAME = "2d";
-
static double configValueWithDefault(IndexDescriptor *desc, const string& name, double def) {
BSONElement e = desc->getInfoElement(name);
if (e.isNumber()) { return e.numberDouble(); }
@@ -41,7 +40,7 @@ namespace mongo {
BSONObjIterator i(descriptor->keyPattern());
while (i.more()) {
BSONElement e = i.next();
- if (e.type() == String && TwoDIndexingParams::TWOD_NAME == e.valuestr()) {
+ if (e.type() == String && IndexNames::GEO_2D == e.valuestr()) {
uassert(16800, "can't have 2 geo fields", _params.geo.size() == 0);
uassert(16801, "2d has to be first in index", _params.other.size() == 0);
_params.geo = e.fieldName();
diff --git a/src/mongo/db/index/2d_common.h b/src/mongo/db/index/2d_common.h
index 630d53afcd2..67426ce209b 100644
--- a/src/mongo/db/index/2d_common.h
+++ b/src/mongo/db/index/2d_common.h
@@ -24,7 +24,6 @@
namespace mongo {
struct TwoDIndexingParams {
- static const string TWOD_NAME;
string geo;
vector<pair<string, int> > other;
shared_ptr<GeoHashConverter> geoHashConverter;
diff --git a/src/mongo/db/index/2d_index_cursor.cpp b/src/mongo/db/index/2d_index_cursor.cpp
index 3c203520748..ab8d9944a89 100644
--- a/src/mongo/db/index/2d_index_cursor.cpp
+++ b/src/mongo/db/index/2d_index_cursor.cpp
@@ -17,7 +17,6 @@
#include "mongo/db/index/2d_index_cursor.h"
#include "mongo/db/btreecursor.h"
-#include "mongo/db/curop.h"
#include "mongo/db/index/2d_access_method.h"
#include "mongo/db/index/btree_interface.h"
#include "mongo/db/index/catalog_hack.h"
@@ -1821,7 +1820,6 @@ namespace mongo {
arr.done();
BSONObjBuilder stats(result.subobjStart("stats"));
- stats.append("time", cc().curop()->elapsedMillis());
stats.appendNumber("btreelocs", gs._nscanned);
stats.appendNumber("nscanned", gs._lookedAt);
stats.appendNumber("objectsLoaded", gs._objectsLoaded);
diff --git a/src/mongo/db/index/catalog_hack.h b/src/mongo/db/index/catalog_hack.h
index 34bf8171075..17eaacf78e5 100644
--- a/src/mongo/db/index/catalog_hack.h
+++ b/src/mongo/db/index/catalog_hack.h
@@ -25,6 +25,7 @@
#include "mongo/db/index/index_access_method.h"
#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/index/s2_access_method.h"
+#include "mongo/db/index_names.h"
#include "mongo/db/keypattern.h"
namespace mongo {
@@ -41,17 +42,17 @@ namespace mongo {
static BtreeBasedAccessMethod* getBtreeBasedIndex(IndexDescriptor* desc) {
string type = KeyPattern::findPluginName(desc->keyPattern());
- if ("hashed" == type) {
+ if (IndexNames::HASHED == type) {
return new HashAccessMethod(desc);
- } else if ("2dsphere" == type) {
+ } else if (IndexNames::GEO_2DSPHERE == type) {
return new S2AccessMethod(desc);
- } else if ("text" == type || "_fts" == type) {
+ } else if (IndexNames::TEXT == type || IndexNames::TEXT_INTERNAL == type) {
return new FTSAccessMethod(desc);
- } else if ("geoHaystack" == type) {
+ } else if (IndexNames::GEO_HAYSTACK == type) {
return new HaystackAccessMethod(desc);
} else if ("" == type) {
return new BtreeAccessMethod(desc);
- } else if ("2d" == type) {
+ } else if (IndexNames::GEO_2D == type) {
return new TwoDAccessMethod(desc);
} else {
cout << "Can't find index for keypattern " << desc->keyPattern() << endl;
@@ -62,17 +63,17 @@ namespace mongo {
static IndexAccessMethod* getIndex(IndexDescriptor* desc) {
string type = KeyPattern::findPluginName(desc->keyPattern());
- if ("hashed" == type) {
+ if (IndexNames::HASHED == type) {
return new HashAccessMethod(desc);
- } else if ("2dsphere" == type) {
+ } else if (IndexNames::GEO_2DSPHERE == type) {
return new S2AccessMethod(desc);
- } else if ("text" == type || "_fts" == type) {
+ } else if (IndexNames::TEXT == type || IndexNames::TEXT_INTERNAL == type) {
return new FTSAccessMethod(desc);
- } else if ("geoHaystack" == type) {
+ } else if (IndexNames::GEO_HAYSTACK == type) {
return new HaystackAccessMethod(desc);
} else if ("" == type) {
return new BtreeAccessMethod(desc);
- } else if ("2d" == type) {
+ } else if (IndexNames::GEO_2D == type) {
return new TwoDAccessMethod(desc);
} else {
cout << "Can't find index for keypattern " << desc->keyPattern() << endl;
diff --git a/src/mongo/db/index/emulated_cursor.h b/src/mongo/db/index/emulated_cursor.h
index f283768b4d6..e4f41631e98 100644
--- a/src/mongo/db/index/emulated_cursor.h
+++ b/src/mongo/db/index/emulated_cursor.h
@@ -20,6 +20,7 @@
#include <set>
#include "mongo/db/cursor.h"
+#include "mongo/db/index_names.h"
#include "mongo/db/index/index_access_method.h"
#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/index/index_cursor.h"
@@ -28,10 +29,6 @@
namespace mongo {
- static const string SPHERE_2D_NAME = "2dsphere";
- static const string HASH_NAME = "hashed";
- static const string GEO_2D_NAME = "2d";
-
/**
* This class is a crutch to help migrate from the old everything-is-a-Cursor world to the new
* index API world. It wraps a new IndexCursor in the old Cursor. We only use this for special
@@ -43,6 +40,14 @@ namespace mongo {
* Create a new EmulatedCursor.
* Takes ownership of the provided indexAccessMethod indexCursor.
* Takes ownership of the IndexDescriptor inside the indexAccessMethod.
+ *
+ * Full semantics of numWanted:
+ * numWanted == 0 : Return any number of results, but try to return in batches of 101.
+ * numWanted == 1 : Return exactly one result.
+ * numWanted > 1 : Return any number of results, but try to return in batches of numWanted.
+ *
+ * In practice, your cursor can ignore numWanted, as enforcement of limits is done
+ * by the caller.
*/
static EmulatedCursor* make(IndexDescriptor* descriptor,
IndexAccessMethod* indexAccessMethod,
@@ -147,13 +152,13 @@ namespace mongo {
options.numWanted = numWanted;
cursor->setOptions(options);
- if (HASH_NAME == _pluginName) {
+ if (IndexNames::HASHED == _pluginName) {
_supportYields = true;
_supportGetMore = true;
_modifiedKeys = true;
_shouldGetSetDup = false;
_autoDedup = true;
- } else if (SPHERE_2D_NAME == _pluginName) {
+ } else if (IndexNames::GEO_2DSPHERE == _pluginName) {
_supportYields = true;
_supportGetMore = true;
_modifiedKeys = true;
@@ -161,7 +166,7 @@ namespace mongo {
// to not de-dup themselves.
_shouldGetSetDup = true;
_autoDedup = false;
- } else if (GEO_2D_NAME == _pluginName) {
+ } else if (IndexNames::GEO_2D == _pluginName) {
_supportYields = false;
_supportGetMore = true;
_modifiedKeys = true;
@@ -190,7 +195,7 @@ namespace mongo {
_nscanned = 0;
}
- if (HASH_NAME == _pluginName) {
+ if (IndexNames::HASHED == _pluginName) {
// Quoted from hashindex.cpp:
// Force a match of the query against the actual document by giving
// the cursor a matcher with an empty indexKeyPattern. This ensures the
@@ -198,7 +203,7 @@ namespace mongo {
// NOTE: this forcing is necessary due to potential hash collisions
_matcher = shared_ptr<CoveredIndexMatcher>(
new CoveredIndexMatcher(query, BSONObj()));
- } else if (SPHERE_2D_NAME == _pluginName) {
+ } else if (IndexNames::GEO_2DSPHERE == _pluginName) {
// Technically, the non-geo indexed fields are in the key, though perhaps not in the
// exact format the matcher expects (arrays). So, we match against all non-geo
// fields. This could possibly be relaxed in some fashion in the future? Requires
@@ -208,7 +213,7 @@ namespace mongo {
while (keyIt.more()) {
BSONElement e = keyIt.next();
- if (e.type() == String && SPHERE_2D_NAME == e.valuestr()) {
+ if (e.type() == String && IndexNames::GEO_2DSPHERE == e.valuestr()) {
fieldsToNuke.append(e.fieldName(), "");
}
}
@@ -217,7 +222,7 @@ namespace mongo {
_matcher = shared_ptr<CoveredIndexMatcher>(
new CoveredIndexMatcher(filteredQuery, _keyPattern));
- } else if (GEO_2D_NAME == _pluginName) {
+ } else if (IndexNames::GEO_2D == _pluginName) {
// No-op matcher.
_matcher = shared_ptr<CoveredIndexMatcher>(
new CoveredIndexMatcher(BSONObj(), BSONObj()));
@@ -225,7 +230,7 @@ namespace mongo {
}
void checkMultiKeyProperties() {
- if (GEO_2D_NAME != _pluginName) {
+ if (IndexNames::GEO_2D != _pluginName) {
_isMultiKey = _shouldGetSetDup = _descriptor->isMultikey();
}
}
diff --git a/src/mongo/db/index/s2_access_method.cpp b/src/mongo/db/index/s2_access_method.cpp
index b4f7cd3f0fb..619775566c5 100644
--- a/src/mongo/db/index/s2_access_method.cpp
+++ b/src/mongo/db/index/s2_access_method.cpp
@@ -20,6 +20,7 @@
#include "mongo/base/status.h"
#include "mongo/db/geo/geoparser.h"
+#include "mongo/db/index_names.h"
#include "mongo/db/index/s2_index_cursor.h"
#include "mongo/db/jsobj.h"
#include "third_party/s2/s2.h"
@@ -43,8 +44,6 @@ namespace {
namespace mongo {
- const string S2IndexingParams::SPHERE_2D_NAME = "2dsphere";
-
// Thanks, Wikipedia.
const double S2IndexingParams::kRadiusOfEarthInMeters = (6378.1 * 1000);
@@ -78,7 +77,7 @@ namespace mongo {
BSONObjIterator i(descriptor->keyPattern());
while (i.more()) {
BSONElement e = i.next();
- if (e.type() == String && S2IndexingParams::SPHERE_2D_NAME == e.valuestr()) {
+ if (e.type() == String && IndexNames::GEO_2DSPHERE == e.valuestr()) {
++geoFields;
}
}
@@ -105,7 +104,7 @@ namespace mongo {
obj.getFieldsDotted(e.fieldName(), fieldElements, false);
BSONObjSet keysForThisField;
- if (S2IndexingParams::SPHERE_2D_NAME == e.valuestr()) {
+ if (IndexNames::GEO_2DSPHERE == e.valuestr()) {
getGeoKeys(fieldElements, &keysForThisField);
} else {
getLiteralKeys(fieldElements, &keysForThisField);
diff --git a/src/mongo/db/index/s2_common.h b/src/mongo/db/index/s2_common.h
index d9de45b9891..6f10f9fd760 100644
--- a/src/mongo/db/index/s2_common.h
+++ b/src/mongo/db/index/s2_common.h
@@ -36,8 +36,6 @@ namespace mongo {
};
struct S2IndexingParams {
- static const string SPHERE_2D_NAME;
-
static const double kRadiusOfEarthInMeters;
// Since we take the cartesian product when we generate keys for an insert,
diff --git a/src/mongo/db/index/s2_index_cursor.cpp b/src/mongo/db/index/s2_index_cursor.cpp
index 0601fb9b5b7..01e38b49d8f 100644
--- a/src/mongo/db/index/s2_index_cursor.cpp
+++ b/src/mongo/db/index/s2_index_cursor.cpp
@@ -17,6 +17,7 @@
#include "mongo/db/index/s2_index_cursor.h"
#include "mongo/db/btreecursor.h"
+#include "mongo/db/index_names.h"
#include "mongo/db/index/index_cursor.h"
#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/index/s2_near_cursor.h"
@@ -42,7 +43,7 @@ namespace mongo {
while (keyIt.more()) {
BSONElement keyElt = keyIt.next();
- if (keyElt.type() != String || S2IndexingParams::SPHERE_2D_NAME != keyElt.valuestr()) {
+ if (keyElt.type() != String || IndexNames::GEO_2DSPHERE != keyElt.valuestr()) {
continue;
}
diff --git a/src/mongo/db/index_names.cpp b/src/mongo/db/index_names.cpp
new file mode 100644
index 00000000000..6a9aac30bc3
--- /dev/null
+++ b/src/mongo/db/index_names.cpp
@@ -0,0 +1,26 @@
+/**
+* Copyright (C) 2013 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "mongo/db/index_names.h"
+
+namespace mongo {
+ const string IndexNames::GEO_2D = "2d";
+ const string IndexNames::GEO_HAYSTACK = "geoHaystack";
+ const string IndexNames::GEO_2DSPHERE = "2dsphere";
+ const string IndexNames::TEXT = "text";
+ const string IndexNames::TEXT_INTERNAL = "_fts";
+ const string IndexNames::HASHED = "hashed";
+} // namespace mongo
diff --git a/src/mongo/db/index_names.h b/src/mongo/db/index_names.h
new file mode 100644
index 00000000000..db16ab0067a
--- /dev/null
+++ b/src/mongo/db/index_names.h
@@ -0,0 +1,39 @@
+/**
+* Copyright (C) 2013 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <string>
+
+namespace mongo {
+
+ using std::string;
+
+ /**
+ * We use the string representation of index names all over the place, so we declare them all
+ * once here.
+ */
+ class IndexNames {
+ public:
+ static const string GEO_2D;
+ static const string GEO_HAYSTACK;
+ static const string GEO_2DSPHERE;
+ static const string TEXT;
+ static const string TEXT_INTERNAL;
+ static const string HASHED;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/db/index_selection.cpp b/src/mongo/db/index_selection.cpp
new file mode 100644
index 00000000000..deaa130d255
--- /dev/null
+++ b/src/mongo/db/index_selection.cpp
@@ -0,0 +1,170 @@
+/**
+* Copyright (C) 2013 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "mongo/db/index_selection.h"
+
+#include "mongo/db/index_names.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/keypattern.h"
+#include "mongo/db/queryutil.h"
+
+namespace mongo {
+
+ IndexSuitability IndexSelection::isSuitableFor(const BSONObj& keyPattern,
+ const FieldRangeSet& queryConstraints,
+ const BSONObj& order) {
+
+ string type = KeyPattern::findPluginName(keyPattern);
+ BSONObj query = queryConstraints.originalQuery();
+
+ if (IndexNames::HASHED == type) {
+ /* This index is only considered "HELPFUL" for a query
+ * if it's the union of at least one equality constraint on the
+ * hashed field. Otherwise it's considered USELESS.
+ * Example queries (supposing the indexKey is {a : "hashed"}):
+ * {a : 3} HELPFUL
+ * {a : 3 , b : 3} HELPFUL
+ * {a : {$in : [3,4]}} HELPFUL
+ * {a : {$gte : 3, $lte : 3}} HELPFUL
+ * {} USELESS
+ * {b : 3} USELESS
+ * {a : {$gt : 3}} USELESS
+ */
+ BSONElement firstElt = keyPattern.firstElement();
+ if (queryConstraints.isPointIntervalSet(firstElt.fieldName())) {
+ return HELPFUL;
+ } else {
+ return USELESS;
+ }
+ } else if (IndexNames::GEO_2DSPHERE == type) {
+ BSONObjIterator i(keyPattern);
+ while (i.more()) {
+ BSONElement ie = i.next();
+
+ if (ie.type() != String || IndexNames::GEO_2DSPHERE != ie.valuestr()) {
+ continue;
+ }
+
+ BSONElement e = query.getFieldDotted(ie.fieldName());
+ // Some locations are given to us as arrays. Sigh.
+ if (Array == e.type()) { return HELPFUL; }
+ if (Object != e.type()) { continue; }
+ // getGtLtOp is horribly misnamed and really means get the operation.
+ switch (e.embeddedObject().firstElement().getGtLtOp()) {
+ case BSONObj::opNEAR:
+ return OPTIMAL;
+ case BSONObj::opWITHIN: {
+ BSONElement elt = e.embeddedObject().firstElement();
+ if (Object != elt.type()) { continue; }
+ const char* fname = elt.embeddedObject().firstElement().fieldName();
+ if (mongoutils::str::equals("$geometry", fname)
+ || mongoutils::str::equals("$centerSphere", fname)) {
+ return OPTIMAL;
+ } else {
+ return USELESS;
+ }
+ }
+ case BSONObj::opGEO_INTERSECTS:
+ return OPTIMAL;
+ default:
+ return USELESS;
+ }
+ }
+ return USELESS;
+ } else if (IndexNames::TEXT == type || IndexNames::TEXT_INTERNAL == type) {
+ return USELESS;
+ } else if (IndexNames::GEO_HAYSTACK == type) {
+ return USELESS;
+ } else if ("" == type) {
+ // This is a quick first pass to determine the suitability of the index. It produces
+ // some false positives (returns HELPFUL for some indexes which are not particularly).
+ // When we return HELPFUL a more precise determination of utility is done by the query
+ // optimizer.
+
+ // check whether any field in the index is constrained at all by the query
+ BSONForEach( elt, keyPattern ){
+ const FieldRange& frange = queryConstraints.range( elt.fieldName() );
+ if( ! frange.universal() )
+ return HELPFUL;
+ }
+
+ // or whether any field in the desired sort order is in the index
+ set<string> orderFields;
+ order.getFieldNames( orderFields );
+ BSONForEach( k, keyPattern ) {
+ if ( orderFields.find( k.fieldName() ) != orderFields.end() )
+ return HELPFUL;
+ }
+ return USELESS;
+ } else if (IndexNames::GEO_2D == type) {
+ string fieldName;
+
+ BSONObjIterator i(keyPattern);
+ while (i.more()) {
+ BSONElement ie = i.next();
+
+ if (ie.type() == String && IndexNames::GEO_2D == ie.valuestr()) {
+ fieldName = ie.fieldName();
+ break;
+ }
+ }
+
+ verify("" != fieldName);
+
+ BSONElement e = query.getFieldDotted(fieldName);
+ switch (e.type()) {
+ case Object: {
+ BSONObj sub = e.embeddedObject();
+ switch (sub.firstElement().getGtLtOp()) {
+ case BSONObj::opNEAR:
+ return OPTIMAL;
+ case BSONObj::opWITHIN: {
+ // Don't return optimal if it's $within: {$geometry: ... }
+ // because we will error out in that case, but the matcher
+ // or 2dsphere index may handle it.
+ BSONElement elt = sub.firstElement();
+ if (Object == elt.type()) {
+ BSONObjIterator it(elt.embeddedObject());
+ while (it.more()) {
+ BSONElement elt = it.next();
+ if (mongoutils::str::equals("$geometry", elt.fieldName())) {
+ return USELESS;
+ }
+ }
+ }
+ return OPTIMAL;
+ }
+ default:
+ // We can try to match if there's no other indexing defined,
+ // this is assumed a point
+ return HELPFUL;
+ }
+ }
+ case Array:
+ // We can try to match if there's no other indexing defined,
+ // this is assumed a point
+ return HELPFUL;
+ default:
+ return USELESS;
+ }
+ } else {
+ cout << "Can't find index for keypattern " << keyPattern << endl;
+ verify(0);
+ return USELESS;
+ }
+ }
+
+} // namespace mongo
diff --git a/src/mongo/db/index_selection.h b/src/mongo/db/index_selection.h
new file mode 100644
index 00000000000..e64978f638e
--- /dev/null
+++ b/src/mongo/db/index_selection.h
@@ -0,0 +1,42 @@
+/**
+* Copyright (C) 2013 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "mongo/db/indexkey.h" // for IndexSuitability
+
+namespace mongo {
+
+ class BSONObj;
+ class FieldRangeSet;
+
+ /**
+ * This class is part of query optimization. For a given index (as uniquely described by
+ * keyPattern) and a given query (queryConstraints) and given sort order (order), return how
+ * "suitable" the index is for the query + sort.
+ *
+ * USELESS indices are never used.
+ * HELPFUL indices are explored and compared to other HELPFUL indices.
+ * OPTIMAL indices short-circuit the search process and are always used.
+ */
+ class IndexSelection {
+ public:
+ static IndexSuitability isSuitableFor(const BSONObj& keyPattern,
+ const FieldRangeSet& queryConstraints,
+ const BSONObj& order);
+ };
+
+} // namespace mongo
diff --git a/src/mongo/db/indexkey.cpp b/src/mongo/db/indexkey.cpp
index 616dbd9a499..b0203713ab4 100644
--- a/src/mongo/db/indexkey.cpp
+++ b/src/mongo/db/indexkey.cpp
@@ -469,41 +469,6 @@ namespace mongo {
}
}
-
- IndexSuitability IndexSpec::suitability( const FieldRangeSet& queryConstraints ,
- const BSONObj& order ) const {
- if ( _indexType.get() )
- return _indexType->suitability( queryConstraints , order );
- return _suitability( queryConstraints , order );
- }
-
- IndexSuitability IndexSpec::_suitability( const FieldRangeSet& queryConstraints ,
- const BSONObj& order ) const {
- // This is a quick first pass to determine the suitability of the index. It produces some
- // false positives (returns HELPFUL for some indexes which are not particularly). When we
- // return HELPFUL a more precise determination of utility is done by the query optimizer.
-
- // check whether any field in the index is constrained at all by the query
- BSONForEach( elt, keyPattern ){
- const FieldRange& frange = queryConstraints.range( elt.fieldName() );
- if( ! frange.universal() )
- return HELPFUL;
- }
- // or whether any field in the desired sort order is in the index
- set<string> orderFields;
- order.getFieldNames( orderFields );
- BSONForEach( k, keyPattern ) {
- if ( orderFields.find( k.fieldName() ) != orderFields.end() )
- return HELPFUL;
- }
- return USELESS;
- }
-
- IndexSuitability IndexType::suitability( const FieldRangeSet& queryConstraints ,
- const BSONObj& order ) const {
- return _spec->_suitability( queryConstraints , order );
- }
-
int IndexSpec::indexVersion() const {
if ( !info.hasField( "v" ) ) {
return DefaultIndexVersionNumber;
diff --git a/src/mongo/db/indexkey.h b/src/mongo/db/indexkey.h
index 187f2fe48bc..2acd38e998d 100644
--- a/src/mongo/db/indexkey.h
+++ b/src/mongo/db/indexkey.h
@@ -18,11 +18,12 @@
#pragma once
-#include "mongo/pch.h"
-#include "diskloc.h"
-#include "jsobj.h"
#include <map>
+#include "mongo/db/diskloc.h"
+#include "mongo/db/index_names.h"
+#include "mongo/db/jsobj.h"
+
namespace mongo {
extern const int DefaultIndexVersionNumber;
@@ -57,16 +58,6 @@ namespace mongo {
*/
virtual BSONElement missingField() const;
- /* Full semantics of numWanted:
- * numWanted == 0 : Return any number of results, but try to return in batches of 101.
- * numWanted == 1 : Return exactly one result.
- * numWanted > 1 : Return any number of results, but try to return in batches of numWanted.
- *
- * In practice, your cursor can ignore numWanted, as enforcement of limits is done
- * by the caller.
- */
- virtual shared_ptr<Cursor> newCursor( const BSONObj& query , const BSONObj& order , int numWanted ) const = 0;
-
/** optional op : changes query to match what's in the index */
virtual BSONObj fixKey( const BSONObj& in ) { return in; }
@@ -78,16 +69,6 @@ namespace mongo {
const BSONObj& keyPattern() const;
- /* Determines the suitability level of this index for answering a given query. The query is
- * represented as a set of constraints given by a FieldRangeSet, and a desired ordering of
- * the output.
- *
- * Note: it is the responsibility of the caller to pass in the correct FieldRangeSet, which
- * may depend upon whether this is a single or multi-key index at the time of calling.
- */
- virtual IndexSuitability suitability( const FieldRangeSet& queryConstraints ,
- const BSONObj& order ) const;
-
virtual bool scanAndOrderRequired( const BSONObj& query , const BSONObj& order ) const ;
protected:
@@ -149,9 +130,9 @@ namespace mongo {
*/
static bool existedBefore24(const string& name) {
return name.empty()
- || name == "2d"
- || name == "geoHaystack"
- || name == "hashed"
+ || name == IndexNames::GEO_2D
+ || name == IndexNames::GEO_HAYSTACK
+ || name == IndexNames::HASHED
;
}
@@ -224,9 +205,6 @@ namespace mongo {
return _details;
}
- IndexSuitability suitability( const FieldRangeSet& queryConstraints ,
- const BSONObj& order ) const ;
-
bool isSparse() const { return _sparse; }
string toString() const;
@@ -235,9 +213,6 @@ namespace mongo {
int indexVersion() const;
- IndexSuitability _suitability( const FieldRangeSet& queryConstraints ,
- const BSONObj& order ) const ;
-
BSONSizeTracker _sizeTracker;
vector<const char*> _fieldNames;
vector<BSONElement> _fixed;
diff --git a/src/mongo/db/query_optimizer_internal.cpp b/src/mongo/db/query_optimizer_internal.cpp
index e182289d750..0bed4fbdaf8 100644
--- a/src/mongo/db/query_optimizer_internal.cpp
+++ b/src/mongo/db/query_optimizer_internal.cpp
@@ -20,6 +20,7 @@
#include "mongo/client/dbclientinterface.h"
#include "mongo/db/db.h"
+#include "mongo/db/index_selection.h"
#include "mongo/db/pagefault.h"
#include "mongo/db/parsed_query.h"
#include "mongo/db/query_plan_selection_policy.h"
@@ -544,7 +545,8 @@ namespace mongo {
IndexDetails& ii = i.next();
const IndexSpec& spec = ii.getSpec();
if (special.has(spec.getTypeName()) &&
- spec.suitability( _qps.frsp().frsForIndex(d, j), _qps.order() ) != USELESS ) {
+ (USELESS != IndexSelection::isSuitableFor(spec.keyPattern,
+ _qps.frsp().frsForIndex(d, j), _qps.order()))) {
uassert( 16330, "'special' query operator not allowed", _allowSpecial );
_qps.setSinglePlan( newPlan( d, j, BSONObj(), BSONObj(), spec.getTypeName()));
return true;
@@ -1554,9 +1556,8 @@ namespace mongo {
// No matches are possible in the index so the index may be useful.
return true;
}
-
- return d->idx( idxNo ).getSpec().suitability( frsp.frsForIndex( d , idxNo ) , order )
- != USELESS;
+ return USELESS != IndexSelection::isSuitableFor(keyPattern, frsp.frsForIndex( d , idxNo ) ,
+ order );
}
void QueryUtilIndexed::clearIndexesForPatterns( const FieldRangeSetPair& frsp,
diff --git a/src/mongo/db/query_plan.cpp b/src/mongo/db/query_plan.cpp
index de8a6b1b342..a055a55df3d 100644
--- a/src/mongo/db/query_plan.cpp
+++ b/src/mongo/db/query_plan.cpp
@@ -18,6 +18,7 @@
#include "mongo/db/btreecursor.h"
#include "mongo/db/cmdline.h"
+#include "mongo/db/index_selection.h"
#include "mongo/db/index/catalog_hack.h"
#include "mongo/db/index/emulated_cursor.h"
#include "mongo/db/index/index_descriptor.h"
@@ -115,8 +116,8 @@ namespace mongo {
// If the parsing or index indicates this is a special query, don't continue the processing
if (!_special.empty() ||
- ( _index->getSpec().getType() &&
- _index->getSpec().getType()->suitability( _frs, _order ) != USELESS ) ) {
+ ( _index->getSpec().getType() && (USELESS !=
+ IndexSelection::isSuitableFor(_index->getSpec().keyPattern, _frs, _order)))) {
_type = _index->getSpec().getType();
if (_special.empty()) _special = _index->getSpec().getType()->getPlugin()->getName();
diff --git a/src/mongo/db/queryutil.cpp b/src/mongo/db/queryutil.cpp
index a191be8e448..dffb52c34bd 100644
--- a/src/mongo/db/queryutil.cpp
+++ b/src/mongo/db/queryutil.cpp
@@ -16,6 +16,7 @@
#include "pch.h"
#include "mongo/db/queryutil.h"
+#include "mongo/db/index_names.h"
#include "pdfile.h"
#include "../util/startup_test.h"
@@ -438,15 +439,15 @@ namespace mongo {
break;
}
case BSONObj::opWITHIN:
- _special.add("2d", SpecialIndices::NO_INDEX_REQUIRED);
- _special.add("2dsphere", SpecialIndices::NO_INDEX_REQUIRED);
+ _special.add(IndexNames::GEO_2D, SpecialIndices::NO_INDEX_REQUIRED);
+ _special.add(IndexNames::GEO_2DSPHERE, SpecialIndices::NO_INDEX_REQUIRED);
break;
case BSONObj::opNEAR:
- _special.add("2d", SpecialIndices::INDEX_REQUIRED);
- _special.add("2dsphere", SpecialIndices::INDEX_REQUIRED);
+ _special.add(IndexNames::GEO_2D, SpecialIndices::INDEX_REQUIRED);
+ _special.add(IndexNames::GEO_2DSPHERE, SpecialIndices::INDEX_REQUIRED);
break;
case BSONObj::opGEO_INTERSECTS:
- _special.add("2dsphere", SpecialIndices::NO_INDEX_REQUIRED);
+ _special.add(IndexNames::GEO_2DSPHERE, SpecialIndices::NO_INDEX_REQUIRED);
break;
case BSONObj::opEXISTS: {
if ( !existsSpec ) {
diff --git a/src/mongo/dbtests/namespacetests.cpp b/src/mongo/dbtests/namespacetests.cpp
index 58ebcce1392..e13a25202f3 100644
--- a/src/mongo/dbtests/namespacetests.cpp
+++ b/src/mongo/dbtests/namespacetests.cpp
@@ -24,6 +24,7 @@
#include "../db/db.h"
#include "../db/json.h"
#include "mongo/db/hashindex.h"
+#include "mongo/db/index_selection.h"
#include "mongo/db/index/btree_key_generator.h"
#include "mongo/db/queryutil.h"
@@ -958,7 +959,7 @@ namespace NamespaceTests {
FieldRangeSet frs( "n/a", BSON( "a" << 2 ), true , true );
// Checking a return value of HELPFUL instead of OPTIMAL is descriptive rather than
// normative. See SERVER-4485.
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -968,7 +969,7 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "a" << 1 ), BSONObj() );
FieldRangeSet frs( "n/a", BSON( "b" << 2 ), true , true );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -978,7 +979,7 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "a" << 1 ), BSONObj() );
FieldRangeSet frs( "n/a", BSON( "a.b" << 2 ), true , true );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -988,7 +989,7 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "a.b" << 1 ), BSONObj() );
FieldRangeSet frs( "n/a", BSON( "a" << 2 ), true , true );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1001,7 +1002,7 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "a.b" << 1 ), BSONObj() );
FieldRangeSet frs( "n/a", BSON( "a" << BSON( "b" << 2 ) ), true , true );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1011,7 +1012,7 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "a" << 1 ), BSONObj() );
FieldRangeSet frs( "n/a", BSONObj(), true , true );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSON( "a" << 1 ) ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSON( "a" << 1 ) ) );
}
};
@@ -1021,7 +1022,7 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "a" << -1 ), BSONObj() );
FieldRangeSet frs( "n/a", BSONObj(), true , true );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSON( "a" << 1 ) ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSON( "a" << 1 ) ) );
}
};
@@ -1034,7 +1035,7 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "a" << 1 ), BSONObj() );
FieldRangeSet frs( "n/a", BSONObj(), true , true );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSON( "b" << 1 << "a" << 1 ) ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSON( "b" << 1 << "a" << 1 ) ) );
}
};
@@ -1044,7 +1045,7 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "a" << 1 ), BSONObj() );
FieldRangeSet frs( "n/a", BSONObj(), true , true );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSON( "b" << 1 ) ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSON( "b" << 1 ) ) );
}
};
@@ -1054,7 +1055,7 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "a" << 1 ), BSONObj() );
FieldRangeSet frs( "n/a", BSONObj(), true , true );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSON( "a.b" << 1 ) ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSON( "a.b" << 1 ) ) );
}
};
@@ -1064,7 +1065,7 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "a.b" << 1 ), BSONObj() );
FieldRangeSet frs( "n/a", BSONObj(), true , true );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSON( "a" << 1 ) ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSON( "a" << 1 ) ) );
}
};
@@ -1074,11 +1075,11 @@ namespace NamespaceTests {
void run() {
IndexSpec spec( BSON( "1" << 1 ), BSONObj() );
FieldRangeSet frs1( "n/a", BSON( "1" << 2 ), true , true );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs1, BSONObj() ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs1, BSONObj() ) );
FieldRangeSet frs2( "n/a", BSON( "01" << 3), true , true );
- ASSERT_EQUALS( USELESS, spec.suitability( frs2, BSON( "01" << 1 ) ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs2, BSON( "01" << 1 ) ) );
FieldRangeSet frs3( "n/a", BSONObj() , true , true );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs3, BSON( "1" << 1 ) ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs3, BSON( "1" << 1 ) ) );
}
};
@@ -1091,7 +1092,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$within:{$box:[[100,0],[120,100]]}}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( OPTIMAL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1102,7 +1103,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$within:{$box:[[100,0],[120,100]]}}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "b" << "2d" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1113,7 +1114,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$near:[100,0]}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( OPTIMAL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1126,7 +1127,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{lat:4,lon:5}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1140,7 +1141,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$gt:4,$lt:5}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1151,7 +1152,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:[1,1]}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1162,7 +1163,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:1}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1173,7 +1174,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1187,7 +1188,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{$and:[{a:{$near:[100,0]}}]}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2d" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1203,7 +1204,7 @@ namespace NamespaceTests {
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
IndexSpec spec( BSON( "a" << "2d" ) );
ASSERT_EQUALS( OPTIMAL,
- spec.suitability( frsp->getSingleKeyFRS(), BSONObj() ) );
+ IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(), BSONObj() ) );
}
};
@@ -1219,7 +1220,7 @@ namespace NamespaceTests {
"coordinates:[40,5]}}}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( OPTIMAL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1231,7 +1232,7 @@ namespace NamespaceTests {
"coordinates:[40,5]}}}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "b" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1242,7 +1243,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$near:[100,0]}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( OPTIMAL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( OPTIMAL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1256,7 +1257,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{lat:4,lon:5}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1267,7 +1268,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$gt:4,$lt:5}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1278,7 +1279,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:[1,1]}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1291,7 +1292,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:1}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1302,7 +1303,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1316,7 +1317,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{$and:[{a:{$near:[100,0]}}]}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "2dsphere" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1332,7 +1333,7 @@ namespace NamespaceTests {
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
IndexSpec spec( BSON( "a" << "2dsphere" ) );
ASSERT_EQUALS( OPTIMAL,
- spec.suitability( frsp->getSingleKeyFRS(), BSONObj() ) );
+ IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(), BSONObj() ) );
}
};
@@ -1347,7 +1348,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:5}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1358,7 +1359,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$gt:4}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( USELESS, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( USELESS, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1369,7 +1370,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{a:{$in:[1,2]}}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1383,7 +1384,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{$and:[{a:5}]}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1397,7 +1398,7 @@ namespace NamespaceTests {
BSONObj query = fromjson( "{$and:[{a:5},{b:5}]}" );
FieldRangeSet frs( "n/a", query, true, true );
IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frs, BSONObj() ) );
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frs, BSONObj() ) );
}
};
@@ -1412,7 +1413,7 @@ namespace NamespaceTests {
OrRangeGenerator org( "n/a", query, true );
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frsp->getSingleKeyFRS(),
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(),
BSONObj() ) );
}
};
@@ -1428,7 +1429,7 @@ namespace NamespaceTests {
OrRangeGenerator org( "n/a", query, true );
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frsp->getSingleKeyFRS(),
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(),
BSONObj() ) );
}
};
@@ -1444,7 +1445,7 @@ namespace NamespaceTests {
OrRangeGenerator org( "n/a", query, true );
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frsp->getSingleKeyFRS(),
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(),
BSONObj() ) );
}
};
@@ -1460,7 +1461,7 @@ namespace NamespaceTests {
OrRangeGenerator org( "n/a", query, true );
scoped_ptr<FieldRangeSetPair> frsp( org.topFrsp() );
IndexSpec spec( BSON( "a" << "hashed" ) );
- ASSERT_EQUALS( HELPFUL, spec.suitability( frsp->getSingleKeyFRS(),
+ ASSERT_EQUALS( HELPFUL, IndexSelection::isSuitableFor(spec.keyPattern, frsp->getSingleKeyFRS(),
BSONObj() ) );
}
};