1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

Merge MariaDB-10.0.7 revision 3961.

This commit is contained in:
Jan Lindström
2014-01-25 11:02:49 +02:00
2297 changed files with 266854 additions and 151902 deletions

View File

@@ -257,15 +257,6 @@ class sys_var_pluginvar: public sys_var
public:
struct st_plugin_int *plugin;
struct st_mysql_sys_var *plugin_var;
/**
variable name from whatever is hard-coded in the plugin source
and doesn't have pluginname- prefix is replaced by an allocated name
with a plugin prefix. When plugin is uninstalled we need to restore the
pointer to point to the hard-coded value, because plugin may be
installed/uninstalled many times without reloading the shared object.
*/
const char *orig_pluginvar_name;
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, size); }
static void operator delete(void *ptr_arg,size_t size)
@@ -278,7 +269,7 @@ public:
(plugin_var_arg->flags & PLUGIN_VAR_READONLY ? READONLY : 0),
0, -1, NO_ARG, pluginvar_show_type(plugin_var_arg), 0, 0,
VARIABLE_NOT_IN_BINLOG, NULL, NULL, NULL),
plugin_var(plugin_var_arg), orig_pluginvar_name(plugin_var_arg->name)
plugin_var(plugin_var_arg)
{ plugin_var->name= name_arg; }
sys_var_pluginvar *cast_pluginvar() { return this; }
bool check_update_type(Item_result type);
@@ -308,7 +299,7 @@ static bool register_builtin(struct st_maria_plugin *, struct st_plugin_int *,
static void unlock_variables(THD *thd, struct system_variables *vars);
static void cleanup_variables(THD *thd, struct system_variables *vars);
static void plugin_vars_free_values(sys_var *vars);
static void restore_pluginvar_names(sys_var *first);
static void restore_ptr_backup(uint n, st_ptr_backup *backup);
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin);
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
static void reap_plugins(void);
@@ -473,9 +464,16 @@ static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
#endif /* HAVE_DLOPEN */
static inline void free_plugin_mem(struct st_plugin_dl *p)
static void free_plugin_mem(struct st_plugin_dl *p)
{
#ifdef HAVE_DLOPEN
if (p->ptr_backup)
{
DBUG_ASSERT(p->nbackups);
DBUG_ASSERT(p->handle);
restore_ptr_backup(p->nbackups, p->ptr_backup);
my_free(p->ptr_backup);
}
if (p->handle)
dlclose(p->handle);
#endif
@@ -706,6 +704,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
uint plugin_dir_len, dummy_errors, dlpathlen, i;
struct st_plugin_dl *tmp= 0, plugin_dl;
void *sym;
st_ptr_backup tmp_backup[array_elements(list_of_services)];
DBUG_ENTER("plugin_dl_add");
DBUG_PRINT("enter", ("dl->str: '%s', dl->length: %d",
dl->str, (int) dl->length));
@@ -772,7 +771,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
{
if ((sym= dlsym(plugin_dl.handle, list_of_services[i].name)))
{
uint ver= (uint)(intptr)*(void**)sym;
void **ptr= (void **)sym;
uint ver= (uint)(intptr)*ptr;
if (ver > list_of_services[i].version ||
(ver >> 8) < (list_of_services[i].version >> 8))
{
@@ -783,10 +783,24 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, ENOEXEC, buf);
goto ret;
}
*(void**)sym= list_of_services[i].service;
tmp_backup[plugin_dl.nbackups++].save(ptr);
*ptr= list_of_services[i].service;
}
}
if (plugin_dl.nbackups)
{
size_t bytes= plugin_dl.nbackups * sizeof(plugin_dl.ptr_backup[0]);
plugin_dl.ptr_backup= (st_ptr_backup *)my_malloc(bytes, MYF(0));
if (!plugin_dl.ptr_backup)
{
restore_ptr_backup(plugin_dl.nbackups, tmp_backup);
report_error(report, ER_OUTOFMEMORY, bytes);
goto ret;
}
memcpy(plugin_dl.ptr_backup, tmp_backup, bytes);
}
/* Duplicate and convert dll name */
plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
@@ -1098,7 +1112,6 @@ static bool plugin_add(MEM_ROOT *tmp_root,
if (!(tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
{
mysql_del_sys_var_chain(tmp.system_vars);
restore_pluginvar_names(tmp.system_vars);
goto err;
}
plugin_array_version++;
@@ -1115,6 +1128,8 @@ static bool plugin_add(MEM_ROOT *tmp_root,
err:
errs++;
if (tmp.nbackups)
restore_ptr_backup(tmp.nbackups, tmp.ptr_backup);
if (name->str)
break;
}
@@ -1193,7 +1208,7 @@ static void plugin_del(struct st_plugin_int *plugin)
mysql_rwlock_wrlock(&LOCK_system_variables_hash);
mysql_del_sys_var_chain(plugin->system_vars);
mysql_rwlock_unlock(&LOCK_system_variables_hash);
restore_pluginvar_names(plugin->system_vars);
restore_ptr_backup(plugin->nbackups, plugin->ptr_backup);
plugin_vars_free_values(plugin->system_vars);
my_hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
plugin_dl_del(plugin->plugin_dl);
@@ -2914,16 +2929,6 @@ static st_bookmark *register_var(const char *plugin, const char *name,
return result;
}
static void restore_pluginvar_names(sys_var *first)
{
for (sys_var *var= first; var; var= var->next)
{
sys_var_pluginvar *pv= var->cast_pluginvar();
pv->plugin_var->name= pv->orig_pluginvar_name;
}
}
/*
returns a pointer to the memory which holds the thd-local variable or
a pointer to the global variable if thd==null.
@@ -3805,7 +3810,7 @@ static my_option *construct_help_options(MEM_ROOT *mem_root,
to get the correct (not double-prefixed) help text.
We won't need @@sysvars anymore and don't care about their proper names.
*/
restore_pluginvar_names(p->system_vars);
restore_ptr_backup(p->nbackups, p->ptr_backup);
if (construct_options(mem_root, p, opts))
DBUG_RETURN(NULL);
@@ -3850,6 +3855,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
sys_var *v __attribute__((unused));
struct st_bookmark *var;
uint len, count= EXTRA_OPTIONS;
st_ptr_backup *tmp_backup= 0;
DBUG_ENTER("test_plugin_options");
DBUG_ASSERT(tmp->plugin && tmp->name.str);
@@ -3922,59 +3928,86 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
plugin_name= tmp->name;
error= 1;
for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
{
st_mysql_sys_var *o= *opt;
/*
PLUGIN_VAR_STR command-line options without PLUGIN_VAR_MEMALLOC, point
directly to values in the argv[] array. For plugins started at the
server startup, argv[] array is allocated with load_defaults(), and
freed when the server is shut down. But for plugins loaded with
INSTALL PLUGIN, the memory allocated with load_defaults() is freed with
freed() at the end of mysql_install_plugin(). Which means we cannot
allow any pointers into that area.
Thus, for all plugins loaded after the server was started,
we copy string values to a plugin's memroot.
*/
if (mysqld_server_started &&
((o->flags & (PLUGIN_VAR_STR | PLUGIN_VAR_NOCMDOPT |
PLUGIN_VAR_MEMALLOC)) == PLUGIN_VAR_STR))
if (tmp->plugin->system_vars)
{
for (len=0, opt= tmp->plugin->system_vars; *opt; len++, opt++) /* no-op */;
tmp_backup= (st_ptr_backup *)my_alloca(len * sizeof(tmp_backup[0]));
DBUG_ASSERT(tmp->nbackups == 0);
DBUG_ASSERT(tmp->ptr_backup == 0);
for (opt= tmp->plugin->system_vars; *opt; opt++)
{
sysvar_str_t* str= (sysvar_str_t *)o;
if (*str->value)
*str->value= strdup_root(mem_root, *str->value);
st_mysql_sys_var *o= *opt;
/*
PLUGIN_VAR_STR command-line options without PLUGIN_VAR_MEMALLOC, point
directly to values in the argv[] array. For plugins started at the
server startup, argv[] array is allocated with load_defaults(), and
freed when the server is shut down. But for plugins loaded with
INSTALL PLUGIN, the memory allocated with load_defaults() is freed with
freed() at the end of mysql_install_plugin(). Which means we cannot
allow any pointers into that area.
Thus, for all plugins loaded after the server was started,
we copy string values to a plugin's memroot.
*/
if (mysqld_server_started &&
((o->flags & (PLUGIN_VAR_STR | PLUGIN_VAR_NOCMDOPT |
PLUGIN_VAR_MEMALLOC)) == PLUGIN_VAR_STR))
{
sysvar_str_t* str= (sysvar_str_t *)o;
if (*str->value)
*str->value= strdup_root(mem_root, *str->value);
}
if (o->flags & PLUGIN_VAR_NOSYSVAR)
continue;
tmp_backup[tmp->nbackups++].save(&o->name);
if ((var= find_bookmark(plugin_name.str, o->name, o->flags)))
v= new (mem_root) sys_var_pluginvar(&chain, var->key + 1, o);
else
{
len= plugin_name.length + strlen(o->name) + 2;
varname= (char*) alloc_root(mem_root, len);
strxmov(varname, plugin_name.str, "-", o->name, NullS);
my_casedn_str(&my_charset_latin1, varname);
convert_dash_to_underscore(varname, len-1);
v= new (mem_root) sys_var_pluginvar(&chain, varname, o);
}
DBUG_ASSERT(v); /* check that an object was actually constructed */
} /* end for */
if (tmp->nbackups)
{
size_t bytes= tmp->nbackups * sizeof(tmp->ptr_backup[0]);
tmp->ptr_backup= (st_ptr_backup *)alloc_root(mem_root, bytes);
if (!tmp->ptr_backup)
{
restore_ptr_backup(tmp->nbackups, tmp_backup);
goto err;
}
memcpy(tmp->ptr_backup, tmp_backup, bytes);
}
if (o->flags & PLUGIN_VAR_NOSYSVAR)
continue;
if ((var= find_bookmark(plugin_name.str, o->name, o->flags)))
v= new (mem_root) sys_var_pluginvar(&chain, var->key + 1, o);
else
if (chain.first)
{
len= plugin_name.length + strlen(o->name) + 2;
varname= (char*) alloc_root(mem_root, len);
strxmov(varname, plugin_name.str, "-", o->name, NullS);
my_casedn_str(&my_charset_latin1, varname);
convert_dash_to_underscore(varname, len-1);
v= new (mem_root) sys_var_pluginvar(&chain, varname, o);
chain.last->next = NULL;
if (mysql_add_sys_var_chain(chain.first))
{
sql_print_error("Plugin '%s' has conflicting system variables",
tmp->name.str);
goto err;
}
tmp->system_vars= chain.first;
}
DBUG_ASSERT(v); /* check that an object was actually constructed */
} /* end for */
if (chain.first)
{
chain.last->next = NULL;
if (mysql_add_sys_var_chain(chain.first))
{
sql_print_error("Plugin '%s' has conflicting system variables",
tmp->name.str);
goto err;
}
tmp->system_vars= chain.first;
my_afree(tmp_backup);
}
DBUG_RETURN(0);
err:
if (tmp_backup)
my_afree(tmp_backup);
if (opts)
my_cleanup_options(opts);
DBUG_RETURN(error);
@@ -4023,3 +4056,38 @@ sys_var *find_plugin_sysvar(st_plugin_int *plugin, st_mysql_sys_var *plugin_var)
return 0;
}
/*
On dlclose() we need to restore values of all symbols that we've modified in
the DSO. The reason is - the DSO might not actually be unloaded, so on the
next dlopen() these symbols will have old values, they won't be
reinitialized.
Perhaps, there can be many reason, why a DSO won't be unloaded. Strictly
speaking, it's implementation defined whether to unload an unused DSO or to
keep it in memory.
In particular, this happens for some plugins: In 2009 a new ELF stub was
introduced, see Ulrich Drepper's email "Unique symbols for C++"
http://www.redhat.com/archives/posix-c++-wg/2009-August/msg00002.html
DSO that has objects with this stub (STB_GNU_UNIQUE) cannot be unloaded
(this is mentioned in the email, see the url above).
These "unique" objects are, for example, static variables in templates,
in inline functions, in classes. So any DSO that uses them can
only be loaded once. And because Boost has them, any DSO that uses Boost
almost certainly cannot be unloaded.
To know whether a particular DSO has these objects, one can use
readelf -s /path/to/plugin.so|grep UNIQUE
There's nothing we can do about it, but to reset the DSO to its initial
state before dlclose().
*/
static void restore_ptr_backup(uint n, st_ptr_backup *backup)
{
while (n--)
(backup++)->restore();
}