#1 + bugfixes
authoradam <anton@adamansky.com>
Thu, 1 Nov 2012 10:27:24 +0000 (17:27 +0700)
committeradam <anton@adamansky.com>
Thu, 1 Nov 2012 10:27:24 +0000 (17:27 +0700)
node/ejdb_native.cc
tcejdb/Makefile.in
tcejdb/bson.c
tcejdb/bson.h
tcejdb/tchdb.c
tcejdb/testejdb/Makefile

index ba26b2a..ac1f982 100644 (file)
@@ -116,7 +116,7 @@ namespace ejdb {
     } TBSONCTX;
 
     static void toBSON0(Handle<Object> obj, bson *bs, TBSONCTX *ctx) {
-        HandleScope scope
+        HandleScope scope;
         assert(ctx && obj->IsObject());
         if (ctx->traversed->Get(obj)->IsObject()) {
             bs->err = BSON_ERROR_ANY;
@@ -208,7 +208,7 @@ namespace ejdb {
 
         struct BSONCmdData {
             std::string cname; //Name of collection
-            std::vector<bson*> bsons; //bsons to save
+            std::vector<bson*> bsons; //bsons to save|query
             std::vector<bson_oid_t> ids; //saved updated oids
             bson_oid_t ref; //Bson ref
 
@@ -230,8 +230,11 @@ namespace ejdb {
 
         struct BSONQCmdData : public BSONCmdData {
             TCLIST *res;
+            int qflags;
+            uint32_t count;
 
-            BSONQCmdData(const char* cname) : BSONCmdData::BSONCmdData(cname), res(NULL) {
+            BSONQCmdData(const char* _cname, int _qflags) :
+            BSONCmdData::BSONCmdData(_cname), res(NULL), qflags(_qflags), count(0) {
             }
 
             virtual ~BSONQCmdData() {
@@ -243,7 +246,7 @@ namespace ejdb {
 
         typedef EIOCmdTask<NodeEJDB> EJBTask;
         typedef EIOCmdTask<NodeEJDB, BSONCmdData> BSONCmdTask;
-        typedef EIOCmdTask<NodeEJDB, BSONQCmdData> QueryCmdTask;
+        typedef EIOCmdTask<NodeEJDB, BSONQCmdData> BSONQCmdTask;
 
         static Persistent<FunctionTemplate> constructor_template;
 
@@ -326,7 +329,7 @@ namespace ejdb {
                 assert(bs);
                 toBSON(Handle<Object>::Cast(v), bs);
                 if (bs->err) {
-                    Local<String> msg = String::New(bs->errstr ? bs->errstr : "bson creation failed");
+                    Local<String> msg = String::New(bs->errstr ? bs->errstr : "BSON creation failed");
                     bson_del(bs);
                     delete cmdata;
                     return scope.Close(ThrowException(Exception::Error(msg)));
@@ -341,6 +344,50 @@ namespace ejdb {
             return scope.Close(args.This());
         }
 
+        static Handle<Value> s_query(const Arguments& args) {
+            HandleScope scope;
+            REQ_ARGS(4);
+            REQ_STR_ARG(0, cname)
+            REQ_ARR_ARG(1, qarr);
+            REQ_INT32_ARG(2, qflags);
+            REQ_FUN_ARG(3, cb);
+
+            if (qarr->Length() == 0) {
+                return scope.Close(ThrowException(Exception::Error(String::New("Query array must have at least one element"))));
+            }
+            BSONQCmdData *cmdata = new BSONQCmdData(*cname, qflags);
+            uint32_t len = qarr->Length();
+            for (uint32_t i = 0; i < len; ++i) {
+                Local<Value> qv = qarr->Get(i);
+                if (i > 0 && i == len - 1 && (qv->IsNull() || qv->IsUndefined())) { //Last hints element can be NULL
+                    cmdata->bsons.push_back(NULL);
+                    continue;
+                } else if (!qv->IsObject()) {
+                    delete cmdata;
+                    return scope.Close(ThrowException(
+                            Exception::Error(
+                            String::New("Each element of query array must be an object (except last hints element)"))
+                            ));
+                }
+                bson *bs = bson_create();
+                bson_init(bs);
+                toBSON(Local<Object>::Cast(qv), bs);
+                bson_finish(bs);
+                if (bs->err) {
+                    Local<String> msg = String::New(bs->errstr ? bs->errstr : "BSON error");
+                    bson_del(bs);
+                    delete cmdata;
+                    return scope.Close(ThrowException(Exception::Error(msg)));
+                }
+                cmdata->bsons.push_back(bs);
+            }
+            NodeEJDB *njb = ObjectWrap::Unwrap< NodeEJDB > (args.This());
+            assert(njb);
+            BSONQCmdTask *task = new BSONQCmdTask(cb, njb, cmdQuery, cmdata, BSONQCmdTask::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());
+        }
+
         ///////////////////////////////////////////////////////////////////////////
         //                            Instance methods                           //
         ///////////////////////////////////////////////////////////////////////////
@@ -348,6 +395,9 @@ namespace ejdb {
         void exec_cmd(EJBTask *task) {
             int cmd = task->cmd;
             switch (cmd) {
+                case cmdQuery:
+                    query((BSONQCmdTask*) task);
+                    break;
                 case cmdLoad:
                     load((BSONCmdTask*) task);
                     break;
@@ -360,6 +410,9 @@ namespace ejdb {
         void exec_cmd_after(EJBTask *task) {
             int cmd = task->cmd;
             switch (cmd) {
+                case cmdQuery:
+                    query_after((BSONQCmdTask*) task);
+                    break;
                 case cmdLoad:
                     load_after((BSONCmdTask*) task);
                     break;
@@ -378,6 +431,7 @@ namespace ejdb {
             assert(cmdata);
             EJCOLL *coll = ejdbcreatecoll(m_jb, cmdata->cname.c_str(), NULL);
             if (!coll) {
+                task->cmd_ret = CMD_RET_ERROR;
                 task->cmd_ret_msg = _jb_error_msg();
                 return;
             }
@@ -429,6 +483,7 @@ namespace ejdb {
             assert(cmdata);
             EJCOLL *coll = ejdbcreatecoll(m_jb, cmdata->cname.c_str(), NULL);
             if (!coll) {
+                task->cmd_ret = CMD_RET_ERROR;
                 task->cmd_ret_msg = _jb_error_msg();
                 return;
             }
@@ -460,6 +515,54 @@ namespace ejdb {
             }
         }
 
+        void query(BSONQCmdTask *task) {
+            if (!_check_state((EJBTask*) task)) {
+                return;
+            }
+            bson oqarrstack[8]; //max 8 $or bsons on stack
+            BSONQCmdData *cmdata = task->cmd_data;
+            EJCOLL *coll = ejdbcreatecoll(m_jb, cmdata->cname.c_str(), NULL);
+            if (!coll) {
+                task->cmd_ret = CMD_RET_ERROR;
+                task->cmd_ret_msg = _jb_error_msg();
+                return;
+            }
+            std::vector<bson*> &bsons = cmdata->bsons;
+            int orsz = (int) bsons.size() - 2; //Minus main qry at begining and hints object at the end
+            if (orsz < 0) orsz = 0;
+            bson *oqarr = ((orsz <= 8) ? oqarrstack : (bson*) malloc(orsz * sizeof (bson)));
+            for (int i = 1; i < (int) bsons.size() - 1; ++i) {
+                oqarr[i - 1] = *(bsons.at(i));
+                break;
+            }
+            TCLIST *res = NULL;
+            EJQ *q = ejdbcreatequery(
+                    m_jb,
+                    bsons.front(),
+                    (orsz > 0 ? oqarr : NULL), orsz,
+                    ((bsons.size() > 1) ? bsons.back() : NULL));
+            if (!q) {
+                task->cmd_ret = CMD_RET_ERROR;
+                task->cmd_ret_msg = _jb_error_msg();
+                goto finish;
+            }
+            res = ejdbqrysearch(coll, q, &cmdata->count, cmdata->qflags, NULL);
+
+
+finish:
+            if (q) {
+                ejdbquerydel(q);
+            }
+            if (oqarr && oqarr != oqarrstack) {
+                free(oqarr);
+            }
+        }
+
+        void query_after(BSONQCmdTask *task) {
+            HandleScope scope;
+
+        }
+
         bool open(const char* dbpath, int mode) {
             m_jb = ejdbnew();
             if (!m_jb) {
@@ -530,6 +633,7 @@ namespace ejdb {
             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);
+            NODE_SET_PROTOTYPE_METHOD(constructor_template, "query", s_query);
         }
 
         void Ref() {
@@ -542,7 +646,7 @@ namespace ejdb {
     };
 
     ///////////////////////////////////////////////////////////////////////////
-    //                        Result set cursor                              //
+    //                        ResultSet cursor                               //
     ///////////////////////////////////////////////////////////////////////////
 
     class NodeEJDBCursor : public ObjectWrap {
@@ -624,7 +728,6 @@ namespace ejdb {
         }
 
         NodeEJDBCursor(TCLIST *rs) : m_rs(rs), m_pos(0) {
-
         }
 
         virtual ~NodeEJDBCursor() {
@@ -659,11 +762,9 @@ namespace ejdb {
         void Unref() {
             ObjectWrap::Unref();
         }
-
     };
 
 
-
     Persistent<FunctionTemplate> NodeEJDB::constructor_template;
     Persistent<FunctionTemplate> NodeEJDBCursor::constructor_template;
 
index 33f9782..c5513bc 100644 (file)
@@ -594,9 +594,7 @@ check-valgrind :
        grep 'at exit' *.vlog | grep -v ' 0 bytes' ; true
 
 check-valgrind-ejdb :
-       make RUNCMD="valgrind --tool=memcheck --leak-check=full --log-file=%p.vlog" -C ./testejdb check-valgrind
-       grep ERROR *.vlog | grep -v ' 0 errors' ; true
-       grep 'at exit' *.vlog | grep -v ' 0 bytes' ; true
+       make RUNCMD="valgrind --tool=memcheck --leak-check=full --error-exitcode=1" -C ./testejdb check
 
 check-large :
        rm -rf casket*
index 35d4a99..091d3ca 100644 (file)
@@ -53,6 +53,14 @@ bson_printf_func bson_errprintf = _bson_errprintf;
 static int ( *oid_fuzz_func)(void) = NULL;
 static int ( *oid_inc_func)(void) = NULL;
 
+static void _bson_reset(bson *b) {
+    b->finished = 0;
+    b->stackPos = 0;
+    b->err = 0;
+    b->errstr = NULL;
+    b->flags = 0;
+}
+
 /* ----------------------------
    READING
    ------------------------------ */
@@ -82,7 +90,6 @@ EJDB_EXPORT int bson_copy(bson *out, const bson *in) {
     bson_init_size(out, bson_size(in));
     memcpy(out->data, in->data, bson_size(in));
     out->finished = 1;
-
     return BSON_OK;
 }
 
@@ -91,20 +98,13 @@ int bson_init_data(bson *b, char *data) {
     return BSON_OK;
 }
 
-int bson_init_finished_data(bson *b, char *data) {
+EJDB_EXPORT int bson_init_finished_data(bson *b, char *data) {
     bson_init_data(b, data);
+    _bson_reset(b);
     b->finished = 1;
     return BSON_OK;
 }
 
-static void _bson_reset(bson *b) {
-    b->finished = 0;
-    b->stackPos = 0;
-    b->err = 0;
-    b->errstr = NULL;
-    b->flags = 0;
-}
-
 EJDB_EXPORT int bson_size(const bson *b) {
     int i;
     if (!b || !b->data)
@@ -1357,7 +1357,7 @@ EJDB_EXPORT bson* bson_create_from_buffer(const void* buf, int bufsz) {
     bson *rv = bson_create();
     bson_init_size(rv, bufsz);
     bson_ensure_space(rv, bufsz - 4);
-    bson_append(rv, buf + 4, bufsz - (4 + 1/*BSON_EOO*/));
+    bson_append(rv, (char*) buf + 4, bufsz - (4 + 1/*BSON_EOO*/));
     bson_finish(rv);
     return rv;
 }
index c9c0b87..5cde388 100644 (file)
@@ -577,7 +577,7 @@ EJDB_EXPORT void bson_init_as_query(bson *b);
  * @return BSON_OK or BSON_ERROR.
  */
 int bson_init_data(bson *b, char *data);
-int bson_init_finished_data(bson *b, char *data);
+EJDB_EXPORT int bson_init_finished_data(bson *b, char *data);
 
 /**
  * Initialize a BSON object, and set its
index 0559c13..39abd39 100644 (file)
@@ -224,19 +224,21 @@ void tchdbdel(TCHDB *hdb){
   assert(hdb);
   if(hdb->fd >= 0) tchdbclose(hdb);
   if(hdb->mmtx){
-    pthread_key_delete(*(pthread_key_t *)hdb->eckey);
     pthread_mutex_destroy(hdb->wmtx);
     pthread_mutex_destroy(hdb->dmtx);
     for(int i = UINT8_MAX; i >= 0; i--){
       pthread_rwlock_destroy((pthread_rwlock_t *)hdb->rmtxs + i);
     }
     pthread_rwlock_destroy(hdb->mmtx);
-    TCFREE(hdb->eckey);
     TCFREE(hdb->wmtx);
     TCFREE(hdb->dmtx);
     TCFREE(hdb->rmtxs);
     TCFREE(hdb->mmtx);
   }
+  if (hdb->eckey) {
+      pthread_key_delete(*(pthread_key_t *)hdb->eckey);
+      TCFREE(hdb->eckey);
+  }
   TCFREE(hdb);
 }
 
@@ -244,8 +246,7 @@ void tchdbdel(TCHDB *hdb){
 /* Get the last happened error code of a hash database object. */
 int tchdbecode(TCHDB *hdb){
   assert(hdb);
-  return hdb->mmtx ?
-    (int)(intptr_t)pthread_getspecific(*(pthread_key_t *)hdb->eckey) : hdb->ecode;
+  return (hdb->eckey) ? (int)(intptr_t)pthread_getspecific(*(pthread_key_t *)hdb->eckey) : hdb->ecode;
 }
 
 
@@ -263,7 +264,6 @@ bool tchdbsetmutex(TCHDB *hdb){
   TCMALLOC(hdb->rmtxs, (UINT8_MAX + 1) * sizeof(pthread_rwlock_t));
   TCMALLOC(hdb->dmtx, sizeof(pthread_mutex_t));
   TCMALLOC(hdb->wmtx, sizeof(pthread_mutex_t));
-  TCMALLOC(hdb->eckey, sizeof(pthread_key_t));
   bool err = false;
   if(pthread_mutexattr_settype(&rma, PTHREAD_MUTEX_RECURSIVE) != 0) err = true;
   if(pthread_rwlock_init(hdb->mmtx, NULL) != 0) err = true;
@@ -272,16 +272,13 @@ bool tchdbsetmutex(TCHDB *hdb){
   }
   if(pthread_mutex_init(hdb->dmtx, &rma) != 0) err = true;
   if(pthread_mutex_init(hdb->wmtx, NULL) != 0) err = true;
-  if(pthread_key_create(hdb->eckey, NULL) != 0) err = true;
   if(err){
     tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__);
     pthread_mutexattr_destroy(&rma);
-    TCFREE(hdb->eckey);
     TCFREE(hdb->wmtx);
     TCFREE(hdb->dmtx);
     TCFREE(hdb->rmtxs);
     TCFREE(hdb->mmtx);
-    hdb->eckey = NULL;
     hdb->wmtx = NULL;
     hdb->dmtx = NULL;
     hdb->rmtxs = NULL;
@@ -350,6 +347,15 @@ bool tchdbsetdfunit(TCHDB *hdb, int32_t dfunit){
 bool tchdbopen(TCHDB *hdb, const char *path, int omode){
   assert(hdb && path);
   if(!HDBLOCKMETHOD(hdb, true)) return false;
+  if (!hdb->eckey) {
+      TCMALLOC(hdb->eckey, sizeof(pthread_key_t));
+      if(pthread_key_create(hdb->eckey, NULL)) {
+          TCFREE(hdb->eckey);
+          hdb->eckey = NULL;
+          HDBUNLOCKMETHOD(hdb);
+          return false;
+      }
+  }
   if(hdb->fd >= 0){
     tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__);
     HDBUNLOCKMETHOD(hdb);
@@ -1264,13 +1270,16 @@ void tchdbsetecode(TCHDB *hdb, int ecode, const char *filename, int line, const
   assert(hdb && filename && line >= 1 && func);
   int myerrno = errno;
   if(!hdb->fatal){
-    if(hdb->mmtx){
-      pthread_setspecific(*(pthread_key_t *)hdb->eckey, (void *)(intptr_t)ecode);
-    } else {
-      hdb->ecode = ecode;
-    }
+      if (hdb->eckey) {
+          pthread_setspecific(*(pthread_key_t *)hdb->eckey, (void *)(intptr_t)ecode);
+      } else {
+          hdb->ecode = ecode;
+      }
+  }
+  if (ecode == TCESUCCESS) {
+      return;
   }
-  if(ecode != TCESUCCESS && ecode != TCEINVALID && ecode != TCEKEEP && ecode != TCENOREC){
+  if(ecode != TCEINVALID && ecode != TCEKEEP && ecode != TCENOREC){
     hdb->fatal = true;
     if(hdb->fd >= 0 && (hdb->omode & HDBOWRITER)) tchdbsetflag(hdb, HDBFFATAL, true);
   }
index 671fb9f..c412640 100644 (file)
@@ -13,7 +13,7 @@ check : all check-t1 check-t2 check-t3;
 
 check-valgrind :
        rm -rf *.vlog
-       make RUNCMD="valgrind --tool=memcheck --leak-check=full --log-file=%p.vlog" check
+       make RUNCMD="valgrind --tool=memcheck --leak-check=full --error-exitcode=1" check
        grep ERROR *.vlog | grep -v ' 0 errors' ; true
        grep 'at exit' *.vlog | grep -v ' 0 bytes' ; true