diff options
Diffstat (limited to 'db/indexkey.cpp')
-rw-r--r-- | db/indexkey.cpp | 161 |
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 ) |