Files
mongo/client/dbclientcursor.h

240 lines
7.7 KiB
C
Raw Normal View History

2011-01-04 00:40:41 -05:00
// file dbclientcursor.h
2010-04-29 10:15:05 -04:00
/* Copyright 2009 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "../pch.h"
#include "../util/net/message.h"
2010-04-29 10:15:05 -04:00
#include "../db/jsobj.h"
#include "../db/json.h"
#include <stack>
namespace mongo {
2011-01-04 00:40:41 -05:00
class AScopedConnection;
2011-01-04 00:40:41 -05:00
2010-11-23 11:56:51 -05:00
/** for mock purposes only -- do not create variants of DBClientCursor, nor hang code here */
class DBClientCursorInterface {
public:
virtual ~DBClientCursorInterface() {}
virtual bool more() = 0;
virtual BSONObj next() = 0;
// TODO bring more of the DBClientCursor interface to here
protected:
DBClientCursorInterface() {}
};
2011-01-04 00:40:41 -05:00
/** Queries return a cursor object */
2010-11-23 11:56:51 -05:00
class DBClientCursor : public DBClientCursorInterface {
2010-04-29 10:15:05 -04:00
public:
2011-01-04 00:40:41 -05:00
/** If true, safe to call next(). Requests more from server if necessary. */
2010-04-29 10:15:05 -04:00
bool more();
2011-01-04 00:40:41 -05:00
/** If true, there is more in our local buffers to be fetched via next(). Returns
false when a getMore request back to server would be required. You can use this
if you want to exhaust whatever data has been fetched to the client already but
2010-04-29 10:15:05 -04:00
then perhaps stop.
*/
int objsLeftInBatch() const { _assertIfNull(); return _putBack.size() + b.nReturned - b.pos; }
bool moreInCurrentBatch() { return objsLeftInBatch() > 0; }
2010-04-29 10:15:05 -04:00
/** next
2011-01-04 00:40:41 -05:00
@return next object in the result cursor.
2010-04-29 10:15:05 -04:00
on an error at the remote server, you will get back:
{ $err: <string> }
if you do not want to handle that yourself, call nextSafe().
*/
BSONObj next();
2011-01-04 00:40:41 -05:00
/**
2010-04-29 10:15:05 -04:00
restore an object previously returned by next() to the cursor
*/
void putBack( const BSONObj &o ) { _putBack.push( o.getOwned() ); }
2011-01-04 00:40:41 -05:00
/** throws AssertionException if get back { $err : ... } */
2010-04-29 10:15:05 -04:00
BSONObj nextSafe() {
BSONObj o = next();
2011-05-28 16:20:18 -04:00
if( strcmp(o.firstElementFieldName(), "$err") == 0 ) {
string s = "nextSafe(): " + o.toString();
2010-04-29 10:15:05 -04:00
if( logLevel >= 5 )
2011-05-28 16:20:18 -04:00
log() << s << endl;
uasserted(13106, s);
2010-04-29 10:15:05 -04:00
}
return o;
}
2010-07-06 12:20:03 -04:00
/** peek ahead at items buffered for future next() calls.
2011-01-04 00:40:41 -05:00
never requests new data from the server. so peek only effective
2010-07-06 12:20:03 -04:00
with what is already buffered.
WARNING: no support for _putBack yet!
*/
void peek(vector<BSONObj>&, int atMost);
/**
* peek ahead and see if an error occurred, and get the error if so.
*/
bool peekError(BSONObj* error = NULL);
2010-04-29 10:15:05 -04:00
/**
iterate the rest of the cursor and return the number if items
*/
2011-01-04 00:40:41 -05:00
int itcount() {
2010-04-29 10:15:05 -04:00
int c = 0;
2011-01-04 00:40:41 -05:00
while ( more() ) {
2010-04-29 10:15:05 -04:00
next();
c++;
}
return c;
}
/** cursor no longer valid -- use with tailable cursors.
note you should only rely on this once more() returns false;
'dead' may be preset yet some data still queued and locally
available from the dbclientcursor.
*/
2011-05-28 21:56:42 -04:00
bool isDead() const { return !this || cursorId == 0; }
2010-04-29 10:15:05 -04:00
2011-05-28 21:56:42 -04:00
bool tailable() const { return (opts & QueryOption_CursorTailable) != 0; }
2011-01-04 00:40:41 -05:00
/** see ResultFlagType (constants.h) for flag values
mostly these flags are for internal purposes -
2010-04-29 10:15:05 -04:00
ResultFlag_ErrSet is the possible exception to that
*/
2011-01-04 00:40:41 -05:00
bool hasResultFlag( int flag ) {
_assertIfNull();
2010-04-29 10:15:05 -04:00
return (resultFlags & flag) != 0;
}
DBClientCursor( DBClientBase* client, const string &_ns, BSONObj _query, int _nToReturn,
2010-04-29 10:15:05 -04:00
int _nToSkip, const BSONObj *_fieldsToReturn, int queryOptions , int bs ) :
_client(client),
2011-01-04 00:40:41 -05:00
ns(_ns),
query(_query),
nToReturn(_nToReturn),
haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_CursorTailable)),
nToSkip(_nToSkip),
fieldsToReturn(_fieldsToReturn),
opts(queryOptions),
batchSize(bs==1?2:bs),
cursorId(),
_ownCursor( true ),
wasError( false ) {
2010-04-29 10:15:05 -04:00
}
2011-01-04 00:40:41 -05:00
DBClientCursor( DBClientBase* client, const string &_ns, long long _cursorId, int _nToReturn, int options ) :
_client(client),
2011-01-04 00:40:41 -05:00
ns(_ns),
nToReturn( _nToReturn ),
haveLimit( _nToReturn > 0 && !(options & QueryOption_CursorTailable)),
opts( options ),
cursorId(_cursorId),
2011-01-04 00:40:41 -05:00
_ownCursor( true ) {
}
2010-04-29 10:15:05 -04:00
virtual ~DBClientCursor();
long long getCursorId() const { return cursorId; }
/** by default we "own" the cursor and will send the server a KillCursor
message when ~DBClientCursor() is called. This function overrides that.
*/
void decouple() { _ownCursor = false; }
2011-01-04 00:40:41 -05:00
void attach( AScopedConnection * conn );
2011-01-04 00:40:41 -05:00
/**
* actually does the query
*/
bool init();
void initLazy( bool isRetry = false );
bool initLazyFinish( bool& retry );
class Batch : boost::noncopyable {
friend class DBClientCursor;
auto_ptr<Message> m;
int nReturned;
int pos;
const char *data;
public:
Batch() : m( new Message() ), nReturned(), pos(), data() { }
};
2010-04-29 10:15:05 -04:00
private:
friend class DBClientBase;
2010-06-06 22:19:06 -04:00
friend class DBClientConnection;
2010-04-29 10:15:05 -04:00
int nextBatchSize();
Batch b;
DBClientBase* _client;
2010-04-29 10:15:05 -04:00
string ns;
BSONObj query;
int nToReturn;
bool haveLimit;
int nToSkip;
const BSONObj *fieldsToReturn;
int opts;
int batchSize;
stack< BSONObj > _putBack;
int resultFlags;
long long cursorId;
bool _ownCursor; // see decouple()
string _scopedHost;
string _lazyHost;
bool wasError;
void dataReceived() { bool retry; string lazyHost; dataReceived( retry, lazyHost ); }
void dataReceived( bool& retry, string& lazyHost );
2010-04-29 10:15:05 -04:00
void requestMore();
2010-06-06 22:19:06 -04:00
void exhaustReceiveMore(); // for exhaust
// Don't call from a virtual function
void _assertIfNull() const { uassert(13348, "connection died", this); }
2010-11-23 11:56:51 -05:00
// non-copyable , non-assignable
DBClientCursor( const DBClientCursor& );
DBClientCursor& operator=( const DBClientCursor& );
// init pieces
void _assembleInit( Message& toSend );
2010-04-29 10:15:05 -04:00
};
2011-01-04 00:40:41 -05:00
2010-07-14 10:28:38 -07:00
/** iterate over objects in current batch only - will not cause a network call
*/
class DBClientCursorBatchIterator {
public:
DBClientCursorBatchIterator( DBClientCursor &c ) : _c( c ), _n() {}
bool moreInCurrentBatch() { return _c.moreInCurrentBatch(); }
BSONObj nextSafe() {
2010-07-15 16:02:58 -07:00
massert( 13383, "BatchIterator empty", moreInCurrentBatch() );
2010-07-14 10:28:38 -07:00
++_n;
return _c.nextSafe();
}
int n() const { return _n; }
private:
DBClientCursor &_c;
int _n;
};
2010-11-23 11:56:51 -05:00
2010-04-29 10:15:05 -04:00
} // namespace mongo
#include "undef_macros.h"