From 884dc6232ad821748d4358443202fef03f688d4c Mon Sep 17 00:00:00 2001 From: Aurelien DARRAGON Date: Tue, 26 Nov 2024 13:03:23 +0100 Subject: [PATCH] MINOR: hlua_fcn: add Patref:add_bulk() There is no cli equivalent for this one. It is similar to Patref:add() excepts thay it takes a table as parameter (for acl: table of keys, for maps: table of keys:values). The goal is to add multiple entries at once to limit locking time to the strict minimum. It is recommended to use this one over Patref:add() when adding multiple entries at once. --- doc/lua-api/index.rst | 16 +++++++++ src/hlua_fcn.c | 75 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/doc/lua-api/index.rst b/doc/lua-api/index.rst index 58a0088a2..74953b8a4 100644 --- a/doc/lua-api/index.rst +++ b/doc/lua-api/index.rst @@ -3498,6 +3498,22 @@ Patref class Affects the live pattern reference version, unless :js:func:`Patref.prepare()` was called and is still ongoing (waiting for commit or giveup) +.. js:function:: patref.add_bulk(ref, table) + + Adds multiple entries at once to the Pattern reference. It is recommended + to use this one over :js:func:`Patref.prepare()` to add a lot of entries + at once because this one is more efficient. + + :param table table: For ACL, a table of keys strings: t[0] = "key1", + t[1] = "key2"... + + For Maps, a table of key:value string pairs: t["key"] = "value" + :returns: true on success and nil on failure (followed by an error message). + + .. Note:: + Affects the live pattern reference version, unless :js:func:`Patref.prepare()` + was called and is still pending (waiting for commit or giveup) + .. js:function:: Patref.del(ref, key) Delete all entries matching the input key in the pattern reference. In diff --git a/src/hlua_fcn.c b/src/hlua_fcn.c index 6c9209df9..9b82f2964 100644 --- a/src/hlua_fcn.c +++ b/src/hlua_fcn.c @@ -2773,6 +2773,80 @@ int hlua_patref_add(lua_State *L) return 1; } +/* re-entrant helper, expects table of string as second argument on the stack */ +static int _hlua_patref_add_bulk(lua_State *L, int status, lua_KContext ctx) +{ + struct hlua_patref *ref = hlua_checkudata(L, 1, class_patref_ref); + char *errmsg; + unsigned int curr_gen; + int count = 0; + int ret; + + if ((ref->flags & HLUA_PATREF_FL_GEN) && + pat_ref_may_commit(ref->ptr, ref->curr_gen)) + curr_gen = ref->curr_gen; + else + curr_gen = ref->ptr->curr_gen; + + HA_RWLOCK_WRLOCK(PATREF_LOCK, &ref->ptr->lock); + + while (lua_next(L, 2) != 0) { + const char *key; + const char *value = NULL; + + /* check if we may do something to try to prevent thread contention, + * unless we run from body/init state where hlua_yieldk is no-op + */ + if (count > 100 && hlua_gethlua(L)) { + /* let's yield and wait for being called again to continue where we left off */ + HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->ptr->lock); + hlua_yieldk(L, 0, 0, _hlua_patref_add_bulk, TICK_ETERNITY, HLUA_CTRLYIELD); // continue + return 0; // not reached + + } + + if (ref->ptr->flags & PAT_REF_SMP) { + /* key:val table */ + luaL_checktype(L, -2, LUA_TSTRING); + key = lua_tostring(L, -2); + luaL_checktype(L, -1, LUA_TSTRING); + value = lua_tostring(L, -1); + } + else { + /* key-only table, use value as key */ + luaL_checktype(L, -1, LUA_TSTRING); + key = lua_tostring(L, -1); + } + + if (!pat_ref_load(ref->ptr, curr_gen, key, value, -1, &errmsg)) { + HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->ptr->lock); + ret = hlua_error(L, errmsg); + ha_free(&errmsg); + return ret; + } + + + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(L, 1); + count += 1; + } + HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->ptr->lock); + lua_pushboolean(L, 1); + return 1; +} +int hlua_patref_add_bulk(lua_State *L) +{ + struct hlua_patref *ref; + + ref = hlua_checkudata(L, 1, class_patref_ref); + + BUG_ON(!ref); + + /* table is in the stack at index 't' */ + lua_pushnil(L); /* first key */ + return _hlua_patref_add_bulk(L, LUA_OK, 0); +} + int hlua_patref_del(lua_State *L) { struct hlua_patref *ref; @@ -2879,6 +2953,7 @@ void hlua_fcn_new_patref(lua_State *L, struct pat_ref *ref) hlua_class_function(L, "giveup", hlua_patref_giveup); hlua_class_function(L, "purge", hlua_patref_purge); hlua_class_function(L, "add", hlua_patref_add); + hlua_class_function(L, "add_bulk", hlua_patref_add_bulk); hlua_class_function(L, "del", hlua_patref_del); hlua_class_function(L, "set", hlua_patref_set); }