Index: TODO =================================================================== diff -u -N -re02cb00ae815bd6f8561a6a03fceacc13fd91903 -r247831dfafdb972eaf34feca38b7b67ce38c9155 --- TODO (.../TODO) (revision e02cb00ae815bd6f8561a6a03fceacc13fd91903) +++ TODO (.../TODO) (revision 247831dfafdb972eaf34feca38b7b67ce38c9155) @@ -2637,6 +2637,10 @@ * define Test as nx::Test * make Test parameter count 1 the default, change to higher numbers where needed +- nsfmongo.c: + * upgrade to newest c-driver (verison 0.3) from git. + * support connection to replica sets + TODO: - maybe change nx::Test to nx::test (user never has to know that nx::Test is a class). Index: library/mongodb/README =================================================================== diff -u -N -r2837e8ce08344ee3f82a7451109f14a4b7cb3395 -r247831dfafdb972eaf34feca38b7b67ce38c9155 --- library/mongodb/README (.../README) (revision 2837e8ce08344ee3f82a7451109f14a4b7cb3395) +++ library/mongodb/README (.../README) (revision 247831dfafdb972eaf34feca38b7b67ce38c9155) @@ -3,7 +3,7 @@ Ingredients: https://github.com/mongodb/mongo - https://github.com/mongodb/mongo-c-driver + https://github.com/mongodb/mongo-c-driver (requires version v0.3 or better) Compile or obtain mongodb (the database). Compile or obtain the mongo-c-driver (client interface) @@ -14,8 +14,11 @@ ./configure --with-tcl=/usr/local/ns/lib --with-nsf=../../ \ --with-mongo=/usr/local/src/mongo-c-driver/src/,/usr/local/src/mongo-c-driver -I had to add MONGO_HAVE_STDINT to the EXTRA_FLAGS on MacOS X +I had to add MONGO_HAVE_STDINT to the EXTRA_FLAGS +of library/mongodb/Makefile.in on MacOS X + EXTRA_CFLAGS = @PKG_CFLAGS@ -DMONGO_HAVE_STDINT + TODO: remove the hardcoded define flag in Makefile.in In order to run the sample script, Index: library/mongodb/example-nsf-mongo.tcl =================================================================== diff -u -N -rfe68b259d9a15328a04a9dc64394dc5ffe5ba5a4 -r247831dfafdb972eaf34feca38b7b67ce38c9155 --- library/mongodb/example-nsf-mongo.tcl (.../example-nsf-mongo.tcl) (revision fe68b259d9a15328a04a9dc64394dc5ffe5ba5a4) +++ library/mongodb/example-nsf-mongo.tcl (.../example-nsf-mongo.tcl) (revision 247831dfafdb972eaf34feca38b7b67ce38c9155) @@ -9,7 +9,7 @@ # > db.persons.find(); # -#set mongoConn [::mongo::connect -port 27017] +#set mongoConn [::mongo::connect -server 127.0.0.1:27017] set mongoConn [::mongo::connect] if {1} { Index: library/mongodb/mongoAPI.decls =================================================================== diff -u -N -r2837e8ce08344ee3f82a7451109f14a4b7cb3395 -r247831dfafdb972eaf34feca38b7b67ce38c9155 --- library/mongodb/mongoAPI.decls (.../mongoAPI.decls) (revision 2837e8ce08344ee3f82a7451109f14a4b7cb3395) +++ library/mongodb/mongoAPI.decls (.../mongoAPI.decls) (revision 247831dfafdb972eaf34feca38b7b67ce38c9155) @@ -13,8 +13,8 @@ } cmd connect NsfMongoConnect { - {-argName "-host" -required 0 -nrargs 1} - {-argName "-port" -required 0 -nrargs 1 -type int} + {-argName "-replica-set" -required 0 -nrargs 1} + {-argName "-server" -required 0 -nrargs 1 -type tclobj} } cmd count NsfMongoCount { Index: library/mongodb/mongoAPI.h =================================================================== diff -u -N -r2837e8ce08344ee3f82a7451109f14a4b7cb3395 -r247831dfafdb972eaf34feca38b7b67ce38c9155 --- library/mongodb/mongoAPI.h (.../mongoAPI.h) (revision 2837e8ce08344ee3f82a7451109f14a4b7cb3395) +++ library/mongodb/mongoAPI.h (.../mongoAPI.h) (revision 247831dfafdb972eaf34feca38b7b67ce38c9155) @@ -21,7 +21,7 @@ static int NsfMongoUpdateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoClose(Tcl_Interp *interp, Tcl_Obj *conn); -static int NsfMongoConnect(Tcl_Interp *interp, CONST char *withHost, int withPort); +static int NsfMongoConnect(Tcl_Interp *interp, CONST char *withReplica_set, Tcl_Obj *withServer); static int NsfMongoCount(Tcl_Interp *interp, Tcl_Obj *conn, CONST char *namespace, Tcl_Obj *query); static int NsfMongoIndex(Tcl_Interp *interp, Tcl_Obj *conn, CONST char *namespace, Tcl_Obj *attributes, int withDropdups, int withUnique); static int NsfMongoInsert(Tcl_Interp *interp, Tcl_Obj *conn, CONST char *namespace, Tcl_Obj *values); @@ -68,11 +68,11 @@ &pc) != TCL_OK) { return TCL_ERROR; } else { - CONST char *withHost = (CONST char *)pc.clientData[0]; - int withPort = (int )PTR2INT(pc.clientData[1]); + CONST char *withReplica_set = (CONST char *)pc.clientData[0]; + Tcl_Obj *withServer = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); - return NsfMongoConnect(interp, withHost, withPort); + return NsfMongoConnect(interp, withReplica_set, withServer); } } @@ -215,8 +215,8 @@ {"conn", NSF_ARG_REQUIRED, 0, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::connect", NsfMongoConnectStub, 2, { - {"-host", 0, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL}, - {"-port", 0, 1, Nsf_ConvertToInteger, NULL,NULL,NULL,NULL,NULL,NULL,NULL}} + {"-replica-set", 0, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"-server", 0, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::count", NsfMongoCountStub, 3, { {"conn", NSF_ARG_REQUIRED, 0, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL}, Index: library/mongodb/nsfmongo.c =================================================================== diff -u -N -rfe68b259d9a15328a04a9dc64394dc5ffe5ba5a4 -r247831dfafdb972eaf34feca38b7b67ce38c9155 --- library/mongodb/nsfmongo.c (.../nsfmongo.c) (revision fe68b259d9a15328a04a9dc64394dc5ffe5ba5a4) +++ library/mongodb/nsfmongo.c (.../nsfmongo.c) (revision 247831dfafdb972eaf34feca38b7b67ce38c9155) @@ -421,6 +421,70 @@ return TCL_OK; } +/* + *---------------------------------------------------------------------- + * + * NsfMongoGetHostPort -- + * + * Obtain from the provided string host and port. The provided + * string might be of the form "host" or "host:port". The parts + * are returned via arguments. + * + * Results: + * Tcl result code and variables bufferPtr, hostPtr and portPtr. + * If bufferPtr is not NULL, the caller must free it. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +/* +The entries of the list might be "host" (dns or ip +* addresses) or of the form "host:port".*/ +static int +NsfMongoGetHostPort(CONST char *string, + char **bufferPtr, char CONST**hostPtr, int *portPtr) { + CONST char *colon, *host; + int port; + + assert(string); + colon = strchr(string, ':'); + + if (colon) { + /* + * The passed string contained a colon; we must copy the entry, + * since string is read only. + */ + int length = strlen(string) + 1; + int offset = colon-string; + char *buffer; + + buffer = ckalloc(length); + *bufferPtr = buffer; + memcpy(buffer, string, length); + buffer[offset] = '\0'; + host = buffer; + port = atoi(buffer+offset+1); + fprintf(stderr, "port=%d\n", port); + } else { + /* + * The passed string contained no colon. + */ + *bufferPtr = NULL; + host = string; + port = 27017; + } + + /* + * Return always host and port via arguments. + */ + *hostPtr = host; + *portPtr = port; + + return TCL_OK; +} + /*********************************************************************** * Define the api functions ***********************************************************************/ @@ -450,36 +514,86 @@ /* cmd connect NsfMongoConnect { - {-argName "-host" -required 0 -nrargs 1} - {-argName "-port" -required 0 -nrargs 1 -type int} + {-argName "-replica-set" -required 0 -nrargs 1} + {-argName "-server" -required 0 -nrargs 1 -type tclobj} } */ static int -NsfMongoConnect(Tcl_Interp *interp, CONST char *host, int port) { - Tcl_HashEntry *hPtr; - char channelName[80]; - int isNew; +NsfMongoConnect(Tcl_Interp *interp, CONST char *replicaSet, Tcl_Obj *server) { + char channelName[80], *buffer = NULL; + int isNew, result, port, objc = 0; mongo_connection *connPtr; - mongo_connection_options opts[1]; mongo_conn_return status; + Tcl_HashEntry *hPtr; + Tcl_Obj **objv; + CONST char *host; - strcpy(opts->host , host ? host : "127.0.0.1"); - opts->port = port != 0 ? port : 27017; + if (server) { + result = Tcl_ListObjGetElements(interp, server, &objc, &objv); + if (result != TCL_OK) { + return NsfPrintError(interp, "The provided servers are not a well-formed list"); + } + } + connPtr = (mongo_connection *)ckalloc(sizeof(mongo_connection)); - status = mongo_connect( connPtr, opts ); + if (objc == 0) { + /* + * No -server argument or an empty list was provided; use the + * mongo default values. + */ + status = mongo_connect( connPtr, "127.0.0.1", 27017 ); + + } else if (objc == 1 && replicaSet == NULL) { + /* + * A single element was provided to -server, we have no replica + * set specified. + */ + NsfMongoGetHostPort(ObjStr(objv[0]), &buffer, &host, &port); + status = mongo_connect( connPtr, host, port ); + if (buffer) {ckfree(buffer);} + + } else if (replicaSet) { + /* + * A list of 1 or more server was provided together with a replica + * set. + */ + int i; + + mongo_replset_init_conn( connPtr, replicaSet); + + for (i = 0; i < objc; i++) { + NsfMongoGetHostPort(ObjStr(objv[i]), &buffer, &host, &port); + mongo_replset_add_seed(connPtr, host, port ); + if (buffer) {ckfree(buffer);} + } + + status = mongo_replset_connect( connPtr ); + + } else { + ckfree((char *)connPtr); + return NsfPrintError(interp, "A list of servers was provided, but not name for the replica set"); + } + + /* + * Process the status from either mongo_connect() or + * mongo_replset_connect(). + */ if (status != mongo_conn_success) { char *errorMsg; - ckfree((char*)connPtr); + ckfree((char *)connPtr); switch (status) { case mongo_conn_bad_arg: errorMsg = "bad arguments"; break; case mongo_conn_no_socket: errorMsg = "no socket"; break; case mongo_conn_fail: errorMsg = "connection failed"; break; case mongo_conn_not_master: errorMsg = "not master"; break; + case mongo_conn_bad_set_name: errorMsg = "replica set name doesn't match the existing replica set"; break; + case mongo_conn_cannot_find_primary: errorMsg = "cannot find primary"; break; default: errorMsg = "unknown Error"; break; } + return NsfPrintError(interp, errorMsg); }