]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: hlua_fcn: add Patref:add_bulk()
authorAurelien DARRAGON <adarragon@haproxy.com>
Tue, 26 Nov 2024 12:03:23 +0000 (13:03 +0100)
committerAurelien DARRAGON <adarragon@haproxy.com>
Fri, 29 Nov 2024 06:23:48 +0000 (07:23 +0100)
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
src/hlua_fcn.c

index 58a0088a22fcfcddd2edc376a29e3ae11f5ead1f..74953b8a49f5801a55b39742c5117804de9de58d 100644 (file)
@@ -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
index 6c9209df9357f8778f464a0f7dd4bdbb1d465c6e..9b82f29645006d6ad4fe48979846361f7e0e289c 100644 (file)
@@ -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);
 }