[Tarantool-patches] [PATCH v3] net.box: allow to store user-defined fields in future object

Igor Munkin imun at tarantool.org
Sat Aug 14 14:17:00 MSK 2021


Vova,

Thanks for the fixes! LGTM, with some nits below.

On 13.08.21, Vladimir Davydov wrote:
> Before commit 954194a1ca5c ("net.box: rewrite request implementation in

Typo: AFAICS full hash has to be used to mention particular commits. I
failed to find this rule in the dev guide[1], but I've found that Cyrill
has recently added the example to Code review procedure in our Wiki[2]
(however, the command doesn't yield the full hash).

> C"), net.box future was a plain Lua table so that the caller could
> attach extra information to it. Now it isn't true anymore - a future is
> a userdata object, and it doesn't have indexing methods.
> 
> For backward compatibility, let's add __index and __newindex fields and
> store user-defined fields in a Lua table, which is created lazily on the
> first __newindex invocation. __index falls back on the metatable methods
> if a field isn't found in the table.
> 
> Follow-up #6241
> Closes #6306
> ---
> https://github.com/tarantool/tarantool/issues/6306
> https://github.com/tarantool/tarantool/tree/vdavydov/netbox-allow-to-store-user-data-in-future-using-lua-table
> 
> Changes in v3:
>  - Use Lua table instead of mhash for storing user data, as suggested
>    by imun at .
> 
> v2: https://lists.tarantool.org/pipermail/tarantool-patches/2021-August/025402.html
> 
>  src/box/lua/net_box.c                         |  51 ++++++++
>  test/box/net.box_fiber-async_gh-3107.result   | 109 +++++++++++++++++-
>  test/box/net.box_fiber-async_gh-3107.test.lua |  39 ++++++-
>  3 files changed, 191 insertions(+), 8 deletions(-)
> 
> diff --git a/src/box/lua/net_box.c b/src/box/lua/net_box.c
> index 229dec590cf9..078bbfb07b18 100644
> --- a/src/box/lua/net_box.c
> +++ b/src/box/lua/net_box.c

<snipped>

> @@ -1420,6 +1430,44 @@ luaT_netbox_request_gc(struct lua_State *L)
>  	return 0;
>  }
>  
> +static int
> +luaT_netbox_request_index(struct lua_State *L)
> +{
> +	struct netbox_request *request = luaT_check_netbox_request(L, 1);
> +	if (request->index_ref != LUA_NOREF) {
> +		lua_rawgeti(L, LUA_REGISTRYINDEX, request->index_ref);
> +		/* Push the key (2nd argument) to the top. */

Minor: It's worth to mention, why you don't use <lua_insert> here
instead (like you do in __newindex). The reason is to save the given key
for the fall back path. You can also add an assert, that coroutine stack
size at the end of this <if> block is the same as at its beginning.

> +		lua_pushvalue(L, 2);
> +		lua_rawget(L, -2);
> +		if (lua_type(L, -1) != LUA_TNIL)
> +			return 1;
> +		/* Pop nil and the index table. */
> +		lua_pop(L, 2);
> +	}
> +	/* Fall back on metatable methods. */
> +	lua_getmetatable(L, 1);
> +	/* Move the metatable before the key (2nd argument). */
> +	lua_insert(L, 2);
> +	lua_rawget(L, 2);
> +	return 1;
> +}
> +
> +static int
> +luaT_netbox_request_newindex(struct lua_State *L)
> +{
> +	struct netbox_request *request = luaT_check_netbox_request(L, 1);
> +	if (request->index_ref == LUA_NOREF) {

Minor: Looks like this condition is met only once. Will this place
perform better with UNLIKELY attribute?

> +		/* Lazily create the index table on the first invocation. */
> +		lua_newtable(L);
> +		request->index_ref = luaL_ref(L, LUA_REGISTRYINDEX);
> +	}
> +	lua_rawgeti(L, LUA_REGISTRYINDEX, request->index_ref);
> +	/* Move the index table before the key (2nd argument). */
> +	lua_insert(L, 2);
> +	lua_rawset(L, 2);
> +	return 0;
> +}
> +
>  /**
>   * Returns true if the response was received for the given request.
>   */

<snipped>

> diff --git a/test/box/net.box_fiber-async_gh-3107.result b/test/box/net.box_fiber-async_gh-3107.result
> index aaaca351a579..60033059335b 100644
> --- a/test/box/net.box_fiber-async_gh-3107.result
> +++ b/test/box/net.box_fiber-async_gh-3107.result
> @@ -10,10 +10,7 @@ net = require('net.box')
>  cond = nil
>  ---
>  ...
> -box.schema.func.create('long_function')
> ----
> -...
> -box.schema.user.grant('guest', 'execute', 'function', 'long_function')
> +box.schema.user.grant('guest', 'execute', 'universe')
>  ---
>  ...
>  function long_function(...) cond = fiber.cond() cond:wait() return ... end
> @@ -104,7 +101,109 @@ err:find('Usage') ~= nil
>  ---
>  - true
>  ...
> -box.schema.func.drop('long_function')
> +-- Storing user data in future object.
> +future = c:eval('return 123', {}, {is_async = true})
> +---
> +...
> +future.abc -- nil
> +---
> +- null
> +...
> +future.abc = nil
> +---
> +...
> +future.abc -- nil
> +---
> +- null
> +...
> +future.abc = 'abc'
> +---
> +...
> +future.abc -- abc
> +---
> +- abc
> +...
> +future.abc = nil
> +---
> +...
> +future.abc -- nil
> +---
> +- null
> +...
> +future.abc = nil

Looks like a typo: future.abc already equals to nil above.

> +---
> +...
> +future.abc -- nil
> +---
> +- null
> +...
> +future:wait_result() -- 123
> +---
> +- [123]
> +...
> +-- Garbage collection of stored user data.
> +future = c:eval('return 123', {}, {is_async = true})
> +---
> +...
> +future.data1 = {1}
> +---
> +...
> +future.data2 = {2}
> +---
> +...
> +future.data3 = {3}
> +---
> +...
> +gc = setmetatable({}, {__mode = 'v'})
> +---
> +...
> +gc.data1 = future.data1
> +---
> +...
> +gc.data2 = future.data2
> +---
> +...
> +gc.data3 = future.data3
> +---
> +...
> +future.data1 = nil
> +---
> +...
> +_ = collectgarbage('collect')
> +---
> +...
> +gc.data1 == nil
> +---
> +- true
> +...
> +future.data2 = 123
> +---
> +...
> +_ = collectgarbage('collect')
> +---
> +...
> +gc.data2 == nil
> +---
> +- true
> +...
> +future:wait_result() -- 123
> +---
> +- [123]
> +...
> +future = nil
> +---
> +...
> +_ = collectgarbage('collect')
> +---
> +...
> +_ = collectgarbage('collect')
> +---
> +...
> +gc.data3 == nil
> +---
> +- true
> +...
> +box.schema.user.revoke('guest', 'execute', 'universe')
>  ---
>  ...
>  c:close()

<snipped>

> -- 
> 2.25.1
> 

[1]: https://www.tarantool.io/en/doc/latest/dev_guide/developer_guidelines/
[2]: https://github.com/tarantool/tarantool/wiki/Code-review-procedure#commit-message

-- 
Best regards,
IM


More information about the Tarantool-patches mailing list