diff options
-rw-r--r-- | client/dbclient.cpp | 8 | ||||
-rw-r--r-- | client/dbclient.h | 8 | ||||
-rw-r--r-- | client/model.cpp | 29 | ||||
-rw-r--r-- | client/model.h | 21 | ||||
-rw-r--r-- | db/makefile | 3 | ||||
-rw-r--r-- | dbgrid/dbgrid.vcproj | 16 | ||||
-rw-r--r-- | dbgrid/dbgrid_commands.cpp | 74 | ||||
-rw-r--r-- | dbgrid/gridconfig.cpp | 116 | ||||
-rw-r--r-- | dbgrid/gridconfig.h | 65 | ||||
-rw-r--r-- | dbgrid/griddb.cpp | 99 | ||||
-rw-r--r-- | dbgrid/request.cpp | 17 | ||||
-rw-r--r-- | grid/message.cpp | 23 | ||||
-rw-r--r-- | util/sock.h | 11 |
13 files changed, 367 insertions, 123 deletions
diff --git a/client/dbclient.cpp b/client/dbclient.cpp index 4182edc6fed..f0529e7ea1d 100644 --- a/client/dbclient.cpp +++ b/client/dbclient.cpp @@ -252,6 +252,14 @@ again: /* --- class dbclientpaired --- */ +string DBClientPaired::toString() { + stringstream ss; + ss << "state: " << master << '\n'; + ss << "left: " << left.toStringLong() << '\n'; + ss << "right: " << right.toStringLong() << '\n'; + return ss.str(); +} + DBClientPaired::DBClientPaired() : left(true), right(true) { diff --git a/client/dbclient.h b/client/dbclient.h index 2548c199c58..4fc5864ab36 100644 --- a/client/dbclient.h +++ b/client/dbclient.h @@ -135,6 +135,12 @@ class DBClientConnection : public DBClientCommands { string serverAddress; // remember for reconnects void checkConnection(); public: + string toStringLong() const { + stringstream ss; + ss << serverAddress; + if( failed ) ss << " failed"; + return ss.str(); + } string toString() const { return serverAddress; } MessagingPort& port() { return *p.get(); } bool isFailed() const { return failed; } @@ -208,6 +214,8 @@ public: /* throws userassertion "no master found" */ virtual BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0); + + string toString(); }; diff --git a/client/model.cpp b/client/model.cpp new file mode 100644 index 00000000000..45d13c3fbd0 --- /dev/null +++ b/client/model.cpp @@ -0,0 +1,29 @@ +// model.cpp + +/** +* 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/>. +*/ + +#include "stdafx.h" +#include "model.h" + +bool Model::load(BSONObj& query) { + BSONObj b = conn()->findOne(getNS(), query); + if( b.isEmpty() ) + return false; + + unserialize(b); + return true; +} diff --git a/client/model.h b/client/model.h index fc8a2bb8f22..942155a42b4 100644 --- a/client/model.h +++ b/client/model.h @@ -20,18 +20,35 @@ #include "dbclient.h" +/* Model is a base class for defining objects which are serializable to the Mongo + database via the client driver. + + *Definition* + Your serializable class should inherit from Model and implement the abstract methods + below. + + *Loading* + To load, first construct an (empty) objet. Then call load(). Do not load an object + more than once. +*/ + class Model { public: Model() { } virtual ~Model() { } virtual const char * getNS() = 0; + virtual void serialize(BSONObjBuilder& to) = 0; + virtual void unserialize(BSONObj& from) = 0; - /* define this as you see fit if you are using the default conn() implementation */ + /* Define this as you see fit if you are using the default conn() implementation. */ static DBClientCommands *globalConn; - /* you can override this if you need to do fancier connection management */ + /* Override this if you need to do fancier connection management than simply using globalConn. */ virtual DBClientCommands* conn() { return globalConn; } + + /* true if successful */ + bool load(BSONObj& query); }; diff --git a/db/makefile b/db/makefile index 99bcf58d1d7..089e85f680a 100644 --- a/db/makefile +++ b/db/makefile @@ -1,6 +1,7 @@ # makefile for our db project FLAGS= ${CFLAGS} -fPIC -ggdb -pthread -O3 -I .. -Isrc/p -I/src/p/db -L/usr/local/lib -L/usr/lib -rdynamic +FLAGS= ${CFLAGS} -fPIC -ggdb -pthread -O0 -I .. -Isrc/p -I/src/p/db -L/usr/local/lib -L/usr/lib -rdynamic LIB_DEPS = -lpcrecpp -lpcre LIB_BOOST = -lboost_thread -lboost_filesystem @@ -12,7 +13,7 @@ JVM_LIBS = -L/opt/java/lib/ OBJS=../stdafx.o ../util/sock.o ../grid/message.o ../util/mmap.o pdfile.o query.o jsobj.o introspect.o btree.o clientcursor.o ../util/util.o javajs.o tests.o json.o repl.o ../client/dbclient.o btreecursor.o cloner.o namespace.o commands.o matcher.o dbcommands.o dbeval.o -DBGRID_OBJS=../stdafx.o json.o ../util/sock.o ../grid/message.o ../util/util.o jsobj.o ../client/dbclient.o ../dbgrid/dbgrid.o ../dbgrid/request.o ../dbgrid/connpool.o ../dbgrid/gridconfig.o commands.o +DBGRID_OBJS=../stdafx.o json.o ../util/sock.o ../grid/message.o ../util/util.o jsobj.o ../client/dbclient.o ../dbgrid/dbgrid.o ../dbgrid/request.o ../dbgrid/connpool.o ../dbgrid/gridconfig.o commands.o ../dbgrid/dbgrid_commands.o ../dbgrid/griddb.o ../client/model.o GPP = g++ diff --git a/dbgrid/dbgrid.vcproj b/dbgrid/dbgrid.vcproj index e2428a8b19f..03948fd222d 100644 --- a/dbgrid/dbgrid.vcproj +++ b/dbgrid/dbgrid.vcproj @@ -183,10 +183,18 @@ >
</File>
<File
+ RelativePath=".\dbgrid_commands.cpp"
+ >
+ </File>
+ <File
RelativePath=".\gridconfig.cpp"
>
</File>
<File
+ RelativePath=".\griddb.cpp"
+ >
+ </File>
+ <File
RelativePath=".\request.cpp"
>
</File>
@@ -229,6 +237,10 @@ >
</File>
<File
+ RelativePath="..\client\model.h"
+ >
+ </File>
+ <File
RelativePath="..\stdafx.h"
>
</File>
@@ -279,6 +291,10 @@ >
</File>
<File
+ RelativePath="..\client\model.cpp"
+ >
+ </File>
+ <File
RelativePath="..\util\sock.cpp"
>
</File>
diff --git a/dbgrid/dbgrid_commands.cpp b/dbgrid/dbgrid_commands.cpp new file mode 100644 index 00000000000..2a1e9b898c7 --- /dev/null +++ b/dbgrid/dbgrid_commands.cpp @@ -0,0 +1,74 @@ +// dbgrid/request.cpp + +/** +* 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/>. +*/ + +/* TODO + _ concurrency control. + _ connection pool + _ hostbyname_nonreentrant() problem + _ gridconfig object which gets config from the grid db. + connect to iad-sb-grid + _ limit() works right? + _ KillCursors + + later + _ secondary indexes +*/ + +#include "stdafx.h" +#include "../grid/message.h" +#include "../db/dbmessage.h" +#include "connpool.h" +#include "../db/commands.h" +#include "gridconfig.h" + +extern string ourHostname; + +namespace dbgrid_cmds { + +class NetStatCmd : public Command { +public: + NetStatCmd() : Command("netstat") { } + bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result) { + result.append("griddb", gridDB.toString()); + result.append("isdbgrid", 1); + return true; + } +} netstat; + +class IsDbGridCmd : public Command { +public: + IsDbGridCmd() : Command("isdbgrid") { } + bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result) { + result.append("isdbgrid", 1); + result.append("hostname", ourHostname); + return true; + } +} isdbgrid; + +class CmdIsMaster : public Command { +public: + CmdIsMaster() : Command("ismaster") { } + + virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result) { + result.append("ismaster", 0.0); + result.append("msg", "isdbgrid"); + return true; + } +} ismaster; + +} diff --git a/dbgrid/gridconfig.cpp b/dbgrid/gridconfig.cpp index 017946405b4..6f3a0cdeba3 100644 --- a/dbgrid/gridconfig.cpp +++ b/dbgrid/gridconfig.cpp @@ -23,110 +23,40 @@ #include "connpool.h" #include "../db/pdfile.h" #include "gridconfig.h" +#include "../client/model.h" -static boost::mutex loc_mutex; -static boost::mutex griddb_mutex; -GridDB gridDB; -GridConfig gridConfig; +/* --- Machine --- */ -GridDB::GridDB() { } +map<string, Machine*> Machine::machines; -void GridDB::init() { - char buf[256]; - int ec = gethostname(buf, 127); - if( ec || *buf == 0 ) { - log() << "can't get this server's hostname errno:" << ec << endl; - sleepsecs(5); - exit(16); - } - - const int DEBUG = 1; - if( DEBUG ) { - cout << "TEMPZ DEBUG mode on not for production" << endl; - strcpy(buf, "iad-sb-n13.10gen.cc"); - } - - char *p = strchr(buf, '-'); - if( p ) - p = strchr(p+1, '-'); - if( !p ) { - log() << "can't parse server's hostname, expect <acode>-<loc>-n<nodenum>, got: " << buf << endl; - sleepsecs(5); - exit(17); - } - p[1] = 0; +/* --- GridConfig --- */ - stringstream sl, sr; - sl << buf << "grid-l"; - sr << buf << "grid-r"; - string hostLeft = sl.str(); - string hostRight = sr.str(); - sl << ":" << Port; - sr << ":" << Port; - string left = sl.str(); - string right = sr.str(); +//static boost::mutex loc_mutex; +Grid grid; - if( DEBUG ) { - left = "10.211.55.4:27017"; - right = "10.211.55.4:27018"; - } - else - /* this loop is not really necessary, we we print out if we can't connect - but it gives much prettier error msg this way if the config is totally - wrong so worthwhile. - */ - while( 1 ) { - if( hostbyname(hostLeft.c_str()).empty() ) { - log() << "can't resolve DNS for " << hostLeft << ", sleeping and then trying again" << endl; - sleepsecs(15); - continue; - } - if( hostbyname(hostRight.c_str()).empty() ) { - log() << "can't resolve DNS for " << hostRight << ", sleeping and then trying again" << endl; - sleepsecs(15); - continue; +ClientConfig* GridConfig::getClientConfig(string client) { + ClientConfig*& cc = clients[client]; + if( cc == 0 ) { + cc = new ClientConfig(); + if( !cc->loadByName(client.c_str()) ) { + log() << "couldn't find client " << client << " in grid db" << endl; + // note here that cc->primary == 0. } - break; } - - log() << "connecting to griddb " << left << ' ' << right << endl; - - bool ok = conn.connect(left.c_str(),right.c_str()); - if( !ok ) - log() << " griddb connect failure at startup (will retry)" << endl; + return cc; } -GridConfig::GridConfig() { -} +/* --- Grid --- */ -Machine* GridConfig::fetchOwner(string& client, const char *ns, BSONObj& objOrKey) { - return 0; -} +Machine* Grid::owner(const char *ns, BSONObj& objOrKey) { + ClientConfig *cc = gc.getClientConfig( nsToClient(ns) ); + if( cc == 0 ) + return 0; -/*threadsafe*/ -Machine* GridConfig::owner(const char *ns, BSONObj& objOrKey) { - string client; - { - boostlock lk(loc_mutex); - ObjLocs::iterator i = loc.find(ns); - if( i != loc.end() ) { - return i->second; - } - i = loc.find(client=nsToClient(ns)); - if( i != loc.end() ) { - return i->second; - } + if( !cc->partitioned ) { + return cc->primary; } - return fetchOwner(client, ns, objOrKey); + uassert("not implemented 100", false); + return 0; } - -/* - -fetch client info - -> specifies general homes -fetch ns info - -> defines ranges -fetch range data - -*/ diff --git a/dbgrid/gridconfig.h b/dbgrid/gridconfig.h index 9ed5244115c..d969c94d949 100644 --- a/dbgrid/gridconfig.h +++ b/dbgrid/gridconfig.h @@ -27,41 +27,84 @@ #include "../client/model.h" class GridDB { - DBClientPaired conn; public: + DBClientPaired conn; enum { Port = 27016 }; /* standard port # for a grid db */ GridDB(); void init(); + string toString() { return conn.toString(); } }; extern GridDB gridDB; /* Machine is the concept of a host that runs the db process. */ class Machine { + static map<string, Machine*> machines; + string name; public: - enum { Port = 27018 /* default port # for dbs that are downstream of a dbgrid */ + string getName() const { return name; } + + Machine(string _name) : name(_name) { } + + enum { + Port = 27018 /* default port # for dbs that are downstream of a dbgrid */ }; + + static Machine* get(string name) { + map<string,Machine*>::iterator i = machines.find(name); + if( i != machines.end() ) + return i->second; + return machines[name] = new Machine(name); + } }; -typedef map<string,Machine*> ObjLocs; +//typedef map<string,Machine*> ObjLocs; /* top level grid configuration */ class ClientConfig : public Model { +public: + string name; // e.g. "alleyinsider" + Machine *primary; + bool partitioned; + + ClientConfig() : primary(0), partitioned(false) { } + + virtual const char * getNS() { return "grid.db.client"; } + virtual void serialize(BSONObjBuilder& to) { + to.append("name", name); + to.appendBool("partitioned", partitioned); + if( primary ) + to.append("primary", primary->getName()); + } + virtual void unserialize(BSONObj& from) { + name = from.getStringField("name"); + partitioned = from.getBoolField("partitioned"); + string p = from.getStringField("primary"); + if( !p.empty() ) + primary = Machine::get(p); + } + + bool loadByName(const char *nm) { + BSONObjBuilder b; + b.append("name", nm); + BSONObj q = b.done(); + return load(q); + } }; class GridConfig { - ObjLocs loc; + map<string,ClientConfig*> clients; +public: + ClientConfig* getClientConfig(string client); +}; - Machine* fetchOwner(string& client, const char *ns, BSONObj& objOrKey); +class Grid { + GridConfig gc; public: /* return which machine "owns" the object in question -- ie which partition we should go to. - - threadsafe. - */ + */ Machine* owner(const char *ns, BSONObj& objOrKey); - - GridConfig(); }; -extern GridConfig gridConfig; +extern Grid grid; diff --git a/dbgrid/griddb.cpp b/dbgrid/griddb.cpp new file mode 100644 index 00000000000..0cc915085a3 --- /dev/null +++ b/dbgrid/griddb.cpp @@ -0,0 +1,99 @@ +// griddb.cpp + +/** +* 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/>. +*/ + +#include "stdafx.h" +#include "../grid/message.h" +#include "../util/unittest.h" +#include "database.h" +#include "connpool.h" +#include "../db/pdfile.h" +#include "gridconfig.h" +#include "../client/model.h" + +static boost::mutex griddb_mutex; +GridDB gridDB; +DBClientCommands *Model::globalConn = &gridDB.conn; +string ourHostname; + +GridDB::GridDB() { } + +void GridDB::init() { + char buf[256]; + int ec = gethostname(buf, 127); + if( ec || *buf == 0 ) { + log() << "can't get this server's hostname errno:" << ec << endl; + sleepsecs(5); + exit(16); + } + ourHostname = buf; + + const int DEBUG = 1; + if( DEBUG ) { + cout << "TEMPZ DEBUG mode on not for production" << endl; + strcpy(buf, "iad-sb-n13.10gen.cc"); + } + + char *p = strchr(buf, '-'); + if( p ) + p = strchr(p+1, '-'); + if( !p ) { + log() << "can't parse server's hostname, expect <acode>-<loc>-n<nodenum>, got: " << buf << endl; + sleepsecs(5); + exit(17); + } + p[1] = 0; + + stringstream sl, sr; + sl << buf << "grid-l"; + sr << buf << "grid-r"; + string hostLeft = sl.str(); + string hostRight = sr.str(); + sl << ":" << Port; + sr << ":" << Port; + string left = sl.str(); + string right = sr.str(); + + if( DEBUG ) { + left = "iad-sb-n7.10gen.cc"; + right = "iad-sb-n7.10gen.cc"; + } + else + /* this loop is not really necessary, we we print out if we can't connect + but it gives much prettier error msg this way if the config is totally + wrong so worthwhile. + */ + while( 1 ) { + if( hostbyname(hostLeft.c_str()).empty() ) { + log() << "can't resolve DNS for " << hostLeft << ", sleeping and then trying again" << endl; + sleepsecs(15); + continue; + } + if( hostbyname(hostRight.c_str()).empty() ) { + log() << "can't resolve DNS for " << hostRight << ", sleeping and then trying again" << endl; + sleepsecs(15); + continue; + } + break; + } + + log() << "connecting to griddb " << left << ' ' << right << "..." << endl; + + bool ok = conn.connect(left.c_str(),right.c_str()); + if( !ok ) + log() << " griddb connect failure at startup (will retry)" << endl; +} diff --git a/dbgrid/request.cpp b/dbgrid/request.cpp index 160e897d3db..ba380b5fbe7 100644 --- a/dbgrid/request.cpp +++ b/dbgrid/request.cpp @@ -55,26 +55,15 @@ void getMore(Message& m, MessagingPort& p) { bool runCommandAgainstRegistered(const char *ns, BSONObj& jsobj, BSONObjBuilder& anObjBuilder); -#include "../db/commands.h" - -class IsDbGridCmd : public Command { -public: - IsDbGridCmd() : Command("isdbgrid") { } - bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result) { - result.append("isdbgrid", 1); - return true; - } -} isdbgridcmd; - void queryOp(Message& m, MessagingPort& p) { DbMessage d(m); QueryMessage q(d); - cout << "TEMPns: " << q.ns << endl; - if( q.ntoreturn == -1 && strstr(q.ns, ".$cmd") ) { BSONObjBuilder builder; - if( runCommandAgainstRegistered(q.ns, q.query, builder) ) { + cout << q.query.toString() << endl; + bool ok = runCommandAgainstRegistered(q.ns, q.query, builder); + if( ok ) { BufBuilder b(32768); b.skip(sizeof(QueryResult)); BSONObj x = builder.done(); diff --git a/grid/message.cpp b/grid/message.cpp index 5733a4d8fb0..ac6e702d27e 100644 --- a/grid/message.cpp +++ b/grid/message.cpp @@ -23,6 +23,7 @@ #include "message.h" #include <time.h> #include "../util/goodies.h" +#include <fcntl.h> // if you want trace output: #define mmm(x) @@ -111,11 +112,29 @@ bool MessagingPort::connect(SockAddr& _far) log() << "ERROR: connect(): invalid socket? " << errno << endl; return false; } - if( ::connect(sock, (sockaddr *) &farEnd.sa, farEnd.addressSize) ) { -// log() << "connect(): failed errno:" << errno << ' ' << farEnd.getPort() << endl; + +#if 0 + long fl = fcntl(sock, F_GETFL, 0); + assert( fl >= 0 ); + fl |= O_NONBLOCK; + fcntl(sock, F_SETFL, fl); + + int res = ::connect(sock, (sockaddr *) &farEnd.sa, farEnd.addressSize); + if( res ) { + if( errno == EINPROGRESS ) + //log() << "connect(): failed errno:" << errno << ' ' << farEnd.getPort() << endl; closesocket(sock); sock = -1; return false; } + +#else + int res = ::connect(sock, (sockaddr *) &farEnd.sa, farEnd.addressSize); + if( res ) { + closesocket(sock); sock = -1; + return false; + } +#endif + disableNagle(sock); return true; } diff --git a/util/sock.h b/util/sock.h index 9187fe84785..f2be1b0f636 100644 --- a/util/sock.h +++ b/util/sock.h @@ -71,6 +71,17 @@ inline void prebindOptions( int sock ){ #endif +inline void setSockReceiveTimeout(int sock, int secs) { +// todo - finish - works? + struct timeval tv; + tv.tv_sec = 0;//secs; + tv.tv_usec = 1000; + int rc = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv)); + if( rc ) { + cout << "ERROR: setsockopt RCVTIMEO failed rc:" << rc << " errno:" << getLastError() << " secs:" << secs << " sock:" << sock << endl; + } +} + // .empty() if err string hostbyname(const char *hostname); |