summaryrefslogtreecommitdiff
path: root/src/mongo/db/dbmessage.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/dbmessage.h')
-rw-r--r--src/mongo/db/dbmessage.h282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/mongo/db/dbmessage.h b/src/mongo/db/dbmessage.h
new file mode 100644
index 00000000000..a789bff849c
--- /dev/null
+++ b/src/mongo/db/dbmessage.h
@@ -0,0 +1,282 @@
+// dbmessage.h
+
+/**
+* Copyright (C) 2008 10gen Inc.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License, version 3,
+* as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "diskloc.h"
+#include "jsobj.h"
+#include "namespace-inl.h"
+#include "../util/net/message.h"
+#include "../client/constants.h"
+#include "instance.h"
+
+namespace mongo {
+
+ /* db response format
+
+ Query or GetMore: // see struct QueryResult
+ int resultFlags;
+ int64 cursorID;
+ int startingFrom;
+ int nReturned;
+ list of marshalled JSObjects;
+ */
+
+/* db request message format
+
+ unsigned opid; // arbitary; will be echoed back
+ byte operation;
+ int options;
+
+ then for:
+
+ dbInsert:
+ string collection;
+ a series of JSObjects
+ dbDelete:
+ string collection;
+ int flags=0; // 1=DeleteSingle
+ JSObject query;
+ dbUpdate:
+ string collection;
+ int flags; // 1=upsert
+ JSObject query;
+ JSObject objectToUpdate;
+ objectToUpdate may include { $inc: <field> } or { $set: ... }, see struct Mod.
+ dbQuery:
+ string collection;
+ int nToSkip;
+ int nToReturn; // how many you want back as the beginning of the cursor data (0=no limit)
+ // greater than zero is simply a hint on how many objects to send back per "cursor batch".
+ // a negative number indicates a hard limit.
+ JSObject query;
+ [JSObject fieldsToReturn]
+ dbGetMore:
+ string collection; // redundant, might use for security.
+ int nToReturn;
+ int64 cursorID;
+ dbKillCursors=2007:
+ int n;
+ int64 cursorIDs[n];
+
+ Note that on Update, there is only one object, which is different
+ from insert where you can pass a list of objects to insert in the db.
+ Note that the update field layout is very similar layout to Query.
+*/
+
+
+#pragma pack(1)
+ struct QueryResult : public MsgData {
+ long long cursorId;
+ int startingFrom;
+ int nReturned;
+ const char *data() {
+ return (char *) (((int *)&nReturned)+1);
+ }
+ int resultFlags() {
+ return dataAsInt();
+ }
+ int& _resultFlags() {
+ return dataAsInt();
+ }
+ void setResultFlagsToOk() {
+ _resultFlags() = ResultFlag_AwaitCapable;
+ }
+ void initializeResultFlags() {
+ _resultFlags() = 0;
+ }
+ };
+
+#pragma pack()
+
+ /* For the database/server protocol, these objects and functions encapsulate
+ the various messages transmitted over the connection.
+
+ See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol
+ */
+ class DbMessage {
+ public:
+ DbMessage(const Message& _m) : m(_m) , mark(0) {
+ // for received messages, Message has only one buffer
+ theEnd = _m.singleData()->_data + _m.header()->dataLen();
+ char *r = _m.singleData()->_data;
+ reserved = (int *) r;
+ data = r + 4;
+ nextjsobj = data;
+ }
+
+ /** the 32 bit field before the ns
+ * track all bit usage here as its cross op
+ * 0: InsertOption_ContinueOnError
+ * 1: fromWriteback
+ */
+ int& reservedField() { return *reserved; }
+
+ const char * getns() const {
+ return data;
+ }
+ void getns(Namespace& ns) const {
+ ns = data;
+ }
+
+ const char * afterNS() const {
+ return data + strlen( data ) + 1;
+ }
+
+ int getInt( int num ) const {
+ const int * foo = (const int*)afterNS();
+ return foo[num];
+ }
+
+ int getQueryNToReturn() const {
+ return getInt( 1 );
+ }
+
+ /**
+ * get an int64 at specified offsetBytes after ns
+ */
+ long long getInt64( int offsetBytes ) const {
+ const char * x = afterNS();
+ x += offsetBytes;
+ const long long * ll = (const long long*)x;
+ return ll[0];
+ }
+
+ void resetPull() { nextjsobj = data; }
+ int pullInt() const { return pullInt(); }
+ int& pullInt() {
+ if ( nextjsobj == data )
+ nextjsobj += strlen(data) + 1; // skip namespace
+ int& i = *((int *)nextjsobj);
+ nextjsobj += 4;
+ return i;
+ }
+ long long pullInt64() const {
+ return pullInt64();
+ }
+ long long &pullInt64() {
+ if ( nextjsobj == data )
+ nextjsobj += strlen(data) + 1; // skip namespace
+ long long &i = *((long long *)nextjsobj);
+ nextjsobj += 8;
+ return i;
+ }
+
+ OID* getOID() const {
+ return (OID *) (data + strlen(data) + 1); // skip namespace
+ }
+
+ void getQueryStuff(const char *&query, int& ntoreturn) {
+ int *i = (int *) (data + strlen(data) + 1);
+ ntoreturn = *i;
+ i++;
+ query = (const char *) i;
+ }
+
+ /* for insert and update msgs */
+ bool moreJSObjs() const {
+ return nextjsobj != 0;
+ }
+ BSONObj nextJsObj() {
+ if ( nextjsobj == data ) {
+ nextjsobj += strlen(data) + 1; // skip namespace
+ massert( 13066 , "Message contains no documents", theEnd > nextjsobj );
+ }
+ massert( 10304 , "Client Error: Remaining data too small for BSON object", theEnd - nextjsobj > 3 );
+ BSONObj js(nextjsobj);
+ massert( 10305 , "Client Error: Invalid object size", js.objsize() > 3 );
+ massert( 10306 , "Client Error: Next object larger than space left in message",
+ js.objsize() < ( theEnd - data ) );
+ if ( cmdLine.objcheck && !js.valid() ) {
+ massert( 10307 , "Client Error: bad object in message", false);
+ }
+ nextjsobj += js.objsize();
+ if ( nextjsobj >= theEnd )
+ nextjsobj = 0;
+ return js;
+ }
+
+ const Message& msg() const { return m; }
+
+ void markSet() {
+ mark = nextjsobj;
+ }
+
+ void markReset() {
+ assert( mark );
+ nextjsobj = mark;
+ }
+
+ private:
+ const Message& m;
+ int* reserved;
+ const char *data;
+ const char *nextjsobj;
+ const char *theEnd;
+
+ const char * mark;
+
+ public:
+ enum ReservedOptions {
+ Reserved_InsertOption_ContinueOnError = 1 << 0 ,
+ Reserved_FromWriteback = 1 << 1
+ };
+ };
+
+
+ /* a request to run a query, received from the database */
+ class QueryMessage {
+ public:
+ const char *ns;
+ int ntoskip;
+ int ntoreturn;
+ int queryOptions;
+ BSONObj query;
+ BSONObj fields;
+
+ /* parses the message into the above fields */
+ QueryMessage(DbMessage& d) {
+ ns = d.getns();
+ ntoskip = d.pullInt();
+ ntoreturn = d.pullInt();
+ query = d.nextJsObj();
+ if ( d.moreJSObjs() ) {
+ fields = d.nextJsObj();
+ }
+ queryOptions = d.msg().header()->dataAsInt();
+ }
+ };
+
+ void replyToQuery(int queryResultFlags,
+ AbstractMessagingPort* p, Message& requestMsg,
+ void *data, int size,
+ int nReturned, int startingFrom = 0,
+ long long cursorId = 0
+ );
+
+
+ /* object reply helper. */
+ void replyToQuery(int queryResultFlags,
+ AbstractMessagingPort* p, Message& requestMsg,
+ BSONObj& responseObj);
+
+ /* helper to do a reply using a DbResponse object */
+ void replyToQuery(int queryResultFlags, Message &m, DbResponse &dbresponse, BSONObj obj);
+
+
+} // namespace mongo