|
@@ -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);
|
|
|
|