summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@10gen.com>2012-02-27 14:46:45 -0500
committerAndy Schwerin <schwerin@10gen.com>2012-03-01 10:30:42 -0500
commit6288c5f13973717a2ec0168f4b28242c0c981bd3 (patch)
tree1dd6b3eee0ec0a85e84db70ca5e9b74ec32e6563 /src/mongo
parenteed4990236f4e9b5a997f7b4e115df0c25edee97 (diff)
downloadmongo-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.cpp63
-rw-r--r--src/mongo/client/dbclient.h45
-rw-r--r--src/mongo/client/dbclient_rs.h3
-rw-r--r--src/mongo/client/syncclusterconnection.h3
-rw-r--r--src/mongo/db/cloner.cpp18
-rw-r--r--src/mongo/db/instance.cpp5
-rw-r--r--src/mongo/db/instance.h5
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;
};