diff options
author | Andy Schwerin <schwerin@10gen.com> | 2012-02-27 14:46:45 -0500 |
---|---|---|
committer | Andy Schwerin <schwerin@10gen.com> | 2012-03-01 10:30:42 -0500 |
commit | 6288c5f13973717a2ec0168f4b28242c0c981bd3 (patch) | |
tree | 1dd6b3eee0ec0a85e84db70ca5e9b74ec32e6563 /src/mongo | |
parent | eed4990236f4e9b5a997f7b4e115df0c25edee97 (diff) | |
download | mongo-6288c5f13973717a2ec0168f4b28242c0c981bd3.tar.gz |
Promote C++ batch query execution functions to DBClientBase.
There's no good reason I can think of why the batch-processing forms of query()
shouldn't be available to all implementations of DBClientBase, and simply
optimized for DBClientConnection when exhaust-mode is available on the
connection.
This change facilitates another optimization, coming soon, which is that
DBDirectClient's batch query form can scan all rows rather than issuing a find
query when the query parameters are appropriate. This allows for a clever
resolution of SERVER-4726, which is really about an unwanted log message.
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/client/dbclient.cpp | 63 | ||||
-rw-r--r-- | src/mongo/client/dbclient.h | 45 | ||||
-rw-r--r-- | src/mongo/client/dbclient_rs.h | 3 | ||||
-rw-r--r-- | src/mongo/client/syncclusterconnection.h | 3 | ||||
-rw-r--r-- | src/mongo/db/cloner.cpp | 18 | ||||
-rw-r--r-- | src/mongo/db/instance.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/instance.h | 5 |
7 files changed, 99 insertions, 43 deletions
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp index 51699fc995b..7140053014a 100644 --- a/src/mongo/client/dbclient.cpp +++ b/src/mongo/client/dbclient.cpp @@ -253,15 +253,20 @@ namespace mongo { enum QueryOptions DBClientWithCommands::availableOptions() { if ( !_haveCachedAvailableOptions ) { - BSONObj ret; - if ( runCommand( "admin", BSON( "availablequeryoptions" << 1 ), ret ) ) { - _cachedAvailableOptions = ( enum QueryOptions )( ret.getIntField( "options" ) ); - } + _cachedAvailableOptions = _lookupAvailableOptions(); _haveCachedAvailableOptions = true; } return _cachedAvailableOptions; } + enum QueryOptions DBClientWithCommands::_lookupAvailableOptions() { + BSONObj ret; + if ( runCommand( "admin", BSON( "availablequeryoptions" << 1 ), ret ) ) { + return QueryOptions( ret.getIntField( "options" ) ); + } + return QueryOptions(0); + } + inline bool DBClientWithCommands::runCommand(const string &dbname, const BSONObj& cmd, BSONObj &info, int options) { string ns = dbname + ".$cmd"; info = findOne(ns, cmd, 0 , options); @@ -703,33 +708,55 @@ namespace mongo { boost::function<void(const BSONObj &)> _f; }; - unsigned long long DBClientConnection::query( boost::function<void(const BSONObj&)> f, const string& ns, Query query, const BSONObj *fieldsToReturn, int queryOptions ) { + unsigned long long DBClientBase::query( boost::function<void(const BSONObj&)> f, const string& ns, Query query, const BSONObj *fieldsToReturn, int queryOptions ) { DBClientFunConvertor fun; fun._f = f; boost::function<void(DBClientCursorBatchIterator &)> ptr( fun ); - return DBClientConnection::query( ptr, ns, query, fieldsToReturn, queryOptions ); + return this->query( ptr, ns, query, fieldsToReturn, queryOptions ); } - unsigned long long DBClientConnection::query( boost::function<void(DBClientCursorBatchIterator &)> f, const string& ns, Query query, const BSONObj *fieldsToReturn, int queryOptions ) { + unsigned long long DBClientBase::query( + boost::function<void(DBClientCursorBatchIterator &)> f, + const string& ns, + Query query, + const BSONObj *fieldsToReturn, + int queryOptions ) { + // mask options queryOptions &= (int)( QueryOption_NoCursorTimeout | QueryOption_SlaveOk ); + + auto_ptr<DBClientCursor> c( this->query(ns, query, 0, 0, fieldsToReturn, queryOptions) ); + uassert( 16090, "socket error for mapping query", c.get() ); + unsigned long long n = 0; - bool doExhaust = ( availableOptions() & QueryOption_Exhaust ); - if ( doExhaust ) { - queryOptions |= (int)QueryOption_Exhaust; + while ( c->more() ) { + DBClientCursorBatchIterator i( *c ); + f( i ); + n += i.n(); } + return n; + } + + unsigned long long DBClientConnection::query( + boost::function<void(DBClientCursorBatchIterator &)> f, + const string& ns, + Query query, + const BSONObj *fieldsToReturn, + int queryOptions ) { + + if ( ! availableOptions() & QueryOption_Exhaust ) { + return DBClientBase::query( f, ns, query, fieldsToReturn, queryOptions ); + } + + // mask options + queryOptions &= (int)( QueryOption_NoCursorTimeout | QueryOption_SlaveOk ); + queryOptions |= (int)QueryOption_Exhaust; + auto_ptr<DBClientCursor> c( this->query(ns, query, 0, 0, fieldsToReturn, queryOptions) ); uassert( 13386, "socket error for mapping query", c.get() ); - if ( !doExhaust ) { - while( c->more() ) { - DBClientCursorBatchIterator i( *c ); - f( i ); - n += i.n(); - } - return n; - } + unsigned long long n = 0; try { while( 1 ) { diff --git a/src/mongo/client/dbclient.h b/src/mongo/client/dbclient.h index 05585e24829..ed1a2749889 100644 --- a/src/mongo/client/dbclient.h +++ b/src/mongo/client/dbclient.h @@ -778,7 +778,13 @@ namespace mongo { BSONObj _countCmd(const string &ns, const BSONObj& query, int options, int limit, int skip ); - enum QueryOptions availableOptions(); + /** + * Look up the options available on this client. Caches the answer from + * _lookupAvailableOptions(), below. + */ + QueryOptions availableOptions(); + + virtual QueryOptions _lookupAvailableOptions(); private: enum QueryOptions _cachedAvailableOptions; @@ -817,6 +823,28 @@ namespace mongo { virtual auto_ptr<DBClientCursor> query(const string &ns, Query query, int nToReturn = 0, int nToSkip = 0, const BSONObj *fieldsToReturn = 0, int queryOptions = 0 , int batchSize = 0 ); + + /** Uses QueryOption_Exhaust, when available. + + Exhaust mode sends back all data queries as fast as possible, with no back-and-forth for + OP_GETMORE. If you are certain you will exhaust the query, it could be useful. + + Use the DBClientCursorBatchIterator version, below, if you want to do items in large + blocks, perhaps to avoid granular locking and such. + */ + virtual unsigned long long query( boost::function<void(const BSONObj&)> f, + const string& ns, + Query query, + const BSONObj *fieldsToReturn = 0, + int queryOptions = 0 ); + + virtual unsigned long long query( boost::function<void(DBClientCursorBatchIterator&)> f, + const string& ns, + Query query, + const BSONObj *fieldsToReturn = 0, + int queryOptions = 0 ); + + /** don't use this - called automatically by DBClientCursor for you @param cursorId id of cursor to retrieve @return an handle to a previously allocated cursor @@ -871,6 +899,8 @@ namespace mongo { */ class DBClientConnection : public DBClientBase { public: + using DBClientBase::query; + /** @param _autoReconnect if true, automatically reconnect on a connection failure @param cp used by DBClientReplicaSet. You do not need to specify this parameter @@ -936,14 +966,11 @@ namespace mongo { return DBClientBase::query( ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions , batchSize ); } - /** Uses QueryOption_Exhaust - Exhaust mode sends back all data queries as fast as possible, with no back-and-for for OP_GETMORE. If you are certain - you will exhaust the query, it could be useful. - - Use DBClientCursorBatchIterator version if you want to do items in large blocks, perhaps to avoid granular locking and such. - */ - unsigned long long query( boost::function<void(const BSONObj&)> f, const string& ns, Query query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); - unsigned long long query( boost::function<void(DBClientCursorBatchIterator&)> f, const string& ns, Query query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); + virtual unsigned long long query( boost::function<void(DBClientCursorBatchIterator &)> f, + const string& ns, + Query query, + const BSONObj *fieldsToReturn, + int queryOptions ); virtual bool runCommand(const string &dbname, const BSONObj& cmd, BSONObj &info, int options=0); diff --git a/src/mongo/client/dbclient_rs.h b/src/mongo/client/dbclient_rs.h index 4030708c6aa..8baffe941b2 100644 --- a/src/mongo/client/dbclient_rs.h +++ b/src/mongo/client/dbclient_rs.h @@ -214,8 +214,9 @@ namespace mongo { an exception) before the failover is complete. Operations are not retried. */ class DBClientReplicaSet : public DBClientBase { - public: + using DBClientBase::query; + /** Call connect() after constructing. autoReconnect is always on for DBClientReplicaSet connections. */ DBClientReplicaSet( const string& name , const vector<HostAndPort>& servers, double so_timeout=0 ); virtual ~DBClientReplicaSet(); diff --git a/src/mongo/client/syncclusterconnection.h b/src/mongo/client/syncclusterconnection.h index f5b22d525fd..5ef2b0a547b 100644 --- a/src/mongo/client/syncclusterconnection.h +++ b/src/mongo/client/syncclusterconnection.h @@ -40,6 +40,9 @@ namespace mongo { */ class SyncClusterConnection : public DBClientBase { public: + + using DBClientBase::query; + /** * @param commaSeparated should be 3 hosts comma separated */ diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index a417cfef8ac..fc72bd11954 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -51,7 +51,7 @@ namespace mongo { } class Cloner: boost::noncopyable { - auto_ptr< DBClientWithCommands > conn; + auto_ptr< DBClientBase > conn; void copy(const char *from_ns, const char *to_ns, bool isindex, bool logForRepl, bool masterSameProcess, bool slaveOk, bool mayYield, bool mayBeInterrupted, Query q = Query()); struct Fun; @@ -63,7 +63,7 @@ namespace mongo { snapshot - use $snapshot mode for copying collections. note this should not be used when it isn't required, as it will be slower. for example repairDatabase need not use it. */ - void setConnection( DBClientWithCommands *c ) { conn.reset( c ); } + void setConnection( DBClientBase *c ) { conn.reset( c ); } /** copy the entire database */ bool go(const char *masterHost, string& errmsg, const string& fromdb, bool logForRepl, bool slaveOk, bool useReplAuth, bool snapshot, bool mayYield, bool mayBeInterrupted, int *errCode = 0); @@ -212,19 +212,7 @@ namespace mongo { f.context = cc().getContext(); mayInterrupt( mayBeInterrupted ); dbtempreleaseif r( mayYield ); - DBClientConnection *remote = dynamic_cast< DBClientConnection* >( conn.get() ); - if ( remote ) { - remote->query( boost::function<void(DBClientCursorBatchIterator &)>( f ), from_collection, query, 0, options ); - } - else { - // there is no exhaust mode for direct client, so we have this hack - auto_ptr<DBClientCursor> c = conn->query( from_collection, query, 0, 0, 0, options ); - assert( c.get() ); - while( c->more() ) { - DBClientCursorBatchIterator i( *c ); - f( i ); - } - } + conn->query( boost::function<void(DBClientCursorBatchIterator &)>( f ), from_collection, query, 0, options ); } if ( storedForLater.size() ) { diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index 1ca0160000b..b1d3c763248 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -819,6 +819,11 @@ namespace mongo { return false; } + QueryOptions DBDirectClient::_lookupAvailableOptions() { + // Exhaust mode is not available in DBDirectClient. + return QueryOptions(DBClientBase::_lookupAvailableOptions() & ~QueryOption_Exhaust); + } + bool DBDirectClient::call( Message &toSend, Message &response, bool assertOk , string * actualServer ) { if ( lastError._get() ) lastError.startRequest( toSend, lastError._get() ); diff --git a/src/mongo/db/instance.h b/src/mongo/db/instance.h index e57eccd1b5b..cf9698a95da 100644 --- a/src/mongo/db/instance.h +++ b/src/mongo/db/instance.h @@ -85,6 +85,8 @@ namespace mongo { */ class DBDirectClient : public DBClientBase { public: + using DBClientBase::query; + virtual auto_ptr<DBClientCursor> query(const string &ns, Query query, int nToReturn = 0, int nToSkip = 0, const BSONObj *fieldsToReturn = 0, int queryOptions = 0, int batchSize = 0); @@ -117,6 +119,9 @@ namespace mongo { double getSoTimeout() const { return 0; } virtual bool lazySupported() const { return true; } + + virtual QueryOptions _lookupAvailableOptions(); + private: static HostAndPort _clientHost; }; |