Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: Cyrill Gorcunov <gorcunov@gmail.com>,
	tml <tarantool-patches@dev.tarantool.org>
Subject: Re: [Tarantool-patches] [PATCH v20 5/7] box/schema.func: switch to new module api
Date: Mon, 5 Apr 2021 17:56:49 +0200	[thread overview]
Message-ID: <31095f87-03f7-f7b4-6e4c-1e331dbe7ee8@tarantool.org> (raw)
In-Reply-To: <20210402123420.885834-6-gorcunov@gmail.com>

Thanks for the patch!

See 6 comments below.

On 02.04.2021 14:34, Cyrill Gorcunov via Tarantool-patches wrote:
> Since we have low level module api now we can switch
> the box.schema.func code to use it. In particular we
> define schema_module structure as a wrapper over the
> modules api -- it carries a pointer to general module
> structure.
> 
> Because of modules reload functionality (which was actually
> a big mistake to introduce in a first place, because it is too
> fragile and in case of unintended misuse may simply crash the
> application in a best case) the schema modules carry own cache
> of modules instances. Thus to make overall code somehow close
> to modules api we do:
> 
> 1) every schema_module variable should be named as `mod`. this
>    allows to distinguish this kind of modules from general
>   `module` variables;

1. For base objects we often use name 'base'. So the module_cache
module would be called 'base', and the schema_module would be
called 'module' like it was before your patch. 'mod' and 'module'
don't give any hint how are they different, since you want to
separate them so hard everywhere.

> 2) cache operations are renamed to cache_find/put/update/del;
> 3) C functions are switched to use module_func low level api;
> 4) because low level modules api carry own references we can
>    take no explicit reference when calling a function.
> 
> diff --git a/src/box/func.c b/src/box/func.c
> index 08918e6db..54d0cbc68 100644
> --- a/src/box/func.c
> +++ b/src/box/func.c
> @@ -227,190 +169,214 @@ module_cache_put(struct module *module)

<...>

> +static struct schema_module *
> +__schema_module_load(const char *name, size_t len, bool force)

2. You can't use the double underscore unless it is absolutely
necessary and can't be avoided.
https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html

