diff options
author | petr@mysql.com <> | 2006-02-21 15:57:56 +0300 |
---|---|---|
committer | petr@mysql.com <> | 2006-02-21 15:57:56 +0300 |
commit | cb5e54e1bdd69257c5fbfb509c4d819a70b6b69c (patch) | |
tree | 97bed2340b3e2c7f36e6d1712661050cd07b1064 /server-tools/instance-manager/instance_map.cc | |
parent | 0766fb3a53d6e4e068a403ab2cb4588514337187 (diff) | |
download | mariadb-git-cb5e54e1bdd69257c5fbfb509c4d819a70b6b69c.tar.gz |
Fix race condition: instance map wasn't locked for the
duration of the whole 'flush instances'. As a consequence,
it was possible to query instance map, while it is in the
inconsistent state. The patch was reworked after review.
Diffstat (limited to 'server-tools/instance-manager/instance_map.cc')
-rw-r--r-- | server-tools/instance-manager/instance_map.cc | 83 |
1 files changed, 68 insertions, 15 deletions
diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc index 611eda457f2..883be15b571 100644 --- a/server-tools/instance-manager/instance_map.cc +++ b/server-tools/instance-manager/instance_map.cc @@ -80,19 +80,44 @@ static void delete_instance(void *u) static int process_option(void *ctx, const char *group, const char *option) { Instance_map *map= NULL; + + map = (Instance_map*) ctx; + return map->process_one_option(group, option); +} + +C_MODE_END + + +/* + Process one option from the configuration file. + + SYNOPSIS + Instance_map::process_one_option() + group group name + option option string (e.g. "--name=value") + + DESCRIPTION + This is an auxiliary function and should not be used externally. + It is used only by flush_instances(), which pass it to + process_option(). The caller ensures proper locking + of the instance map object. +*/ + +int Instance_map::process_one_option(const char *group, const char *option) +{ Instance *instance= NULL; static const char prefix[]= { 'm', 'y', 's', 'q', 'l', 'd' }; - map = (Instance_map*) ctx; if (strncmp(group, prefix, sizeof prefix) == 0 && ((my_isdigit(default_charset_info, group[sizeof prefix])) || group[sizeof(prefix)] == '\0')) { - if ((instance= map->find(group, strlen(group))) == NULL) + if (!(instance= (Instance *) hash_search(&hash, (byte *) group, + strlen(group)))) { - if ((instance= new Instance) == 0) + if (!(instance= new Instance)) goto err; - if (instance->init(group) || map->add_instance(instance)) + if (instance->init(group) || my_hash_insert(&hash, (byte *) instance)) goto err_instance; } @@ -108,8 +133,6 @@ err: return 1; } -C_MODE_END - Instance_map::Instance_map(const char *default_mysqld_path_arg): mysqld_path(default_mysqld_path_arg) @@ -144,30 +167,61 @@ void Instance_map::unlock() pthread_mutex_unlock(&LOCK_instance_map); } +/* + Re-read instance configuration file. + + SYNOPSIS + Instance_map::flush_instances() + + DESCRIPTION + This function will: + - clear the current list of instances. This removes both + running and stopped instances. + - load a new instance configuration from the file. + - pass on the new map to the guardian thread: it will start + all instances that are marked `guarded' and not yet started. + Note, as the check whether an instance is started is currently + very simple (returns true if there is a MySQL server running + at the given port), this function has some peculiar + side-effects: + * if the port number of a running instance was changed, the + old instance is forgotten, even if it was running. The new + instance will be started at the new port. + * if the configuration was changed in a way that two + instances swapped their port numbers, the guardian thread + will not notice that and simply report that both instances + are configured successfully and running. + In order to avoid such side effects one should never call + FLUSH INSTANCES without prior stop of all running instances. + + TODO + FLUSH INSTANCES should return an error if it's called + while there is a running instance. +*/ int Instance_map::flush_instances() { int rc; + /* + Guardian thread relies on the instance map repository for guarding + instances. This is why refreshing instance map, we need (1) to stop + guardian (2) reload the instance map (3) reinitialize the guardian + with new instances. + */ guardian->lock(); pthread_mutex_lock(&LOCK_instance_map); hash_free(&hash); hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0, get_instance_key, delete_instance, 0); - pthread_mutex_unlock(&LOCK_instance_map); rc= load(); guardian->init(); + pthread_mutex_unlock(&LOCK_instance_map); guardian->unlock(); return rc; } -int Instance_map::add_instance(Instance *instance) -{ - return my_hash_insert(&hash, (byte *) instance); -} - - Instance * Instance_map::find(const char *name, uint name_len) { @@ -190,10 +244,9 @@ int Instance_map::complete_initialization() if ((instance= new Instance) == 0) goto err; - if (instance->init("mysqld") || add_instance(instance)) + if (instance->init("mysqld") || my_hash_insert(&hash, (byte *) instance)) goto err_instance; - /* After an instance have been added to the instance_map, hash_free should handle it's deletion => goto err, not |