Beispiel #1
0
    // static
    void HashAccessMethod::getKeysImpl(const BSONObj& obj, const string& hashedField, HashSeed seed,
                                       int hashVersion, bool isSparse, BSONObjSet* keys) {
        const char* cstr = hashedField.c_str();
        BSONElement fieldVal = obj.getFieldDottedOrArray(cstr);
        uassert(16766, "Error: hashed indexes do not currently support array values",
                fieldVal.type() != Array );

        if (!fieldVal.eoo()) {
            BSONObj key = BSON( "" << makeSingleKey(fieldVal, seed, hashVersion));
            keys->insert(key);
        }
        else if (!isSparse) {
            BSONObj nullObj = BSON("" << BSONNULL);
            keys->insert(BSON("" << makeSingleKey(nullObj.firstElement(), seed, hashVersion)));
        }
    }
Beispiel #2
0
    void HashedIndexType::getKeys( const BSONObj &obj, BSONObjSet &keys ) const {
        string hashedFieldCopy = string( _hashedField );
        const char* hashedFieldCopyPtr = hashedFieldCopy.c_str();
        BSONElement fieldVal = obj.getFieldDottedOrArray( hashedFieldCopyPtr );

        uassert( 16244 , "Error: hashed indexes do not currently support array values" , fieldVal.type() != Array );

        if ( ! fieldVal.eoo() ) {
            BSONObj key = BSON( "" << makeSingleKey( fieldVal , _seed , _hashVersion  ) );
            keys.insert( key );
        }
        else if (! _isSparse ) {
            BSONObj nullobj = BSON( _hashedField << BSONNULL );
            BSONElement nullElt = nullobj.firstElement();
            BSONObj key = BSON( "" << makeSingleKey( nullElt , _seed , _hashVersion  ) );
            keys.insert( key );
        }
    }
    void HashAccessMethod::getKeys(const BSONObj& obj, BSONObjSet* keys) {
        const char* cstr = _hashedField.c_str();
        BSONElement fieldVal = obj.getFieldDottedOrArray(cstr);
        uassert(16766, "Error: hashed indexes do not currently support array values",
                fieldVal.type() != Array );

        if (!fieldVal.eoo()) {
            BSONObj key = BSON( "" << makeSingleKey( fieldVal , _seed , _hashVersion  ) );
            keys->insert( key );
        } else if (!_descriptor->isSparse()) {
            keys->insert( _missingKey.copy() );
        }
    }
Beispiel #4
0
    shared_ptr<Cursor> HashedIndexType::newCursor( const BSONObj& query ,
            const BSONObj& order , int numWanted ) const {

        //Use FieldRangeSet to parse the query into a vector of intervals
        //These should be point-intervals if this cursor is ever used
        //So the FieldInterval vector will be, e.g. <[1,1], [3,3], [6,6]>
        FieldRangeSet frs( "" , query , true, true );
        const vector<FieldInterval>& intervals = frs.range( _hashedField.c_str() ).intervals();

        //Force a match of the query against the actual document by giving
        //the cursor a matcher with an empty indexKeyPattern.  This insures the
        //index is not used as a covered index.
        //NOTE: this forcing is necessary due to potential hash collisions
        const shared_ptr< CoveredIndexMatcher > forceDocMatcher(
                new CoveredIndexMatcher( query , BSONObj() ) );

        //Construct a new query based on the hashes of the previous point-intervals
        //e.g. {a : {$in : [ hash(1) , hash(3) , hash(6) ]}}
        BSONObjBuilder newQueryBuilder;
        BSONObjBuilder inObj( newQueryBuilder.subobjStart( _hashedField ) );
        BSONArrayBuilder inArray( inObj.subarrayStart("$in") );
        vector<FieldInterval>::const_iterator i;
        for( i = intervals.begin(); i != intervals.end(); ++i ){
            if ( ! i->equality() ){
                const shared_ptr< BtreeCursor > exhaustiveCursor(
                        BtreeCursor::make( nsdetails( _spec->getDetails()->parentNS().c_str()),
                                           *( _spec->getDetails() ),
                                           BSON( "" << MINKEY ) ,
                                           BSON( "" << MAXKEY ) ,
                                           true ,
                                           1 ) );
                exhaustiveCursor->setMatcher( forceDocMatcher );
                return exhaustiveCursor;
            }
            inArray.append( makeSingleKey( i->_lower._bound , _seed , _hashVersion ) );
        }
        inArray.done();
        inObj.done();
        BSONObj newQuery = newQueryBuilder.obj();

        //Use the point-intervals of the new query to create a Btree cursor
        FieldRangeSet newfrs( "" , newQuery , true, true );
        shared_ptr<FieldRangeVector> newVector(
                new FieldRangeVector( newfrs , *_spec , 1 ) );

        const shared_ptr< BtreeCursor > cursor(
                BtreeCursor::make( nsdetails( _spec->getDetails()->parentNS().c_str()),
                        *( _spec->getDetails() ),  newVector , 1 ) );
        cursor->setMatcher( forceDocMatcher );
        return cursor;
    }