> +{
> +	struct schema_module *mod = malloc(sizeof(*mod));
> +	if (mod != NULL) {
> +		mod->module = NULL;
> +		mod->refs = 0;
> +		rlist_create(&mod->funcs);
> +	} else {
> +		diag_set(OutOfMemory, sizeof(*mod),
> +			 "malloc", "struct schema_module");
> +		return NULL;
>  	}
>  
> -	module->handle = dlopen(load_name, RTLD_NOW | RTLD_LOCAL);
> -	if (unlink(load_name) != 0)
> -		say_warn("failed to unlink dso link %s", load_name);
> -	if (rmdir(dir_name) != 0)
> -		say_warn("failed to delete temporary dir %s", dir_name);
> -	if (module->handle == NULL) {
> -		diag_set(ClientError, ER_LOAD_MODULE, package_len,
> -			  package, dlerror());
> -		goto error;
> +	if (force)
> +		mod->module = module_load_force(name, len);
> +	else
> +		mod->module = module_load(name, len);
> +
> +	if (!mod->module) {

3. Please, use explicit == NULL.

> +		free(mod);
> +		return NULL;
>  	}

<...>

> +static int
> +schema_func_c_load(struct schema_module *mod, const char *func_name,
> +		   struct func_c *func)

4. There is a simple rule for method naming and the order of
their arguments: always start the method name with the struct
name, and pass the object in the first argument, like C++.

Here it should be func_c_load_from(), func_c_unload(), and
'func' must be the first argument.

func_c_load_from() so as to emphasize it takes the module to
load from explicitly, on the contrary with func_c_load().

Using the prefix 'schema' for that does not make it easier to
understand the difference between schema_func_c_load and
func_c_load.

>  {
> -	box_function_f f = (box_function_f)dlsym(module->handle, name);
> -	if (f == NULL) {
> -		diag_set(ClientError, ER_LOAD_FUNCTION, name, dlerror());
> -		return NULL;
> +	assert(module_func_is_empty(&func->mf));
> +
> +	if (module_func_load(mod->module, func_name, &func->mf) != 0)
> +		return -1;
> +
> +	func->mod = mod;
> +	rlist_move(&mod->funcs, &func->item);
> +	schema_module_ref(mod);
> +
> +	return 0;
> +}
> +
> +static void
> +schema_func_c_unload(struct func_c *func)
> +{
> +	if (!module_func_is_empty(&func->mf)) {
> +		rlist_del(&func->item);
> +		schema_module_unref(func->mod);
> +		module_func_unload(&func->mf);
> +		func_c_create(func);
>  	}
> -	return f;
>  }
>  
>  int
>  schema_module_reload(const char *package, const char *package_end)
>  {
> -	struct module *old_module = module_cache_find(package, package_end);
> -	if (old_module == NULL) {
> +	struct schema_module *old = cache_find(package, package_end);
> +	if (old == NULL) {
>  		/* Module wasn't loaded - do nothing. */
>  		diag_set(ClientError, ER_NO_SUCH_MODULE, package);
>  		return -1;
>  	}
>  
> -	struct module *new_module = module_load(package, package_end);
> -	if (new_module == NULL)
> +	struct schema_module *new = schema_module_load_force(package, package_end);
> +	if (new == NULL)
>  		return -1;
>  
> +	/*
> +	 * Keep an extra reference to the old module
> +	 * so it won't be freed until reload is complete,
> +	 * otherwise we might free old module then fail
> +	 * on some function loading and in result won't
> +	 * be able to restore old symbols.
> +	 */
> +	schema_module_ref(old);
>  	struct func_c *func, *tmp_func;
> -	rlist_foreach_entry_safe(func, &old_module->funcs, item, tmp_func) {
> -		/* Move immediately for restore sake. */
> -		rlist_move(&new_module->funcs, &func->item);
> +	rlist_foreach_entry_safe(func, &old->funcs, item, tmp_func) {
>  		struct func_name name;
>  		func_split_name(func->base.def->name, &name);
> -		func->func = module_sym(new_module, name.sym);
> -		if (func->func == NULL)
> +		schema_func_c_unload(func);
> +		if (schema_func_c_load(new, name.sym, func) != 0) {
> +			/*
> +			 * WARN: A hack accessing new->funcs directly
> +			 * to start restore from this failing function.
> +			 */

5. Please, drop the hack. You can restore this function individually
right here, and proceed to the restoration of the other functions.

There might be other solutions, but this looks the easiest.

> +			rlist_move(&new->funcs, &func->item);
>  			goto restore;
> -		func->module = new_module;
> +		}
>  	}
> diff --git a/test/box/gh-4648-func-load-unload.result b/test/box/gh-4648-func-load-unload.result
> index e695dd365..91b78d083 100644
> --- a/test/box/gh-4648-func-load-unload.result
> +++ b/test/box/gh-4648-func-load-unload.result
> @@ -71,7 +71,8 @@ check_module_count_diff(-1)
>   | ...
>  
>  -- A not finished invocation of a function from a module prevents
> --- its unload. Until the call is finished.
> +-- low level module intance unload while schema level module is
> +-- free to unload immediately when dropped.

6. As you can see from the issue description in this test, it was
exactly about unloading the dlopen's handle. Not about the module
object deletion. After your change, even if the modules are never
truly unloaded, the test will pass which is obviously not what is
supposed to happen. You need to move the error injection to
module_cache.c to make it work like before and fail if the module
wasn't fully unloaded.

  reply	other threads:[~2021-04-05 15:56 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-02 12:34 [Tarantool-patches] [PATCH v20 0/7] box: implement box.lib Lua module Cyrill Gorcunov via Tarantool-patches
2021-04-02 12:34 ` [Tarantool-patches] [PATCH v20 1/7] box/schema: make sure hashes are created Cyrill Gorcunov via Tarantool-patches
2021-04-05  9:28   ` Serge Petrenko via Tarantool-patches
2021-04-05  9:50     ` Cyrill Gorcunov via Tarantool-patches
2021-04-05 10:13       ` Serge Petrenko via Tarantool-patches
2021-04-05 15:45   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-06  7:44     ` Cyrill Gorcunov via Tarantool-patches
2021-04-02 12:34 ` [Tarantool-patches] [PATCH v20 2/7] box/func: module_reload -- drop redundant argument Cyrill Gorcunov via Tarantool-patches
2021-04-05 10:23   ` Serge Petrenko via Tarantool-patches
2021-04-05 10:26     ` Serge Petrenko via Tarantool-patches
2021-04-05 10:31       ` Cyrill Gorcunov via Tarantool-patches
2021-04-02 12:34 ` [Tarantool-patches] [PATCH v20 3/7] box/func: fix modules functions restore Cyrill Gorcunov via Tarantool-patches
2021-04-05 10:53   ` Serge Petrenko via Tarantool-patches
2021-04-05 11:26     ` Cyrill Gorcunov via Tarantool-patches
2021-04-05 11:42       ` Serge Petrenko via Tarantool-patches
2021-04-05 15:47   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-06  8:38     ` Cyrill Gorcunov via Tarantool-patches
2021-04-06 20:02       ` Vladislav Shpilevoy via Tarantool-patches
2021-04-06 20:42         ` Cyrill Gorcunov via Tarantool-patches
2021-04-02 12:34 ` [Tarantool-patches] [PATCH v20 4/7] box/module_cache: introduce modules subsystem Cyrill Gorcunov via Tarantool-patches
2021-04-05 12:34   ` Serge Petrenko via Tarantool-patches
2021-04-05 15:52   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-06 14:33     ` Cyrill Gorcunov via Tarantool-patches
2021-04-06 20:09       ` Vladislav Shpilevoy via Tarantool-patches
2021-04-06 22:05         ` Cyrill Gorcunov via Tarantool-patches
2021-04-06 23:43           ` Vladislav Shpilevoy via Tarantool-patches
2021-04-07  7:03             ` Cyrill Gorcunov via Tarantool-patches
2021-04-02 12:34 ` [Tarantool-patches] [PATCH v20 5/7] box/schema.func: switch to new module api Cyrill Gorcunov via Tarantool-patches
2021-04-05 15:56   ` Vladislav Shpilevoy via Tarantool-patches [this message]
2021-04-02 12:34 ` [Tarantool-patches] [PATCH v20 6/7] box: implement box.lib module Cyrill Gorcunov via Tarantool-patches
2021-04-05 16:04   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-07 16:59     ` Cyrill Gorcunov via Tarantool-patches
2021-04-07 20:22       ` Cyrill Gorcunov via Tarantool-patches
2021-04-07 20:28         ` Vladislav Shpilevoy via Tarantool-patches
2021-04-07 20:37           ` Cyrill Gorcunov via Tarantool-patches
2021-04-07 20:45             ` Cyrill Gorcunov via Tarantool-patches
2021-04-07 21:04               ` Vladislav Shpilevoy via Tarantool-patches
2021-04-02 12:34 ` [Tarantool-patches] [PATCH v20 7/7] test: add box.lib test Cyrill Gorcunov via Tarantool-patches
2021-04-05 16:04   ` Vladislav Shpilevoy via Tarantool-patches
2021-04-05 15:45 ` [Tarantool-patches] [PATCH v20 0/7] box: implement box.lib Lua module Vladislav Shpilevoy via Tarantool-patches

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=31095f87-03f7-f7b4-6e4c-1e331dbe7ee8@tarantool.org \
    --to=tarantool-patches@dev.tarantool.org \
    --cc=gorcunov@gmail.com \
    --cc=v.shpilevoy@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH v20 5/7] box/schema.func: switch to new module api' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox