From 09845dd135d63f07b2795d28f1bef71af998d26e Mon Sep 17 00:00:00 2001 From: adam Date: Wed, 31 Oct 2012 13:57:00 +0700 Subject: [PATCH] #1 --- node/ejdb_native.cc | 230 ++++++++++++++++++++++++++++++++------ node/nbproject/configurations.xml | 6 +- tcejdb/bson.c | 4 + tcejdb/bson.h | 3 +- tcejdb/ejdb.c | 4 + tcejdb/ejdb.h | 8 ++ 6 files changed, 213 insertions(+), 42 deletions(-) diff --git a/node/ejdb_native.cc b/node/ejdb_native.cc index cc9f05b..1b9bdb5 100644 --- a/node/ejdb_native.cc +++ b/node/ejdb_native.cc @@ -16,6 +16,7 @@ using namespace node; using namespace v8; +static const int CMD_RET_ERROR = 1; #define DEFINE_INT64_CONSTANT(target, constant) \ (target)->Set(v8::String::NewSymbol(#constant), \ @@ -23,17 +24,21 @@ using namespace v8; static_cast( \ v8::ReadOnly|v8::DontDelete)) -static Persistent sym_close; -static Persistent sym_save; -static Persistent sym_load; -static Persistent sym_query; - namespace ejdb { - /** Convert V8 object into binary json instance. After usage, it must be freed by bson_del() */ - static void toBSON(Handle obj, bson *bs) { + typedef struct { + Handle traversed; + } TBSONCTX; + + static void toBSON0(Handle obj, bson *bs, TBSONCTX *ctx) { HandleScope scope; - assert(obj->IsObject()); + assert(ctx && obj->IsObject()); + if (ctx->traversed->Get(obj)->IsObject()) { + bs->err = BSON_ERROR_ANY; + bs->errstr = strdup("Circular object reference"); + return; + } + ctx->traversed->Set(obj, obj); Local pnames = obj->GetOwnPropertyNames(); for (uint32_t i = 0; i < pnames->Length(); ++i) { Local pn = pnames->Get(i); @@ -77,7 +82,7 @@ namespace ejdb { } else { bson_append_start_object(bs, *spn); } - toBSON(Handle::Cast(pv), bs); + toBSON0(Handle::Cast(pv), bs, ctx); if (pv->IsArray()) { bson_append_finish_array(bs); } else { @@ -87,6 +92,14 @@ namespace ejdb { } } + /** Convert V8 object into binary json instance. After usage, it must be freed by bson_del() */ + static void toBSON(Handle obj, bson *bs) { + HandleScope scope; + TBSONCTX ctx; + ctx.traversed = Object::New(); + toBSON0(obj, bs, &ctx); + } + /////////////////////////////////////////////////////////////////////////// // Main NodeEJDB // /////////////////////////////////////////////////////////////////////////// @@ -94,16 +107,25 @@ namespace ejdb { class NodeEJDB : public ObjectWrap { enum { //Commands - cmdSave = 1 //Save JSON object + cmdSave = 1, //Save JSON object + cmdLoad = 2, //Load BSON by oid + cmdQuery = 3 //Query collection }; - struct BSONCmdData { - std::vector bsons; + //Any bson cmd data - BSONCmdData() { + struct BSONCmdData { + std::string cname; //Name of collection + std::vector bsons; //bsons to save + std::vector ids; //saved updated oids + bson_oid_t ref; //Bson ref + + BSONCmdData(const char* cname) { + this->cname = cname; + memset(&ref, 0, sizeof (ref)); } - ~BSONCmdData() { + virtual ~BSONCmdData() { std::vector::iterator it; for (it = bsons.begin(); it < bsons.end(); it++) { bson *bs = *(it); @@ -112,8 +134,24 @@ namespace ejdb { } }; + //Query cmd data + + struct BSONQCmdData : public BSONCmdData { + TCLIST *res; + + BSONQCmdData(const char* cname) : BSONCmdData::BSONCmdData(cname), res(NULL) { + } + + virtual ~BSONQCmdData() { + if (res) { + tclistdel(res); + } + } + }; + typedef EIOCmdTask EJBTask; - typedef EIOCmdTask EJBSONTask; + typedef EIOCmdTask BSONCmdTask; + typedef EIOCmdTask QueryCmdTask; static Persistent constructor_template; @@ -126,7 +164,7 @@ namespace ejdb { NodeEJDB *njb = new NodeEJDB(); if (!njb->open(*dbPath, mode)) { std::ostringstream os; - os << "Unable to open database: " << (*dbPath) << " error: " << njb->jb_error_msg(); + os << "Unable to open database: " << (*dbPath) << " error: " << njb->_jb_error_msg(); EJ_LOG_ERROR("%s", os.str().c_str()); delete njb; return scope.Close(ThrowException(Exception::Error(String::New(os.str().c_str())))); @@ -136,17 +174,17 @@ namespace ejdb { } static void s_exec_cmd_eio(uv_work_t *req) { - EJBTask *task = static_cast(req->data); + EJBTask *task = static_cast (req->data); NodeEJDB *njb = task->wrapped; assert(njb); - //TODO njb->exec_cmd(task); + njb->exec_cmd(task); } static void s_exec_cmd_eio_after(uv_work_t *req) { - EJBTask *task = static_cast(req->data); + EJBTask *task = static_cast (req->data); NodeEJDB *njb = task->wrapped; assert(njb); - //TODO njb->exec_cmd_after(task); + njb->exec_cmd_after(task); delete task; } @@ -155,18 +193,40 @@ namespace ejdb { NodeEJDB *njb = ObjectWrap::Unwrap< NodeEJDB > (args.This()); assert(njb); if (!njb->close()) { - return scope.Close(ThrowException(Exception::Error(String::New(njb->jb_error_msg())))); + return scope.Close(ThrowException(Exception::Error(String::New(njb->_jb_error_msg())))); } return scope.Close(args.This()); } + static Handle s_load(const Arguments& args) { + HandleScope scope; + REQ_ARGS(3); + REQ_STR_ARG(0, cname); //Collection name + REQ_STR_ARG(1, soid); //String OID + REQ_FUN_ARG(2, cb); //Callback + if (soid.length() != 24) { + return scope.Close(ThrowException(Exception::Error(String::New("Argument 2: Invalid OID string")))); + } + bson_oid_t oid; + bson_oid_from_string(&oid, *soid); + BSONCmdData *cmdata = new BSONCmdData(*cname); + cmdata->ref = oid; + + NodeEJDB *njb = ObjectWrap::Unwrap< NodeEJDB > (args.This()); + assert(njb); + BSONCmdTask *task = new BSONCmdTask(cb, njb, cmdLoad, cmdata, BSONCmdTask::delete_val); + uv_queue_work(uv_default_loop(), &task->uv_work, s_exec_cmd_eio, s_exec_cmd_eio_after); + return scope.Close(args.This()); + } + static Handle s_save(const Arguments& args) { HandleScope scope; - REQ_ARGS(2); - REQ_ARR_ARG(0, oarr); - REQ_FUN_ARG(1, cb); + REQ_ARGS(3); + REQ_STR_ARG(0, cname); //Collection name + REQ_ARR_ARG(1, oarr); //Array of JAVA objects + REQ_FUN_ARG(2, cb); //Callback - BSONCmdData *cmdata = new BSONCmdData(); + BSONCmdData *cmdata = new BSONCmdData(*cname); for (uint32_t i = 0; i < oarr->Length(); ++i) { Local v = oarr->Get(i); if (!v->IsObject()) continue; @@ -184,18 +244,100 @@ namespace ejdb { } NodeEJDB *njb = ObjectWrap::Unwrap< NodeEJDB > (args.This()); assert(njb); - EJBSONTask *task = new EJBSONTask(cb, njb, cmdSave, cmdata, EJBSONTask::delete_val); + BSONCmdTask *task = new BSONCmdTask(cb, njb, cmdSave, cmdata, BSONCmdTask::delete_val); uv_queue_work(uv_default_loop(), &task->uv_work, s_exec_cmd_eio, s_exec_cmd_eio_after); return scope.Close(args.This()); } - NodeEJDB() : m_jb(NULL) { + /////////////////////////////////////////////////////////////////////////// + // Instance methods // + /////////////////////////////////////////////////////////////////////////// + + void exec_cmd(EJBTask *task) { + int cmd = task->cmd; + switch (cmd) { + case cmdLoad: + load((BSONCmdTask*) task); + break; + case cmdSave: + save((BSONCmdTask*) task); + break; + } } - virtual ~NodeEJDB() { - if (m_jb) { - ejdbdel(m_jb); + void exec_cmd_after(EJBTask *task) { + int cmd = task->cmd; + switch (cmd) { + case cmdLoad: + load_after((BSONCmdTask*) task); + break; + case cmdSave: + save_after((BSONCmdTask*) task); + break; } + delete task; + } + + void save(BSONCmdTask *task) { + if (!_check_state((EJBTask*) task)) { + return; + } + BSONCmdData *cmdata = task->cmd_data; + assert(cmdata); + EJCOLL *coll = ejdbcreatecoll(m_jb, cmdata->cname.c_str(), NULL); + if (!coll) { + task->cmd_ret_msg = _jb_error_msg(); + } + + std::vector::iterator it; + for (it = cmdata->bsons.begin(); it < cmdata->bsons.end(); it++) { + bson *bs = *(it); + assert(bs); + bson_oid_t oid; + if (!ejdbsavebson(coll, bs, &oid)) { + task->cmd_ret = CMD_RET_ERROR; + task->cmd_ret_msg = _jb_error_msg(); + break; + } + cmdata->ids.push_back(oid); + } + } + + void save_after(BSONCmdTask *task) { + HandleScope scope; + Local argv[2]; + if (task->cmd_ret != 0) { + argv[0] = Exception::Error(String::New(task->cmd_ret_msg.c_str())); + } else { + argv[0] = Local::New(Null()); + } + Local oids = Array::New(); + std::vector::iterator it; + int32_t c = 0; + for (it = task->cmd_data->ids.begin(); it < task->cmd_data->ids.end(); it++) { + char oidhex[25]; + bson_oid_t& oid = *it; + bson_oid_to_string(&oid, oidhex); + oids->Set(Integer::New(c++), String::New(oidhex)); + } + argv[1] = oids; + TryCatch try_catch; + task->cb->Call(Context::GetCurrent()->Global(), 2, argv); + if (try_catch.HasCaught()) { + FatalException(try_catch); + } + } + + void load(BSONCmdTask *task) { + if (!_check_state((EJBTask*) task)) { + return; + } + + } + + void load_after(BSONCmdTask *task) { + HandleScope scope; + } bool open(const char* dbpath, int mode) { @@ -210,8 +352,26 @@ namespace ejdb { return m_jb ? ejdbclose(m_jb) : false; } - const char* jb_error_msg() { - return m_jb ? ejdberrmsg(ejdbecode(m_jb)) : "unknown error"; + const char* _jb_error_msg() { + return m_jb ? ejdberrmsg(ejdbecode(m_jb)) : "Unknown error"; + } + + bool _check_state(EJBTask *task) { + if (!ejdbisopen(m_jb)) { + task->cmd_ret = CMD_RET_ERROR; + task->cmd_ret_msg = "Database is not opened"; + return false; + } + return true; + } + + NodeEJDB() : m_jb(NULL) { + } + + virtual ~NodeEJDB() { + if (m_jb) { + ejdbdel(m_jb); + } } public: @@ -245,15 +405,11 @@ namespace ejdb { NODE_DEFINE_CONSTANT(target, JBQRYCOUNT); //Symbols - sym_close = NODE_PSYMBOL("close"); - sym_save = NODE_PSYMBOL("save"); - sym_load = NODE_PSYMBOL("load"); - sym_query = NODE_PSYMBOL("query"); - target->Set(v8::String::NewSymbol("NodeEJDB"), constructor_template->GetFunction()); NODE_SET_PROTOTYPE_METHOD(constructor_template, "close", s_close); NODE_SET_PROTOTYPE_METHOD(constructor_template, "save", s_save); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "load", s_load); } void Ref() { diff --git a/node/nbproject/configurations.xml b/node/nbproject/configurations.xml index 58f454e..c158788 100644 --- a/node/nbproject/configurations.xml +++ b/node/nbproject/configurations.xml @@ -9,10 +9,6 @@ - Makefile - binding.Makefile - config.gypi - ejdb_native.target.mk @@ -3246,6 +3242,8 @@ + + pthread_mutex.h diff --git a/tcejdb/bson.c b/tcejdb/bson.c index 78d725c..1a5db45 100644 --- a/tcejdb/bson.c +++ b/tcejdb/bson.c @@ -757,6 +757,10 @@ EJDB_EXPORT void bson_destroy(bson *b) { b->data = 0; b->cur = 0; b->finished = 1; + if (b->errstr) { + bson_free_func(b->errstr); + b->errstr = NULL; + } } } diff --git a/tcejdb/bson.h b/tcejdb/bson.h index 8a75c01..49d28cc 100644 --- a/tcejdb/bson.h +++ b/tcejdb/bson.h @@ -54,7 +54,8 @@ enum bson_validity_t { BSON_NOT_UTF8 = (1 << 1), /**< A key or a string is not valid UTF-8. */ BSON_FIELD_HAS_DOT = (1 << 2), /**< Warning: key contains '.' character. */ BSON_FIELD_INIT_DOLLAR = (1 << 3), /**< Warning: key starts with '$' character. */ - BSON_ALREADY_FINISHED = (1 << 4) /**< Trying to modify a finished BSON object. */ + BSON_ALREADY_FINISHED = (1 << 4), /**< Trying to modify a finished BSON object. */ + BSON_ERROR_ANY = (1 << 5) /**< Unspecified error */ }; enum bson_binary_subtype_t { diff --git a/tcejdb/ejdb.c b/tcejdb/ejdb.c index 7a07d5d..f0e85de 100644 --- a/tcejdb/ejdb.c +++ b/tcejdb/ejdb.c @@ -150,6 +150,10 @@ EJDB_EXPORT bool ejdbclose(EJDB *jb) { return rv; } +EJDB_EXPORT bool ejdbisopen(EJDB *jb) { + return JBISOPEN(jb); +} + EJDB_EXPORT bool ejdbopen(EJDB *jb, const char *path, int mode) { assert(jb && path); assert(jb->metadb); diff --git a/tcejdb/ejdb.h b/tcejdb/ejdb.h index cdb1771..78b1fbf 100644 --- a/tcejdb/ejdb.h +++ b/tcejdb/ejdb.h @@ -121,6 +121,14 @@ EJDB_EXPORT bool ejdbclose(EJDB *jb); */ EJDB_EXPORT bool ejdbopen(EJDB *jb, const char *path, int mode); + +/** + * Return true if database is in open state + * @param jb EJDB database hadle + * @return True if database is in open state otherwise false + */ +EJDB_EXPORT bool ejdbisopen(EJDB *jb); + /** * Retrieve collection handle for collection specified `collname`. * If collection with specified name does't exists it will return NULL. -- 2.7.4