MINOR: hlua_fcn: implement index and pair metamethods for patref class

patref object may now leverage index and pair methamethods to list and
access patref elements at a specific index (=key)

Also, patref:is_map() method may be used to know if the patref stores acl
(key only) or map-style (key:value) patterns.
This commit is contained in:
Aurelien DARRAGON 2024-11-19 12:01:51 +01:00
parent 31784efad2
commit 2021072391
3 changed files with 162 additions and 2 deletions

View File

@ -3434,7 +3434,15 @@ Patref class
(reference) which often is a filename, unless it is prefixed by 'virt@'
for virtual references or 'opt@' for references that don't necessarily
point to real file. From Lua, :ref:`patref_class` object may be used to
directly manipulate existing pattern reference storage.
directly manipulate existing pattern reference storage. For convenience,
Patref objects may be directly accessed and listed as a table thanks to
index and pairs metamethods. Note however that for the index metamethod,
in case of duplicated entries, only the first matching entry is returned.
.. Warning::
Not meant to be shared bewteen multiple contexts. If multiple contexts
need to work on the same pattern reference, each context should have
its own patref object.
Patref object is obtained using the :js:func:`core.get_patref()`
function
@ -3443,6 +3451,11 @@ Patref class
:returns: the name of the pattern reference object.
.. js:function:: Patref.is_map(ref)
:returns: true if the pattern reference is used to handle maps instead
of acl, false otherwise.
.. _applethttp_class:
AppletHTTP class

View File

@ -234,6 +234,12 @@ struct hlua_server_list_iterator_context {
struct proxy *px;
};
struct hlua_patref_iterator_context {
struct pat_ref *ref;
struct bref bref; /* back-reference from the pat_ref_elt being accessed
* during listing */
};
#else /* USE_LUA */
/************************ For use when Lua is disabled ********************/

View File

@ -29,7 +29,7 @@
#include <haproxy/hlua_fcn.h>
#include <haproxy/http.h>
#include <haproxy/net_helper.h>
#include <haproxy/pattern-t.h>
#include <haproxy/pattern.h>
#include <haproxy/protocol.h>
#include <haproxy/proxy.h>
#include <haproxy/regex.h>
@ -2629,6 +2629,17 @@ int hlua_patref_get_name(lua_State *L)
return 1;
}
int hlua_patref_is_map(lua_State *L)
{
struct pat_ref *ref;
ref = hlua_checkudata(L, 1, class_patref_ref);
BUG_ON(!ref);
lua_pushboolean(L, !!(ref->flags & PAT_REF_MAP));
return 1;
}
void hlua_fcn_new_patref(lua_State *L, struct pat_ref *ref)
{
lua_newtable(L);
@ -2646,6 +2657,133 @@ void hlua_fcn_new_patref(lua_State *L, struct pat_ref *ref)
/* set public methods */
hlua_class_function(L, "get_name", hlua_patref_get_name);
hlua_class_function(L, "is_map", hlua_patref_is_map);
}
int hlua_listable_patref_newindex(lua_State *L) {
/* not yet supported */
return 0;
}
/* first arg is the pat_ref
* second arg is the required index, in case of duplicate, only the
* first matching entry is returned.
*/
int hlua_listable_patref_index(lua_State *L)
{
struct pat_ref *ref;
const char *key;
struct pat_ref_elt *elt;
ref = hlua_checkudata(L, 1, class_patref_ref);
key = luaL_checkstring(L, 2);
/* Perform pat ref element lookup by key */
HA_RWLOCK_WRLOCK(PATREF_LOCK, &ref->lock);
elt = pat_ref_find_elt(ref, key);
if (elt == NULL) {
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->lock);
lua_pushnil(L);
return 1;
}
if (elt->sample)
lua_pushstring(L, elt->sample);
else
lua_pushboolean(L, 1); // acl: just push true to tell that the key exists
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->lock);
return 1;
}
static int _hlua_listable_patref_pairs_iterator(lua_State *L, int status, lua_KContext ctx)
{
int context_index;
struct hlua_patref_iterator_context *hctx;
struct pat_ref_elt *elt;
int cnt = 0;
context_index = lua_upvalueindex(1);
hctx = lua_touserdata(L, context_index);
HA_RWLOCK_WRLOCK(PATREF_LOCK, &hctx->ref->lock);
if (LIST_ISEMPTY(&hctx->bref.users)) {
/* first iteration */
hctx->bref.ref = hctx->ref->head.n;
}
else
LIST_DEL_INIT(&hctx->bref.users); // drop back ref from previous iteration
next:
/* reached end of list? */
if (hctx->bref.ref == &hctx->ref->head) {
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &hctx->ref->lock);
lua_pushnil(L);
return 1;
}
elt = LIST_ELEM(hctx->bref.ref, struct pat_ref_elt *, list);
if (elt->gen_id != hctx->ref->curr_gen) {
/* 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 (cnt > 10000 && hlua_gethlua(L)) {
/* let's yield and wait for being called again to continue where we left off */
LIST_APPEND(&elt->back_refs, &hctx->bref.users);
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &hctx->ref->lock);
hlua_yieldk(L, 0, 0, _hlua_listable_patref_pairs_iterator, TICK_ETERNITY, HLUA_CTRLYIELD); // continue
return 0; // not reached
}
hctx->bref.ref = elt->list.n;
cnt++;
goto next;
}
LIST_APPEND(&elt->back_refs, &hctx->bref.users);
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &hctx->ref->lock);
hctx->bref.ref = elt->list.n;
lua_pushstring(L, elt->pattern);
if (elt->sample)
lua_pushstring(L, elt->sample);
else
return 1;
return 2;
}
/* iterator must return key as string and value as patref
* element value (as string), if we reach end of list, it
* returns nil. The context knows the last returned patref's
* value. if the context contains patref_elem == NULL, we
* start enumeration. We use pat_ref element iterator logic
* to iterate through the list.
*/
int hlua_listable_patref_pairs_iterator(lua_State *L)
{
return _hlua_listable_patref_pairs_iterator(L, LUA_OK, 0);
}
/* init the iterator context, return iterator function
* with context as closure. The only argument is a
* patref list object.
*/
int hlua_listable_patref_pairs(lua_State *L)
{
struct hlua_patref_iterator_context *ctx;
struct pat_ref *ref;
ref = hlua_checkudata(L, 1, class_patref_ref);
ctx = lua_newuserdata(L, sizeof(*ctx));
ctx->ref = ref;
LIST_INIT(&ctx->bref.users);
lua_pushcclosure(L, hlua_listable_patref_pairs_iterator, 1);
return 1;
}
void hlua_fcn_reg_core_fcn(lua_State *L)
@ -2708,6 +2846,9 @@ void hlua_fcn_reg_core_fcn(lua_State *L)
/* Create patref object. */
lua_newtable(L);
hlua_class_function(L, "__index", hlua_listable_patref_index);
hlua_class_function(L, "__newindex", hlua_listable_patref_newindex);
hlua_class_function(L, "__pairs", hlua_listable_patref_pairs);
class_patref_ref = hlua_register_metatable(L, CLASS_PATREF);
/* Create server object. */