summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEliot Horowitz <ehorowitz@shopwiki.com>2008-09-14 22:03:01 -0400
committerEliot Horowitz <ehorowitz@shopwiki.com>2008-09-14 22:03:01 -0400
commit245779485e82ef8fbaf4773ee7ef3f1442bacb4b (patch)
tree7ca25325e89789d43aec98d0bdcb0cf169be03dd
parent31eff8fb7cfa94783fcfb47622199a0ed27a0a53 (diff)
parent3332989338a5815c30a039213bf2e4581759e8c8 (diff)
downloadmongo-245779485e82ef8fbaf4773ee7ef3f1442bacb4b.tar.gz
Merge branch 'master' of ssh://git.latenightcoders.com/data/gitroot/p
-rw-r--r--db/cloner.cpp87
-rw-r--r--db/commands.cpp18
-rw-r--r--db/commands.h7
-rw-r--r--db/db.cpp80
-rw-r--r--db/dbclient.cpp13
-rw-r--r--db/dbclient.h51
-rw-r--r--db/jsobj.cpp7
-rw-r--r--db/jsobj.h2
-rw-r--r--db/makefile2
-rw-r--r--db/pdfile.cpp8
-rw-r--r--db/pdfile.h3
-rw-r--r--db/query.cpp8
-rw-r--r--db/repl.cpp187
-rw-r--r--db/repl.h9
-rw-r--r--db/replset.h50
-rw-r--r--dbgrid/dbgrid.cpp135
-rw-r--r--dbgrid/dbgrid.vcproj268
-rw-r--r--stdafx.cpp5
-rw-r--r--stdafx.h23
-rw-r--r--util/goodies.h6
20 files changed, 847 insertions, 122 deletions
diff --git a/db/cloner.cpp b/db/cloner.cpp
index e06d4d8276d..cf2699a6295 100644
--- a/db/cloner.cpp
+++ b/db/cloner.cpp
@@ -22,40 +22,46 @@
#include "../util/builder.h"
#include "jsobj.h"
#include "query.h"
+#include "commands.h"
extern int port;
bool userCreateNS(const char *ns, JSObj& j, string& err);
class Cloner: boost::noncopyable {
DBClientConnection conn;
- void copy(const char *collection);
+ void copy(const char *from_ns, const char *to_ns);
public:
Cloner() { }
- bool go(const char *masterHost, string& errmsg);
+ bool go(const char *masterHost, string& errmsg, const string& fromdb);
};
-void Cloner::copy(const char *collection) {
- auto_ptr<DBClientCursor> c( conn.query(collection, emptyObj) );
+void Cloner::copy(const char *from_collection, const char *to_collection) {
+ auto_ptr<DBClientCursor> c( conn.query(from_collection, emptyObj) );
assert( c.get() );
while( c->more() ) {
JSObj js = c->next();
- theDataFileMgr.insert(collection, (void*) js.objdata(), js.objsize());
+ theDataFileMgr.insert(to_collection, (void*) js.objdata(), js.objsize());
}
}
-bool Cloner::go(const char *masterHost, string& errmsg) {
+bool Cloner::go(const char *masterHost, string& errmsg, const string& fromdb) {
+ string todb = client->name;
if( (string("localhost") == masterHost || string("127.0.0.1") == masterHost) && port == DBPort ) {
- errmsg = "can't clone from self (localhost). sources configuration may be wrong.";
- return false;
+ if( fromdb == todb ) {
+ // guard against an "infinite" loop
+ /* if you are replicating, the local.sources config may be wrong if you get this */
+ errmsg = "can't clone from self (localhost).";
+ return false;
+ }
}
if( !conn.connect(masterHost, errmsg) )
return false;
- string ns = client->name + ".system.namespaces";
+ string ns = fromdb + ".system.namespaces";
auto_ptr<DBClientCursor> c( conn.query(ns.c_str(), emptyObj) );
if( c.get() == 0 ) {
- errmsg = "query failed system.namespaces";
+ errmsg = "query failed " + ns;
return false;
}
@@ -64,26 +70,71 @@ bool Cloner::go(const char *masterHost, string& errmsg) {
Element e = collection.findElement("name");
assert( !e.eoo() );
assert( e.type() == String );
- const char *name = e.valuestr();
- if( strstr(name, ".system.") || strchr(name, '$') )
+ const char *from_name = e.valuestr();
+ if( strstr(from_name, ".system.") || strchr(from_name, '$') )
continue;
JSObj options = collection.getObjectField("options");
+ /* change name "<fromdb>.collection" -> <todb>.collection */
+ const char *p = strchr(from_name, '.');
+ assert(p);
+ string to_name = todb + p;
if( !options.isEmpty() ) {
string err;
- userCreateNS(name, options, err);
+ userCreateNS(to_name.c_str(), options, err);
}
- copy(name);
+ copy(from_name, to_name.c_str());
}
// now build the indexes
- string system_indexes = client->name + ".system.indexes";
- copy(system_indexes.c_str());
+ string system_indexes_from = fromdb + ".system.indexes";
+ string system_indexes_to = todb + ".system.indexes";
+ copy(system_indexes_from.c_str(), system_indexes_to.c_str());
return true;
}
-bool cloneFrom(const char *masterHost, string& errmsg)
+bool cloneFrom(const char *masterHost, string& errmsg, const string& fromdb)
{
Cloner c;
- return c.go(masterHost, errmsg);
+ return c.go(masterHost, errmsg, fromdb);
}
+
+/* Usage:
+ mydb.$cmd.findOne( { clone: "fromhost" } );
+*/
+class CmdClone : public Command {
+public:
+ CmdClone() : Command("clone") { }
+
+ virtual bool run(const char *ns, JSObj& cmdObj, string& errmsg, JSObjBuilder& result) {
+ string from = cmdObj.getStringField("clone");
+ if( from.empty() )
+ return false;
+ return cloneFrom(from.c_str(), errmsg, client->name);
+ }
+} cmdclone;
+
+/* Usage:
+ admindb.$cmd.findOne( { copydb: 1, fromhost: <hostname>, fromdb: <db>, todb: <db> } );
+*/
+class CmdCopyDb : public Command {
+public:
+ CmdCopyDb() : Command("copydb") { }
+ virtual bool adminOnly() { return true; }
+
+ virtual bool run(const char *ns, JSObj& cmdObj, string& errmsg, JSObjBuilder& result) {
+ string fromhost = cmdObj.getStringField("fromhost");
+ string fromdb = cmdObj.getStringField("fromdb");
+ string todb = cmdObj.getStringField("todb");
+ if( fromhost.empty() || todb.empty() || fromdb.empty() ) {
+ errmsg = "parms missing - {copydb: 1, fromhost: <hostname>, fromdb: <db>, todb: <db>}";
+ return false;
+ }
+ string temp = todb + ".";
+ setClient(temp.c_str());
+ bool res = cloneFrom(fromhost.c_str(), errmsg, fromdb);
+ client = 0;
+ return res;
+ }
+} cmdcopydb;
+
diff --git a/db/commands.cpp b/db/commands.cpp
index a9c393649d5..ce343e98924 100644
--- a/db/commands.cpp
+++ b/db/commands.cpp
@@ -40,7 +40,14 @@ int runCount(const char *ns, JSObj& cmd, string& err);
const int edebug=0;
-map<string,Command*> Command::commands;
+static map<string,Command*> *commands;
+
+Command::Command(const char *_name) : name(_name) {
+ // register ourself.
+ if( commands == 0 )
+ commands = new map<string,Command*>;
+ (*commands)[name] = this;
+}
bool dbEval(JSObj& cmd, JSObjBuilder& result) {
Element e = cmd.firstElement();
@@ -303,7 +310,7 @@ bool _runCommands(const char *ns, JSObj& jsobj, stringstream& ss, BufBuilder &b,
/* check for properly registered command objects. Note that all the commands below should be
migrated over to the command object format.
*/
- else if( (i = Command::commands.find(e.fieldName())) != Command::commands.end() ) {
+ else if( (i = commands->find(e.fieldName())) != commands->end() ) {
valid = true;
string errmsg;
Command *c = i->second;
@@ -373,13 +380,6 @@ bool _runCommands(const char *ns, JSObj& jsobj, stringstream& ss, BufBuilder &b,
}
anObjBuilder.append("n", (double) nn);
}
- else if( strcmp( e.fieldName(), "clone") == 0 ) {
- valid = true;
- string err;
- ok = cloneFrom(e.valuestr(), err);
- if( !err.empty() )
- anObjBuilder.append("errmsg", err.c_str());
- }
else if( strcmp( e.fieldName(), "create") == 0 ) {
valid = true;
string ns = us + '.' + e.valuestr();
diff --git a/db/commands.h b/db/commands.h
index 884c761d09b..062867a1997 100644
--- a/db/commands.h
+++ b/db/commands.h
@@ -31,10 +31,5 @@ public:
/* return true if only the admin ns has privileges to run this command. */
virtual bool adminOnly() { return false; }
- static map<string,Command*> commands;
-
- Command(const char *_name) : name(_name) {
- // register ourself.
- commands[name] = this;
- }
+ Command(const char *_name);
};
diff --git a/db/db.cpp b/db/db.cpp
index 0ecbd0359a0..a6137a83d1a 100644
--- a/db/db.cpp
+++ b/db/db.cpp
@@ -45,7 +45,7 @@ int dbLocked = 0;
void closeAllSockets();
void startReplication();
-void pairWith(const char *remoteEnd);
+void pairWith(const char *remoteEnd, const char *arb);
struct MyStartupTests {
MyStartupTests() {
@@ -58,10 +58,17 @@ struct MyStartupTests {
*/
int opLogging = 0;
+// turn on or off the oplog.* files which the db can generate.
+// these files are for diagnostic purposes and are unrelated to
+// local.oplog.$main used by replication.
+//
+#define OPLOG if( 0 )
+
struct OpLog {
ofstream *f;
OpLog() : f(0) { }
void init() {
+ OPLOG {
stringstream ss;
ss << "oplog." << hex << time(0);
string name = ss.str();
@@ -70,17 +77,26 @@ struct OpLog {
problem() << "couldn't open log stream" << endl;
throw 1717;
}
+ }
}
+ void flush() {
+ OPLOG f->flush();
+ }
+ void write(char *data,int len) {
+ OPLOG f->write(data,len);
+ }
void readop(char *data, int len) {
+ OPLOG {
bool log = (opLogging & 4) == 0;
OCCASIONALLY log = true;
if( log )
f->write(data,len);
+ }
}
} _oplog;
-void flushOpLog() { _oplog.f->flush(); }
-#define oplog (*(_oplog.f))
-#define OPWRITE if( opLogging & 1 ) oplog.write((char *) m.data, m.data->len);
+void flushOpLog() { _oplog.flush(); }
+//#define oplog (*(_oplog.f))
+#define OPWRITE if( opLogging & 1 ) _oplog.write((char *) m.data, m.data->len);
#define OPREAD if( opLogging & 2 ) _oplog.readop((char *) m.data, m.data->len);
/* example for
@@ -253,22 +269,33 @@ void receivedQuery(DbResponse& dbresponse, /*AbstractMessagingPort& dbMsgPort, *
try {
msgdata = runQuery(m, ns, ntoskip, ntoreturn, query, fields, ss, m.data->dataAsInt());
}
- catch( AssertionException ) {
+ catch( AssertionException& e ) {
ss << " exception ";
- problem() << " Caught Assertion in runQuery ns:" << ns << endl;
+ problem() << " Caught Assertion in runQuery ns:" << ns << ' ' << e.toString() << '\n';
log() << " ntoskip:" << ntoskip << " ntoreturn:" << ntoreturn << '\n';
- log() << " query:" << query.toString() << '\n';
- msgdata = (QueryResult*) malloc(sizeof(QueryResult));
+ log() << " query:" << query.toString() << endl;
+
+ JSObjBuilder err;
+ err.append("$err", e.msg.empty() ? "assertion during query" : e.msg);
+ JSObj errObj = err.done();
+
+ BufBuilder b;
+ b.skip(sizeof(QueryResult));
+ b.append((void*) errObj.objdata(), errObj.objsize());
+
+ msgdata = (QueryResult *) b.buf();
+ b.decouple();
QueryResult *qr = msgdata;
qr->_data[0] = 0;
qr->_data[1] = 0;
qr->_data[2] = 0;
qr->_data[3] = 0;
- qr->len = sizeof(QueryResult);
+ qr->len = b.len();
qr->setOperation(opReply);
qr->cursorId = 0;
qr->startingFrom = 0;
- qr->nReturned = 0;
+ qr->nReturned = 1;
+
}
Message *resp = new Message();
resp->setData(msgdata, true); // transport will free
@@ -300,8 +327,8 @@ void receivedGetMore(DbResponse& dbresponse, /*AbstractMessagingPort& dbMsgPort,
try {
msgdata = getMore(ns, ntoreturn, cursorid);
}
- catch( AssertionException ) {
- ss << " exception ";
+ catch( AssertionException& e ) {
+ ss << " exception " + e.toString();
msgdata = emptyMoreResult(cursorid);
}
Message *resp = new Message();
@@ -467,7 +494,7 @@ void jniCallback(Message& m, Message& out)
ss << "killcursors ";
receivedKillCursors(m);
}
- catch( AssertionException ) {
+ catch( AssertionException& ) {
problem() << "Caught Assertion in kill cursors, continuing" << endl;
ss << " exception ";
}
@@ -492,7 +519,7 @@ void jniCallback(Message& m, Message& out)
}
}
- catch( AssertionException ) {
+ catch( AssertionException& ) {
problem() << "Caught AssertionException in jniCall()" << endl;
}
@@ -592,9 +619,9 @@ void connThread()
ss << "insert ";
receivedInsert(m, ss);
}
- catch( AssertionException ) {
- problem() << " Caught Assertion insert, continuing" << endl;
- ss << " exception ";
+ catch( AssertionException& e ) {
+ problem() << " Caught Assertion insert, continuing\n";
+ ss << " exception " + e.toString();
}
}
else if( m.data->operation() == dbUpdate ) {
@@ -603,9 +630,9 @@ void connThread()
ss << "update ";
receivedUpdate(m, ss);
}
- catch( AssertionException ) {
+ catch( AssertionException& e ) {
problem() << " Caught Assertion update, continuing" << endl;
- ss << " exception ";
+ ss << " exception " + e.toString();
}
}
else if( m.data->operation() == dbDelete ) {
@@ -614,9 +641,9 @@ void connThread()
ss << "remove ";
receivedDelete(m);
}
- catch( AssertionException ) {
+ catch( AssertionException& e ) {
problem() << " Caught Assertion receivedDelete, continuing" << endl;
- ss << " exception ";
+ ss << " exception " + e.toString();
}
}
else if( m.data->operation() == dbGetMore ) {
@@ -632,9 +659,9 @@ void connThread()
ss << "killcursors ";
receivedKillCursors(m);
}
- catch( AssertionException ) {
+ catch( AssertionException& e ) {
problem() << " Caught Assertion in kill cursors, continuing" << endl;
- ss << " exception ";
+ ss << " exception " + e.toString();
}
}
else {
@@ -663,7 +690,7 @@ void connThread()
}
}
- catch( AssertionException ) {
+ catch( AssertionException& ) {
problem() << "Uncaught AssertionException, terminating" << endl;
exit(15);
}
@@ -905,7 +932,8 @@ int main(int argc, char* argv[], char *envp[] )
else if( s == "--slave" )
slave = true;
else if( s == "--pairwith" ) {
- pairWith( argv[++i] );
+ pairWith( argv[i+1], argv[i+2] );
+ i += 2;
}
else if( s == "--dbpath" )
dbpath = argv[++i];
@@ -941,7 +969,7 @@ int main(int argc, char* argv[], char *envp[] )
cout << " --port <portno> --dbpath <root> --appsrvpath <root of appsrv>" << endl;
cout << " --nocursors --nojni" << endl;
cout << " --oplog<n> 0=off 1=W 2=R 3=both 7=W+some reads" << endl;
- cout << " --pairwith <server:port>" << endl;
+ cout << " --pairwith <server:port> <arbiter>" << endl;
cout << endl;
return 0;
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..3af4f544452 100644
--- a/db/dbclient.h
+++ b/db/dbclient.h
@@ -19,10 +19,11 @@
#pragma once
#include "../grid/message.h"
+#include "jsobj.h"
/* 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 +31,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 +73,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 +104,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/jsobj.cpp b/db/jsobj.cpp
index 6894cd79741..8aa517aebf1 100644
--- a/db/jsobj.cpp
+++ b/db/jsobj.cpp
@@ -19,6 +19,8 @@
#include "stdafx.h"
#include "jsobj.h"
#include "../util/goodies.h"
+#include <limits>
+
Element nullElement;
@@ -371,6 +373,11 @@ JSObj JSObj::extractFields(JSObj& pattern) {
return b.doneAndDecouple();
}
+int JSObj::getIntField(const char *name) {
+ Element e = getField(name);
+ return e.type() == Number ? (int) e.number() : INT_MIN;
+}
+
bool JSObj::getBoolField(const char *name) {
Element e = getField(name);
return e.type() == Bool ? e.boolean() : false;
diff --git a/db/jsobj.h b/db/jsobj.h
index 9ce429c48af..a2b5e416aa5 100644
--- a/db/jsobj.h
+++ b/db/jsobj.h
@@ -248,6 +248,8 @@ public:
JSObj getObjectField(const char *name);
+ int getIntField(const char *name); // INT_MIN if not present
+
bool getBoolField(const char *name);
/* makes a new JSObj with the fields specified in pattern.
diff --git a/db/makefile b/db/makefile
index 89c6a590197..44adbad76cd 100644
--- a/db/makefile
+++ b/db/makefile
@@ -12,7 +12,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 dbclient.o btreecursor.o cloner.o namespace.o commands.o matcher.o
-DBGRID_OBJS=../stdafx.o ../util/sock.o ../grid/message.o ../util/util.o jsobj.o dbclient.o ../dbgrid/dbgrid.o
+DBGRID_OBJS=../stdafx.o ../util/sock.o ../grid/message.o ../util/util.o jsobj.o dbclient.o ../dbgrid/dbgrid.o ../dbgrid/request.o ../dbgrid/database.o
GPP = g++
diff --git a/db/pdfile.cpp b/db/pdfile.cpp
index 18340ab8853..9180e6fabff 100644
--- a/db/pdfile.cpp
+++ b/db/pdfile.cpp
@@ -442,7 +442,7 @@ void _unindexRecord(const char *ns, IndexDetails& id, JSObj& obj, const DiskLoc&
try {
ok = id.head.btree()->unindex(id.head, id, j, dl);
}
- catch(AssertionException) {
+ catch(AssertionException&) {
problem() << "Assertion failure: _unindex failed " << id.indexNamespace() << endl;
cout << "Assertion failure: _unindex failed" << '\n';
cout << " obj:" << obj.toString() << '\n';
@@ -590,7 +590,7 @@ void DataFileMgr::update(
try {
idx.head.btree()->unindex(idx.head, idx, *removed[i], dl);
}
- catch(AssertionException) {
+ catch(AssertionException&) {
ss << " exception update unindex ";
problem() << " caught assertion update unindex " << idxns.c_str() << endl;
}
@@ -604,7 +604,7 @@ void DataFileMgr::update(
idx.head,
dl, *added[i], false, idx, true);
}
- catch(AssertionException) {
+ catch(AssertionException&) {
ss << " exception update index ";
cout << " caught assertion update index " << idxns.c_str() << '\n';
problem() << " caught assertion update index " << idxns.c_str() << endl;
@@ -644,7 +644,7 @@ void _indexRecord(IndexDetails& idx, JSObj& obj, DiskLoc newRecordLoc) {
idx.head.btree()->insert(idx.head, newRecordLoc,
(JSObj&) *i, false, idx, true);
}
- catch(AssertionException) {
+ catch(AssertionException&) {
problem() << " caught assertion _indexRecord " << idx.indexNamespace() << endl;
}
}
diff --git a/db/pdfile.h b/db/pdfile.h
index b97bb997e17..d0fb8dfc9ad 100644
--- a/db/pdfile.h
+++ b/db/pdfile.h
@@ -391,7 +391,8 @@ inline bool setClient(const char *ns) {
client = c;
return justCreated;
}
-/* we normally keep around a curNs ptr -- if this ns is temporary,
+
+/* We normally keep around a curNs ptr -- if this ns is temporary,
use this instead so we don't have a bad ptr. we could have made a copy,
but trying to be fast as we call setClient this for every single operation.
*/
diff --git a/db/query.cpp b/db/query.cpp
index 7f5a575dc3c..0430f631084 100644
--- a/db/query.cpp
+++ b/db/query.cpp
@@ -28,6 +28,7 @@
#include "javajs.h"
#include "json.h"
#include "repl.h"
+#include "replset.h"
#include "scanandorder.h"
/* We cut off further objects once we cross this threshold; thus, you might get
@@ -418,8 +419,9 @@ bool runCommands(const char *ns, JSObj& jsobj, stringstream& ss, BufBuilder &b,
try {
return _runCommands(ns, jsobj, ss, b, anObjBuilder);
}
- catch( AssertionException ) {
- ;
+ catch( AssertionException e ) {
+ if( !e.msg.empty() )
+ anObjBuilder.append("assertion", e.msg);
}
ss << " assertion ";
anObjBuilder.append("errmsg", "db assertion failure");
@@ -533,6 +535,8 @@ QueryResult* runQuery(Message& message, const char *ns, int ntoskip, int _ntoret
}
else {
+ uassert("not master", isMaster() || (queryOptions & Option_SlaveOk));
+
JSObj query = jsobj.getObjectField("query");
JSObj order = jsobj.getObjectField("orderby");
if( query.isEmpty() && order.isEmpty() )
diff --git a/db/repl.cpp b/db/repl.cpp
index e41473b0e5c..23d07b0de26 100644
--- a/db/repl.cpp
+++ b/db/repl.cpp
@@ -33,20 +33,151 @@
#include "query.h"
#include "json.h"
#include "db.h"
+#include "commands.h"
-extern int port;
extern boost::mutex dbMutex;
auto_ptr<Cursor> findTableScan(const char *ns, JSObj& order);
bool userCreateNS(const char *ns, JSObj& j, string& err);
int _updateObjects(const char *ns, JSObj updateobj, JSObj pattern, bool upsert, stringstream& ss, bool logOp=false);
bool _runCommands(const char *ns, JSObj& jsobj, stringstream& ss, BufBuilder &b, JSObjBuilder& anObjBuilder);
-bool cloneFrom(const char *masterHost, string& errmsg);
void ensureHaveIdIndex(const char *ns);
#include "replset.h"
+/* --- ReplPair -------------------------------- */
+
ReplPair *replPair = 0;
+JSObj ismasterobj = fromjson("{ismaster:1}");
+
+/* peer unreachable, try our arbiter */
+void ReplPair::arbitrate() {
+ if( arbHost == "-" ) {
+ // no arbiter. we are up, let's assume he is down and network is not partitioned.
+ setMaster(State_Master, "remote unreachable");
+ return;
+ }
+
+ auto_ptr<DBClientConnection> conn( new DBClientConnection() );
+ string errmsg;
+ if( !conn->connect(arbHost.c_str(), errmsg) ) {
+ setMaster(State_CantArb, "can't connect to arb");
+ return;
+ }
+
+ JSObj res = conn->findOne("admin.$cmd", ismasterobj);
+ if( res.isEmpty() ) {
+ setMaster(State_CantArb, "can't arb 2");
+ return;
+ }
+
+ setMaster(State_Master, "remote down, arbiter reached");
+}
+
+/* --------------------------------------------- */
+
+class CmdIsMaster : public Command {
+public:
+ CmdIsMaster() : Command("ismaster") { }
+
+ virtual bool run(const char *ns, JSObj& cmdObj, string& errmsg, JSObjBuilder& result) {
+ if( replPair ) {
+ int x = replPair->state;
+ result.append("ismaster", replPair->state);
+ result.append("remote", replPair->remote);
+ if( !replPair->info.empty() )
+ result.append("info", replPair->info);
+ }
+ else {
+ result.append("ismaster", 1);
+ result.append("msg", "not paired");
+ }
+
+ return true;
+ }
+} cmdismaster;
+
+/* negotiate who is master
+
+ -1=not set (probably means we just booted)
+ 0=was slave
+ 1=was master
+
+ remote,local -> new remote,local
+ !1,1 -> 0,1
+ 1,!1 -> 1,0
+ -1,-1 -> dominant->1, nondom->0
+ 0,0 -> dominant->1, nondom->0
+ 1,1 -> dominant->1, nondom->0
+
+ { negotiatemaster:1, i_was:<state>, your_name:<hostname> }
+ returns:
+ { ok:1, you_are:..., i_am:... }
+*/
+class CmdNegotiateMaster : public Command {
+public:
+ CmdNegotiateMaster() : Command("negotiatemaster") { }
+
+ virtual bool adminOnly() { return true; }
+
+ virtual bool run(const char *ns, JSObj& cmdObj, string& errmsg, JSObjBuilder& result) {
+ if( replPair == 0 ) {
+ problem() << "got negotiatemaster cmd but we are not in paired mode." << endl;
+ errmsg = "not paired";
+ return false;
+ }
+
+ int was = cmdObj.getIntField("i_was");
+ string myname = cmdObj.getStringField("your_name");
+ if( myname.empty() || was < -1 ) {
+ errmsg = "your_name/i_was not specified";
+ return false;
+ }
+
+ int me, you;
+ if( was == replPair->state ) {
+ if( replPair->dominant(myname) ) {
+ me=1;you=0;
+ }
+ else {
+ me=0;you=1;
+ }
+ }
+ else if( was == 1 ) {
+ me=0;you=1;
+ }
+ else {
+ me=1;you=0;
+ }
+
+ replPair->state = me;
+ result.append("you_are", you);
+ result.append("i_am", me);
+
+ return true;
+ }
+} cmdnegotiatemaster;
+
+void ReplPair::negotiate(DBClientConnection *conn) {
+ JSObjBuilder b;
+ b.append("negotiatemaster",1);
+ b.append("i_was", state);
+ b.append("your_name", remoteHost);
+ JSObj cmd = b.done();
+ JSObj res = conn->findOne("admin.$cmd", cmd);
+ if( res.getIntField("ok") != 1 ) {
+ problem() << "negotiate fails: " << res.toString() << '\n';
+ setMaster(State_Confused);
+ return;
+ }
+ int x = res.getIntField("you_are");
+ if( x != 0 && x != 1 ) {
+ problem() << "negotiate: bad you_are value " << res.toString() << endl;
+ return;
+ }
+ setMaster(x);
+}
+
OpTime last(0, 0);
OpTime OpTime::now() {
@@ -177,8 +308,10 @@ void ReplSource::loadAll(vector<ReplSource*>& v) {
auto_ptr<Cursor> c = findTableScan("local.sources", emptyObj);
while( c->ok() ) {
ReplSource tmp(c->current());
- if( replPair && tmp.hostName == replPair->remote && tmp.sourceName == "main" )
+ if( replPair && tmp.hostName == replPair->remote && tmp.sourceName == "main" ) {
gotPairWith = true;
+ tmp.paired = true;
+ }
addSourceToList(v, tmp, old);
c->advance();
}
@@ -211,7 +344,7 @@ bool ReplSource::resync(string db) {
log() << "resync: cloning database " << db << endl;
//Cloner c;
string errmsg;
- bool ok = cloneFrom(hostName.c_str(), errmsg);
+ bool ok = cloneFrom(hostName.c_str(), errmsg, client->name);
//bool ok = c.go(hostName.c_str(), errmsg);
if( !ok ) {
problem() << "resync of " << db << " from " << hostName << " failed " << errmsg << endl;
@@ -320,7 +453,7 @@ void ReplSource::sync_pullOpLog_applyOperation(JSObj& op) {
_runCommands(ns, o, ss, bb, ob);
}
}
- catch( UserAssertionException e ) {
+ catch( UserAssertionException& e ) {
log() << "sync: caught user assertion " << e.msg << '\n';
}
client = 0;
@@ -344,7 +477,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;
}
@@ -370,7 +503,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);
@@ -380,7 +513,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 ) {
@@ -452,11 +588,18 @@ bool ReplSource::sync() {
if( !conn->connect(hostName.c_str(), errmsg) ) {
resetConnection();
log() << "pull: cantconn " << errmsg << endl;
+ if( replPair && paired ) {
+ assert( startsWith(hostName.c_str(), replPair->remoteHost.c_str()) );
+ replPair->arbitrate();
+ }
sleepsecs(1);
return false;
}
}
+ if( paired )
+ replPair->negotiate(conn.get());
+
/*
// get current mtime at the server.
JSObj o = conn->findOne("admin.$cmd", opTimeQuery);
@@ -546,6 +689,7 @@ _ reuse that cursor when we can
void replMain() {
vector<ReplSource*> sources;
+ bool first = true;
while( 1 ) {
{
@@ -553,8 +697,10 @@ void replMain() {
ReplSource::loadAll(sources);
}
- if( sources.empty() )
+ if( !first && sources.empty() )
sleepsecs(20);
+
+ first=false;
for( vector<ReplSource*>::iterator i = sources.begin(); i != sources.end(); i++ ) {
ReplSource *s = *i;
@@ -562,13 +708,18 @@ void replMain() {
try {
ok = s->sync();
}
- catch( SyncException ) {
- log() << "caught SyncException, sleeping 1 minutes" << endl;
- sleepsecs(60);
+ catch( SyncException& ) {
+ log() << "caught SyncException, sleeping 10 secs" << endl;
+ sleepsecs(10);
}
- catch( AssertionException ) {
- log() << "replMain caught AssertionException, sleeping 1 minutes" << endl;
- sleepsecs(60);
+ catch( AssertionException& e ) {
+ if( e.severe() ) {
+ log() << "replMain caught AssertionException, sleeping 1 minutes" << endl;
+ sleepsecs(60);
+ }
+ else {
+ log() << e.toString() << '\n';
+ }
}
if( !ok )
s->resetConnection();
@@ -591,7 +742,7 @@ void replSlaveThread() {
break;
sleepsecs(5);
}
- catch( AssertionException ) {
+ catch( AssertionException& ) {
problem() << "Assertion in replSlaveThread(): sleeping 5 minutes before retry" << endl;
sleepsecs(300);
}
@@ -667,6 +818,6 @@ void startReplication() {
}
/* called from main at server startup */
-void pairWith(const char *remoteEnd) {
- replPair = new ReplPair(remoteEnd);
+void pairWith(const char *remoteEnd, const char *arb) {
+ replPair = new ReplPair(remoteEnd, arb);
}
diff --git a/db/repl.h b/db/repl.h
index 52f2719073f..d5d0763c369 100644
--- a/db/repl.h
+++ b/db/repl.h
@@ -33,7 +33,7 @@ class DBClientCursor;
extern bool slave;
extern bool master;
-bool cloneFrom(const char *masterHost, string& errmsg);
+bool cloneFrom(const char *masterHost, string& errmsg, const string& fromdb);
#pragma pack(push,4)
class OpTime {
@@ -98,7 +98,7 @@ class ReplSource {
ReplSource();
public:
bool paired; // --pair in use
- string hostName; // ip addr or hostname
+ string hostName; // ip addr or hostname plus optionally, ":<port>"
string sourceName; // a logical source name.
string only; // only a certain db. note that in the sources collection, this may not be changed once you start replicating.
@@ -118,7 +118,10 @@ public:
ReplSource(JSObj);
bool sync();
void save(); // write ourself to local.sources
- void resetConnection() { conn = auto_ptr<DBClientConnection>(0); }
+ void resetConnection() {
+ conn = auto_ptr<DBClientConnection>(0);
+ cursor = auto_ptr<DBClientCursor>(0);
+ }
// make a jsobj from our member fields of the form
// { host: ..., source: ..., syncedTo: ... }
diff --git a/db/replset.h b/db/replset.h
index 58b32046b55..c82655a9825 100644
--- a/db/replset.h
+++ b/db/replset.h
@@ -16,6 +16,8 @@
#pragma once
+extern int port;
+
/* ReplPair is a pair of db servers replicating to one another and cooperating.
Only one member of the pair is active at a time; so this is a smart master/slave
@@ -28,17 +30,56 @@
*/
class ReplPair {
-
public:
+ enum {
+ State_CantArb = -3,
+ State_Confused = -2,
+ State_Negotiating = -1,
+ State_Slave = 0,
+ State_Master = 1
+ };
+
+ int state;
+ string info; // commentary about our current state
+ string arbHost; // "-" for no arbiter. "host[:port]"
int remotePort;
string remoteHost;
string remote; // host:port if port specified.
+ int date; // -1 not yet set; 0=slave; 1=master
+
+ ReplPair(const char *remoteEnd, const char *arbiter);
+
+ bool dominant(const string& myname) {
+ if( myname == remoteHost )
+ return port > remotePort;
+ return myname > remoteHost;
+ }
- ReplPair(const char *remoteEnd);
+ void setMaster(int n, const char *_comment = "") {
+ info = _comment;
+ if( n == state )
+ return;
+ log() << "pair: setting master=" << n << " was " << state << '\n';
+ state = n;
+ }
+ /* negotiate with our peer who is master */
+ void negotiate(DBClientConnection *conn);
+
+ /* peer unreachable, try our arbitrator */
+ void arbitrate();
};
-ReplPair::ReplPair(const char *remoteEnd) {
+extern ReplPair *replPair;
+
+/* we should not allow most operations when not the master */
+inline bool isMaster() {
+ return replPair == 0 || replPair->state == ReplPair::State_Master ||
+ client->name == "local"; // local is always allowed
+}
+
+inline ReplPair::ReplPair(const char *remoteEnd, const char *arb) {
+ state = -1;
remote = remoteEnd;
remotePort = DBPort;
remoteHost = remoteEnd;
@@ -50,4 +91,7 @@ ReplPair::ReplPair(const char *remoteEnd) {
if( remotePort == DBPort )
remote = remoteHost; // don't include ":27017" as it is default; in case ran in diff ways over time to normalizke the hostname format in sources collection
}
+
+ arbHost = arb;
+ uassert("arbiter parm is empty", !arbHost.empty());
}
diff --git a/dbgrid/dbgrid.cpp b/dbgrid/dbgrid.cpp
new file mode 100644
index 00000000000..42e986beb5b
--- /dev/null
+++ b/dbgrid/dbgrid.cpp
@@ -0,0 +1,135 @@
+// dbgrid.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"
+
+const char *curNs = "";
+Client *client = 0;
+
+/* this is a good place to set a breakpoint when debugging, as lots of warning things
+ (assert, wassert) call it.
+*/
+void sayDbContext(const char *errmsg) {
+ if( errmsg )
+ problem() << errmsg << endl;
+ printStackTrace();
+}
+
+#if !defined(_WIN32)
+
+#include <signal.h>
+
+void pipeSigHandler( int signal ) {
+ psignal( signal, "Signal Received : ");
+}
+
+#else
+void setupSignals() {}
+#endif
+
+void usage() {
+ cout << "Mongo dbgrid usage:\n";
+ cout << " --port <portno>\n";
+ cout << endl;
+}
+
+int port = 0;
+MessagingPort *grab = 0;
+void processRequest(Message&, MessagingPort&);
+
+void _dbGridConnThread() {
+ MessagingPort& dbMsgPort = *grab;
+ grab = 0;
+ Message m;
+ while( 1 ) {
+ m.reset();
+
+ if( !dbMsgPort.recv(m) ) {
+ log() << "end connection " << dbMsgPort.farEnd.toString() << endl;
+ dbMsgPort.shutdown();
+ break;
+ }
+
+ processRequest(m, dbMsgPort);
+ }
+
+}
+
+void dbGridConnThread() {
+ try {
+ _dbGridConnThread();
+ } catch( ... ) {
+ problem() << "uncaught exception in dbgridconnthread, terminating" << endl;
+ dbexit(15);
+ }
+}
+
+class DbGridListener : public Listener {
+public:
+ DbGridListener(int p) : Listener(p) { }
+ virtual void accepted(MessagingPort *mp) {
+ assert( grab == 0 );
+ grab = mp;
+ boost::thread thr(dbGridConnThread);
+ while( grab )
+ sleepmillis(1);
+ }
+};
+
+void start() {
+ Database::load();
+ log() << "waiting for connections on port " << port << "..." << endl;
+ DbGridListener l(port);
+ l.listen();
+}
+
+int main(int argc, char* argv[], char *envp[] ) {
+#if !defined(_WIN32)
+ signal(SIGPIPE, pipeSigHandler);
+#endif
+
+ for (int i = 1; i < argc; i++) {
+ if( argv[i] == 0 ) continue;
+ string s = argv[i];
+ if( s == "--port" ) {
+ port = atoi(argv[++i]);
+ }
+ }
+
+ bool ok = port != 0;
+
+ if( !ok ) {
+ usage();
+ return 1;
+ }
+
+ log() << "dbgrid starting" << endl;
+ UnitTest::runTests();
+ start();
+ dbexit(0);
+ return 0;
+}
+
+#undef exit
+void dbexit(int rc, const char *why) {
+ log() << "dbexit: " << why << " rc:" << rc << endl;
+ exit(rc);
+}
diff --git a/dbgrid/dbgrid.vcproj b/dbgrid/dbgrid.vcproj
new file mode 100644
index 00000000000..99da4d063b7
--- /dev/null
+++ b/dbgrid/dbgrid.vcproj
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="dbgrid"
+ ProjectGUID="{E03717ED-69B4-4D21-BC55-DF6690B585C6}"
+ RootNamespace="dbgrid"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;..\pcre-7.4&quot;;..\boost"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_DEPRECATE;BOOST_ALL_NO_LIB;BOOST_LIB_DIAGNOSTIC;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="stdafx.h"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="2"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\database.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\dbgrid.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\request.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\database.h"
+ >
+ </File>
+ <File
+ RelativePath="..\util\goodies.h"
+ >
+ </File>
+ <File
+ RelativePath="..\stdafx.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <Filter
+ Name="libs_etc"
+ >
+ <File
+ RelativePath="..\..\boostw\boost_1_34_1\boost\config\auto_link.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\boost\boost\Debug\boost.lib"
+ >
+ </File>
+ <File
+ RelativePath="..\..\boostw\boost_1_34_1\boost\version.hpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Shared Source Files"
+ >
+ <File
+ RelativePath="..\db\dbclient.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\db\jsobj.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\grid\message.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\util\sock.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\stdafx.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\util\util.cpp"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/stdafx.cpp b/stdafx.cpp
index b050390966f..f37f5a0ea7a 100644
--- a/stdafx.cpp
+++ b/stdafx.cpp
@@ -54,7 +54,6 @@ void uasserted(const char *msg) {
}
void msgasserted(const char *msg) {
- cout << "Assertion: " << msg << '\n';
- throw AssertionException();
+ log() << "Assertion: " << msg << '\n';
+ throw MsgAssertionException(msg);
}
-
diff --git a/stdafx.h b/stdafx.h
index 00ace4a66dc..bb7d5a9e702 100644
--- a/stdafx.h
+++ b/stdafx.h
@@ -48,21 +48,32 @@ inline void * ourrealloc(void *ptr, size_t size) {
#include "targetver.h"
-//#include "assert.h"
-
+#include <string>
+using namespace std;
// you can catch these
class AssertionException {
public:
- const char *msg;
- AssertionException() { msg = ""; }
+ string msg;
+ AssertionException() { }
+ virtual bool severe() { return true; }
virtual bool isUserAssertion() { return false; }
+ virtual string toString() { return msg; }
};
/* we use the same mechanism for bad things the user does -- which are really just errors */
class UserAssertionException : public AssertionException {
public:
UserAssertionException(const char *_msg) { msg = _msg; }
+ virtual bool severe() { return false; }
virtual bool isUserAssertion() { return true; }
+ virtual string toString() { return "userassert:" + msg; }
+};
+
+class MsgAssertionException : public AssertionException {
+public:
+ MsgAssertionException(const char *_msg) { msg = _msg; }
+ virtual bool severe() { return false; }
+ virtual string toString() { return "massert:" + msg; }
};
void asserted(const char *msg, const char *file, unsigned line);
@@ -107,13 +118,11 @@ typedef char _TCHAR;
#include <iostream>
#include <fstream>
-using namespace std;
-
#include "time.h"
#include <map>
-#include <string>
#include <vector>
#include <set>
+//using namespace std;
#if !defined(_WIN32)
typedef int HANDLE;
diff --git a/util/goodies.h b/util/goodies.h
index a400a39b280..c08ee8fc0d6 100644
--- a/util/goodies.h
+++ b/util/goodies.h
@@ -192,6 +192,12 @@ public:
//typedef boostlock lock;
+inline bool startsWith(const char *str, const char *prefix) {
+ unsigned l = strlen(prefix);
+ if( strlen(str) < l ) return false;
+ return strncmp(str, prefix, l) == 0;
+}
+
inline bool endsWith(const char *p, const char *suffix) {
int a = strlen(p);
int b = strlen(suffix);