From 4c093c6879dc551d94c02b425e09b0f7f22f792c Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 18 Mar 2013 19:34:05 +0700 Subject: [PATCH] #51 --- luaejdb/ejdb.lua | 75 ++++++++++++++- luaejdb/luaejdb.c | 262 +++++++++++++++++++++++++++++++++++++++++++++++----- luaejdb/test/t1.lua | 26 +++++- tcejdb/ejdb.h | 2 +- 4 files changed, 339 insertions(+), 26 deletions(-) diff --git a/luaejdb/ejdb.lua b/luaejdb/ejdb.lua index cb8185e..aa3de39 100644 --- a/luaejdb/ejdb.lua +++ b/luaejdb/ejdb.lua @@ -162,9 +162,80 @@ function DB:count(cname, q, sflags, ...) return count, log end - function DB:update(cname, q, ...) - return self:count(cname, q, ...) + return self:count(cname, q, ...) +end + +function DB:dropIndexes(cname, fpath) + return self:_setIndex(cname, fpath, "", "a") +end + +function DB:optimizeIndexes(cname, fpath) + return self:_setIndex(cname, fpath, "", "o") +end + +function DB:ensureStringIndex(cname, fpath) + return self:_setIndex(cname, fpath, "s", "") +end + +function DB:rebuildStringIndex(cname, fpath) + return self:_setIndex(cname, fpath, "s", "r") +end + +function DB:dropStringIndex(cname, fpath) + return self:_setIndex(cname, fpath, "s", "d") +end + +function DB:ensureIStringIndex(cname, fpath) + return self:_setIndex(cname, fpath, "i", "") +end + +function DB:rebuildIStringIndex(cname, fpath) + return self:_setIndex(cname, fpath, "i", "r") +end + +function DB:dropIStringIndex(cname, fpath) + return self:_setIndex(cname, fpath, "i", "d") +end + +function DB:ensureNumberIndex(cname, fpath) + return self:_setIndex(cname, fpath, "n", "") +end + +function DB:rebuildNumberIndex(cname, fpath) + return self:_setIndex(cname, fpath, "n", "r") +end + +function DB:dropNumberIndex(cname, fpath) + return self:_setIndex(cname, fpath, "n", "d") +end + +function DB:ensureArrayIndex(cname, fpath) + return self:_setIndex(cname, fpath, "a", "") +end + +function DB:rebuildArrayIndex(cname, fpath) + return self:_setIndex(cname, fpath, "a", "r") +end + +function DB:dropArrayIndex(cname, fpath) + return self:_setIndex(cname, fpath, "a", "d") +end + +function DB:beginTransaction(cname) + return self:_txctl(cname, "b") +end + +function DB:commitTransaction(cname) + return self:_txctl(cname, "c") +end + +function DB:rollbackTransaction(cname) + return self:_txctl(cname, "a") +end + +function DB:getTransactionStatus(cname) + return self:_txctl(cname, "s") end -- ------- EJDB Query ------------- diff --git a/luaejdb/luaejdb.c b/luaejdb/luaejdb.c index 0eb6ae3..ec1ddc2 100644 --- a/luaejdb/luaejdb.c +++ b/luaejdb/luaejdb.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include "luabson.h" @@ -52,35 +52,35 @@ static int set_ejdb_error(lua_State *L, EJDB *jb) { return luaL_error(L, emsg); } -static void check_ejdb(lua_State *L, EJDB *jb) { +static bool ejcollockmethod(EJCOLL *coll, bool wr) { + assert(coll && coll->jb); + if (!coll->mmtx) return false; + if (wr ? pthread_rwlock_wrlock((pthread_rwlock_t*) coll->mmtx) != 0 : pthread_rwlock_rdlock((pthread_rwlock_t*) coll->mmtx) != 0) { + return false; + } + return (coll->tdb && coll->tdb->open); +} + +static bool ejcollunlockmethod(EJCOLL *coll) { + assert(coll && coll->jb); + if (!coll->mmtx) return false; + if (pthread_rwlock_unlock((pthread_rwlock_t*) coll->mmtx) != 0) { + return false; + } + return true; +} + +static EJDB *check_ejdb(lua_State *L, EJDB *jb) { if (jb == NULL) { luaL_error(L, "Closed EJDB database"); } + return jb; } static void init_db_consts(lua_State *L) { if (!lua_istable(L, -1)) { luaL_error(L, "Table must be on top of lua stack"); } - TBLSETNUMCONST(JBOREADER); - TBLSETNUMCONST(JBOWRITER); - TBLSETNUMCONST(JBOCREAT); - TBLSETNUMCONST(JBOTRUNC); - TBLSETNUMCONST(JBONOLCK); - TBLSETNUMCONST(JBOLCKNB); - TBLSETNUMCONST(JBOTSYNC); - TBLSETNUMCONST(JBIDXDROP); - TBLSETNUMCONST(JBIDXDROPALL); - TBLSETNUMCONST(JBIDXOP); - TBLSETNUMCONST(JBIDXREBLD); - TBLSETNUMCONST(JBIDXNUM); - TBLSETNUMCONST(JBIDXSTR); - TBLSETNUMCONST(JBIDXISTR); - TBLSETNUMCONST(JBIDXARR); - TBLSETNUMCONST(JBQRYCOUNT); - TBLSETNUMCONST(JBQRYLOG); - TBLSETNUMCONST(DEFAULT_OPEN_MODE); - TBLSETNUMCONST(BSON_DOUBLE); TBLSETNUMCONST(BSON_STRING); TBLSETNUMCONST(BSON_OBJECT); @@ -377,6 +377,7 @@ static int db_sync(lua_State *L) { lua_getfield(L, 1, EJDBUDATAKEY); EJDBDATA *data = luaL_checkudata(L, -1, EJDBUDATAMT); EJDB *jb = data->db; + check_ejdb(L, jb); if (lua_isstring(L, 2)) { //sync coll const char *cname = lua_tostring(L, 2); EJCOLL *coll = ejdbgetcoll(jb, cname); @@ -394,10 +395,221 @@ static int db_sync(lua_State *L) { } static int db_set_index(lua_State *L) { - //todo + luaL_checktype(L, 1, LUA_TTABLE); //self + lua_getfield(L, 1, EJDBUDATAKEY); + EJDB *jb = ((EJDBDATA*) luaL_checkudata(L, -1, EJDBUDATAMT))->db; + check_ejdb(L, jb); + const char *cname = luaL_checkstring(L, 2); //collections name + const char *fpath = luaL_checkstring(L, 3); //index field path + //index types: + // s: string + // i: ignore case string index + // n: number index + // a: array toke index + const char *itypes = luaL_checkstring(L, 4); + const char *iop = luaL_checkstring(L, 5); //index operation + + int i; + uint32_t iflags = 0; + for (i = 0; itypes[i] != '\0'; ++i) { + switch (itypes[i]) { + case 's': + iflags |= JBIDXSTR; + break; + case 'i': + iflags |= JBIDXISTR; + break; + case 'n': + iflags |= JBIDXNUM; + break; + case 'a': + iflags |= JBIDXARR; + break; + case '*': + iflags |= (JBIDXSTR | JBIDXISTR | JBIDXNUM | JBIDXARR); + break; + } + } + + for (i = 0; iop[i] != '\0'; ++i) { + switch (iop[i]) { + case 'd': + iflags |= JBIDXDROP; + break; + case 'a': + iflags |= JBIDXDROPALL; + break; + case 'o': + iflags |= JBIDXOP; + break; + case 'r': + iflags |= JBIDXREBLD; + break; + } + } + + EJCOLL *coll = ejdbgetcoll(jb, cname); + if (!coll) { + return 0; + } + if (!ejdbsetindex(coll, fpath, iflags)) { + return set_ejdb_error(L, jb); + } + return 0; +} + +static int db_txctl(lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); //self + lua_getfield(L, 1, EJDBUDATAKEY); + EJDB *jb = ((EJDBDATA*) luaL_checkudata(L, -1, EJDBUDATAMT))->db; + check_ejdb(L, jb); + const char *cname = luaL_checkstring(L, 2); //collections name + const char *cmd = luaL_checkstring(L, 3); //command + EJCOLL *coll = ejdbcreatecoll(jb, cname, NULL); + if (!coll) { + return set_ejdb_error(L, jb); + } + int i; + bool jbret = true; + for (i = 0; cmd[i] != '\0'; ++i) { + switch (cmd[i]) { + case 'b': //begin transaction + jbret = ejdbtranbegin(coll); + break; + case 'c': + jbret = ejdbtrancommit(coll); + break; + case 'a': + jbret = ejdbtranabort(coll); + break; + case 's': + { + bool status; + jbret = ejdbtranstatus(coll, &status); + if (jbret) { + lua_pushboolean(L, status); + return 1; + } + } + } + } + if (!jbret) { + return set_ejdb_error(L, jb); + } return 0; } +static int db_meta(lua_State *L) { + lua_checkstack(L, 6); + int argc = lua_gettop(L); + luaL_checktype(L, 1, LUA_TTABLE); //self + lua_getfield(L, 1, EJDBUDATAKEY); + EJDB *jb = ((EJDBDATA*) luaL_checkudata(L, -1, EJDBUDATAMT))->db; + check_ejdb(L, jb); + bool jbret = true; + lua_pop(L, 1); + + lua_newtable(L); //+root info + + lua_pushstring(L, jb->metadb->hdb->path); + lua_setfield(L, -2, "file"); + + lua_newtable(L); //+collections + TCLIST *cols = ejdbgetcolls(jb); + if (!cols) { + return set_ejdb_error(L, jb); + } + for (int i = 0; i < TCLISTNUM(cols); ++i) { + EJCOLL *coll = (EJCOLL*) TCLISTVALPTR(cols, i); + if (!ejcollockmethod(coll, false)) continue; + + lua_pushlstring(L, coll->cname, coll->cnamesz); //coll key + + lua_newtable(L); //+ coll table + + lua_pushlstring(L, coll->cname, coll->cnamesz); + lua_setfield(L, -2, "name"); + + lua_pushstring(L, coll->tdb->hdb->path); + lua_setfield(L, -2, "file"); + + lua_pushinteger(L, coll->tdb->hdb->rnum); + lua_setfield(L, -2, "records"); + + lua_newtable(L); //+ coll options + + lua_pushinteger(L, coll->tdb->hdb->bnum); + lua_setfield(L, -2, "buckets"); + + lua_pushinteger(L, coll->tdb->hdb->rcnum); + lua_setfield(L, -2, "cachedrecords"); + + lua_pushboolean(L, coll->tdb->opts & TDBTLARGE); + lua_setfield(L, -2, "large"); + + lua_pushboolean(L, coll->tdb->opts & TDBTDEFLATE); + lua_setfield(L, -2, "compressed"); + lua_setfield(L, -2, "options"); + + lua_newtable(L); //+ coll indexes + + int ic = 0; + for (int j = 0; j < coll->tdb->inum; ++j) { + TDBIDX *idx = (coll->tdb->idxs + j); + if (idx->type != TDBITLEXICAL && idx->type != TDBITDECIMAL && idx->type != TDBITTOKEN) { + continue; + } + lua_newtable(L); //+ index details + + lua_pushstring(L, idx->name + 1); + lua_setfield(L, -2, "field"); + + lua_pushstring(L, idx->name); + lua_setfield(L, -2, "iname"); + + switch (idx->type) { + case TDBITLEXICAL: + lua_pushstring(L, "lexical"); + lua_setfield(L, -2, "type"); + break; + case TDBITDECIMAL: + lua_pushstring(L, "decimal"); + lua_setfield(L, -2, "type"); + break; + case TDBITTOKEN: + lua_pushstring(L, "token"); + lua_setfield(L, -2, "type"); + break; + } + TCBDB *idb = (TCBDB*) idx->db; + if (idb) { + lua_pushinteger(L, idb->rnum); + lua_setfield(L, -2, "records"); + + lua_pushstring(L, idb->hdb->path); + lua_setfield(L, -2, "file"); + } + lua_rawseti(L, -2, ++ic); + } + lua_setfield(L, -2, "indexes"); + lua_settable(L, -3); + + ejcollunlockmethod(coll); + } + lua_setfield(L, -2, "collections"); + + if (cols) { + tclistdel(cols); + } + if (!jbret) { + return set_ejdb_error(L, jb); + } + if (lua_gettop(L) - argc != 1) { + return luaL_error(L, "db_meta: Invalid stack size: %d should be: %d", (lua_gettop(L) - argc), 1); + } + return 1; +} + static int db_save(lua_State *L) { int argc = lua_gettop(L); luaL_checktype(L, 1, LUA_TTABLE); //self @@ -700,6 +912,12 @@ static int db_open(lua_State *L) { lua_pushcfunction(L, db_set_index); lua_setfield(L, -2, "_setIndex"); + lua_pushcfunction(L, db_txctl); + lua_setfield(L, -2, "_txctl"); + + lua_pushcfunction(L, db_meta); + lua_setfield(L, -2, "getDBMeta"); + if (lua_gettop(L) - argc != 1) { ejdbdel(db); udb->db = NULL; diff --git a/luaejdb/test/t1.lua b/luaejdb/test/t1.lua index 6bc3acd..757bfb5 100644 --- a/luaejdb/test/t1.lua +++ b/luaejdb/test/t1.lua @@ -171,7 +171,6 @@ assert(count == 1) assert(vobj["foo"] == "bar") db:ensureCollection("ecoll", { large = true, records = 200000 }) -db:dropCollection("ecoll", true); assert(db:count("mycoll", Q("_id", firstOid)) == 1) db:remove("mycoll", firstOid) @@ -180,6 +179,31 @@ assert(db:count("mycoll", Q("_id", firstOid)) == 0) db:sync("mycoll") -- sync only mycoll db:sync() -- sync whole db +db:ensureStringIndex("mycoll", "foo") +local _, log = db:count("mycoll", Q("foo", "bar"), "l") +assert(log:find("MAIN IDX: 'sfoo'")) + +db:dropIndexes("mycoll", "foo") + +local _, log = db:count("mycoll", Q("foo", "bar"), "l") +assert(log:find("MAIN IDX: 'NONE'")) + +assert(db:getTransactionStatus("mycoll") == false) +db:beginTransaction("mycoll") +assert(db:getTransactionStatus("mycoll") == true) +db:save("mycoll", {name=1}) +assert(db:findOne("mycoll", Q("name", 1))); +db:rollbackTransaction("mycoll") +assert(db:getTransactionStatus("mycoll") == false) +assert(db:findOne("mycoll", Q("name", 1)) == nil); + + +db:ensureStringIndex("mycoll", "foo") + +print(inspect(db:getDBMeta())) + +db:dropCollection("ecoll", true); + assert(db:isOpen() == true) db:close() assert(db:isOpen() == false) diff --git a/tcejdb/ejdb.h b/tcejdb/ejdb.h index c17a903..b9c8d3c 100644 --- a/tcejdb/ejdb.h +++ b/tcejdb/ejdb.h @@ -73,7 +73,7 @@ enum { /** Database open modes */ enum { /** Index modes, index types. */ JBIDXDROP = 1 << 0, /**< Drop index. */ JBIDXDROPALL = 1 << 1, /**< Drop index for all types. */ - JBIDXOP = 1 << 2, /**< Optimize index. */ + JBIDXOP = 1 << 2, /**< Optimize indexes. */ JBIDXREBLD = 1 << 3, /**< Rebuild index. */ JBIDXNUM = 1 << 4, /**< Number index. */ JBIDXSTR = 1 << 5, /**< String index.*/ -- 2.7.4