summaryrefslogtreecommitdiff
path: root/client/dbclientcursor.h
diff options
context:
space:
mode:
Diffstat (limited to 'client/dbclientcursor.h')
-rw-r--r--client/dbclientcursor.h204
1 files changed, 204 insertions, 0 deletions
diff --git a/client/dbclientcursor.h b/client/dbclientcursor.h
new file mode 100644
index 0000000..51cdc13
--- /dev/null
+++ b/client/dbclientcursor.h
@@ -0,0 +1,204 @@
+// file dbclientcursor.h
+
+/* 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/message.h"
+#include "../db/jsobj.h"
+#include "../db/json.h"
+#include <stack>
+
+namespace mongo {
+
+ class AScopedConnection;
+
+ /** Queries return a cursor object */
+ class DBClientCursor : boost::noncopyable {
+ public:
+ /** If true, safe to call next(). Requests more from server if necessary. */
+ bool more();
+
+ /** 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
+ then perhaps stop.
+ */
+ int objsLeftInBatch() const { _assertIfNull(); return _putBack.size() + nReturned - pos; }
+ bool moreInCurrentBatch() { return objsLeftInBatch() > 0; }
+
+ /** next
+ @return next object in the result cursor.
+ 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();
+
+ /**
+ restore an object previously returned by next() to the cursor
+ */
+ void putBack( const BSONObj &o ) { _putBack.push( o.getOwned() ); }
+
+ /** throws AssertionException if get back { $err : ... } */
+ BSONObj nextSafe() {
+ BSONObj o = next();
+ BSONElement e = o.firstElement();
+ if( strcmp(e.fieldName(), "$err") == 0 ) {
+ if( logLevel >= 5 )
+ log() << "nextSafe() error " << o.toString() << endl;
+ uassert(13106, "nextSafe(): " + o.toString(), false);
+ }
+ return o;
+ }
+
+ /** peek ahead at items buffered for future next() calls.
+ never requests new data from the server. so peek only effective
+ with what is already buffered.
+ WARNING: no support for _putBack yet!
+ */
+ void peek(vector<BSONObj>&, int atMost);
+
+ /**
+ iterate the rest of the cursor and return the number if items
+ */
+ int itcount(){
+ int c = 0;
+ while ( more() ){
+ 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.
+ */
+ bool isDead() const {
+ return !this || cursorId == 0;
+ }
+
+ bool tailable() const {
+ return (opts & QueryOption_CursorTailable) != 0;
+ }
+
+ /** see ResultFlagType (constants.h) for flag values
+ mostly these flags are for internal purposes -
+ ResultFlag_ErrSet is the possible exception to that
+ */
+ bool hasResultFlag( int flag ){
+ _assertIfNull();
+ return (resultFlags & flag) != 0;
+ }
+
+ DBClientCursor( DBConnector *_connector, const string &_ns, BSONObj _query, int _nToReturn,
+ int _nToSkip, const BSONObj *_fieldsToReturn, int queryOptions , int bs ) :
+ connector(_connector),
+ ns(_ns),
+ query(_query),
+ nToReturn(_nToReturn),
+ haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_CursorTailable)),
+ nToSkip(_nToSkip),
+ fieldsToReturn(_fieldsToReturn),
+ opts(queryOptions),
+ batchSize(bs==1?2:bs),
+ m(new Message()),
+ cursorId(),
+ nReturned(),
+ pos(),
+ data(),
+ _ownCursor( true ){
+ }
+
+ DBClientCursor( DBConnector *_connector, const string &_ns, long long _cursorId, int _nToReturn, int options ) :
+ connector(_connector),
+ ns(_ns),
+ nToReturn( _nToReturn ),
+ haveLimit( _nToReturn > 0 && !(options & QueryOption_CursorTailable)),
+ opts( options ),
+ m(new Message()),
+ cursorId( _cursorId ),
+ nReturned(),
+ pos(),
+ data(),
+ _ownCursor( true ){
+ }
+
+ 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; }
+
+ void attach( AScopedConnection * conn );
+
+ private:
+ friend class DBClientBase;
+ friend class DBClientConnection;
+ bool init();
+ int nextBatchSize();
+ DBConnector *connector;
+ string ns;
+ BSONObj query;
+ int nToReturn;
+ bool haveLimit;
+ int nToSkip;
+ const BSONObj *fieldsToReturn;
+ int opts;
+ int batchSize;
+ auto_ptr<Message> m;
+ stack< BSONObj > _putBack;
+ int resultFlags;
+ long long cursorId;
+ int nReturned;
+ int pos;
+ const char *data;
+ void dataReceived();
+ void requestMore();
+ void exhaustReceiveMore(); // for exhaust
+ bool _ownCursor; // see decouple()
+ string _scopedHost;
+
+ // Don't call from a virtual function
+ void _assertIfNull() const { uassert(13348, "connection died", this); }
+ };
+
+ /** 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() {
+ massert( 13383, "BatchIterator empty", moreInCurrentBatch() );
+ ++_n;
+ return _c.nextSafe();
+ }
+ int n() const { return _n; }
+ private:
+ DBClientCursor &_c;
+ int _n;
+ };
+
+} // namespace mongo
+
+#include "undef_macros.h"