Query ConfigDiffTracker<ValType,ShardType>::
configDiffQuery( const set<ChunkVersion>& extraMinorVersions ) const
{
    verifyAttached();

    //
    // Basic idea behind the query is to find all the chunks $gt the current max version, and
    // then also update chunks that we need minor versions - splits and (2.0) max chunks on
    // shards
    //

    static const int maxMinorVersionClauses = 50;
    BSONObjBuilder queryB;

    int numStaleMinorClauses = extraMinorVersions.size() + _maxShardVersions->size();

#ifdef _DEBUG
    // In debug builds, randomly trigger full reloads to exercise both codepaths
    if( rand() % 2 ) numStaleMinorClauses = maxMinorVersionClauses;
#endif

    queryB.append(ChunkType::ns(), _ns);

    //
    // If we have only a few minor versions to refresh, we can be more selective in our query
    //
    if( numStaleMinorClauses < maxMinorVersionClauses ) {

        //
        // Get any version changes higher than we know currently
        //
        BSONArrayBuilder queryOrB( queryB.subarrayStart( "$or" ) );
        {
            BSONObjBuilder queryNewB( queryOrB.subobjStart() );
            {
                BSONObjBuilder ts(queryNewB.subobjStart(ChunkType::DEPRECATED_lastmod()));
                // We should *always* pull at least a single chunk back, this lets us quickly
                // detect if our collection was unsharded (and most of the time if it was
                // resharded) in the meantime
                ts.appendTimestamp( "$gte", _maxVersion->toLong() );
                ts.done();
            }

            queryNewB.done();
        }

        // Get any shard version changes higher than we know currently
        // Needed since there could have been a split of the max version chunk of any shard
        // TODO: Ideally, we shouldn't care about these
        for( typename map<ShardType, ChunkVersion>::const_iterator it = _maxShardVersions->begin(); it != _maxShardVersions->end(); it++ ) {

            BSONObjBuilder queryShardB( queryOrB.subobjStart() );
            queryShardB.append(ChunkType::shard(), nameFrom( it->first ) );
            {
                BSONObjBuilder ts(queryShardB.subobjStart(ChunkType::DEPRECATED_lastmod()));
                ts.appendTimestamp( "$gt", it->second.toLong() );
                ts.done();
            }
            queryShardB.done();
        }

        // Get any minor version changes we've marked as interesting
        // TODO: Ideally we shouldn't care about these
        for( set<ChunkVersion>::const_iterator it = extraMinorVersions.begin(); it != extraMinorVersions.end(); it++ ) {

            BSONObjBuilder queryShardB( queryOrB.subobjStart() );
            {
                BSONObjBuilder ts(queryShardB.subobjStart(ChunkType::DEPRECATED_lastmod()));
                ts.appendTimestamp( "$gt", it->toLong() );
                ts.appendTimestamp( "$lt",
                                    ChunkVersion( it->majorVersion() + 1, 0, OID() ).toLong() );
                ts.done();
            }
            queryShardB.done();
        }

        queryOrB.done();
    }

    BSONObj query = queryB.obj();

    LOG(2) << "major version query from " << *_maxVersion << " and over "
           << _maxShardVersions->size() << " shards is " << query << endl;

    //
    // NOTE: IT IS IMPORTANT FOR CONSISTENCY THAT WE SORT BY ASC VERSION, TO HANDLE
    // CURSOR YIELDING BETWEEN CHUNKS BEING MIGRATED.
    //
    // This ensures that changes to chunk version (which will always be higher) will always
    // come *after* our current position in the chunk cursor.
    //

    Query queryObj(query);
    queryObj.sort(BSON( "lastmod" << 1 ));

    return Query( query );
}
Beispiel #2
0
    Query ConfigDiffTracker<ValType,ShardType>::
        configDiffQuery( const set<ShardChunkVersion>& extraMinorVersions ) const
    {
        verifyAttached();

        //
        // Basic idea behind the query is to find all the chunks $gt the current max version, and
        // then also update chunks that we need minor versions - splits and (2.0) max chunks on
        // shards
        //

        static const int maxMinorVersionClauses = 50;
        BSONObjBuilder queryB;

        int numStaleMinorClauses = extraMinorVersions.size() + _maxShardVersions->size();

#ifdef _DEBUG
        // In debug builds, randomly trigger full reloads to exercise both codepaths
        if( rand() % 2 ) numStaleMinorClauses = maxMinorVersionClauses;
#endif

        if( numStaleMinorClauses < maxMinorVersionClauses ){

            BSONArrayBuilder queryOrB( queryB.subarrayStart( "$or" ) );

            //
            // Get any version changes higher than we know currently
            //

            {
                BSONObjBuilder queryNewB( queryOrB.subobjStart() );

                queryNewB.append( "ns", _ns );
                {
                    BSONObjBuilder ts( queryNewB.subobjStart( "lastmod" ) );
                    // We should *always* pull at least a single chunk back, this lets us quickly
                    // detect if our collection was unsharded (and most of the time if it was
                    // resharded) in the meantime
                    ts.appendTimestamp( "$gte", _maxVersion->toLong() );
                    ts.done();
                }

                queryNewB.done();
            }

            // Get any shard version changes higher than we know currently
            // Needed since there could have been a split of the max version chunk of any shard
            // TODO: Ideally, we shouldn't care about these
            for( typename map<ShardType, ShardChunkVersion>::const_iterator it = _maxShardVersions->begin(); it != _maxShardVersions->end(); it++ ){
                BSONObjBuilder queryShardB( queryOrB.subobjStart() );

                queryShardB.append( "ns", _ns );
                queryShardB.append( "shard", nameFrom( it->first ) );
                {
                    BSONObjBuilder ts( queryShardB.subobjStart( "lastmod" ) );
                    ts.appendTimestamp( "$gt", it->second.toLong() );
                    ts.done();
                }
                queryShardB.done();
            }

            // Get any minor version changes we've marked as interesting
            // TODO: Ideally we shouldn't care about these
            for( set<ShardChunkVersion>::const_iterator it = extraMinorVersions.begin(); it != extraMinorVersions.end(); it++ ){
                BSONObjBuilder queryShardB( queryOrB.subobjStart() );

                queryShardB.append( "ns", _ns );
                {
                    BSONObjBuilder ts( queryShardB.subobjStart( "lastmod" ) );
                    ts.appendTimestamp( "$gt", it->toLong() );
                    ts.appendTimestamp( "$lt",
                                        ShardChunkVersion( it->majorVersion() + 1, 0, OID() ).toLong() );
                    ts.done();
                }
                queryShardB.done();
            }

            queryOrB.done();
        }
        else{

            //
            // We don't want to send a giant $or query to the server, so just get all the chunks
            //

            queryB.append( "ns", _ns );
        }

        BSONObj query = queryB.obj();

        // log() << "major version query from " << *_maxVersion << " and over " << _maxShardVersions->size() << " shards is " << query << endl;

        return Query( query );
    }