summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDwight <dmerriman@gmail.com>2008-09-11 13:04:30 -0400
committerDwight <dmerriman@gmail.com>2008-09-11 13:04:30 -0400
commit2b67b580854063516ed3892a52287239cc1bd706 (patch)
tree31b8c35db87a78854d231764591a522793765f62
parent1d4379a5d203135ba457f5a992c3aa261d8876ad (diff)
downloadmongo-2b67b580854063516ed3892a52287239cc1bd706.tar.gz
Option_SlaveOk
-rw-r--r--db/dbclient.cpp13
-rw-r--r--db/dbclient.h50
-rw-r--r--db/query.cpp2
-rw-r--r--db/repl.cpp9
-rw-r--r--db/replset.h5
-rw-r--r--stdafx.cpp1
6 files changed, 53 insertions, 27 deletions
diff --git a/db/dbclient.cpp b/db/dbclient.cpp
index 8365ae759ac..ee0856a1a59 100644
--- a/db/dbclient.cpp
+++ b/db/dbclient.cpp
@@ -23,9 +23,11 @@
#include "jsobj.h"
#include "query.h"
-JSObj DBClientConnection::findOne(const char *ns, JSObj query, JSObj *fieldsToReturn) {
+JSObj DBClientConnection::findOne(const char *ns, JSObj query, JSObj *fieldsToReturn, int queryOptions) {
auto_ptr<DBClientCursor> c =
- this->query(ns, query, 1, 0, fieldsToReturn);
+ this->query(ns, query, 1, 0, fieldsToReturn, queryOptions);
+
+ massert( "DBClientConnection::findOne: transport error", c.get() );
if( !c->more() )
return JSObj();
@@ -63,10 +65,11 @@ bool DBClientConnection::connect(const char *serverAddress, string& errmsg) {
return true;
}
-auto_ptr<DBClientCursor> DBClientConnection::query(const char *ns, JSObj query, int nToReturn, int nToSkip, JSObj *fieldsToReturn, bool tailable) {
+auto_ptr<DBClientCursor> DBClientConnection::query(const char *ns, JSObj query, int nToReturn, int nToSkip, JSObj *fieldsToReturn, int queryOptions) {
// see query.h for the protocol we are using here.
BufBuilder b;
- int opts = tailable ? Option_CursorTailable : 0;
+ int opts = queryOptions;
+ assert( (opts&Option_ALLMASK) == opts );
b.append(opts);
b.append(ns);
b.append(nToSkip);
@@ -159,7 +162,7 @@ void testClient() {
assert( c.connect("127.0.0.1", err) );
cout << "query foo.bar..." << endl;
auto_ptr<DBClientCursor> cursor =
- c.query("foo.bar", emptyObj, 0, 0, 0, true);
+ c.query("foo.bar", emptyObj, 0, 0, 0, Option_CursorTailable);
DBClientCursor *cc = cursor.get();
while( 1 ) {
bool m = cc->more();
diff --git a/db/dbclient.h b/db/dbclient.h
index e9eeb1c2e6e..d02dabc4d2b 100644
--- a/db/dbclient.h
+++ b/db/dbclient.h
@@ -22,7 +22,7 @@
/* the query field 'options' can have these bits set: */
enum {
- /* Tailable means cursor is not closed when the last data is retrieved. rather, the cursor makrs
+ /* Tailable means cursor is not closed when the last data is retrieved. rather, the cursor marks
the final object's position. you can resume using the cursor later, from where it was located,
if more data were received. Set on dbQuery and dbGetMore.
@@ -30,7 +30,13 @@ enum {
final object it references were deleted. Thus, you should be prepared to requery if you get back
ResultFlag_CursorNotFound.
*/
- Option_CursorTailable = 2
+ Option_CursorTailable = 2,
+
+ /* allow query of replica slave. normally these return an error except for namespace "local".
+ */
+ Option_SlaveOk = 4,
+
+ Option_ALLMASK = 6
};
class JSObj;
@@ -66,7 +72,19 @@ public:
}
bool more(); // if true, safe to call next()
- JSObj next(); // returns next object in the result cursor
+
+ /* returns 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().
+ */
+ JSObj next();
+
+ JSObj nextSafe() {
+ JSObj o = next();
+ Element e = o.firstElement();
+ assert( strcmp(e.fieldName(), "$err") != 0 );
+ }
// cursor no longer valid -- use with tailable cursors.
// note you should only rely on this once more() returns false;
@@ -85,22 +103,22 @@ public:
bool connect(const char *serverHostname, string& errmsg);
/* send a query to the database.
- ns: namespace to query, format is <dbname>.<collectname>[.<collectname>]*
- query: query to perform on the collection. this is a JSObj (binary JSON)
- You may format as
- { query: { ... }, order: { ... } }
- to specify a sort order.
- nToReturn: n to return. 0 = unlimited
- nToSkip: start with the nth item
+ ns: namespace to query, format is <dbname>.<collectname>[.<collectname>]*
+ query: query to perform on the collection. this is a JSObj (binary JSON)
+ You may format as
+ { query: { ... }, order: { ... } }
+ to specify a sort order.
+ nToReturn: n to return. 0 = unlimited
+ nToSkip: start with the nth item
fieldsToReturn:
- optional template of which fields to select. if unspecified, returns all fields
- tailable: see query.h tailable comments
+ optional template of which fields to select. if unspecified, returns all fields
+ queryOptions: see options enum at top of this file
- returns: cursor.
- returns 0 if error
+ returns: cursor.
+ 0 if error (connection failure)
*/
auto_ptr<DBClientCursor> query(const char *ns, JSObj query, int nToReturn = 0, int nToSkip = 0,
- JSObj *fieldsToReturn = 0, bool tailable = false);
+ JSObj *fieldsToReturn = 0, int queryOptions = 0);
- JSObj findOne(const char *ns, JSObj query, JSObj *fieldsToReturn = 0);
+ JSObj findOne(const char *ns, JSObj query, JSObj *fieldsToReturn = 0, int queryOptions = 0);
};
diff --git a/db/query.cpp b/db/query.cpp
index 9dbd58d7882..0430f631084 100644
--- a/db/query.cpp
+++ b/db/query.cpp
@@ -535,7 +535,7 @@ QueryResult* runQuery(Message& message, const char *ns, int ntoskip, int _ntoret
}
else {
- uassert("not master", isMaster());
+ uassert("not master", isMaster() || (queryOptions & Option_SlaveOk));
JSObj query = jsobj.getObjectField("query");
JSObj order = jsobj.getObjectField("orderby");
diff --git a/db/repl.cpp b/db/repl.cpp
index 32cbb1ff790..9be567a1426 100644
--- a/db/repl.cpp
+++ b/db/repl.cpp
@@ -443,7 +443,7 @@ void ReplSource::sync_pullOpLog() {
query.append("ts", q.done());
// query = { ts: { $gte: syncedTo } }
- cursor = conn->query( ns.c_str(), query.done(), 0, 0, 0, true );
+ cursor = conn->query( ns.c_str(), query.done(), 0, 0, 0, Option_CursorTailable );
c = cursor.get();
tailing = false;
}
@@ -469,7 +469,7 @@ void ReplSource::sync_pullOpLog() {
if( !c->more() ) {
if( tailing )
- log() << "pull: " << ns << " no new activity\n";
+ ; //log() << "pull: " << ns << " no new activity\n";
else
log() << "pull: " << ns << " oplog is empty\n";
sleepsecs(3);
@@ -479,7 +479,10 @@ void ReplSource::sync_pullOpLog() {
int n = 0;
JSObj op = c->next();
Element ts = op.findElement("ts");
- assert( ts.type() == Date );
+ if( ts.type() != Date ) {
+ problem() << "pull: bad object read from remote oplog: " << op.toString() << '\n';
+ assert(false);
+ }
OpTime t( ts.date() );
bool initial = syncedTo.isNull();
if( initial || tailing ) {
diff --git a/db/replset.h b/db/replset.h
index 2999431e86c..98216d7530b 100644
--- a/db/replset.h
+++ b/db/replset.h
@@ -59,7 +59,10 @@ public:
extern ReplPair *replPair;
/* we should not allow most operations when not the master */
-inline bool isMaster() { return replPair == 0 || replPair->state == 1; }
+inline bool isMaster() {
+ return replPair == 0 || replPair->state == 1 ||
+ client->name == "local"; // local is always allowed
+}
inline ReplPair::ReplPair(const char *remoteEnd) {
state = -1;
diff --git a/stdafx.cpp b/stdafx.cpp
index b050390966f..5fb9dcded68 100644
--- a/stdafx.cpp
+++ b/stdafx.cpp
@@ -57,4 +57,3 @@ void msgasserted(const char *msg) {
cout << "Assertion: " << msg << '\n';
throw AssertionException();
}
-