[Tarantool-patches] [PATCH 3/4] fiber: keep reference to userdata if fiber created once

Oleg Babin olegrok at tarantool.org
Thu Aug 26 09:14:24 MSK 2021


Thanks for your review. My answers below.

On 25.08.2021 23:33, Vladislav Shpilevoy wrote:
> Hi! Thanks for the patch!
>
> See 5 comments below.
>
>> diff --git a/src/lua/fiber.c b/src/lua/fiber.c
>> index 5575f2079..268ddf9cc 100644
>> --- a/src/lua/fiber.c
>> +++ b/src/lua/fiber.c
>> @@ -87,27 +87,31 @@ luaL_testcancel(struct lua_State *L)
>>   static const char *fiberlib_name = "fiber";
>>   
>>   /**
>> - * @pre: stack top contains a table
>> - * @post: sets table field specified by name of the table on top
>> - * of the stack to a weak kv table and pops that weak table.
>> + * Trigger invoked when the fiber has stopped execution of its
>> + * current request. Only purpose - delete storage.lua.ref and
>> + * storage.lua.storage_ref keeping a reference of Lua
>> + * fiber and fiber.storage objects. Unlike Lua stack,
>> + * Lua fiber storage may be created not only for fibers born from
>> + * Lua land. For example, an IProto request may execute a Lua
>> + * function, which can create the storage. Trigger guarantees,
>> + * that even for non-Lua fibers the Lua storage is destroyed.
>>    */
>> -static void
>> -lbox_create_weak_table(struct lua_State *L, const char *name)
>> +static int
>> +lbox_fiber_on_stop(struct trigger *trigger, void *event)
>>   {
>> -	lua_newtable(L);
>> -	/* and a metatable */
>> -	lua_newtable(L);
>> -	/* weak keys and values */
>> -	lua_pushstring(L, "kv");
>> -	/* pops 'kv' */
>> -	lua_setfield(L, -2, "__mode");
>> -	/* pops the metatable */
>> -	lua_setmetatable(L, -2);
>> -	/* assigns and pops table */
>> -	lua_setfield(L, -2, name);
>> -	/* gets memoize back. */
>> -	lua_getfield(L, -1, name);
>> -	assert(! lua_isnil(L, -1));
>> +	struct fiber *f = (struct fiber *) event;
> 1. In new code we do not use whitespaces after unary operators,
> including type casts. But here you don't need a cast. void * is
> implicitly compatible with any other pointer type in C.

Fixed

>> +	int storage_ref = f->storage.lua.storage_ref;
>> +	if (storage_ref > 0) {
>> +		luaL_unref(tarantool_L, LUA_REGISTRYINDEX, storage_ref);
>> +		f->storage.lua.storage_ref = LUA_NOREF;
>> +	}
>> +	int ref = f->storage.lua.ref;
>> +	assert(ref > 0);
>> +	luaL_unref(tarantool_L, LUA_REGISTRYINDEX, ref);
>> +	f->storage.lua.ref = LUA_NOREF;
>> +	trigger_clear(trigger);
>> +	free(trigger);
>> +	return 0;
>>   }
>>   
>>   /**
>> @@ -116,42 +120,26 @@ lbox_create_weak_table(struct lua_State *L, const char *name)
>>   static void
>>   lbox_pushfiber(struct lua_State *L, struct fiber *f)
>>   {
>> -	/*
>> -	 * Use 'memoize'  pattern and keep a single userdata for
>> -	 * the given fiber. This is important to not run __gc
>> -	 * twice for a copy of an attached fiber -- __gc should
>> -	 * not remove attached fiber's coro prematurely.
>> -	 */
>> -	luaL_getmetatable(L, fiberlib_name);
>> -	lua_getfield(L, -1, "memoize");
>> -	if (lua_isnil(L, -1)) {
>> -		/* first access - instantiate memoize */
>> -		/* pop the nil */
>> -		lua_pop(L, 1);
>> -		/* create memoize table */
>> -		lbox_create_weak_table(L, "memoize");
>> -	}
>> -	/* Find out whether the fiber is  already in the memoize table. */
>> -	uint64_t fid = f->fid;
>> -	luaL_pushuint64(L, fid);
>> -	lua_gettable(L, -2);
>> -	if (lua_isnil(L, -1)) {
>> -		/* no userdata for fiber created so far */
>> -		/* pop the nil */
>> -		lua_pop(L, 1);
>> -		/* push the key back */
>> -		luaL_pushuint64(L, fid);
>> +	int ref = f->storage.lua.ref;
>> +	if (ref <= 0) {
>> +		struct trigger *t = (struct trigger *)malloc(sizeof(*t));
> 2. No need to cast, in C it works as is.
Fixed.
>> +		if (t == NULL) {
>> +			diag_set(OutOfMemory, sizeof(*t), "malloc", "t");
>> +			luaT_error(L);
>> +		}
>> +		trigger_create(t, lbox_fiber_on_stop, NULL, (trigger_f0) free);
> 3. Should not be a whitespace after the cast.
Fixed.
>> +		trigger_add(&f->on_stop, t);
>> +
>> +		uint64_t fid = f->fid;
>>   		/* create a new userdata */
>>   		uint64_t *ptr = lua_newuserdata(L, sizeof(*ptr));
>>   		*ptr = fid;
> 4. Did you consider pushing the fiber's pointer instead of its ID?
> And keep the fiber struct from deletion until it has no refs in
> Lua anymore. That would eliminate lookup in fiber hash on each attempt
> to access it. Also might make it simpler to return stuff like fiber.csw
> in Lua. I remember there was a problem with the fiber being deleted by
> the time you try to access its members. This would solve it.

I'll think about it. I guess it's possible but it's required more time 
and could be done

on the top of this patch.


>>   		luaL_getmetatable(L, fiberlib_name);
>>   		lua_setmetatable(L, -2);
>> -		/* memoize it */
>> -		lua_settable(L, -3);
>> -		luaL_pushuint64(L, fid);
>> -		/* get it back */
>> -		lua_gettable(L, -2);
>> +		ref = luaL_ref(L, LUA_REGISTRYINDEX);
>> +		f->storage.lua.ref = ref;
>>   	}
>> +	lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
>>   }
>> @@ -703,8 +669,6 @@ lbox_fiber_storage(struct lua_State *L)
>>   			diag_set(OutOfMemory, sizeof(*t), "malloc", "t");
>>   			return luaT_error(L);
>>   		}
>> -		trigger_create(t, lbox_fiber_on_stop, NULL, (trigger_f0) free);
> 5. The trigger 't' now is not used and leaks.

