瀏覽代碼

Add store module; fix LMDB readed conflict in graph iterator.

scossu 2 周之前
父節點
當前提交
fc21630c65
共有 6 個文件被更改,包括 117 次插入54 次删除
  1. 0 25
      lsup-scm-1.rockspec
  2. 13 3
      scratch.lua
  3. 31 25
      src/lua_graph.c
  4. 1 1
      src/lua_namespace.c
  5. 71 0
      src/lua_store.c
  6. 1 0
      src/lua_term.c

+ 0 - 25
lsup-scm-1.rockspec

@@ -1,11 +1,9 @@
 package = "lsup"
 version = "scm-1"
 source = {
-   --url = "./"
    url = "git://git.knowledgetx.com/scossu/lsup_rdf.git",
    branch = "master",
    tag = "HEAD",
-   --tag = "scm",
 }
 description = {
    summary = "Compact, minimalistic RDF library and persistent store.",
@@ -22,27 +20,4 @@ dependencies = {
 }
 build = {
    type = "make",
-   --build_target = "lua",
-   --install_target = "lua_install",
-   --[=[
-   modules = {
-      lsup = {
-         sources = {
-             "src/lua_*.c",
-             --[[
-             "src/lua_namespace.c",
-             "src/lua_term.c",
-             "src/lua_triple.c",
-             "src/lua_graph.c",
-             "src/lua_lsup.c",
-             --]]
-         },
-         --defines = {},
-         --libraries = {"lsuprdf_dbg"},
-         --incdirs = {"./include", "./ext/log/src", "./ext/hashmap"},
-         --libdirs = {}
-      }
-   },
-   --copy_directories = {}
-   --]=]
 }

+ 13 - 3
scratch.lua

@@ -1,6 +1,7 @@
 term = require "lsup.term"
 triple = require "lsup.triple"
 graph = require "lsup.graph"
+store = require "lsup.store"
 
 ---[[
 t1 = term.new_bnode()
@@ -21,11 +22,20 @@ triples = {
     triple.new (t1, t2, t5),
 }
 
-gr1 = graph.new()
+mdb_store = store.new(store.MDB, "file:///tmp/lsup_lua.db", true)
+print("MDB store: ".. type(mdb_store))
+gr1 = graph.new(mdb_store)
+
 ct = gr1:add(triples)
 print("Triples added: " .. ct)
-gr2 = graph.new()
-for i in gr1:lookup() do print(i) end
+--[[
+print("graph 2")
+gr2 = graph.new(mdb_store)
+print("graph 3")
+gr3 = graph.new()
+--]]
+for i in gr1:lookup(t1) do print(i) end
+---[[
 
 lm = gr1:connections(t1, term.LINK_OUTBOUND)
 print("Connections")

+ 31 - 25
src/lua_graph.c

@@ -16,26 +16,15 @@ static LSUP_Graph **allocate_graph (lua_State *L)
 
 static int l_graph_new (lua_State *L)
 {
-    const LSUP_StoreType store_type = lua_tointeger (L, 1);
+    LSUP_Store *store;  // TODO This might be const. Check LSUP_rdf.
+
+    if (!lua_isnoneornil (L, 1))
+        store = *(LSUP_Store **)luaL_checkudata (L, 1, "LSUP.Store");
+    else store = NULL;
     const char *uri_str = lua_tostring (L, 2);
 
     LSUP_Graph **gp = allocate_graph (L);
 
-    LSUP_Store *store = NULL;
-    if (store_type) {
-        const LSUP_StoreInt *sif = LSUP_store_int (store_type);
-        if (UNLIKELY (!sif)) return luaL_error (
-                L, "No interface defined for store type: %d.", store_type);
-
-        // TODO Move store creation fn and handle into a separate module.
-        store = LSUP_store_new (store_type, NULL, 0);
-        // Set up the store if a function for that is defined.
-        if (sif->setup_fn) {
-            if (sif->setup_fn(NULL, false) < LSUP_OK)
-                return luaL_error (L, "Error initializing back end store.");
-        }
-    }
-
     // TODO Make store ID, nsm and initial size accessible.
     *gp = LSUP_graph_new (store, uri_str, NULL);
     LUA_NLCHECK (*gp, "Error creating graph.");
@@ -167,22 +156,27 @@ static int l_graph_add (lua_State *L)
 
 static int graph_iter_next (lua_State *L)
 {
-    LSUP_GraphIterator *it =
-        *(LSUP_GraphIterator **)lua_touserdata (L, lua_upvalueindex (1));
+    LSUP_GraphIterator **it_p = lua_touserdata (L, lua_upvalueindex (1));
 
     LSUP_Triple **spo_p = lua_newuserdatauv (L, sizeof (*spo_p), 1);
     luaL_getmetatable (L, "LSUP.Triple");
     lua_setmetatable (L, -2);
     *spo_p = NULL;
 
-    LSUP_rc rc = LSUP_graph_iter_next (it, spo_p);
+    LSUP_rc rc = LSUP_graph_iter_next (*it_p, spo_p);
 
-    if (rc == LSUP_END) {
-        lua_pushnil (L);
-        lua_pushstring (L, "End of lookup results.");
-        return 2;
+    if (rc != LSUP_OK) {
+        LSUP_graph_iter_free (*it_p);
+        *it_p = NULL;
+
+        if (rc == LSUP_END) {
+            lua_pushnil (L);
+            lua_pushstring (L, "End of lookup results.");
+            return 2;
+        }
+
+        LUA_PCHECK (rc, "Error retrieving a lookup result.");
     }
-    LUA_PCHECK (rc, "Error retrieving a lookup result.");
 
     return 1;
 }
@@ -216,11 +210,22 @@ static int l_graph_lookup (lua_State *L)
 }
 
 
+/** @brief Free an iterator handle.
+ *
+ * This is only called if the iterator is abandoned before the
+ * iteration cycle is over (either by end of loop or error).
+ *
+ * @note A new iterator should not be started without first garbage-collecting
+ * an incomplete one. That would cause a MDB_BAD_RSLOT error on an LMDB-backed
+ * graph, because it attempts to open a new read transaction while the old
+ * iterator is keeping the old one open.
+ */
 static int graph_iter_gc (lua_State *L)
 {
     LSUP_GraphIterator **it_p = lua_touserdata (L, 1);
 
-    if (UNLIKELY (!it_p || *it_p)) return 0;
+    if (UNLIKELY (!it_p || !*it_p)) return 0;
+    LOG_DEBUG ("Garbage collecting iterator @%p", it_p);
 
     LSUP_graph_iter_free (*it_p);
     *it_p = NULL;
@@ -240,6 +245,7 @@ static int l_graph_connections (lua_State *L)
 
     LSUP_LinkMap **lm_p = lua_newuserdata (L, sizeof *lm_p);
     *lm_p = LSUP_graph_connections (gr, t, type);
+    LUA_NLCHECK (*lm_p, "Error creating Link map.");
     luaL_getmetatable (L, "LSUP.LinkMap");
     lua_setmetatable (L, -2);
 

+ 1 - 1
src/lua_namespace.c

@@ -15,7 +15,7 @@ int l_nsmap_new (lua_State *L)
     lua_setmetatable (L, -2);
 
     *nsm_p = LSUP_nsmap_new ();
-    if (!*nsm_p) return luaL_error (L, "Error while creating a term!");
+    if (!*nsm_p) return luaL_error (L, "Error while creating namespace map.");
 
     return 1;
 }

+ 71 - 0
src/lua_store.c

@@ -0,0 +1,71 @@
+#include "lua_lsup.h"
+
+
+static int l_store_new (lua_State *L)
+{
+    const LSUP_StoreType store_type = luaL_checkinteger (L, 1);
+    const char *id = luaL_optstring (L, 2, NULL);
+    const bool clear = lua_toboolean (L, 3);
+
+    LSUP_Store **store_p = lua_newuserdatauv (L, sizeof (*store_p), 1);
+    luaL_getmetatable (L, "LSUP.Store");
+    lua_setmetatable (L, -2);
+
+    const LSUP_StoreInt *sif = LSUP_store_int (store_type);
+    if (UNLIKELY (!sif)) return luaL_error (
+            L, "No interface defined for store type: %d.", store_type);
+
+    if (clear) LOG_DEBUG("Clearing old store.");
+    *store_p = LSUP_store_new (store_type, id, 0);
+    if (!*store_p) return luaL_error (L, "Error creating back end store.");
+
+    // Set up the store if a function for that is defined.
+    if (sif->setup_fn && sif->setup_fn (id, clear) < LSUP_OK)
+        return luaL_error (L, "Error initializing back end store.");
+
+    return 1;
+}
+
+
+static int store_gc (lua_State *L)
+{
+    LSUP_Store **sp = luaL_checkudata(L, 1, "LSUP.Store");
+
+    LSUP_store_free (*sp);
+    *sp = NULL;
+
+    return 0;
+}
+
+
+// TODO add transaction handling.
+
+
+static const luaL_Reg store_lib_fn [] = {
+    {"new", l_store_new},
+    {NULL}
+};
+
+
+static const LEnumConst store_enums[] = {
+    {"HTABLE", LSUP_STORE_HTABLE},
+    {"MDB", LSUP_STORE_MDB},
+
+    {NULL, 0}
+};
+
+
+int luaopen_lsup_store (lua_State *L)
+{
+    LSUP_init();  // This is idempotent: no problem calling it multiple times.
+    luaL_newmetatable (L, "LSUP.Store");
+    lua_pushvalue (L, -1);
+    lua_setfield (L, -2, "__index");
+    lua_pushcfunction (L, store_gc);
+    lua_setfield (L, -2, "__gc");
+
+    luaL_newlib (L, store_lib_fn);
+    push_int_const (L, store_enums);
+
+    return 1;
+}

+ 1 - 0
src/lua_term.c

@@ -433,6 +433,7 @@ static int l_lmap_iter_init (lua_State *L)
     LSUP_LinkMapIterator **lmit_p =
         (LSUP_LinkMapIterator  **)lua_newuserdata (L, sizeof *lmit_p);
     *lmit_p = LSUP_link_map_iter_new (lm);
+    LUA_NLCHECK (*lmit_p, "Error creating Link map iterator.");
     luaL_getmetatable (L, "LSUP.LMapIterator");
     lua_setmetatable (L, -2);