[tarantool-patches] Re: [PATCH 3/4] tuple: use global msgpack serializer in Lua tuple
Vladislav Shpilevoy
v.shpilevoy at tarantool.org
Sun Sep 8 18:02:13 MSK 2019
Kostja proposed to use triggers instead of a version
number. Here is a new commit:
diff --git a/src/box/lua/tuple.c b/src/box/lua/tuple.c
index 3902288bf..b9ea63350 100644
--- a/src/box/lua/tuple.c
+++ b/src/box/lua/tuple.c
@@ -58,6 +58,11 @@
static const char *tuplelib_name = "box.tuple";
static const char *tuple_iteratorlib_name = "box.tuple.iterator";
+/*
+ * Special serializer for box.tuple.new() to disable storage
+ * optimization for excessively sparse arrays as a tuple always
+ * must be regular MP_ARRAY.
+ */
static struct luaL_serializer tuple_serializer;
extern char tuple_lua[]; /* Lua source */
@@ -548,6 +553,21 @@ static const struct luaL_Reg lbox_tuple_iterator_meta[] = {
/* }}} */
+static inline void
+tuple_serializer_fill(void)
+{
+ luaL_serializer_copy_options(&tuple_serializer, luaL_msgpack_default);
+ tuple_serializer.encode_sparse_ratio = 0;
+}
+
+static void
+on_msgpack_serializer_update(struct trigger *trigger, void *event)
+{
+ (void) trigger;
+ (void) event;
+ tuple_serializer_fill();
+}
+
void
box_lua_tuple_init(struct lua_State *L)
{
@@ -564,14 +584,11 @@ box_lua_tuple_init(struct lua_State *L)
luamp_set_encode_extension(luamp_encode_extension_box);
- /*
- * Create special serializer for box.tuple.new().
- * Disable storage optimization for excessively
- * sparse arrays as a tuple always must be regular
- * MP_ARRAY.
- */
- luaL_serializer_create(&tuple_serializer);
- tuple_serializer.encode_sparse_ratio = 0;
+ tuple_serializer_fill();
+ trigger_create(&tuple_serializer.on_update_up,
+ on_msgpack_serializer_update, NULL, NULL);
+ trigger_add(&luaL_msgpack_default->on_update_down,
+ &tuple_serializer.on_update_up);
/* Get CTypeID for `struct tuple' */
int rc = luaL_cdef(L, "struct tuple;");
diff --git a/src/lua/utils.c b/src/lua/utils.c
index a082a2e5b..fa33d5eba 100644
--- a/src/lua/utils.c
+++ b/src/lua/utils.c
@@ -251,12 +251,20 @@ static struct {
void
luaL_serializer_create(struct luaL_serializer *cfg)
{
+ rlist_create(&cfg->on_update_down);
for (int i = 0; OPTIONS[i].name != NULL; i++) {
int *pval = (int *) ((char *) cfg + OPTIONS[i].offset);
*pval = OPTIONS[i].defvalue;
}
}
+void
+luaL_serializer_copy_options(struct luaL_serializer *dst,
+ const struct luaL_serializer *src)
+{
+ memcpy(dst, src, offsetof(struct luaL_serializer, end_of_options));
+}
+
/**
* Configure one field in @a cfg.
* @param L Lua stack.
@@ -319,6 +327,7 @@ luaL_serializer_cfg(struct lua_State *L)
else
lua_setfield(L, 1, OPTIONS[i].name);
}
+ trigger_run(&cfg->on_update_down, cfg);
return 0;
}
@@ -342,7 +351,7 @@ luaL_newserializer(struct lua_State *L, const char *modname, const luaL_Reg *reg
lua_newuserdata(L, sizeof(*serializer));
luaL_getmetatable(L, LUAL_SERIALIZER);
lua_setmetatable(L, -2);
- memset(serializer, 0, sizeof(*serializer));
+ luaL_serializer_create(serializer);
for (; reg->name != NULL; reg++) {
/* push luaL_serializer as upvalue */
@@ -362,7 +371,6 @@ luaL_newserializer(struct lua_State *L, const char *modname, const luaL_Reg *reg
/* Save configuration values to serializer.cfg */
for (int i = 0; OPTIONS[i].name != NULL; i++) {
int *pval = (int *) ((char *) serializer + OPTIONS[i].offset);
- *pval = OPTIONS[i].defvalue;
switch (OPTIONS[i].type) {
case LUA_TBOOLEAN:
lua_pushboolean(L, *pval);
diff --git a/src/lua/utils.h b/src/lua/utils.h
index d42cc3992..4c10a0a8f 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -36,6 +36,7 @@
#include <math.h> /* modf, isfinite */
#include <msgpuck.h> /* enum mp_type */
+#include "trigger.h"
#if defined(__cplusplus)
extern "C" {
@@ -242,6 +243,23 @@ struct luaL_serializer {
/** Enable support for compact represenation (internal, YAML-only). */
int has_compact;
+ /**
+ * Border where copyable fields end. Is used to copy
+ * serializer options into an existing serializer without
+ * erasure of its non-option fields like triggers.
+ */
+ char end_of_options[0];
+ /**
+ * Trigger object to subscribe on updates of a more
+ * general serializer. For example, tuple serializer
+ * subscribes on msgpack.
+ */
+ struct trigger on_update_up;
+ /**
+ * List of triggers on update of this serializer. To push
+ * updates down to dependent serializers.
+ */
+ struct rlist on_update_down;
};
extern int luaL_nil_ref;
@@ -254,6 +272,14 @@ extern int luaL_array_metatable_ref;
struct luaL_serializer *
luaL_newserializer(struct lua_State *L, const char *modname, const luaL_Reg *reg);
+/**
+ * Copy all option fields of @a src into @a dst. Other fields,
+ * such as triggers, are not touched.
+ */
+void
+luaL_serializer_copy_options(struct luaL_serializer *dst,
+ const struct luaL_serializer *src);
+
static inline struct luaL_serializer *
luaL_checkserializer(struct lua_State *L) {
return (struct luaL_serializer *)
diff --git a/test/box/tuple.result b/test/box/tuple.result
index 895462518..83f74d111 100644
--- a/test/box/tuple.result
+++ b/test/box/tuple.result
@@ -1395,3 +1395,49 @@ d:update{{'-', 1, dec.new('1e37')}}
---
- [80000000000000000000000000000000000000]
...
+--
+-- gh-4434: tuple should use global msgpack serializer.
+--
+max_depth = msgpack.cfg.encode_max_depth
+---
+...
+t = nil
+---
+...
+for i = 1, max_depth + 5 do t = {t} end
+---
+...
+tuple = box.tuple.new(t):totable()
+---
+...
+level = 0
+---
+...
+while tuple ~= nil do level = level + 1 tuple = tuple[1] end
+---
+...
+level == max_depth or {level, max_depth}
+---
+- true
+...
+msgpack.cfg({encode_max_depth = max_depth + 5})
+---
+...
+tuple = box.tuple.new(t):totable()
+---
+...
+level = 0
+---
+...
+while tuple ~= nil do level = level + 1 tuple = tuple[1] end
+---
+...
+-- Level should be bigger now, because the default msgpack
+-- serializer allows deeper tables.
+level == max_depth + 5 or {level, max_depth}
+---
+- true
+...
+msgpack.cfg({encode_max_depth = max_depth})
+---
+...
diff --git a/test/box/tuple.test.lua b/test/box/tuple.test.lua
index 9762fc8b3..c8a0c03c5 100644
--- a/test/box/tuple.test.lua
+++ b/test/box/tuple.test.lua
@@ -473,3 +473,24 @@ d = box.tuple.new(dec.new('9e37'))
d
d:update{{'+', 1, dec.new('1e37')}}
d:update{{'-', 1, dec.new('1e37')}}
+
+--
+-- gh-4434: tuple should use global msgpack serializer.
+--
+max_depth = msgpack.cfg.encode_max_depth
+t = nil
+for i = 1, max_depth + 5 do t = {t} end
+tuple = box.tuple.new(t):totable()
+level = 0
+while tuple ~= nil do level = level + 1 tuple = tuple[1] end
+level == max_depth or {level, max_depth}
+
+msgpack.cfg({encode_max_depth = max_depth + 5})
+tuple = box.tuple.new(t):totable()
+level = 0
+while tuple ~= nil do level = level + 1 tuple = tuple[1] end
+-- Level should be bigger now, because the default msgpack
+-- serializer allows deeper tables.
+level == max_depth + 5 or {level, max_depth}
+
+msgpack.cfg({encode_max_depth = max_depth})
diff --git a/test/unit/luaT_tuple_new.c b/test/unit/luaT_tuple_new.c
index 609d64e45..8f25c8e07 100644
--- a/test/unit/luaT_tuple_new.c
+++ b/test/unit/luaT_tuple_new.c
@@ -170,8 +170,8 @@ main()
luaL_openlibs(L);
box_init();
- box_lua_tuple_init(L);
luaopen_msgpack(L);
+ box_lua_tuple_init(L);
lua_pop(L, 1);
return test_basic(L);
More information about the Tarantool-patches
mailing list