I rethought the problem and ended up implementing a memorize function:
static int l_store_new (lua_State *L)
{
const VOLK_StoreType store_type = luaL_checkinteger (L, 1);
if (VOLK_store_int (store_type)->features & VOLK_STORE_EMBED)
luaL_error (
L, "Explicitly creating an embedded store is not allowed.",
2);
const char *id = luaL_optstring (L, 2, NULL);
const bool clear = lua_toboolean (L, 3);
const char *reg_key = lua_pushfstring (
L, "VOLK_store-%d-%s", store_type, id ? id : "default");
int check_type = lua_rawgetp (L, LUA_REGISTRYINDEX, reg_key);
// if check_type is not nil, the store userdata is now on top of
the stack.
if (check_type == LUA_TNIL) {
VOLK_Store **store_p = lua_newuserdatauv (L, sizeof (*store_p), 0);
luaL_setmetatable (L, "VOLK.Store");
lua_rawsetp (L, LUA_REGISTRYINDEX, reg_key);
if (clear) log_info ("Clearing old store.");
*store_p = VOLK_store_new (store_type, id, 0, clear);
LUA_NLCHECK (*store_p, "Error creating back end store.");
LOG_DEBUG ("Created first instance of store %s @%p", reg_key,
store_p);
} else LOG_DEBUG (
"Reusing store handle %s @%p",
reg_key, lua_topointer (L, -1));
return 1;
}
The changes were minimal and only to the new() function, no ref counting
or new tables needed, no changes to the finalizer.
The DB handle is tiny and used all throughout the library, and there
shouldn't be many variations of it in a normal application, so I don't
mind leaving it indefinitely until the program closes.
This seems to work as expected:
$ luap
Lua 5.4.8 Copyright (C) 1994-2025 Lua.org, PUC-Rio
luap 0.9 Copyright (C) 2012-2023 Dimitris Papavasiliou, Boris Nagaev
> store = require "volksdata.store"
> s1 =
store.new(store.T_MDB)
10:37:48 INFO src/store_mdb.c:218: `VOLK_MDB_STORE_URN' environment
variable is not set. The default URN file:///tmp/mdb_store has been set
as the store ID.
10:37:48 INFO src/store_mdb.c:375: Created environment at /tmp/mdb_store
10:37:48 DEBUG src/lua_store.c:46: Created first instance of store
VOLK_store-1-default @0x5e7b60f2af00
> s2 =
store.new(store.T_MDB)
10:37:52 DEBUG src/lua_store.c:48: Reusing store handle
VOLK_store-1-default @0x5e7b60f2af00
> s3 =
store.new(store.T_MDB, "file:///tmp/alt_store")
10:38:12 INFO src/store_mdb.c:375: Created environment at /tmp/alt_store
10:38:12 DEBUG src/lua_store.c:46: Created first instance of store
VOLK_store-1-file:///tmp/alt_store @0x5e7b61231a90
> s4 =
store.new(store.T_MDB, "file:///tmp/alt_store")
10:38:20 DEBUG src/lua_store.c:48: Reusing store handle
VOLK_store-1-file:///tmp/alt_store @0x5e7b61231a90
> <CTRL-D>
10:38:22 DEBUG src/lua_store.c:69: Garbage collecting store @0x5e7b61231ac0.
10:38:22 DEBUG src/store.c:72: Freeing store @0x5e7b61231ac0
10:38:22 INFO src/store_mdb.c:394: Closing MDB env at /tmp/alt_store.
10:38:22 DEBUG src/lua_store.c:69: Garbage collecting store @0x5e7b60f2afc0.
10:38:22 DEBUG src/store.c:72: Freeing store @0x5e7b60f2afc0
10:38:22 INFO src/store_mdb.c:394: Closing MDB env at /tmp/mdb_store.
Thanks for all the hints! Happy New Year!
s