summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/SConscript1
-rw-r--r--src/mongo/db/hashindex.cpp13
-rw-r--r--src/mongo/db/hashindex.h3
-rw-r--r--src/mongo/db/keypattern.cpp117
-rw-r--r--src/mongo/db/keypattern.h108
-rw-r--r--src/mongo/db/queryutil.cpp69
-rw-r--r--src/mongo/db/queryutil.h33
-rw-r--r--src/mongo/s/chunk.cpp4
-rw-r--r--src/mongo/s/shardkey.cpp24
-rw-r--r--src/mongo/s/shardkey.h41
10 files changed, 271 insertions, 142 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index 435a048d79f..ba7377c0762 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -129,6 +129,7 @@ env.StaticLibrary("coredb", [
"db/pipeline/pipeline.cpp",
"db/dbcommands_generic.cpp",
"db/dbwebserver.cpp",
+ "db/keypattern.cpp",
"db/matcher.cpp",
"db/pipeline/accumulator.cpp",
"db/pipeline/accumulator_add_to_set.cpp",
diff --git a/src/mongo/db/hashindex.cpp b/src/mongo/db/hashindex.cpp
index 034306bf7fd..c33c9fd4515 100644
--- a/src/mongo/db/hashindex.cpp
+++ b/src/mongo/db/hashindex.cpp
@@ -26,13 +26,11 @@ namespace mongo {
const string HashedIndexType::HASHED_INDEX_TYPE_IDENTIFIER = "hashed";
HashedIndexType::HashedIndexType( const IndexPlugin* plugin , const IndexSpec* spec ) :
- IndexType( plugin , spec ) {
-
- _keyPattern = spec->keyPattern;
+ IndexType( plugin , spec ) , _keyPattern( spec->keyPattern ) {
//change these if single-field limitation lifted later
uassert( 16241 , "Currently only single field hashed index supported." ,
- _keyPattern.nFields() == 1 );
+ _keyPattern.toBSON().nFields() == 1 );
uassert( 16242 , "Currently hashed indexes cannot guarantee uniqueness. Use a regular index." ,
! (spec->info).getField("unique").booleanSafe() );
@@ -52,7 +50,7 @@ namespace mongo {
_hashVersion = (spec->info).getField("hashVersion").numberInt();
//Get the hashfield name
- BSONElement firstElt = _keyPattern.firstElement();
+ BSONElement firstElt = spec->keyPattern.firstElement();
massert( 16243 , "error: no hashed index field" ,
firstElt.str().compare( HASHED_INDEX_TYPE_IDENTIFIER ) == 0 );
_hashedField = firstElt.fieldName();
@@ -75,13 +73,12 @@ namespace mongo {
uassert( 16244 , "Error: hashed indexes do not currently support array values" , fieldVal.type() != Array );
if ( ! fieldVal.eoo() ) {
- BSONObj key = BSON( "" << makeSingleKey( fieldVal , _seed , _hashVersion ) );
+ BSONObj key = _keyPattern.extractSingleKey( obj ) ;
keys.insert( key );
}
else if (! _isSparse ) {
BSONObj nullobj = BSON( _hashedField << BSONNULL );
- BSONElement nullElt = nullobj.firstElement();
- BSONObj key = BSON( "" << makeSingleKey( nullElt , _seed , _hashVersion ) );
+ BSONObj key = _keyPattern.extractSingleKey( nullobj );
keys.insert( key );
}
}
diff --git a/src/mongo/db/hashindex.h b/src/mongo/db/hashindex.h
index a360ea8669a..3a96f82178c 100644
--- a/src/mongo/db/hashindex.h
+++ b/src/mongo/db/hashindex.h
@@ -19,6 +19,7 @@
#include "mongo/db/btree.h"
#include "mongo/db/hasher.h"
#include "mongo/db/index.h"
+#include "mongo/db/keypattern.h"
#include "mongo/db/matcher.h"
#include "mongo/db/namespace-inl.h"
#include "mongo/db/pdfile.h"
@@ -110,7 +111,7 @@ namespace mongo {
private:
string _hashedField;
- BSONObj _keyPattern;
+ KeyPattern _keyPattern;
HashSeed _seed; //defaults to zero if not in the IndexSpec
HashVersion _hashVersion; //defaults to zero if not in the IndexSpec
bool _isSparse;
diff --git a/src/mongo/db/keypattern.cpp b/src/mongo/db/keypattern.cpp
new file mode 100644
index 00000000000..93b4ab050fc
--- /dev/null
+++ b/src/mongo/db/keypattern.cpp
@@ -0,0 +1,117 @@
+// @file keypattern.cpp
+
+/**
+* Copyright (C) 2012 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/keypattern.h"
+#include "mongo/util/mongoutils/str.h"
+#include "mongo/db/hasher.h"
+#include "mongo/db/queryutil.h"
+
+namespace mongo {
+
+ BSONObj KeyPattern::extractSingleKey(const BSONObj& doc ) const {
+ if ( _pattern.isEmpty() )
+ return BSONObj();
+
+ if ( mongoutils::str::equals( _pattern.firstElement().valuestrsafe() , "hashed" ) ){
+ BSONElement fieldVal = doc.getFieldDotted( _pattern.firstElementFieldName() );
+ return BSON( _pattern.firstElementFieldName() <<
+ BSONElementHasher::hash64( fieldVal ,
+ BSONElementHasher::DEFAULT_HASH_SEED ) );
+ }
+
+ return doc.extractFields( _pattern );
+ }
+
+ bool KeyPattern::isSpecial() const {
+ BSONForEach(e, _pattern) {
+ int fieldVal = e.numberInt();
+ if ( fieldVal != 1 && fieldVal != -1 ){
+ return true;
+ }
+ }
+ return false;
+ }
+
+ BoundList KeyPattern::keyBounds( const FieldRangeSet& queryConstraints ) const {
+ typedef vector< pair< shared_ptr<BSONObjBuilder> ,
+ shared_ptr<BSONObjBuilder> > > BoundBuilders;
+ BoundBuilders builders;
+ builders.push_back( make_pair( shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ),
+ shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ) ) );
+ BSONObjIterator i( _pattern );
+ // until equalityOnly is false, we are just dealing with equality (no range or $in querys).
+ bool equalityOnly = true;
+ while( i.more() ) {
+ BSONElement e = i.next();
+ const FieldRange &fr = queryConstraints.range( e.fieldName() );
+ int number = (int) e.number(); // returns 0.0 if not numeric
+ bool forward = ( number >= 0 );
+ if ( equalityOnly ) {
+ if ( fr.equality() ) {
+ for( BoundBuilders::const_iterator j = builders.begin(); j != builders.end(); ++j ) {
+ j->first->appendAs( fr.min(), "" );
+ j->second->appendAs( fr.min(), "" );
+ }
+ }
+ else {
+ equalityOnly = false;
+
+ BoundBuilders newBuilders;
+ const vector<FieldInterval> &intervals = fr.intervals();
+ for( BoundBuilders::const_iterator i = builders.begin(); i != builders.end(); ++i ) {
+ BSONObj first = i->first->obj();
+ BSONObj second = i->second->obj();
+
+ if ( forward ) {
+ for( vector<FieldInterval>::const_iterator j = intervals.begin(); j != intervals.end(); ++j ) {
+ uassert( 16449, "combinatorial limit of $in partitioning of result set exceeded", newBuilders.size() < MAX_IN_COMBINATIONS );
+ newBuilders.push_back( make_pair( shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ), shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ) ) );
+ newBuilders.back().first->appendElements( first );
+ newBuilders.back().second->appendElements( second );
+ newBuilders.back().first->appendAs( j->_lower._bound, "" );
+ newBuilders.back().second->appendAs( j->_upper._bound, "" );
+ }
+ }
+ else {
+ for( vector<FieldInterval>::const_reverse_iterator j = intervals.rbegin(); j != intervals.rend(); ++j ) {
+ uassert( 16450, "combinatorial limit of $in partitioning of result set exceeded", newBuilders.size() < MAX_IN_COMBINATIONS );
+ newBuilders.push_back( make_pair( shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ), shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ) ) );
+ newBuilders.back().first->appendElements( first );
+ newBuilders.back().second->appendElements( second );
+ newBuilders.back().first->appendAs( j->_upper._bound, "" );
+ newBuilders.back().second->appendAs( j->_lower._bound, "" );
+ }
+ }
+ }
+ builders = newBuilders;
+ }
+ }
+ else {
+ for( BoundBuilders::const_iterator j = builders.begin(); j != builders.end(); ++j ) {
+ j->first->appendAs( forward ? fr.min() : fr.max(), "" );
+ j->second->appendAs( forward ? fr.max() : fr.min(), "" );
+ }
+ }
+ }
+ BoundList ret;
+ for( BoundBuilders::const_iterator i = builders.begin(); i != builders.end(); ++i )
+ ret.push_back( make_pair( i->first->obj(), i->second->obj() ) );
+ return ret;
+ }
+
+} // namespace mongo
diff --git a/src/mongo/db/keypattern.h b/src/mongo/db/keypattern.h
new file mode 100644
index 00000000000..afb7a04af76
--- /dev/null
+++ b/src/mongo/db/keypattern.h
@@ -0,0 +1,108 @@
+// @file keypattern.h - Utilities for manipulating index/shard key patterns.
+
+/**
+* Copyright (C) 2012 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/jsobj.h"
+
+namespace mongo {
+
+ class FieldRangeSet;
+
+ /**
+ * A BoundList contains intervals specified by inclusive start
+ * and end bounds. The intervals should be nonoverlapping and occur in
+ * the specified direction of traversal. For example, given a simple index {i:1}
+ * and direction +1, one valid BoundList is: (1, 2); (4, 6). The same BoundList
+ * would be valid for index {i:-1} with direction -1.
+ */
+ typedef vector<pair<BSONObj,BSONObj> > BoundList;
+
+ /** A KeyPattern is an expression describing a transformation of a document into a
+ * document key. Document keys are used to store documents in indices and to target
+ * sharded queries.
+ *
+ * Examples:
+ * { a : 1 }
+ * { a : 1 , b : -1 }
+ * { a : "hashed" }
+ */
+ class KeyPattern {
+ public:
+ KeyPattern( const BSONObj& pattern ): _pattern( pattern ) {}
+
+ /*
+ * Returns a BSON representation of this KeyPattern.
+ */
+ BSONObj toBSON() const { return _pattern; }
+
+ /*
+ * Returns true if the given fieldname is the name of one element of the (potentially)
+ * compound key described by this KeyPattern.
+ */
+ bool hasField( const char* fieldname ) const { return _pattern.hasField( fieldname ); }
+
+ /*
+ * Returns true if the key described by this KeyPattern is a prefix of
+ * the (potentially) compound key described by 'other'
+ */
+ bool isPrefixOf( const KeyPattern& other ) const {
+ return _pattern.isPrefixOf( other.toBSON() );
+ }
+
+ /**
+ * Returns true if this KeyPattern contains any computed values, (e.g. {a : "hashed"}),
+ * and false if this KeyPattern consists of only ascending/descending fields
+ * (e.g. {a : 1, b : -1}). With our current index expression language, "special" patterns
+ * are any patterns that are not a simple list of field names and 1/-1 values.
+ */
+ bool isSpecial() const;
+
+ string toString() const{ return toBSON().toString(); }
+
+ /* Given a document, extracts the index key corresponding to this KeyPattern
+ * Warning: assumes that there is a *single* key to be extracted!
+ *
+ * Examples:
+ * If 'this' KeyPattern is { a : 1 }
+ * { a: "hi" , b : 4} --> returns { a : "hi" }
+ * { c : 4 , a : 2 } --> returns { a : 2 }
+ * { b : 2 } (bad input, don't call with this)
+ * { a : [1,2] } (bad input, don't call with this)
+ *
+ * If 'this' KeyPattern is { a : "hashed" }
+ * { a: 1 } --> returns { a : NumberLong("5902408780260971510") }
+ */
+ BSONObj extractSingleKey( const BSONObj& doc ) const;
+
+ /**@param fromQuery a FieldRangeSet formed from parsing a query
+ * @return an ordered list of bounds generated using this KeyPattern
+ * and the constraints from the FieldRangeSet
+ *
+ * The value of frsp->matchPossibleForSingleKeyFRS(fromQuery) should be true,
+ * otherwise this function could throw.
+ *
+ */
+ BoundList keyBounds( const FieldRangeSet& queryConstraints ) const;
+
+ private:
+ BSONObj _pattern;
+ };
+
+
+} // namespace mongo
diff --git a/src/mongo/db/queryutil.cpp b/src/mongo/db/queryutil.cpp
index b926160664e..bdfc561ac90 100644
--- a/src/mongo/db/queryutil.cpp
+++ b/src/mongo/db/queryutil.cpp
@@ -25,8 +25,6 @@
namespace mongo {
- static const unsigned maxCombinations = 4000000;
-
ParsedQuery::ParsedQuery( QueryMessage& qm )
: _ns( qm.ns ) , _ntoskip( qm.ntoskip ) , _ntoreturn( qm.ntoreturn ) , _options( qm.queryOptions ) {
init( qm.query );
@@ -1163,7 +1161,7 @@ namespace mongo {
verify( !_ranges.back().empty() );
}
uassert( 13385, "combinatorial limit of $in partitioning of result set exceeded",
- size() < maxCombinations );
+ size() < MAX_IN_COMBINATIONS );
}
BSONObj FieldRangeVector::startKey() const {
@@ -1260,71 +1258,6 @@ namespace mongo {
return QueryPattern( *this, sort );
}
- // TODO get rid of this
- BoundList FieldRangeSet::indexBounds( const BSONObj &keyPattern, int direction ) const {
- typedef vector<pair<shared_ptr<BSONObjBuilder>, shared_ptr<BSONObjBuilder> > > BoundBuilders;
- BoundBuilders builders;
- builders.push_back( make_pair( shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ), shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ) ) );
- BSONObjIterator i( keyPattern );
- bool equalityOnly = true; // until equalityOnly is false, we are just dealing with equality (no range or $in querys).
- while( i.more() ) {
- BSONElement e = i.next();
- const FieldRange &fr = range( e.fieldName() );
- int number = (int) e.number(); // returns 0.0 if not numeric
- bool forward = ( ( number >= 0 ? 1 : -1 ) * ( direction >= 0 ? 1 : -1 ) > 0 );
- if ( equalityOnly ) {
- if ( fr.equality() ) {
- for( BoundBuilders::const_iterator j = builders.begin(); j != builders.end(); ++j ) {
- j->first->appendAs( fr.min(), "" );
- j->second->appendAs( fr.min(), "" );
- }
- }
- else {
- equalityOnly = false;
-
- BoundBuilders newBuilders;
- const vector<FieldInterval> &intervals = fr.intervals();
- for( BoundBuilders::const_iterator i = builders.begin(); i != builders.end(); ++i ) {
- BSONObj first = i->first->obj();
- BSONObj second = i->second->obj();
-
- if ( forward ) {
- for( vector<FieldInterval>::const_iterator j = intervals.begin(); j != intervals.end(); ++j ) {
- uassert( 13303, "combinatorial limit of $in partitioning of result set exceeded", newBuilders.size() < maxCombinations );
- newBuilders.push_back( make_pair( shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ), shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ) ) );
- newBuilders.back().first->appendElements( first );
- newBuilders.back().second->appendElements( second );
- newBuilders.back().first->appendAs( j->_lower._bound, "" );
- newBuilders.back().second->appendAs( j->_upper._bound, "" );
- }
- }
- else {
- for( vector<FieldInterval>::const_reverse_iterator j = intervals.rbegin(); j != intervals.rend(); ++j ) {
- uassert( 13304, "combinatorial limit of $in partitioning of result set exceeded", newBuilders.size() < maxCombinations );
- newBuilders.push_back( make_pair( shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ), shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ) ) );
- newBuilders.back().first->appendElements( first );
- newBuilders.back().second->appendElements( second );
- newBuilders.back().first->appendAs( j->_upper._bound, "" );
- newBuilders.back().second->appendAs( j->_lower._bound, "" );
- }
- }
- }
- builders = newBuilders;
- }
- }
- else {
- for( BoundBuilders::const_iterator j = builders.begin(); j != builders.end(); ++j ) {
- j->first->appendAs( forward ? fr.min() : fr.max(), "" );
- j->second->appendAs( forward ? fr.max() : fr.min(), "" );
- }
- }
- }
- BoundList ret;
- for( BoundBuilders::const_iterator i = builders.begin(); i != builders.end(); ++i )
- ret.push_back( make_pair( i->first->obj(), i->second->obj() ) );
- return ret;
- }
-
int FieldRangeSet::numNonUniversalRanges() const {
int count = 0;
for( map<string,FieldRange>::const_iterator i = _ranges.begin(); i != _ranges.end(); ++i ) {
diff --git a/src/mongo/db/queryutil.h b/src/mongo/db/queryutil.h
index bdea78b7361..32bf3541e88 100644
--- a/src/mongo/db/queryutil.h
+++ b/src/mongo/db/queryutil.h
@@ -25,6 +25,9 @@ namespace mongo {
extern const int MaxBytesToReturnToClientAtOnce;
+ //maximum number of intervals produced by $in queries.
+ static const unsigned MAX_IN_COMBINATIONS = 4000000;
+
/* This is for languages whose "objects" are not well ordered (JSON is well ordered).
[ { a : ... } , { b : ... } ] -> { a : ..., b : ... }
*/
@@ -381,15 +384,6 @@ namespace mongo {
// _elemMatchContext for the FieldRange on 'a.b' is the query
// element having field name '$elemMatch'.
};
-
- /**
- * A BoundList contains intervals specified by inclusive start
- * and end bounds. The intervals should be nonoverlapping and occur in
- * the specified direction of traversal. For example, given a simple index {i:1}
- * and direction +1, one valid BoundList is: (1, 2); (4, 6). The same BoundList
- * would be valid for index {i:-1} with direction -1.
- */
- typedef vector<pair<BSONObj,BSONObj> > BoundList;
class QueryPattern;
@@ -477,18 +471,6 @@ namespace mongo {
const FieldRangeSet &operator-=( const FieldRangeSet &other );
/** @return intersection of 'this' with 'other'. */
const FieldRangeSet &operator&=( const FieldRangeSet &other );
-
- /**
- * @return an ordered list of bounds generated using an index key pattern
- * and traversal direction.
- *
- * The value of matchPossible() should be true, otherwise this function
- * may @throw.
- *
- * NOTE This function is deprecated in the query optimizer and only
- * currently used by sharding code.
- */
- BoundList indexBounds( const BSONObj &keyPattern, int direction ) const;
/**
* @return - A new FieldRangeSet based on this FieldRangeSet, but with only
@@ -597,17 +579,16 @@ namespace mongo {
* already been scanned.
*/
FieldRangeSetPair &operator-=( const FieldRangeSet &scanned );
-
- BoundList shardKeyIndexBounds( const BSONObj &keyPattern ) const {
- return _singleKey.indexBounds( keyPattern, 1 );
- }
- bool matchPossibleForShardKey( const BSONObj &keyPattern ) const {
+ bool matchPossibleForSingleKeyFRS( const BSONObj &keyPattern ) const {
return _singleKey.matchPossibleForIndex( keyPattern );
}
BSONObj originalQuery() const { return _singleKey.originalQuery(); }
+ const FieldRangeSet getSingleKeyFRS() const { return _singleKey; }
+ const FieldRangeSet getMultiKeyFRS() const { return _singleKey; }
+
string toString() const;
private:
FieldRangeSetPair( const FieldRangeSet &singleKey, const FieldRangeSet &multiKey )
diff --git a/src/mongo/s/chunk.cpp b/src/mongo/s/chunk.cpp
index cec8cdde8ad..d1fd4b7899d 100644
--- a/src/mongo/s/chunk.cpp
+++ b/src/mongo/s/chunk.cpp
@@ -1101,8 +1101,8 @@ namespace mongo {
return;
}
- if ( frsp->matchPossibleForShardKey( _key.key() ) ) {
- BoundList ranges = frsp->shardKeyIndexBounds(_key.key());
+ if ( frsp->matchPossibleForSingleKeyFRS( _key.key() ) ) {
+ BoundList ranges = _key.keyBounds( frsp->getSingleKeyFRS() );
for (BoundList::const_iterator it=ranges.begin(), end=ranges.end();
it != end; ++it) {
diff --git a/src/mongo/s/shardkey.cpp b/src/mongo/s/shardkey.cpp
index 83338a71fdc..a2ad2ce02f2 100644
--- a/src/mongo/s/shardkey.cpp
+++ b/src/mongo/s/shardkey.cpp
@@ -26,7 +26,7 @@
namespace mongo {
ShardKeyPattern::ShardKeyPattern( BSONObj p ) : pattern( p.getOwned() ) {
- pattern.getFieldNames(patternfields);
+ pattern.toBSON().getFieldNames( patternfields );
BSONObjBuilder min;
BSONObjBuilder max;
@@ -57,26 +57,16 @@ namespace mongo {
return true;
}
- bool ShardKeyPattern::isPrefixOf( const BSONObj& otherPattern ) const {
+ bool ShardKeyPattern::isPrefixOf( const KeyPattern& otherPattern ) const {
return pattern.isPrefixOf( otherPattern );
}
- bool ShardKeyPattern::isUniqueIndexCompatible( const BSONObj& uniqueIndexPattern ) const {
- if ( ! uniqueIndexPattern.isEmpty() &&
- str::equals( uniqueIndexPattern.firstElementFieldName(), "_id" ) ){
+ bool ShardKeyPattern::isUniqueIndexCompatible( const KeyPattern& uniqueIndexPattern ) const {
+ if ( ! uniqueIndexPattern.toBSON().isEmpty() &&
+ str::equals( uniqueIndexPattern.toBSON().firstElementFieldName(), "_id" ) ){
return true;
}
- return pattern.isFieldNamePrefixOf( uniqueIndexPattern );
- }
-
- bool ShardKeyPattern::isSpecial() const {
- BSONForEach(e, pattern) {
- int fieldVal = e.numberInt();
- if ( fieldVal != 1 && fieldVal != -1 ){
- return true;
- }
- }
- return false;
+ return pattern.toBSON().isFieldNamePrefixOf( uniqueIndexPattern.toBSON() );
}
string ShardKeyPattern::toString() const {
@@ -86,7 +76,7 @@ namespace mongo {
BSONObj ShardKeyPattern::moveToFront(const BSONObj& obj) const {
vector<const char*> keysToMove;
keysToMove.push_back("_id");
- BSONForEach(e, pattern) {
+ BSONForEach(e, pattern.toBSON()) {
if (strchr(e.fieldName(), '.') == NULL && strcmp(e.fieldName(), "_id") != 0)
keysToMove.push_back(e.fieldName());
}
diff --git a/src/mongo/s/shardkey.h b/src/mongo/s/shardkey.h
index c67cd2820ab..efbf82d52fe 100644
--- a/src/mongo/s/shardkey.h
+++ b/src/mongo/s/shardkey.h
@@ -18,9 +18,12 @@
#pragma once
+#include "mongo/db/keypattern.h"
+
namespace mongo {
class Chunk;
+ class FieldRangeSet;
/* A ShardKeyPattern is a pattern indicating what data to extract from the object to make the shard key from.
Analogous to an index key pattern.
@@ -66,7 +69,7 @@ namespace mongo {
*/
bool hasShardKey( const BSONObj& obj ) const;
- BSONObj key() const { return pattern; }
+ BSONObj key() const { return pattern.toBSON(); }
string toString() const;
@@ -83,7 +86,7 @@ namespace mongo {
* @return
* true if 'this' is a prefix (not necessarily contained) of 'otherPattern'.
*/
- bool isPrefixOf( const BSONObj& otherPattern ) const;
+ bool isPrefixOf( const KeyPattern& otherPattern ) const;
/**
* @return
@@ -106,7 +109,7 @@ namespace mongo {
* is never capable of being a unique index, and thus is an invalid setting
* for the 'uniqueIndexPattern' argument.
*/
- bool isUniqueIndexCompatible( const BSONObj& uniqueIndexPattern ) const;
+ bool isUniqueIndexCompatible( const KeyPattern& uniqueIndexPattern ) const;
/**
* @return
@@ -115,15 +118,27 @@ namespace mongo {
* With our current index expression language, "special" shard keys are any keys
* that are not a simple list of field names and 1/-1 values.
*/
- bool isSpecial() const;
+ bool isSpecial() const { return pattern.isSpecial(); }
/**
* @return BSONObj with _id and shardkey at front. May return original object.
*/
BSONObj moveToFront(const BSONObj& obj) const;
+ /**@param queryConstraints a FieldRangeSet formed from parsing a query
+ * @return an ordered list of bounds generated using this KeyPattern
+ * and the constraints from the FieldRangeSet
+ *
+ * The value of frsp->matchPossibleForSingleKeyFRS(fromQuery) should be true,
+ * otherwise this function could throw.
+ *
+ */
+ BoundList keyBounds( const FieldRangeSet& queryConstraints ) const{
+ return pattern.keyBounds( queryConstraints );
+ }
+
private:
- BSONObj pattern;
+ KeyPattern pattern;
BSONObj gMin;
BSONObj gMax;
@@ -132,21 +147,7 @@ namespace mongo {
};
inline BSONObj ShardKeyPattern::extractKey(const BSONObj& from) const {
- BSONObj k = from;
- bool needExtraction = false;
-
- BSONObjIterator a(from);
- BSONObjIterator b(pattern);
- while (a.more() && b.more()){
- if (strcmp(a.next().fieldName(), b.next().fieldName()) != 0){
- needExtraction = true;
- break;
- }
- }
-
- if (needExtraction || a.more() != b.more())
- k = from.extractFields(pattern);
-
+ BSONObj k = pattern.extractSingleKey( from );
uassert(13334, "Shard Key must be less than 512 bytes", k.objsize() < 512);
return k;
}