[tarantool-patches] Re: [PATCH v1 1/1] lua: export key_def methods for LUA key_def object
Alexander Turenko
alexander.turenko at tarantool.org
Tue Mar 26 04:46:25 MSK 2019
You don't include the fixup commit, so I'll paste it here and comment:
> diff --git a/src/box/lua/key_def.c b/src/box/lua/key_def.c
> index 36c469526..f819bfed9 100644
> --- a/src/box/lua/key_def.c
> +++ b/src/box/lua/key_def.c
> @@ -33,6 +33,7 @@
>
> #include <lua.h>
> #include <lauxlib.h>
> +#include "fiber.h"
> #include "diag.h"
> #include "box/key_def.h"
> #include "box/box.h"
> @@ -94,11 +95,11 @@ luaT_key_def_set_part(struct lua_State *L, struct key_part_def *part)
> /* Set part->is_nullable and part->nullable_action. */
> lua_pushstring(L, "is_nullable");
> lua_gettable(L, -2);
> - if (lua_isnil(L, -1)) {
> + if (lua_isnil(L, -1) || lua_toboolean(L, -1) == false) {
lua_toboolean() returns int, so it would be better to compare it with 0
explicitly. BTW, nice catch.
> part->is_nullable = false;
> part->nullable_action = ON_CONFLICT_ACTION_DEFAULT;
> } else {
> - part->is_nullable = lua_toboolean(L, -1);
> + part->is_nullable = true;
> part->nullable_action = ON_CONFLICT_ACTION_NONE;
> }
> lua_pop(L, 1);
> @@ -143,9 +144,29 @@ luaT_key_def_set_part(struct lua_State *L, struct key_part_def *part)
> /* Set part->sort_order. */
> part->sort_order = SORT_ORDER_ASC;
>
> - /* Set part->path. */
> - part->path = NULL;
> -
> + /* Set part->path for JSON index. */
> + lua_pushstring(L, "path");
> + lua_gettable(L, -2);
> + if (!lua_isnil(L, -1)) {
> + size_t path_len;
> + const char *path = lua_tolstring(L, -1, &path_len);
> + if (json_path_validate(path, path_len, TUPLE_INDEX_BASE) != 0) {
> + diag_set(ClientError, ER_WRONG_INDEX_OPTIONS,
> + 0 /* FIXME */ + TUPLE_INDEX_BASE, "invalid path");
FIXME?
> + return -1;
> + }
> + char *tmp = region_alloc(&fiber()->gc, path_len + 1);
Should we do region_used() in lbox_key_def_new() before the loop and do
region_truncate() after?
Even more, I guess we can don't copy strings here at all: lua will not
collect them until we'll return from key_def.new() and it is enough.
> + if (tmp == NULL) {
> + diag_set(OutOfMemory, path_len + 1, "region", "path");
> + return -1;
> + }
> + memcpy(tmp, path, path_len);
> + tmp[path_len] = '\0';
> + part->path = tmp;
> + } else {
> + part->path = NULL;
> + }
> + lua_pop(L, 1);
> return 0;
> }
On Mon, Mar 25, 2019 at 03:27:41PM +0300, Kirill Shcherbatov wrote:
> Functions extract_key, compare, compare_with_key, merge defined
> for key_def introduced for LUA key_def object.
>
> Close #4025
See also a list of issues from mine patch, they are closed with this
patchset too.
> +void
> +lbox_fill_key_part(struct lua_State *L, const struct key_part *part)
Such functions are usually named lbox_pushfoo(), in this case I propose
lbox_push_key_part().
> +static int
> +lbox_key_def_extract_key(lua_State *L)
> +{
> + struct key_def *key_def;
> + struct tuple *tuple;
> + if (lua_gettop(L) != 2 || (key_def = check_key_def(L, 1)) == NULL ||
> + (tuple = luaT_istuple(L, 2)) == NULL)
> + return luaL_error(L, "Usage key_def:extract_key(tuple)");
Nit: Add a colon after 'Usage' (here and below).
> +static int
> +lbox_key_def_compare_with_key(lua_State *L)
> +{
> + struct key_def *key_def;
> + struct tuple *tuple, *key_tuple;
> + if (lua_gettop(L) != 3 || (key_def = check_key_def(L, 1)) == NULL ||
> + (tuple = luaT_istuple(L, 2)) == NULL)
> + goto usage_error;
> +
> + lua_remove(L, 1);
> + lua_remove(L, 1);
> + if (luaT_tuple_new(L, box_tuple_format_default()) != 1 ||
Maybe extract
https://github.com/tarantool/tarantool/commit/6427413d27dad7cdaaff46a5705ad45b93549275
too and use it here (it is part of Totktonada/gh-3276-on-board-merger patchset?
> +static int
> +lbox_key_def_merge(lua_State *L)
> +{
> + struct key_def *key_def_a, *key_def_b;
> + if (lua_gettop(L) != 2 || (key_def_a = check_key_def(L, 1)) == NULL ||
> + (key_def_b = check_key_def(L, 2)) == NULL)
> + return luaL_error(L, "Usage key_def:merge(second_key_def)");
> +
> + struct key_def *new_key_def = key_def_merge(key_def_a, key_def_b);
> + if (new_key_def == NULL)
> + return luaT_error(L);
> +
> + *(struct key_def **)luaL_pushcdata(L, key_def_type_id) = new_key_def;
Nit: add a whitespace after cast.
> + lua_pushcfunction(L, lbox_key_def_gc);
> + luaL_setcdatagc(L, -2);
> + return 1;
> +}
> +
> +static int
> +lbox_key_def_to_map(struct lua_State *L)
Why tomap? It produce an array as result. Maybe lbox_key_def_to_table()? Or
maybe just lbox_key_def_serialize() like lbox_fiber_serialize() (and don't
expose it as :tomap() / :totable()).
> + lua_createtable(L, key_def->part_count, 0);
> + for (uint32_t i = 0; i < key_def->part_count; ++i) {
> + lua_pushnumber(L, i + 1);
> + lbox_fill_key_part(L, &key_def->parts[i]);
> + lua_settable(L, -3);
lua_rawgei() is more convenient here.
> +/**
> + * Prepare a new table representing a key_part on top of the Lua
> + * stack.
> + */
I would rephrase a bit:
> Push a new table representing a key_part to a Lua stack.
> +ffi.metatype(key_def_t, {
> + __index = function(self, key)
> + return methods[key]
> + end,
> + __tostring = function(key_def) return "<struct key_def&>" end,
Nit: add a whitespace before the ampersand.
> diff --git a/test/box/tuple.test.lua b/test/box/tuple.test.lua
> index 8030b0884..0a626b36a 100644
> --- a/test/box/tuple.test.lua
> +++ b/test/box/tuple.test.lua
There is test/box-tap/key_def.test.lua (introduced in the first path).
> @@ -416,3 +416,42 @@ s2:frommap({a="1", k="11"})
> s2:frommap({a="1", k="11"}):tomap({names_only = true})
>
> s2:drop()
> +
> +--
> +-- gh-4025: Introduce built-in function to get index key
> +-- from tuple.
> +--
> +key_def = require('key_def')
> +s = box.schema.space.create('test', {engine='vinyl'})
Why vinyl? I don't think we even need to create a space for this test.
> +pk = s:create_index('pk')
> +sk = s:create_index('sk', {unique=false, parts = {{2, 'number'}, {3, 'number'}}})
> +tuple_a = box.tuple.new({1, 1, 22})
> +tuple_b = box.tuple.new({2, 1, 11})
> +tuple_c = box.tuple.new({3, 1, 22})
> +pk_def = key_def.new(pk.parts)
> +pk_def:extract_key(tuple_a)
> +sk_def = key_def.new(sk.parts)
> +sk_def:extract_key(tuple_a)
> +s:insert(tuple_a)
> +s:insert(tuple_b)
> +for _, tuple in pairs(sk:select({1, nil})) do pk:delete(pk_def:extract_key(tuple)) end
> +s:select()
> +pk_def:compare(tuple_b, tuple_a)
> +pk_def:compare(tuple_b, tuple_c)
> +sk_def:compare(tuple_b, tuple_a)
> +sk_def:compare(tuple_a, tuple_c)
> +
> +pk_sk_def = pk_def:merge(sk_def)
> +pk_sk_def:extract_key(tuple_a)
> +pk_sk_def:compare(tuple_a, tuple_b)
> +sk_pk_def = sk_def:merge(pk_def)
> +sk_pk_def:extract_key(tuple_a)
> +sk_pk_def:compare(tuple_a, tuple_b)
> +
> +key = sk_def:extract_key(tuple_a)
> +sk_def:compare_with_key(tuple_a, key)
> +sk_def:compare_with_key(tuple_a, {1, 20})
> +sk_def:tomap()
> +sk_def
> +print(sk_def)
> +key_def.new(sk_def:tomap())
> --
> 2.21.0
>
More information about the Tarantool-patches
mailing list