Index: TODO =================================================================== diff -u -rc7f559b495780389f79b9c67843d3e05efcc5e8f -rdf67ed7db2b0cda881c4a9e704379a2a02d415b6 --- TODO (.../TODO) (revision c7f559b495780389f79b9c67843d3e05efcc5e8f) +++ TODO (.../TODO) (revision df67ed7db2b0cda881c4a9e704379a2a02d415b6) @@ -2970,6 +2970,11 @@ - renamed tclAPI.h to nsfAPI.h - added nsf.m4 to git for the time being +- mongdb: + * added preliminary gridfs interface + * refactored some code + * added new types for "gridfs" and "gridfile" + * added new example file example-nsf-gridfs.tcl TODO: - do we have to adjust the documentation in xotcl2 for object initialization? Index: generic/gentclAPI.tcl =================================================================== diff -u -r5b61f8a3e6a8142e1553f50d2010439089e1cd0d -rdf67ed7db2b0cda881c4a9e704379a2a02d415b6 --- generic/gentclAPI.tcl (.../gentclAPI.tcl) (revision 5b61f8a3e6a8142e1553f50d2010439089e1cd0d) +++ generic/gentclAPI.tcl (.../gentclAPI.tcl) (revision df67ed7db2b0cda881c4a9e704379a2a02d415b6) @@ -41,6 +41,7 @@ } proc genifd {parameterDefinitions} { + #puts stderr $parameterDefinitions set l [list] foreach parameterDefinition $parameterDefinitions { array set "" $parameterDefinition @@ -142,6 +143,7 @@ switch -glob $(-type) { "" {set type "CONST char *"} "boolean" {set type "int "} + "int32" {set type "int "} "class" {set type "NsfClass *"} "object" {set type "NsfObject *"} "tclobj" {set type "Tcl_Obj *"} Index: library/mongodb/example-nsf-gridfs.tcl =================================================================== diff -u --- library/mongodb/example-nsf-gridfs.tcl (revision 0) +++ library/mongodb/example-nsf-gridfs.tcl (revision df67ed7db2b0cda881c4a9e704379a2a02d415b6) @@ -0,0 +1,74 @@ +package require nx +package require nsf::mongo + +# +# This sample script shows some basic interactions from the nsf mongo +# interface with gridFS. It connects to mongo, opens a GridFS named +# "myfs" and inserts a file into the file systems. Run the script +# with the current directory of nsfmongo, such it can find the README +# file. +# +# After running the script, one can use the following command to +# inspect the content in the GridFS via the mongo shell +# +# $ mongo +# > use myfs +# > show collections +# +# or via the mongofiles interface: +# +# $ mongofiles -d myfs list +# + +set mongoConn [::mongo::connect] + +# +# Open a GridFS in the mongo datbase "myfs" and use the usual prefix +# "fs", such GridFS names the collections "fs.chunks" and "fs.files". +# +set gridFS [::mongo::gridfs::open $mongoConn myfs fs] + +# +# The current version of gridfs_store_file() is quite unfriendly, +# since it assumes that the file exists, and aborts otherwise. So, we +# perform the existance test here. +# +# Note that the input file name can be "-" for reading from stdin. +# +# Store a known file: +# +set fn README +if {[file readable $fn]} { + set r [::mongo::gridfs::store_file $gridFS $fn $fn text/plain] + puts stderr r=$r +} else { + puts stderr "no such file: $fn" +} + +# unknown file +set fn unknown-file +if {[file readable $fn]} { + set r [::mongo::gridfs::store_file $gridFS $fn $fn text/plain] + puts stderr r=$r +} else { + puts stderr "no such file: $fn" +} + +set f [mongo::gridfile::open $gridFS README] +puts stderr "opened file $f" +puts stderr meta=[mongo::gridfile::get_metadata $f] +puts stderr contentlength=[mongo::gridfile::get_contentlength $f] +puts stderr contenttype=[mongo::gridfile::get_contenttype $f] +while {1} { + set chunk [mongo::gridfile::read $f 500] + puts stderr "read chunk-len [string length $chunk] content [string range $chunk 0 10]..." + if {[string length $chunk] < 500} break; +} +mongo::gridfile::close $f +puts stderr OK + +# +# close everything +# +::mongo::gridfs::close $gridFS +::mongo::close $mongoConn Index: library/mongodb/mongoAPI.decls =================================================================== diff -u -ra5bf2874a6cb0338860062dce1846279c1704444 -rdf67ed7db2b0cda881c4a9e704379a2a02d415b6 --- library/mongodb/mongoAPI.decls (.../mongoAPI.decls) (revision a5bf2874a6cb0338860062dce1846279c1704444) +++ library/mongodb/mongoAPI.decls (.../mongoAPI.decls) (revision df67ed7db2b0cda881c4a9e704379a2a02d415b6) @@ -1,17 +1,16 @@ +# -*- Tcl -*- +# +# API declarations for the nsf mongo interface +# + # namespaces for types of methods array set ns { - cmd "::mongo" - objectMethod "::nsf::methods::object" - objectInfoMethod "::nsf::methods::object::info" - classMethod "::nsf::methods::class" - classInfoMethod "::nsf::methods::class::info" - checkMethod "::nsf::cmd::ParameterType" + cmd "::mongo" } cmd close NsfMongoClose { {-argName "conn" -required 1 -type tclobj} } - cmd connect NsfMongoConnect { {-argName "-replica-set" -required 0 -nrargs 1} {-argName "-server" -required 0 -nrargs 1 -type tclobj} @@ -61,3 +60,53 @@ {-argName "-all" -required 0 -nrargs 0} } +# +# GridFS +# +cmd gridfs::open NsfMongoGridFSOpen { + {-argName "conn" -required 1 -type tclobj} + {-argName "dbname" -required 1} + {-argName "prefix" -required 1} +} + +cmd gridfs::store_file NsfMongoGridFSStoreFile { + {-argName "gfs" -required 1 -type tclobj} + {-argName "filename" -required 1} + {-argName "remotename" -required 1} + {-argName "contenttype" -required 1} +} + +cmd gridfs::remove_file NsfMongoGridFSRemoveFile { + {-argName "gfs" -required 1 -type tclobj} + {-argName "filename" -required 1} +} + +cmd gridfs::close NsfMongoGridFSClose { + {-argName "gfs" -required 1 -type tclobj} +} + +# +# GridFile +# + +cmd gridfile::close NsfMongoGridFileClose { + {-argName "gridfile" -required 1 -type tclobj} +} + +cmd gridfile::get_contentlength NsfMongoGridFileGetContentlength { + {-argName "gridfile" -required 1 -type tclobj} +} +cmd gridfile::get_contenttype NsfMongoGridFileGetContentType { + {-argName "gridfile" -required 1 -type tclobj} +} +cmd gridfile::get_metadata NsfMongoGridFileGetMetaData { + {-argName "gridfile" -required 1 -type tclobj} +} +cmd gridfile::open NsfMongoGridFileOpen { + {-argName "gfs" -required 1 -type tclobj} + {-argName "filename" -required 1} +} +cmd gridfile::read NsfMongoGridFileRead { + {-argName "gridfile" -required 1 -type tclobj} + {-argName "size" -required 1 -type int32} +} Index: library/mongodb/mongoAPI.h =================================================================== diff -u -r5b61f8a3e6a8142e1553f50d2010439089e1cd0d -rdf67ed7db2b0cda881c4a9e704379a2a02d415b6 --- library/mongodb/mongoAPI.h (.../mongoAPI.h) (revision 5b61f8a3e6a8142e1553f50d2010439089e1cd0d) +++ library/mongodb/mongoAPI.h (.../mongoAPI.h) (revision df67ed7db2b0cda881c4a9e704379a2a02d415b6) @@ -4,16 +4,21 @@ static Nsf_methodDefinition method_definitions[]; static CONST char *method_command_namespace_names[] = { - "::nsf::methods::object::info", - "::nsf::methods::object", - "::mongo", - "::nsf::cmd::ParameterType", - "::nsf::methods::class::info", - "::nsf::methods::class" + "::mongo" }; static int NsfMongoCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoConnectStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoCountStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoGridFSCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoGridFSOpenStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoGridFSRemoveFileStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoGridFSStoreFileStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoGridFileCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoGridFileGetContentTypeStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoGridFileGetContentlengthStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoGridFileGetMetaDataStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoGridFileOpenStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoGridFileReadStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoIndexStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoInsertStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoQueryStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); @@ -23,6 +28,16 @@ static int NsfMongoClose(Tcl_Interp *interp, Tcl_Obj *conn); 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 NsfMongoGridFSClose(Tcl_Interp *interp, Tcl_Obj *gfs); +static int NsfMongoGridFSOpen(Tcl_Interp *interp, Tcl_Obj *conn, CONST char *dbname, CONST char *prefix); +static int NsfMongoGridFSRemoveFile(Tcl_Interp *interp, Tcl_Obj *gfs, CONST char *filename); +static int NsfMongoGridFSStoreFile(Tcl_Interp *interp, Tcl_Obj *gfs, CONST char *filename, CONST char *remotename, CONST char *contenttype); +static int NsfMongoGridFileClose(Tcl_Interp *interp, Tcl_Obj *gridfile); +static int NsfMongoGridFileGetContentType(Tcl_Interp *interp, Tcl_Obj *gridfile); +static int NsfMongoGridFileGetContentlength(Tcl_Interp *interp, Tcl_Obj *gridfile); +static int NsfMongoGridFileGetMetaData(Tcl_Interp *interp, Tcl_Obj *gridfile); +static int NsfMongoGridFileOpen(Tcl_Interp *interp, Tcl_Obj *gfs, CONST char *filename); +static int NsfMongoGridFileRead(Tcl_Interp *interp, Tcl_Obj *gridfile, int size); 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); static int NsfMongoQuery(Tcl_Interp *interp, Tcl_Obj *conn, CONST char *namespace, Tcl_Obj *query, Tcl_Obj *withAtts, int withLimit, int withSkip); @@ -33,6 +48,16 @@ NsfMongoCloseIdx, NsfMongoConnectIdx, NsfMongoCountIdx, + NsfMongoGridFSCloseIdx, + NsfMongoGridFSOpenIdx, + NsfMongoGridFSRemoveFileIdx, + NsfMongoGridFSStoreFileIdx, + NsfMongoGridFileCloseIdx, + NsfMongoGridFileGetContentTypeIdx, + NsfMongoGridFileGetContentlengthIdx, + NsfMongoGridFileGetMetaDataIdx, + NsfMongoGridFileOpenIdx, + NsfMongoGridFileReadIdx, NsfMongoIndexIdx, NsfMongoInsertIdx, NsfMongoQueryIdx, @@ -99,6 +124,189 @@ } static int +NsfMongoGridFSCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + (void)clientData; + + + + if (objc != 2) { + return NsfArgumentError(interp, "wrong # of arguments:", + method_definitions[NsfMongoGridFSCloseIdx].paramDefs, + NULL, objv[0]); + } + + return NsfMongoGridFSClose(interp, objc == 2 ? objv[1] : NULL); + +} + +static int +NsfMongoGridFSOpenStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + ParseContext pc; + (void)clientData; + + if (ArgumentParse(interp, objc, objv, NULL, objv[0], + method_definitions[NsfMongoGridFSOpenIdx].paramDefs, + method_definitions[NsfMongoGridFSOpenIdx].nrParameters, 1, + &pc) != TCL_OK) { + return TCL_ERROR; + } else { + Tcl_Obj *conn = (Tcl_Obj *)pc.clientData[0]; + CONST char *dbname = (CONST char *)pc.clientData[1]; + CONST char *prefix = (CONST char *)pc.clientData[2]; + + assert(pc.status == 0); + return NsfMongoGridFSOpen(interp, conn, dbname, prefix); + + } +} + +static int +NsfMongoGridFSRemoveFileStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + ParseContext pc; + (void)clientData; + + if (ArgumentParse(interp, objc, objv, NULL, objv[0], + method_definitions[NsfMongoGridFSRemoveFileIdx].paramDefs, + method_definitions[NsfMongoGridFSRemoveFileIdx].nrParameters, 1, + &pc) != TCL_OK) { + return TCL_ERROR; + } else { + Tcl_Obj *gfs = (Tcl_Obj *)pc.clientData[0]; + CONST char *filename = (CONST char *)pc.clientData[1]; + + assert(pc.status == 0); + return NsfMongoGridFSRemoveFile(interp, gfs, filename); + + } +} + +static int +NsfMongoGridFSStoreFileStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + ParseContext pc; + (void)clientData; + + if (ArgumentParse(interp, objc, objv, NULL, objv[0], + method_definitions[NsfMongoGridFSStoreFileIdx].paramDefs, + method_definitions[NsfMongoGridFSStoreFileIdx].nrParameters, 1, + &pc) != TCL_OK) { + return TCL_ERROR; + } else { + Tcl_Obj *gfs = (Tcl_Obj *)pc.clientData[0]; + CONST char *filename = (CONST char *)pc.clientData[1]; + CONST char *remotename = (CONST char *)pc.clientData[2]; + CONST char *contenttype = (CONST char *)pc.clientData[3]; + + assert(pc.status == 0); + return NsfMongoGridFSStoreFile(interp, gfs, filename, remotename, contenttype); + + } +} + +static int +NsfMongoGridFileCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + (void)clientData; + + + + if (objc != 2) { + return NsfArgumentError(interp, "wrong # of arguments:", + method_definitions[NsfMongoGridFileCloseIdx].paramDefs, + NULL, objv[0]); + } + + return NsfMongoGridFileClose(interp, objc == 2 ? objv[1] : NULL); + +} + +static int +NsfMongoGridFileGetContentTypeStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + (void)clientData; + + + + if (objc != 2) { + return NsfArgumentError(interp, "wrong # of arguments:", + method_definitions[NsfMongoGridFileGetContentTypeIdx].paramDefs, + NULL, objv[0]); + } + + return NsfMongoGridFileGetContentType(interp, objc == 2 ? objv[1] : NULL); + +} + +static int +NsfMongoGridFileGetContentlengthStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + (void)clientData; + + + + if (objc != 2) { + return NsfArgumentError(interp, "wrong # of arguments:", + method_definitions[NsfMongoGridFileGetContentlengthIdx].paramDefs, + NULL, objv[0]); + } + + return NsfMongoGridFileGetContentlength(interp, objc == 2 ? objv[1] : NULL); + +} + +static int +NsfMongoGridFileGetMetaDataStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + (void)clientData; + + + + if (objc != 2) { + return NsfArgumentError(interp, "wrong # of arguments:", + method_definitions[NsfMongoGridFileGetMetaDataIdx].paramDefs, + NULL, objv[0]); + } + + return NsfMongoGridFileGetMetaData(interp, objc == 2 ? objv[1] : NULL); + +} + +static int +NsfMongoGridFileOpenStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + ParseContext pc; + (void)clientData; + + if (ArgumentParse(interp, objc, objv, NULL, objv[0], + method_definitions[NsfMongoGridFileOpenIdx].paramDefs, + method_definitions[NsfMongoGridFileOpenIdx].nrParameters, 1, + &pc) != TCL_OK) { + return TCL_ERROR; + } else { + Tcl_Obj *gfs = (Tcl_Obj *)pc.clientData[0]; + CONST char *filename = (CONST char *)pc.clientData[1]; + + assert(pc.status == 0); + return NsfMongoGridFileOpen(interp, gfs, filename); + + } +} + +static int +NsfMongoGridFileReadStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + ParseContext pc; + (void)clientData; + + if (ArgumentParse(interp, objc, objv, NULL, objv[0], + method_definitions[NsfMongoGridFileReadIdx].paramDefs, + method_definitions[NsfMongoGridFileReadIdx].nrParameters, 1, + &pc) != TCL_OK) { + return TCL_ERROR; + } else { + Tcl_Obj *gridfile = (Tcl_Obj *)pc.clientData[0]; + int size = (int )PTR2INT(pc.clientData[1]); + + assert(pc.status == 0); + return NsfMongoGridFileRead(interp, gridfile, size); + + } +} + +static int NsfMongoIndexStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { ParseContext pc; (void)clientData; @@ -224,6 +432,44 @@ {"namespace", NSF_ARG_REQUIRED, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"query", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, +{"::mongo::gridfs::close", NsfMongoGridFSCloseStub, 1, { + {"gfs", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, +{"::mongo::gridfs::open", NsfMongoGridFSOpenStub, 3, { + {"conn", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"dbname", NSF_ARG_REQUIRED, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"prefix", NSF_ARG_REQUIRED, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, +{"::mongo::gridfs::remove_file", NsfMongoGridFSRemoveFileStub, 2, { + {"gfs", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"filename", NSF_ARG_REQUIRED, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, +{"::mongo::gridfs::store_file", NsfMongoGridFSStoreFileStub, 4, { + {"gfs", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"filename", NSF_ARG_REQUIRED, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"remotename", NSF_ARG_REQUIRED, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"contenttype", NSF_ARG_REQUIRED, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, +{"::mongo::gridfile::close", NsfMongoGridFileCloseStub, 1, { + {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, +{"::mongo::gridfile::get_contenttype", NsfMongoGridFileGetContentTypeStub, 1, { + {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, +{"::mongo::gridfile::get_contentlength", NsfMongoGridFileGetContentlengthStub, 1, { + {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, +{"::mongo::gridfile::get_metadata", NsfMongoGridFileGetMetaDataStub, 1, { + {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, +{"::mongo::gridfile::open", NsfMongoGridFileOpenStub, 2, { + {"gfs", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"filename", NSF_ARG_REQUIRED, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, +{"::mongo::gridfile::read", NsfMongoGridFileReadStub, 2, { + {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"size", NSF_ARG_REQUIRED, 1, Nsf_ConvertToInt32, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, {"::mongo::index", NsfMongoIndexStub, 5, { {"conn", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"namespace", NSF_ARG_REQUIRED, 1, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, Index: library/mongodb/nsfmongo.c =================================================================== diff -u -ra5bf2874a6cb0338860062dce1846279c1704444 -rdf67ed7db2b0cda881c4a9e704379a2a02d415b6 --- library/mongodb/nsfmongo.c (.../nsfmongo.c) (revision a5bf2874a6cb0338860062dce1846279c1704444) +++ library/mongodb/nsfmongo.c (.../nsfmongo.c) (revision df67ed7db2b0cda881c4a9e704379a2a02d415b6) @@ -19,14 +19,17 @@ #include #include "bson.h" #include "mongo.h" +#include #include #include #include -static Tcl_HashTable mongoConnsHashTable, *mongoConnsHashTablePtr = &mongoConnsHashTable; +static Tcl_HashTable mongoHashTable, *mongoHashTablePtr = &mongoHashTable; static NsfMutex mongoMutex = 0; static int mongoConns = 0; +static int mongoGridFSCount = 0; +static int mongoGridFileCount = 0; /*********************************************************************** * The following definitions should not be here, but they are included @@ -111,33 +114,99 @@ /* *---------------------------------------------------------------------- * - * MongoGetConn -- + * MongoHashAdd -- * - * Obtain a mongo connection from the hash table key returned via - * NsfMongoConnect. + * Add an entry to our locally maintained hash table and set its + * value to the provided valuePtr. The keys are generated based + * on the passed formatString and counter. * * Results: - * mongo connection or NULL if not found/invalid. + * Void. * * Side effects: * None. * *---------------------------------------------------------------------- */ -mongo_connection * -MongoGetConn(Tcl_Obj *connObj) { - mongo_connection *connPtr = NULL; +static void +MongoHashAdd(char *buffer, CONST char *formatString, int *counterPtr, void *valuePtr) { Tcl_HashEntry *hPtr; - + int isNew; + NsfMutexLock(&mongoMutex); - hPtr = Tcl_CreateHashEntry(mongoConnsHashTablePtr, ObjStr(connObj), NULL); + sprintf(buffer, formatString, (*counterPtr)++); + hPtr = Tcl_CreateHashEntry(mongoHashTablePtr, buffer, &isNew); + NsfMutexUnlock(&mongoMutex); + Tcl_SetHashValue(hPtr, valuePtr); +} - if (hPtr) { - connPtr = Tcl_GetHashValue(hPtr); + +/* + *---------------------------------------------------------------------- + * + * MongoHashGet -- + * + * Get an entry to our locally maintained hash table and make + * sure that the prefix matches (this ensures that the right type + * of entry is obtained). If the prefix does not match, or there + * is no such entry in the table, the function returns NULL. + * + * Results: + * valuePtr or NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static void * +MongoHashGet(char *key, char *prefix) { + Tcl_HashEntry *hPtr; + void *valuePtr = NULL; + + /* make sure to return the right type of hash entry */ + if (strncmp(prefix, key, strlen(prefix)) == 0) { + + NsfMutexLock(&mongoMutex); + hPtr = Tcl_CreateHashEntry(mongoHashTablePtr, key, NULL); + + if (hPtr) { + valuePtr = Tcl_GetHashValue(hPtr); + } + NsfMutexUnlock(&mongoMutex); } - NsfMutexUnlock(&mongoMutex); + return valuePtr; +} - return connPtr; +/* + *---------------------------------------------------------------------- + * + * MongoHashDelete -- + * + * Delete an hash entry from our locally maintained hash table + * free the associated memory, if valuePtr is provided. + * + * Results: + * valuePtr or NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static void +MongoHashDelete(CONST char *key, void *valuePtr) { + Tcl_HashEntry *hPtr; + + if (valuePtr) { + ckfree((char *)valuePtr); + } + + NsfMutexLock(&mongoMutex); + hPtr = Tcl_CreateHashEntry(mongoHashTablePtr, key, NULL); + assert(hPtr); + Tcl_DeleteHashEntry(hPtr); + NsfMutexUnlock(&mongoMutex); } /* @@ -206,7 +275,7 @@ default: tag = "unknown"; elemObj = Tcl_NewStringObj("", 0); - fprintf( stderr , "BsonToList: unknown type %d\n" , t ); + NsfLog(interp, NSF_LOG_WARN, "BsonToList: unknown type %d", t); } Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(key, -1)); @@ -333,7 +402,6 @@ case bson_date: { long v; result = Tcl_GetLongFromObj(interp, value, &v); - fprintf(stderr, "bson date v %ld result %d\n", v, result); if (result != TCL_OK) break; bson_append_date(bbPtr, name, v); break; @@ -495,18 +563,11 @@ */ static int NsfMongoClose(Tcl_Interp *interp, Tcl_Obj *connObj) { - mongo_connection *connPtr = MongoGetConn(connObj); + mongo_connection *connPtr = MongoHashGet(ObjStr(connObj), "mongo_conn"); if (connPtr) { - Tcl_HashEntry *hPtr; - mongo_destroy(connPtr); - ckfree((char *)connPtr); - - NsfMutexLock(&mongoMutex); - hPtr = Tcl_CreateHashEntry(mongoConnsHashTablePtr, ObjStr(connObj), NULL); - Tcl_DeleteHashEntry(hPtr); - NsfMutexUnlock(&mongoMutex); + MongoHashDelete(ObjStr(connObj), connPtr); } return TCL_OK; } @@ -520,10 +581,9 @@ static int NsfMongoConnect(Tcl_Interp *interp, CONST char *replicaSet, Tcl_Obj *server) { char channelName[80], *buffer = NULL; - int isNew, result, port, objc = 0; + int result, port, objc = 0; mongo_connection *connPtr; mongo_conn_return status; - Tcl_HashEntry *hPtr; Tcl_Obj **objv; CONST char *host; @@ -596,13 +656,9 @@ return NsfPrintError(interp, errorMsg); } - NsfMutexLock(&mongoMutex); - sprintf(channelName, "mongo_conn%d", mongoConns++); - hPtr = Tcl_CreateHashEntry(mongoConnsHashTablePtr, channelName, &isNew); - NsfMutexUnlock(&mongoMutex); - Tcl_SetHashValue(hPtr, connPtr); - + MongoHashAdd(channelName, "mongo_conn%d", &mongoConns, connPtr); Tcl_SetObjResult(interp, Tcl_NewStringObj(channelName, -1)); + return TCL_OK; } @@ -617,7 +673,7 @@ NsfMongoCount(Tcl_Interp *interp, Tcl_Obj *connObj, CONST char *namespace, Tcl_Obj *queryObj) { int objc, result; Tcl_Obj **objv; - mongo_connection *connPtr = MongoGetConn(connObj); + mongo_connection *connPtr = MongoHashGet(ObjStr(connObj), "mongo_conn"); char *db, *collection; int count, length; bson query[1]; @@ -668,7 +724,7 @@ static int NsfMongoIndex(Tcl_Interp *interp, Tcl_Obj *connObj, CONST char *namespace, Tcl_Obj *attributesObj, int withDropdups, int withUnique) { - mongo_connection *connPtr = MongoGetConn(connObj); + mongo_connection *connPtr = MongoHashGet(ObjStr(connObj), "mongo_conn"); bson_bool_t success; int objc, result, options = 0; Tcl_Obj **objv; @@ -704,7 +760,7 @@ } */ static int NsfMongoInsert(Tcl_Interp *interp, Tcl_Obj *connObj, CONST char *namespace, Tcl_Obj *valuesObj) { - mongo_connection *connPtr = MongoGetConn(connObj); + mongo_connection *connPtr = MongoHashGet(ObjStr(connObj), "mongo_conn"); int i, objc, result; Tcl_Obj **objv, *resultObj; bson_buffer buf[1]; @@ -757,7 +813,7 @@ int withLimit, int withSkip) { int objc1, objc2, result; Tcl_Obj **objv1, **objv2, *resultObj; - mongo_connection *connPtr = MongoGetConn(connObj); + mongo_connection *connPtr = MongoHashGet(ObjStr(connObj), "mongo_conn"); mongo_cursor *cursor; bson query[1]; bson atts[1]; @@ -817,7 +873,7 @@ NsfMongoRemove(Tcl_Interp *interp, Tcl_Obj *connObj, CONST char *namespace, Tcl_Obj *conditionObj) { int objc, result; Tcl_Obj **objv; - mongo_connection *connPtr = MongoGetConn(connObj); + mongo_connection *connPtr = MongoHashGet(ObjStr(connObj), "mongo_conn"); bson query[1]; if (connPtr == NULL) { @@ -851,7 +907,7 @@ Tcl_Obj *conditionObj, Tcl_Obj *valuesObj, int withUpsert, int withAll) { int objc, result, options = 0; Tcl_Obj **objv; - mongo_connection *connPtr = MongoGetConn(connObj); + mongo_connection *connPtr = MongoHashGet(ObjStr(connObj), "mongo_conn"); bson cond[1], values[1]; if (connPtr == NULL) { @@ -880,8 +936,240 @@ return TCL_OK; } +/*********************************************************************** + * GridFS interface + ***********************************************************************/ +/* +cmd gridfs::open NsfMongoGridFSOpen { + {-argName "conn" -required 1 -type tclobj} + {-argName "dbname" -required 1} + {-argName "prefix" -required 1} +} +*/ +static int +NsfMongoGridFSOpen(Tcl_Interp *interp, Tcl_Obj *connObj, + CONST char *dbname, CONST char *prefix) { + char buffer[80]; + gridfs *gfsPtr; + mongo_connection *connPtr = MongoHashGet(ObjStr(connObj), "mongo_conn"); + + if (connPtr == NULL) { + return NsfObjErrType(interp, "", connObj, "connection", NULL); + } + + gfsPtr = (gridfs *)ckalloc(sizeof(gridfs)); + gridfs_init(connPtr, dbname, prefix, gfsPtr); + + MongoHashAdd(buffer, "mongo_fs%d", &mongoGridFSCount, gfsPtr); + Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, -1)); + + return TCL_OK; +} + + +/* +cmd gridfs::remove_file NsfMongoGridFSRemoveFile { + {-argName "gfs" -required 1 -type tclobj} + {-argName "filename" -required 1} +} +*/ +static int +NsfMongoGridFSRemoveFile(Tcl_Interp *interp, Tcl_Obj *gridFSObj, + CONST char *filename) { + gridfs *gridfsPtr = MongoHashGet(ObjStr(gridFSObj), "mongo_fs"); + + if (gridfsPtr == NULL) { + return NsfObjErrType(interp, "", gridFSObj, "GridFS", NULL); + } + + /* the current interfaces does not return a status ! */ + gridfs_remove_filename(gridfsPtr, filename); + + return TCL_OK; +} + +/* +cmd gridfs::store_file NsfMongoGridFSStoreFile { + {-argName "gfs" -required 1 -type tclobj} + {-argName "filename" -required 1} + {-argName "remotename" -required 1} + {-argName "contenttype" -required 1} +} +*/ +static int +NsfMongoGridFSStoreFile(Tcl_Interp *interp, Tcl_Obj *gridFSObj, + CONST char *filename, CONST char *remotename, + CONST char *contenttype) { + gridfs *gridfsPtr = MongoHashGet(ObjStr(gridFSObj), "mongo_fs"); + bson b; + + if (gridfsPtr == NULL) { + return NsfObjErrType(interp, "", gridFSObj, "GridFS", NULL); + } + + b = gridfs_store_file(gridfsPtr, filename, remotename, contenttype); + + Tcl_SetObjResult(interp, BsonToList(interp, b.data, 0)); + + return TCL_OK; +} + +/* +cmd gridfs::close NsfMongoGridFSClose { + {-argName "gfs" -required 1 -type tclobj} +} +*/ +static int +NsfMongoGridFSClose(Tcl_Interp *interp, Tcl_Obj *gridFSObj) { + gridfs *gridfsPtr = MongoHashGet(ObjStr(gridFSObj), "mongo_fs"); + + if (gridfsPtr == NULL) { + return NsfObjErrType(interp, "", gridFSObj, "GridFS", NULL); + } + + gridfs_destroy(gridfsPtr); + MongoHashDelete(ObjStr(gridFSObj), gridfsPtr); + + return TCL_OK; +} + /*********************************************************************** + * GridFile interface + ***********************************************************************/ + +/* +cmd gridfile::close NsfMongoGridFileClose { + {-argName "gridfile" -required 1 -type tclobj} +} +*/ +static int +NsfMongoGridFileClose(Tcl_Interp *interp, Tcl_Obj *gridFileObj) { + gridfile* gridFilePtr = MongoHashGet(ObjStr(gridFileObj), "mongo_file"); + + if (gridFilePtr == NULL) { + return NsfObjErrType(interp, "", gridFileObj, "GridFile", NULL); + } + + gridfile_destroy(gridFilePtr); + MongoHashDelete(ObjStr(gridFileObj), gridFilePtr); + + return TCL_OK; +} + +/* +cmd gridfile::get_contentlength NsfMongoGridFileGetContentlength { + {-argName "gridfile" -required 1 -type tclobj} +} +*/ +static int +NsfMongoGridFileGetContentlength(Tcl_Interp *interp, Tcl_Obj *gridFileObj) { + gridfile* gridFilePtr = MongoHashGet(ObjStr(gridFileObj), "mongo_file"); + gridfs_offset len; + + if (gridFilePtr == NULL) { + return NsfObjErrType(interp, "", gridFileObj, "GridFile", NULL); + } + len = gridfile_get_contentlength(gridFilePtr); + Tcl_SetObjResult(interp, Tcl_NewLongObj(len)); + + return TCL_OK; +} + +/* +cmd gridfile::get_contenttype NsfMongoGridFileGetContentType { + {-argName "gridfile" -required 1 -type tclobj} +} +*/ +static int +NsfMongoGridFileGetContentType(Tcl_Interp *interp, Tcl_Obj *gridFileObj) { + gridfile* gridFilePtr = MongoHashGet(ObjStr(gridFileObj), "mongo_file"); + CONST char *contentType; + + if (gridFilePtr == NULL) { + return NsfObjErrType(interp, "", gridFileObj, "GridFile", NULL); + } + contentType = gridfile_get_contenttype(gridFilePtr); + Tcl_SetObjResult(interp, Tcl_NewStringObj(contentType, -1)); + + return TCL_OK; +} + +/* +cmd gridfile::get_metadata NsfMongoGridFileGetMetaData { + {-argName "gridfile" -required 1 -type tclobj} +} +*/ +static int +NsfMongoGridFileGetMetaData(Tcl_Interp *interp, Tcl_Obj *gridFileObj) { + gridfile* gridFilePtr = MongoHashGet(ObjStr(gridFileObj), "mongo_file"); + bson b; + + if (gridFilePtr == NULL) { + return NsfObjErrType(interp, "", gridFileObj, "GridFile", NULL); + } + b = gridfile_get_metadata(gridFilePtr); + Tcl_SetObjResult(interp, BsonToList(interp, b.data, 0)); + + return TCL_OK; +} + +/* +cmd gridfile::open NsfMongoGridFileOpen { + {-argName "gfs" -required 1 -type tclobj} + {-argName "filename" -required 1} +} +*/ +static int +NsfMongoGridFileOpen(Tcl_Interp *interp, Tcl_Obj *gridFSObj, + CONST char *filename) { + char buffer[80]; + gridfs *gridfsPtr = MongoHashGet(ObjStr(gridFSObj), "mongo_fs"); + gridfile* gridFilePtr; + int result; + + if (gridfsPtr == NULL) { + return NsfObjErrType(interp, "", gridFSObj, "GridFS", NULL); + } + + gridFilePtr = (gridfile *)ckalloc(sizeof(gridfile)); + result = gridfs_find_filename(gridfsPtr, filename, gridFilePtr); + + if (result == 1) { + MongoHashAdd(buffer, "mongo_file%d", &mongoGridFileCount, gridFilePtr); + Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, -1)); + } else { + ckfree((char *)gridFilePtr); + Tcl_ResetResult(interp); + } + + return TCL_OK; +} + +/* +cmd gridfile::read NsfMongoGridFileRead { + {-argName "gridfile" -required 1 -type tclobj} + {-argName "size" -required 1 -type int} +} +*/ +static int +NsfMongoGridFileRead(Tcl_Interp *interp, Tcl_Obj *gridFileObj, int size) { + gridfile* gridFilePtr = MongoHashGet(ObjStr(gridFileObj), "mongo_file"); + int readSize; + char *buffer; + + if (gridFilePtr == NULL) { + return NsfObjErrType(interp, "", gridFileObj, "GridFile", NULL); + } + buffer = ckalloc(size); + readSize = gridfile_read(gridFilePtr, size, buffer); + Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, readSize)); + ckfree(buffer); + + return TCL_OK; +} + +/*********************************************************************** * Finally, provide the necessary Tcl package interface. ***********************************************************************/ @@ -919,7 +1207,7 @@ Tcl_CreateExitHandler(Nsfmongo_Exit, interp); NsfMutexLock(&mongoMutex); - Tcl_InitHashTable(mongoConnsHashTablePtr, TCL_STRING_KEYS); + Tcl_InitHashTable(mongoHashTablePtr, TCL_STRING_KEYS); NsfMutexUnlock(&mongoMutex); /* create all method commands (will use the namespaces above) */