summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHari Khalsa <hkhalsa@10gen.com>2014-01-03 14:33:07 -0500
committerHari Khalsa <hkhalsa@10gen.com>2014-01-06 12:11:34 -0500
commite89dccbef9b83ac8101dcceab64f5c6e09b6de50 (patch)
tree3ce9939609d46db43ee3e2f447f079dbdca0e3f6
parent81d8d29c4e2a7a706b6fb0f4d4f821ca2ed38161 (diff)
downloadmongo-e89dccbef9b83ac8101dcceab64f5c6e09b6de50.tar.gz
SERVER-10363 SERVER-11387 pay attention to special geo idx params
-rw-r--r--src/mongo/db/exec/2dnear.cpp3
-rw-r--r--src/mongo/db/exec/s2near.cpp69
-rw-r--r--src/mongo/db/exec/s2near.h8
-rw-r--r--src/mongo/db/exec/sort.cpp2
-rw-r--r--src/mongo/db/geo/core.h12
-rw-r--r--src/mongo/db/index/expression_index.h17
-rw-r--r--src/mongo/db/index/s2_access_method.h3
-rw-r--r--src/mongo/db/query/get_runner.cpp3
-rw-r--r--src/mongo/db/query/index_bounds_builder.cpp37
-rw-r--r--src/mongo/db/query/index_bounds_builder.h58
-rw-r--r--src/mongo/db/query/index_bounds_builder_test.cpp60
-rw-r--r--src/mongo/db/query/index_entry.h31
-rw-r--r--src/mongo/db/query/planner_access.cpp8
-rw-r--r--src/mongo/db/query/planner_ixselect.cpp37
14 files changed, 224 insertions, 124 deletions
diff --git a/src/mongo/db/exec/2dnear.cpp b/src/mongo/db/exec/2dnear.cpp
index 33093a8572d..ba80cea73fb 100644
--- a/src/mongo/db/exec/2dnear.cpp
+++ b/src/mongo/db/exec/2dnear.cpp
@@ -511,8 +511,7 @@ namespace twod_exec {
// If we're not, and we're done with points, break
if(! inWindow && expandedPoints >= _max) break;
- bool expandApprox = !currPt.isExact() &&
- (!_uniqueDocs || (finish && _needDistance) || inWindow);
+ bool expandApprox = !currPt.isExact() && (!_uniqueDocs || finish || inWindow);
if (expandApprox) {
// Add new point(s). These will only be added in a radius of 2 * _distError
diff --git a/src/mongo/db/exec/s2near.cpp b/src/mongo/db/exec/s2near.cpp
index a30f89ed338..eabb4c3d550 100644
--- a/src/mongo/db/exec/s2near.cpp
+++ b/src/mongo/db/exec/s2near.cpp
@@ -41,10 +41,15 @@
namespace mongo {
S2NearStage::S2NearStage(const S2NearParams& params, WorkingSet* ws) {
+ _initted = false;
_params = params;
_ws = ws;
_worked = false;
_failed = false;
+ }
+
+ void S2NearStage::init() {
+ _initted = true;
// The field we're near-ing from is the n-th field. Figure out what that 'n' is. We
// put the cover for the search annulus in this spot in the bounds.
@@ -74,8 +79,36 @@ namespace mongo {
_innerRadius = _outerRadius = _minDistance;
_outerRadiusInclusive = false;
- // XXX: where do we grab finestIndexedLevel from really? idx descriptor?
- int finestIndexedLevel = S2::kAvgEdge.GetClosestLevel(500.0 / kRadiusOfEarthInMeters);
+ // Grab the IndexDescriptor.
+ Database* db = cc().database();
+ if (!db) {
+ _failed = true;
+ return;
+ }
+
+ Collection* collection = db->getCollection(_params.ns);
+ if (!collection) {
+ _failed = true;
+ return;
+ }
+
+ _descriptor = collection->getIndexCatalog()->findIndexByKeyPattern(_params.indexKeyPattern);
+ if (NULL == _descriptor) {
+ _failed = true;
+ return;
+ }
+
+ // The user can override this so we honor it. We could ignore it though -- it's just used
+ // to set _radiusIncrement, not to do any covering.
+ int finestIndexedLevel;
+ BSONElement fl = _descriptor->infoObj()["finestIndexedLevel"];
+ if (fl.isNumber()) {
+ finestIndexedLevel = fl.numberInt();
+ }
+ else {
+ finestIndexedLevel = S2::kAvgEdge.GetClosestLevel(500.0 / kRadiusOfEarthInMeters);
+ }
+
// Start with a conservative _radiusIncrement. When we're done searching a shell we
// increment the two radii by this.
_radiusIncrement = 5 * S2::kAvgEdge.GetValue(finestIndexedLevel) * kRadiusOfEarthInMeters;
@@ -88,6 +121,8 @@ namespace mongo {
}
PlanStage::StageState S2NearStage::work(WorkingSetID* out) {
+ if (!_initted) { init(); }
+
if (_failed) { return PlanStage::FAILURE; }
if (isEOF()) { return PlanStage::IS_EOF; }
++_commonStats.works;
@@ -113,7 +148,8 @@ namespace mongo {
// Remove from invalidation map.
WorkingSetMember* member = _ws->get(*out);
if (member->hasLoc()) {
- unordered_map<DiskLoc, WorkingSetID, DiskLoc::Hasher>::iterator it = _invalidationMap.find(member->loc);
+ unordered_map<DiskLoc, WorkingSetID, DiskLoc::Hasher>::iterator it
+ = _invalidationMap.find(member->loc);
verify(_invalidationMap.end() != it);
_invalidationMap.erase(it);
}
@@ -161,32 +197,15 @@ namespace mongo {
_annulus.Release(NULL);
_annulus.Init(&regions);
- _params.baseBounds.fields[_nearFieldIndex].intervals.clear();
- ExpressionMapping::cover2dsphere(_annulus, &_params.baseBounds.fields[_nearFieldIndex]);
-
// Step 3: Actually create the ixscan.
- // TODO: Cache params.
-
- Database* db = cc().database();
- if ( !db ) {
- _failed = true;
- return;
- }
-
- Collection* collection = db->getCollection( _params.ns );
- if ( !collection ) {
- _failed = true;
- return;
- }
IndexScanParams params;
- params.descriptor =
- collection->getIndexCatalog()->findIndexByKeyPattern(_params.indexKeyPattern );
+ params.descriptor = _descriptor;
+ _params.baseBounds.fields[_nearFieldIndex].intervals.clear();
+ ExpressionMapping::cover2dsphere(_annulus,
+ params.descriptor->infoObj(),
+ &_params.baseBounds.fields[_nearFieldIndex]);
- if ( !params.descriptor ) {
- _failed = true;
- return;
- }
params.bounds = _params.baseBounds;
params.direction = 1;
IndexScan* scan = new IndexScan(params, _ws, NULL);
diff --git a/src/mongo/db/exec/s2near.h b/src/mongo/db/exec/s2near.h
index 9f1513d3235..87613908f6f 100644
--- a/src/mongo/db/exec/s2near.h
+++ b/src/mongo/db/exec/s2near.h
@@ -33,6 +33,7 @@
#include "mongo/db/exec/plan_stage.h"
#include "mongo/db/geo/geoquery.h"
#include "mongo/db/geo/s2common.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/matcher/expression.h"
#include "mongo/db/query/index_bounds.h"
@@ -75,6 +76,7 @@ namespace mongo {
PlanStageStats* getStats();
private:
+ void init();
StageState addResultToQueue(WorkingSetID* out);
void nextAnnulus();
@@ -137,6 +139,12 @@ namespace mongo {
// Did we encounter an unrecoverable error?
bool _failed;
+ // Have we init()'d yet?
+ bool _initted;
+
+ // What index are we searching over?
+ IndexDescriptor* _descriptor;
+
CommonStats _commonStats;
};
diff --git a/src/mongo/db/exec/sort.cpp b/src/mongo/db/exec/sort.cpp
index de55f0b7a67..33fb68aadb0 100644
--- a/src/mongo/db/exec/sort.cpp
+++ b/src/mongo/db/exec/sort.cpp
@@ -217,7 +217,7 @@ namespace mongo {
params.options = QueryPlannerParams::NO_TABLE_SCAN;
// We're creating a "virtual index" with key pattern equal to the sort order.
- IndexEntry sortOrder(sortObj, true, false, "doesnt_matter");
+ IndexEntry sortOrder(sortObj, true, false, "doesnt_matter", BSONObj());
params.indices.push_back(sortOrder);
CanonicalQuery* rawQueryForSort;
diff --git a/src/mongo/db/geo/core.h b/src/mongo/db/geo/core.h
index 29688a2a411..ca4b7138be7 100644
--- a/src/mongo/db/geo/core.h
+++ b/src/mongo/db/geo/core.h
@@ -46,16 +46,4 @@ namespace mongo {
cos(deg2rad(max(-89.0, y - maxDistDegrees))));
}
- inline bool twoDWontWrap(double x, double y, double radius) {
- // XXX XXX XXX SERVER-11387
- // The 0.001 for error is totally bogus and must depend on the bits used.
- double yscandist = rad2deg(radius) + 0.001;
- double xscandist = computeXScanDistance(y, yscandist);
- bool ret = x + xscandist < 180
- && x - xscandist > -180
- && y + yscandist < 90
- && y - yscandist > -90;
- return ret;
- }
-
}
diff --git a/src/mongo/db/index/expression_index.h b/src/mongo/db/index/expression_index.h
index d172af5836b..3806b1e1c4b 100644
--- a/src/mongo/db/index/expression_index.h
+++ b/src/mongo/db/index/expression_index.h
@@ -47,11 +47,20 @@ namespace mongo {
return bob.obj();
}
- static void cover2dsphere(const S2Region& region, OrderedIntervalList* oilOut) {
- // XXX: should grab coarsest level from the index since the user can possibly change it.
- int coarsestIndexedLevel =
- S2::kAvgEdge.GetClosestLevel(100 * 1000.0 / kRadiusOfEarthInMeters);
+ // TODO: what should we really pass in for indexInfoObj?
+ static void cover2dsphere(const S2Region& region,
+ const BSONObj& indexInfoObj,
+ OrderedIntervalList* oilOut) {
+ int coarsestIndexedLevel;
+ BSONElement ce = indexInfoObj["coarsestIndexedLevel"];
+ if (ce.isNumber()) {
+ coarsestIndexedLevel = ce.numberInt();
+ }
+ else {
+ coarsestIndexedLevel =
+ S2::kAvgEdge.GetClosestLevel(100 * 1000.0 / kRadiusOfEarthInMeters);
+ }
// The min level of our covering is the level whose cells are the closest match to the
// *area* of the region (or the max indexed level, whichever is smaller) The max level
diff --git a/src/mongo/db/index/s2_access_method.h b/src/mongo/db/index/s2_access_method.h
index 5736d4cb8ce..b3a34b4e679 100644
--- a/src/mongo/db/index/s2_access_method.h
+++ b/src/mongo/db/index/s2_access_method.h
@@ -49,9 +49,6 @@ namespace mongo {
virtual Status newCursor(IndexCursor** out) const;
private:
- friend class Geo2dFindNearCmd;
- const S2IndexingParams& getParams() const { return _params; }
-
virtual void getKeys(const BSONObj& obj, BSONObjSet* keys);
// getKeys calls the helper methods below.
diff --git a/src/mongo/db/query/get_runner.cpp b/src/mongo/db/query/get_runner.cpp
index d3c020ba557..e33785a777d 100644
--- a/src/mongo/db/query/get_runner.cpp
+++ b/src/mongo/db/query/get_runner.cpp
@@ -130,7 +130,8 @@ namespace mongo {
plannerParams.indices.push_back(IndexEntry(desc->keyPattern(),
desc->isMultikey(),
desc->isSparse(),
- desc->indexName()));
+ desc->indexName(),
+ desc->infoObj()));
}
// Tailable: If the query requests tailable the collection must be capped.
diff --git a/src/mongo/db/query/index_bounds_builder.cpp b/src/mongo/db/query/index_bounds_builder.cpp
index 23c5e524743..44cd185b9fe 100644
--- a/src/mongo/db/query/index_bounds_builder.cpp
+++ b/src/mongo/db/query/index_bounds_builder.cpp
@@ -178,18 +178,26 @@ namespace mongo {
}
// static
- void IndexBoundsBuilder::translateAndIntersect(const MatchExpression* expr, const BSONElement& elt,
- OrderedIntervalList* oilOut, BoundsTightness* tightnessOut) {
+ void IndexBoundsBuilder::translateAndIntersect(const MatchExpression* expr,
+ const BSONElement& elt,
+ const IndexEntry& index,
+ OrderedIntervalList* oilOut,
+ BoundsTightness* tightnessOut) {
OrderedIntervalList arg;
- translate(expr, elt, &arg, tightnessOut);
- // translate outputs arg in sorted order. intersectize assumes that its arguments are sorted.
+ translate(expr, elt, index, &arg, tightnessOut);
+
+ // translate outputs arg in sorted order. intersectize assumes that its arguments are
+ // sorted.
intersectize(arg, oilOut);
}
// static
- void IndexBoundsBuilder::translateAndUnion(const MatchExpression* expr, const BSONElement& elt,
- OrderedIntervalList* oilOut, BoundsTightness* tightnessOut) {
- translate(expr, elt, oilOut, tightnessOut);
+ void IndexBoundsBuilder::translateAndUnion(const MatchExpression* expr,
+ const BSONElement& elt,
+ const IndexEntry& index,
+ OrderedIntervalList* oilOut,
+ BoundsTightness* tightnessOut) {
+ translate(expr, elt, index, oilOut, tightnessOut);
unionize(oilOut);
}
@@ -203,8 +211,11 @@ namespace mongo {
}
// static
- void IndexBoundsBuilder::translate(const MatchExpression* expr, const BSONElement& elt,
- OrderedIntervalList* oilOut, BoundsTightness* tightnessOut) {
+ void IndexBoundsBuilder::translate(const MatchExpression* expr,
+ const BSONElement& elt,
+ const IndexEntry& index,
+ OrderedIntervalList* oilOut,
+ BoundsTightness* tightnessOut) {
oilOut->name = elt.fieldName();
bool isHashed = false;
@@ -219,12 +230,12 @@ namespace mongo {
if (MatchExpression::ELEM_MATCH_VALUE == expr->matchType()) {
OrderedIntervalList acc;
- translate(expr->getChild(0), elt, &acc, tightnessOut);
+ translate(expr->getChild(0), elt, index, &acc, tightnessOut);
for (size_t i = 1; i < expr->numChildren(); ++i) {
OrderedIntervalList next;
BoundsTightness tightness;
- translate(expr->getChild(i), elt, &next, &tightness);
+ translate(expr->getChild(i), elt, index, &next, &tightness);
intersectize(next, &acc);
}
@@ -235,6 +246,7 @@ namespace mongo {
if (!oilOut->intervals.empty()) {
std::sort(oilOut->intervals.begin(), oilOut->intervals.end(), IntervalComparison);
}
+
// $elemMatch value requires an array.
// Scalars and directly nested objects are not matched with $elemMatch.
// We can't tell if a multi-key index key is derived from an array field.
@@ -293,7 +305,6 @@ namespace mongo {
bob.appendAs(dataElt, "");
BSONObj dataObj = bob.obj();
verify(dataObj.isOwned());
- QLOG() << "data obj is " << dataObj.toString() << endl;
Interval interval = makeRangeInterval(dataObj, typeMatch(dataObj), false);
// If the operand to LT is equal to the lower bound X, the interval [X, X) is invalid
@@ -427,7 +438,7 @@ namespace mongo {
}
const S2Region& region = gme->getGeoQuery().getRegion();
- ExpressionMapping::cover2dsphere(region, oilOut);
+ ExpressionMapping::cover2dsphere(region, index.infoObj, oilOut);
*tightnessOut = IndexBoundsBuilder::INEXACT_FETCH;
}
else {
diff --git a/src/mongo/db/query/index_bounds_builder.h b/src/mongo/db/query/index_bounds_builder.h
index 9a4bfe8e75e..bf9413bda0e 100644
--- a/src/mongo/db/query/index_bounds_builder.h
+++ b/src/mongo/db/query/index_bounds_builder.h
@@ -32,6 +32,7 @@
#include "mongo/db/hasher.h"
#include "mongo/db/matcher/expression_parser.h"
#include "mongo/db/query/index_bounds.h"
+#include "mongo/db/query/index_entry.h"
namespace mongo {
@@ -40,12 +41,13 @@ namespace mongo {
*/
class IndexBoundsBuilder {
public:
-
enum BoundsTightness {
// Index bounds are exact.
EXACT,
+
// Index bounds are inexact, and a fetch is required.
INEXACT_FETCH,
+
// Index bounds are inexact, but no fetch is required
INEXACT_COVERED
};
@@ -57,30 +59,39 @@ namespace mongo {
static void allValuesForField(const BSONElement& elt, OrderedIntervalList* out);
/**
- * Turn the MatchExpression in 'expr' into a set of index bounds. The field that 'expr'
- * is concerned with is indexed according to the keypattern element 'elt'.
+ * Turn the MatchExpression in 'expr' into a set of index bounds. The field that 'expr' is
+ * concerned with is indexed according to the keypattern element 'elt' from index 'index'.
*
* If 'expr' is elemMatch, the index tag is affixed to a child.
*
* The expression must be a predicate over one field. That is, expr->isLeaf() or
* expr->isArray() must be true, and expr->isLogical() must be false.
*/
- static void translate(const MatchExpression* expr, const BSONElement& elt,
- OrderedIntervalList* oilOut, BoundsTightness* tightnessOut);
+ static void translate(const MatchExpression* expr,
+ const BSONElement& elt,
+ const IndexEntry& index,
+ OrderedIntervalList* oilOut,
+ BoundsTightness* tightnessOut);
/**
* Creates bounds for 'expr' (indexed according to 'elt'). Intersects those bounds
* with the bounds in oilOut, which is an in/out parameter.
*/
- static void translateAndIntersect(const MatchExpression* expr, const BSONElement& elt,
- OrderedIntervalList* oilOut, BoundsTightness* tightnessOut);
+ static void translateAndIntersect(const MatchExpression* expr,
+ const BSONElement& elt,
+ const IndexEntry& index,
+ OrderedIntervalList* oilOut,
+ BoundsTightness* tightnessOut);
/**
* Creates bounds for 'expr' (indexed according to 'elt'). Unions those bounds
* with the bounds in oilOut, which is an in/out parameter.
*/
- static void translateAndUnion(const MatchExpression* expr, const BSONElement& elt,
- OrderedIntervalList* oilOut, BoundsTightness* tightnessOut);
+ static void translateAndUnion(const MatchExpression* expr,
+ const BSONElement& elt,
+ const IndexEntry& index,
+ OrderedIntervalList* oilOut,
+ BoundsTightness* tightnessOut);
/**
* Make a range interval from the provided object.
@@ -89,10 +100,14 @@ namespace mongo {
* The two inclusive flags indicate whether or not the start/end fields are included in the
* interval (closed interval if included, open if not).
*/
- static Interval makeRangeInterval(const BSONObj& obj, bool startInclusive,
+ static Interval makeRangeInterval(const BSONObj& obj,
+ bool startInclusive,
+ bool endInclusive);
+
+ static Interval makeRangeInterval(const string& start,
+ const string& end,
+ bool startInclusive,
bool endInclusive);
- static Interval makeRangeInterval(const string& start, const string& end,
- bool startInclusive, bool endInclusive);
/**
* Make a point interval from the provided object.
@@ -121,18 +136,27 @@ namespace mongo {
*
* used to optimize queries in some simple regex cases that start with '^'
*/
- static string simpleRegex(const char* regex, const char* flags, BoundsTightness* tightnessOut);
+ static string simpleRegex(const char* regex,
+ const char* flags,
+ BoundsTightness* tightnessOut);
+ /**
+ * Returns an Interval from minKey to maxKey
+ */
static Interval allValues();
- static void translateRegex(const RegexMatchExpression* rme, OrderedIntervalList* oil,
+ static void translateRegex(const RegexMatchExpression* rme,
+ OrderedIntervalList* oil,
BoundsTightness* tightnessOut);
- static void translateEquality(const BSONElement& data, bool isHashed,
- OrderedIntervalList* oil, BoundsTightness* tightnessOut);
+ static void translateEquality(const BSONElement& data,
+ bool isHashed,
+ OrderedIntervalList* oil,
+ BoundsTightness* tightnessOut);
static void unionize(OrderedIntervalList* oilOut);
- static void intersectize(const OrderedIntervalList& arg, OrderedIntervalList* oilOut);
+ static void intersectize(const OrderedIntervalList& arg,
+ OrderedIntervalList* oilOut);
};
} // namespace mongo
diff --git a/src/mongo/db/query/index_bounds_builder_test.cpp b/src/mongo/db/query/index_bounds_builder_test.cpp
index 9bb8387d891..b236c8d7847 100644
--- a/src/mongo/db/query/index_bounds_builder_test.cpp
+++ b/src/mongo/db/query/index_bounds_builder_test.cpp
@@ -49,6 +49,8 @@ namespace {
double negativeInfinity = -numeric_limits<double>::infinity();
double positiveInfinity = numeric_limits<double>::infinity();
+ IndexEntry testIndex = IndexEntry(BSONObj());
+
/**
* Utility function to create MatchExpression
*/
@@ -71,10 +73,10 @@ namespace {
auto_ptr<MatchExpression> expr(parseMatchExpression(*it));
BSONElement elt = it->firstElement();
if (toUnion.begin() == it) {
- IndexBoundsBuilder::translate(expr.get(), elt, oilOut, tightnessOut);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, oilOut, tightnessOut);
}
else {
- IndexBoundsBuilder::translateAndUnion(expr.get(), elt, oilOut, tightnessOut);
+ IndexBoundsBuilder::translateAndUnion(expr.get(), elt, testIndex, oilOut, tightnessOut);
}
}
}
@@ -91,10 +93,10 @@ namespace {
auto_ptr<MatchExpression> expr(parseMatchExpression(*it));
BSONElement elt = it->firstElement();
if (toIntersect.begin() == it) {
- IndexBoundsBuilder::translate(expr.get(), elt, oilOut, tightnessOut);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, oilOut, tightnessOut);
}
else {
- IndexBoundsBuilder::translateAndIntersect(expr.get(), elt, oilOut, tightnessOut);
+ IndexBoundsBuilder::translateAndIntersect(expr.get(), elt, testIndex, oilOut, tightnessOut);
}
}
}
@@ -117,13 +119,13 @@ namespace {
auto_ptr<MatchExpression> expr(parseMatchExpression(obj));
BSONElement elt = obj.firstElement();
if (constraints.begin() == it) {
- IndexBoundsBuilder::translate(expr.get(), elt, oilOut, tightnessOut);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, oilOut, tightnessOut);
}
else if (isIntersect) {
- IndexBoundsBuilder::translateAndIntersect(expr.get(), elt, oilOut, tightnessOut);
+ IndexBoundsBuilder::translateAndIntersect(expr.get(), elt, testIndex, oilOut, tightnessOut);
}
else {
- IndexBoundsBuilder::translateAndUnion(expr.get(), elt, oilOut, tightnessOut);
+ IndexBoundsBuilder::translateAndUnion(expr.get(), elt, testIndex, oilOut, tightnessOut);
}
}
}
@@ -141,7 +143,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -159,7 +161,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -173,7 +175,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -187,7 +189,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -201,7 +203,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -215,7 +217,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -229,7 +231,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 0U);
ASSERT_EQUALS(tightness, IndexBoundsBuilder::EXACT);
@@ -241,7 +243,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -255,7 +257,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -269,7 +271,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -283,7 +285,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 0U);
ASSERT_EQUALS(tightness, IndexBoundsBuilder::EXACT);
@@ -295,7 +297,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -309,7 +311,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -323,7 +325,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -337,7 +339,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -351,7 +353,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -365,7 +367,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 2U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -381,7 +383,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 4U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -401,7 +403,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 3U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -587,7 +589,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.name, "a");
ASSERT_EQUALS(oil.intervals.size(), 1U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
@@ -722,7 +724,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.intervals.size(), 2U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
Interval(fromjson("{'': '', '': {}}"), true, false)));
@@ -737,7 +739,7 @@ namespace {
BSONElement elt = obj.firstElement();
OrderedIntervalList oil;
IndexBoundsBuilder::BoundsTightness tightness;
- IndexBoundsBuilder::translate(expr.get(), elt, &oil, &tightness);
+ IndexBoundsBuilder::translate(expr.get(), elt, testIndex, &oil, &tightness);
ASSERT_EQUALS(oil.intervals.size(), 2U);
ASSERT_EQUALS(Interval::INTERVAL_EQUALS, oil.intervals[0].compare(
Interval(fromjson("{'': 'foo', '': 'fop'}"), true, false)));
diff --git a/src/mongo/db/query/index_entry.h b/src/mongo/db/query/index_entry.h
index f5a7f0288c9..0b772438347 100644
--- a/src/mongo/db/query/index_entry.h
+++ b/src/mongo/db/query/index_entry.h
@@ -39,15 +39,16 @@ namespace mongo {
* This name sucks, but every name involving 'index' is used somewhere.
*/
struct IndexEntry {
- IndexEntry(const BSONObj& kp, bool mk, bool sp, const string& n)
- : keyPattern(kp), multikey(mk), sparse(sp), name(n) { }
-
- IndexEntry(const IndexEntry& other) {
- keyPattern = other.keyPattern;
- multikey = other.multikey;
- sparse = other.sparse;
- name = other.name;
- }
+ IndexEntry(const BSONObj& kp,
+ bool mk = false,
+ bool sp = false,
+ const string& n = "default_name",
+ const BSONObj& io = BSONObj())
+ : keyPattern(kp),
+ multikey(mk),
+ sparse(sp),
+ name(n),
+ infoObj(io) { }
BSONObj keyPattern;
@@ -57,15 +58,25 @@ namespace mongo {
string name;
+ // Geo indices have extra parameters. We need those available to plan correctly.
+ BSONObj infoObj;
+
std::string toString() const {
stringstream ss;
- ss << keyPattern.toString();
+ ss << "kp: " << keyPattern.toString();
+
if (multikey) {
ss << " multikey";
}
+
if (sparse) {
ss << " sparse";
}
+
+ if (!infoObj.isEmpty()) {
+ ss << " io: " << infoObj.toString();
+ }
+
return ss.str();
}
};
diff --git a/src/mongo/db/query/planner_access.cpp b/src/mongo/db/query/planner_access.cpp
index 16245186bae..a30406da5d3 100644
--- a/src/mongo/db/query/planner_access.cpp
+++ b/src/mongo/db/query/planner_access.cpp
@@ -156,7 +156,7 @@ namespace mongo {
isn->maxScan = query.getParsed().getMaxScan();
isn->addKeyMetadata = query.getParsed().returnKey();
- IndexBoundsBuilder::translate(expr, index.keyPattern.firstElement(),
+ IndexBoundsBuilder::translate(expr, index.keyPattern.firstElement(), index,
&isn->bounds.fields[0], tightnessOut);
// QLOG() << "bounds are " << isn->bounds.toString() << " exact " << *exact << endl;
@@ -212,15 +212,15 @@ namespace mongo {
OrderedIntervalList* oil = &boundsToFillOut->fields[pos];
if (boundsToFillOut->fields[pos].name.empty()) {
- IndexBoundsBuilder::translate(expr, keyElt, oil, tightnessOut);
+ IndexBoundsBuilder::translate(expr, keyElt, index, oil, tightnessOut);
}
else {
if (MatchExpression::AND == mergeType) {
- IndexBoundsBuilder::translateAndIntersect(expr, keyElt, oil, tightnessOut);
+ IndexBoundsBuilder::translateAndIntersect(expr, keyElt, index, oil, tightnessOut);
}
else {
verify(MatchExpression::OR == mergeType);
- IndexBoundsBuilder::translateAndUnion(expr, keyElt, oil, tightnessOut);
+ IndexBoundsBuilder::translateAndUnion(expr, keyElt, index, oil, tightnessOut);
}
}
}
diff --git a/src/mongo/db/query/planner_ixselect.cpp b/src/mongo/db/query/planner_ixselect.cpp
index b176b2c4d7c..5f126eacb29 100644
--- a/src/mongo/db/query/planner_ixselect.cpp
+++ b/src/mongo/db/query/planner_ixselect.cpp
@@ -31,6 +31,7 @@
#include <vector>
#include "mongo/db/geo/core.h"
+#include "mongo/db/geo/hash.h"
#include "mongo/db/matcher/expression_array.h"
#include "mongo/db/matcher/expression_geo.h"
#include "mongo/db/matcher/expression_text.h"
@@ -41,6 +42,36 @@
namespace mongo {
+ static double fieldWithDefault(const BSONObj& infoObj, const string& name, double def) {
+ BSONElement e = infoObj[name];
+ if (e.isNumber()) { return e.numberDouble(); }
+ return def;
+ }
+
+ /**
+ * 2d indices don't handle wrapping so we can't use them for queries that wrap.
+ */
+ static bool twoDWontWrap(const Circle& circle, const IndexEntry& index) {
+ // XXX: where does this really belong
+ GeoHashConverter::Parameters params;
+ params.bits = static_cast<unsigned>(fieldWithDefault(index.infoObj, "bits", 26));
+ params.max = fieldWithDefault(index.infoObj, "max", 180.0);
+ params.min = fieldWithDefault(index.infoObj, "min", -180.0);
+ double numBuckets = (1024 * 1024 * 1024 * 4.0);
+ params.scaling = numBuckets / (params.max - params.min);
+
+ GeoHashConverter conv(params);
+
+ // FYI: old code used flat not spherical error.
+ double yscandist = rad2deg(circle.radius) + conv.getErrorSphere();
+ double xscandist = computeXScanDistance(circle.center.y, yscandist);
+ bool ret = circle.center.x + xscandist < 180
+ && circle.center.x - xscandist > -180
+ && circle.center.y + yscandist < 90
+ && circle.center.y - yscandist > -90;
+ return ret;
+ }
+
// static
void QueryPlannerIXSelect::getFields(MatchExpression* node,
string prefix,
@@ -163,10 +194,10 @@ namespace mongo {
}
verify(SPHERE == gc._cap->crs);
- // No wrapping in 2d centerSphere, don't use 2d index for that.
const Circle& circle = gc._cap->circle;
- // An overestimate.
- return twoDWontWrap(circle.center.x, circle.center.y, circle.radius);
+
+ // No wrapping around the edge of the world is allowed in 2d centerSphere.
+ return twoDWontWrap(circle, index);
}
return false;
}