summaryrefslogtreecommitdiff
path: root/db/indexkey.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'db/indexkey.cpp')
-rw-r--r--db/indexkey.cpp161
1 files changed, 103 insertions, 58 deletions
diff --git a/db/indexkey.cpp b/db/indexkey.cpp
index 70dd770..34f30fa 100644
--- a/db/indexkey.cpp
+++ b/db/indexkey.cpp
@@ -17,7 +17,7 @@
*/
#include "pch.h"
-#include "namespace.h"
+#include "namespace-inl.h"
#include "index.h"
#include "btree.h"
#include "query.h"
@@ -28,98 +28,136 @@ namespace mongo {
map<string,IndexPlugin*> * IndexPlugin::_plugins;
IndexType::IndexType( const IndexPlugin * plugin , const IndexSpec * spec )
- : _plugin( plugin ) , _spec( spec ){
-
+ : _plugin( plugin ) , _spec( spec ) {
+
}
- IndexType::~IndexType(){
+ IndexType::~IndexType() {
}
-
- const BSONObj& IndexType::keyPattern() const {
- return _spec->keyPattern;
+
+ const BSONObj& IndexType::keyPattern() const {
+ return _spec->keyPattern;
}
IndexPlugin::IndexPlugin( const string& name )
- : _name( name ){
+ : _name( name ) {
if ( ! _plugins )
_plugins = new map<string,IndexPlugin*>();
(*_plugins)[name] = this;
}
-
- int IndexType::compare( const BSONObj& l , const BSONObj& r ) const {
- return l.woCompare( r , _spec->keyPattern );
- }
- void IndexSpec::_init(){
- assert( keyPattern.objsize() );
-
+ string IndexPlugin::findPluginName( const BSONObj& keyPattern ) {
string pluginName = "";
BSONObjIterator i( keyPattern );
- BSONObjBuilder nullKeyB;
+
while( i.more() ) {
BSONElement e = i.next();
- _fieldNames.push_back( e.fieldName() );
- _fixed.push_back( BSONElement() );
- nullKeyB.appendNull( "" );
- if ( e.type() == String ){
- uassert( 13007 , "can only have 1 index plugin / bad index key pattern" , pluginName.size() == 0 );
- pluginName = e.valuestr();
- }
-
+ if ( e.type() != String )
+ continue;
+
+ uassert( 13007 , "can only have 1 index plugin / bad index key pattern" , pluginName.size() == 0 || pluginName == e.String() );
+ pluginName = e.String();
}
-
- _nullKey = nullKeyB.obj();
-
- BSONObjBuilder b;
- b.appendNull( "" );
- _nullObj = b.obj();
- _nullElt = _nullObj.firstElement();
-
- if ( pluginName.size() ){
- IndexPlugin * plugin = IndexPlugin::get( pluginName );
- if ( ! plugin ){
- log() << "warning: can't find plugin [" << pluginName << "]" << endl;
+
+ return pluginName;
+ }
+
+ int IndexType::compare( const BSONObj& l , const BSONObj& r ) const {
+ return l.woCompare( r , _spec->keyPattern );
+ }
+
+ void IndexSpec::_init() {
+ assert( keyPattern.objsize() );
+
+ // some basics
+ _nFields = keyPattern.nFields();
+ _sparse = info["sparse"].trueValue();
+ uassert( 13529 , "sparse only works for single field keys" , ! _sparse || _nFields );
+
+
+ {
+ // build _nullKey
+
+ BSONObjBuilder b;
+ BSONObjIterator i( keyPattern );
+
+ while( i.more() ) {
+ BSONElement e = i.next();
+ _fieldNames.push_back( e.fieldName() );
+ _fixed.push_back( BSONElement() );
+ b.appendNull( "" );
}
- else {
- _indexType.reset( plugin->generate( this ) );
+ _nullKey = b.obj();
+ }
+
+ {
+ // _nullElt
+ BSONObjBuilder b;
+ b.appendNull( "" );
+ _nullObj = b.obj();
+ _nullElt = _nullObj.firstElement();
+ }
+
+ {
+ // handle plugins
+ string pluginName = IndexPlugin::findPluginName( keyPattern );
+ if ( pluginName.size() ) {
+ IndexPlugin * plugin = IndexPlugin::get( pluginName );
+ if ( ! plugin ) {
+ log() << "warning: can't find plugin [" << pluginName << "]" << endl;
+ }
+ else {
+ _indexType.reset( plugin->generate( this ) );
+ }
}
}
+
_finishedInit = true;
}
-
+
void IndexSpec::getKeys( const BSONObj &obj, BSONObjSetDefaultOrder &keys ) const {
- if ( _indexType.get() ){
+ if ( _indexType.get() ) {
_indexType->getKeys( obj , keys );
return;
}
vector<const char*> fieldNames( _fieldNames );
vector<BSONElement> fixed( _fixed );
_getKeys( fieldNames , fixed , obj, keys );
- if ( keys.empty() )
+ if ( keys.empty() && ! _sparse )
keys.insert( _nullKey );
}
void IndexSpec::_getKeys( vector<const char*> fieldNames , vector<BSONElement> fixed , const BSONObj &obj, BSONObjSetDefaultOrder &keys ) const {
BSONElement arrElt;
unsigned arrIdx = ~0;
+ int numNotFound = 0;
+
for( unsigned i = 0; i < fieldNames.size(); ++i ) {
if ( *fieldNames[ i ] == '\0' )
continue;
+
BSONElement e = obj.getFieldDottedOrArray( fieldNames[ i ] );
- if ( e.eoo() )
+
+ if ( e.eoo() ) {
e = _nullElt; // no matching field
+ numNotFound++;
+ }
+
if ( e.type() != Array )
fieldNames[ i ] = ""; // no matching field or non-array match
+
if ( *fieldNames[ i ] == '\0' )
fixed[ i ] = e; // no need for further object expansion (though array expansion still possible)
+
if ( e.type() == Array && arrElt.eoo() ) { // we only expand arrays on a single path -- track the path here
arrIdx = i;
arrElt = e;
}
+
// enforce single array path here
- if ( e.type() == Array && e.rawdata() != arrElt.rawdata() ){
+ if ( e.type() == Array && e.rawdata() != arrElt.rawdata() ) {
stringstream ss;
ss << "cannot index parallel arrays [" << e.fieldName() << "] [" << arrElt.fieldName() << "]";
uasserted( 10088 , ss.str() );
@@ -127,13 +165,19 @@ namespace mongo {
}
bool allFound = true; // have we found elements for all field names in the key spec?
- for( vector<const char*>::const_iterator i = fieldNames.begin(); i != fieldNames.end(); ++i ){
- if ( **i != '\0' ){
+ for( vector<const char*>::const_iterator i = fieldNames.begin(); i != fieldNames.end(); ++i ) {
+ if ( **i != '\0' ) {
allFound = false;
break;
}
}
+ if ( _sparse && numNotFound == _nFields ) {
+ // we didn't find any fields
+ // so we're not going to index this document
+ return;
+ }
+
bool insertArrayNull = false;
if ( allFound ) {
@@ -143,11 +187,11 @@ namespace mongo {
for( vector< BSONElement >::iterator i = fixed.begin(); i != fixed.end(); ++i )
b.appendAs( *i, "" );
keys.insert( b.obj() );
- }
+ }
else {
// terminal array element to expand, so generate all keys
BSONObjIterator i( arrElt.embeddedObject() );
- if ( i.more() ){
+ if ( i.more() ) {
while( i.more() ) {
BSONObjBuilder b(_sizeTracker);
for( unsigned j = 0; j < fixed.size(); ++j ) {
@@ -159,18 +203,19 @@ namespace mongo {
keys.insert( b.obj() );
}
}
- else if ( fixed.size() > 1 ){
+ else if ( fixed.size() > 1 ) {
insertArrayNull = true;
}
}
- } else {
+ }
+ else {
// nonterminal array element to expand, so recurse
assert( !arrElt.eoo() );
BSONObjIterator i( arrElt.embeddedObject() );
- if ( i.more() ){
+ if ( i.more() ) {
while( i.more() ) {
BSONElement e = i.next();
- if ( e.type() == Object ){
+ if ( e.type() == Object ) {
_getKeys( fieldNames, fixed, e.embeddedObject(), keys );
}
}
@@ -179,12 +224,12 @@ namespace mongo {
insertArrayNull = true;
}
}
-
+
if ( insertArrayNull ) {
// x : [] - need to insert undefined
BSONObjBuilder b(_sizeTracker);
for( unsigned j = 0; j < fixed.size(); ++j ) {
- if ( j == arrIdx ){
+ if ( j == arrIdx ) {
b.appendUndefined( "" );
}
else {
@@ -199,12 +244,12 @@ namespace mongo {
}
}
- bool anyElementNamesMatch( const BSONObj& a , const BSONObj& b ){
+ bool anyElementNamesMatch( const BSONObj& a , const BSONObj& b ) {
BSONObjIterator x(a);
- while ( x.more() ){
+ while ( x.more() ) {
BSONElement e = x.next();
BSONObjIterator y(b);
- while ( y.more() ){
+ while ( y.more() ) {
BSONElement f = y.next();
FieldCompareResult res = compareDottedFieldNames( e.fieldName() , f.fieldName() );
if ( res == SAME || res == LEFT_SUBFIELD || res == RIGHT_SUBFIELD )
@@ -213,13 +258,13 @@ namespace mongo {
}
return false;
}
-
+
IndexSuitability IndexSpec::suitability( const BSONObj& query , const BSONObj& order ) const {
if ( _indexType.get() )
return _indexType->suitability( query , order );
return _suitability( query , order );
}
-
+
IndexSuitability IndexSpec::_suitability( const BSONObj& query , const BSONObj& order ) const {
// TODO: optimize
if ( anyElementNamesMatch( keyPattern , query ) == 0 && anyElementNamesMatch( keyPattern , order ) == 0 )