Beispiel #5
0
    HashedIndexType::HashedIndexType( const IndexPlugin* plugin , const IndexSpec* spec ) :
            IndexType( plugin , spec ) , _keyPattern( spec->keyPattern ) {

        //change these if single-field limitation lifted later
        uassert( 16241 , "Currently only single field hashed index supported." ,
                _keyPattern.toBSON().nFields() == 1 );
        uassert( 16242 , "Currently hashed indexes cannot guarantee uniqueness. Use a regular index." ,
                ! (spec->info).getField("unique").booleanSafe() );

        //Default _seed to 0 if "seed" is not included in the index spec
        //or if the value of "seed" is not a number
        _seed = (spec->info).getField("seed").numberInt();

        //Default _isSparse to false if "sparse" is not included in the index spec
        //or if the value of "sparse" is not a boolean
        _isSparse = (spec->info).getField("sparse").booleanSafe();

        //In case we have hashed indexes based on other hash functions in
        //the future, we store a hashVersion number. If hashVersion changes,
        // "makeSingleKey" will need to change accordingly.
        //Defaults to 0 if "hashVersion" is not included in the index spec
        //or if the value of "hashversion" is not a number
        _hashVersion = (spec->info).getField("hashVersion").numberInt();

        //Get the hashfield name
        BSONElement firstElt = spec->keyPattern.firstElement();
        massert( 16243 , "error: no hashed index field" ,
                firstElt.str().compare( HASHED_INDEX_TYPE_IDENTIFIER ) == 0 );
        _hashedField = firstElt.fieldName();

        // Explicit null valued fields and missing fields are both represented in hashed indexes
        // using the hash value of the null BSONElement.  This is partly for historical reasons
        // (hash of null was used in the initial release of hashed indexes and changing would alter
        // the data format).  Additionally, in certain places the hashed index code and the index
        // bound calculation code assume null and missing are indexed identically.
        BSONObj nullObj = BSON( "" << BSONNULL );
        _missingKey = BSON( "" << makeSingleKey( nullObj.firstElement(), _seed, _hashVersion ) );
    }
    HashAccessMethod::HashAccessMethod(IndexDescriptor* descriptor)
        : BtreeBasedAccessMethod(descriptor) {

        const string HASHED_INDEX_TYPE_IDENTIFIER = "hashed";

        //change these if single-field limitation lifted later
        uassert(16763, "Currently only single field hashed index supported." ,
                1 == descriptor->getNumFields());
        uassert(16764, "Currently hashed indexes cannot guarantee uniqueness. Use a regular index.",
                !descriptor->unique());

        //Default _seed to 0 if "seed" is not included in the index spec
        //or if the value of "seed" is not a number
        _seed = descriptor->getInfoElement("seed").numberInt();

        //In case we have hashed indexes based on other hash functions in
        //the future, we store a hashVersion number. If hashVersion changes,
        // "makeSingleKey" will need to change accordingly.
        //Defaults to 0 if "hashVersion" is not included in the index spec
        //or if the value of "hashversion" is not a number
        _hashVersion = descriptor->getInfoElement("hashVersion").numberInt();

        //Get the hashfield name
        BSONElement firstElt = descriptor->keyPattern().firstElement();
        massert(16765, "error: no hashed index field",
                firstElt.str().compare(HASHED_INDEX_TYPE_IDENTIFIER) == 0);
        _hashedField = firstElt.fieldName();

        // Explicit null valued fields and missing fields are both represented in hashed indexes
        // using the hash value of the null BSONElement.  This is partly for historical reasons
        // (hash of null was used in the initial release of hashed indexes and changing would alter
        // the data format).  Additionally, in certain places the hashed index code and the index
        // bound calculation code assume null and missing are indexed identically.
        BSONObj nullObj = BSON("" << BSONNULL);
        _missingKey = BSON("" << makeSingleKey(nullObj.firstElement(), _seed, _hashVersion));
    }