Oh, I've missed it. Malloc is removed.


>> -		trigger_add(&f->on_stop, t);
>>   		lua_newtable(L); /* create local storage on demand */
>>   		storage_ref = luaL_ref(L, LUA_REGISTRYINDEX);
>>   		f->storage.lua.storage_ref = storage_ref;
>>

Diff:

diff --git a/src/lua/fiber.c b/src/lua/fiber.c
index 268ddf9cc..83a6b4850 100644
--- a/src/lua/fiber.c
+++ b/src/lua/fiber.c
@@ -99,7 +99,7 @@ static const char *fiberlib_name = "fiber";
  static int
  lbox_fiber_on_stop(struct trigger *trigger, void *event)
  {
-    struct fiber *f = (struct fiber *) event;
+    struct fiber *f = event;
      int storage_ref = f->storage.lua.storage_ref;
      if (storage_ref > 0) {
          luaL_unref(tarantool_L, LUA_REGISTRYINDEX, storage_ref);
@@ -122,12 +122,12 @@ lbox_pushfiber(struct lua_State *L, struct fiber *f)
  {
      int ref = f->storage.lua.ref;
      if (ref <= 0) {
-        struct trigger *t = (struct trigger *)malloc(sizeof(*t));
+        struct trigger *t = malloc(sizeof(*t));
          if (t == NULL) {
              diag_set(OutOfMemory, sizeof(*t), "malloc", "t");
              luaT_error(L);
          }
-        trigger_create(t, lbox_fiber_on_stop, NULL, (trigger_f0) free);
+        trigger_create(t, lbox_fiber_on_stop, NULL, (trigger_f0)free);
          trigger_add(&f->on_stop, t);

          uint64_t fid = f->fid;
@@ -663,12 +663,6 @@ lbox_fiber_storage(struct lua_State *L)
      struct fiber *f = lbox_checkfiber(L, 1);
      int storage_ref = f->storage.lua.storage_ref;
      if (storage_ref <= 0) {
-        struct trigger *t = (struct trigger *)
-            malloc(sizeof(*t));
-        if (t == NULL) {
-            diag_set(OutOfMemory, sizeof(*t), "malloc", "t");
-            return luaT_error(L);
-        }
          lua_newtable(L); /* create local storage on demand */
          storage_ref = luaL_ref(L, LUA_REGISTRYINDEX);
          f->storage.lua.storage_ref = storage_ref;



More information about the Tarantool-patches mailing list