diff options
Diffstat (limited to 'server-tools/instance-manager/commands.cc')
-rw-r--r-- | server-tools/instance-manager/commands.cc | 1752 |
1 files changed, 0 insertions, 1752 deletions
diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc deleted file mode 100644 index 56bd720b3e9..00000000000 --- a/server-tools/instance-manager/commands.cc +++ /dev/null @@ -1,1752 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "commands.h" - -#include <my_global.h> -#include <m_ctype.h> -#include <mysql.h> -#include <my_dir.h> - -#include "buffer.h" -#include "guardian.h" -#include "instance_map.h" -#include "log.h" -#include "manager.h" -#include "messages.h" -#include "mysqld_error.h" -#include "mysql_manager_error.h" -#include "options.h" -#include "priv.h" -#include "protocol.h" - -/************************************************************************** - {{{ Static functions. -**************************************************************************/ - -/** - modify_defaults_to_im_error -- a map of error codes of - mysys::modify_defaults_file() into Instance Manager error codes. -*/ - -static const int modify_defaults_to_im_error[]= { 0, ER_OUT_OF_RESOURCES, - ER_ACCESS_OPTION_FILE }; - - -/** - Parse version number from the version string. - - SYNOPSIS - parse_version_number() - version_str - version - version_size - - DESCRIPTION - TODO - - TODO: Move this function to Instance_options and parse version number - only once. - - NOTE: This function is used only in SHOW INSTANCE STATUS statement at the - moment. -*/ - -static int parse_version_number(const char *version_str, char *version, - uint version_size) -{ - const char *start= version_str; - const char *end; - - // skip garbage - while (!my_isdigit(default_charset_info, *start)) - start++; - - end= start; - // skip digits and dots - while (my_isdigit(default_charset_info, *end) || *end == '.') - end++; - - if ((uint)(end - start) >= version_size) - return -1; - - strncpy(version, start, end-start); - version[end-start]= '\0'; - - return 0; -} - -/************************************************************************** - }}} -**************************************************************************/ - -/************************************************************************** - Implementation of Instance_name. -**************************************************************************/ - -Instance_name::Instance_name(const LEX_STRING *name) -{ - str.str= str_buffer; - str.length= name->length; - - if (str.length > MAX_INSTANCE_NAME_SIZE - 1) - str.length= MAX_INSTANCE_NAME_SIZE - 1; - - strmake(str.str, name->str, str.length); -} - -/************************************************************************** - Implementation of Show_instances. -**************************************************************************/ - -/** - Implementation of SHOW INSTANCES statement. - - Possible error codes: - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instances::execute(st_net *net, ulong /* connection_id */) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net))) - return err_code; - - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instances::write_header(st_net *net) -{ - LIST name, state; - LEX_STRING name_field, state_field; - LIST *field_list; - - name_field.str= (char *) "instance_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - state_field.str= (char *) "state"; - state_field.length= DEFAULT_FIELD_LENGTH; - state.data= &state_field; - - field_list= list_add(NULL, &state); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instances::write_data(st_net *net) -{ - my_bool err_status= FALSE; - - Instance *instance; - Instance_map::Iterator iterator(instance_map); - - instance_map->lock(); - - while ((instance= iterator.next())) - { - Buffer send_buf; /* buffer for packets */ - size_t pos= 0; - - instance->lock(); - - const char *instance_name= instance->options.instance_name.str; - const char *state_name= instance->get_state_name(); - - if (store_to_protocol_packet(&send_buf, instance_name, &pos) || - store_to_protocol_packet(&send_buf, state_name, &pos) || - my_net_write(net, send_buf.buffer, pos)) - { - err_status= TRUE; - } - - instance->unlock(); - - if (err_status) - break; - } - - instance_map->unlock(); - - return err_status ? ER_OUT_OF_RESOURCES : 0; -} - - -/************************************************************************** - Implementation of Flush_instances. -**************************************************************************/ - -/** - Implementation of FLUSH INSTANCES statement. - - Possible error codes: - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_THERE_IS_ACTIVE_INSTACE If there is an active instance -*/ - -int Flush_instances::execute(st_net *net, ulong connection_id) -{ - int err_status= Manager::flush_instances(); - - if (err_status) - return err_status; - - return net_send_ok(net, connection_id, NULL) ? ER_OUT_OF_RESOURCES : 0; -} - - -/************************************************************************** - Implementation of Instance_cmd. -**************************************************************************/ - -Instance_cmd::Instance_cmd(const LEX_STRING *instance_name_arg): - instance_name(instance_name_arg) -{ - /* - MT-NOTE: we can not make a search for Instance object here, - because it can dissappear after releasing the lock. - */ -} - - -/************************************************************************** - Implementation of Abstract_instance_cmd. -**************************************************************************/ - -Abstract_instance_cmd::Abstract_instance_cmd( - const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -int Abstract_instance_cmd::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - instance_map->lock(); - - instance= instance_map->find(get_instance_name()); - - if (!instance) - { - instance_map->unlock(); - return ER_BAD_INSTANCE_NAME; - } - - instance->lock(); - instance_map->unlock(); - - err_code= execute_impl(net, instance); - - instance->unlock(); - - if (!err_code) - err_code= send_ok_response(net, connection_id); - - return err_code; -} - - -/************************************************************************** - Implementation of Show_instance_status. -**************************************************************************/ - -Show_instance_status::Show_instance_status(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE STATUS statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_status::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_status::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_status::write_header(st_net *net) -{ - LIST name, state, version, version_number, mysqld_compatible; - LIST *field_list; - LEX_STRING name_field, state_field, version_field, - version_number_field, mysqld_compatible_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "instance_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - state_field.str= (char *) "state"; - state_field.length= DEFAULT_FIELD_LENGTH; - state.data= &state_field; - - version_field.str= (char *) "version"; - version_field.length= MAX_VERSION_LENGTH; - version.data= &version_field; - - version_number_field.str= (char *) "version_number"; - version_number_field.length= MAX_VERSION_LENGTH; - version_number.data= &version_number_field; - - mysqld_compatible_field.str= (char *) "mysqld_compatible"; - mysqld_compatible_field.length= DEFAULT_FIELD_LENGTH; - mysqld_compatible.data= &mysqld_compatible_field; - - field_list= list_add(NULL, &mysqld_compatible); - field_list= list_add(field_list, &version); - field_list= list_add(field_list, &version_number); - field_list= list_add(field_list, &state); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_status::write_data(st_net *net, Instance *instance) -{ - Buffer send_buf; /* buffer for packets */ - char version_num_buf[MAX_VERSION_LENGTH]; - size_t pos= 0; - - const char *state_name= instance->get_state_name(); - const char *version_tag= "unknown"; - const char *version_num= "unknown"; - const char *mysqld_compatible_status= - instance->is_mysqld_compatible() ? "yes" : "no"; - - if (instance->options.mysqld_version) - { - if (parse_version_number(instance->options.mysqld_version, version_num_buf, - sizeof(version_num_buf))) - return ER_OUT_OF_RESOURCES; - - version_num= version_num_buf; - version_tag= instance->options.mysqld_version; - } - - if (store_to_protocol_packet(&send_buf, get_instance_name()->str, &pos) || - store_to_protocol_packet(&send_buf, state_name, &pos) || - store_to_protocol_packet(&send_buf, version_num, &pos) || - store_to_protocol_packet(&send_buf, version_tag, &pos) || - store_to_protocol_packet(&send_buf, mysqld_compatible_status, &pos) || - my_net_write(net, send_buf.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Show_instance_options. -**************************************************************************/ - -Show_instance_options::Show_instance_options( - const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE OPTIONS statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_options::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_options::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_options::write_header(st_net *net) -{ - LIST name, option; - LIST *field_list; - LEX_STRING name_field, option_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "option_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - option_field.str= (char *) "value"; - option_field.length= DEFAULT_FIELD_LENGTH; - option.data= &option_field; - - field_list= list_add(NULL, &option); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_options::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - size_t pos= 0; - - if (store_to_protocol_packet(&send_buff, "instance_name", &pos) || - store_to_protocol_packet(&send_buff, get_instance_name()->str, &pos) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - /* Loop through the options. */ - - for (int i= 0; i < instance->options.get_num_options(); i++) - { - Named_value option= instance->options.get_option(i); - const char *option_value= option.get_value()[0] ? option.get_value() : ""; - - pos= 0; - - if (store_to_protocol_packet(&send_buff, option.get_name(), &pos) || - store_to_protocol_packet(&send_buff, option_value, &pos) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - } - - return 0; -} - - -/************************************************************************** - Implementation of Start_instance. -**************************************************************************/ - -Start_instance::Start_instance(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of START INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_INSTANCE_MISCONFIGURED The instance configuration is invalid - ER_INSTANCE_ALREADY_STARTED The instance is already started - ER_CANNOT_START_INSTANCE The instance could not have been started - - TODO: as soon as this method operates only with Instance, we probably - should introduce a new method (execute_stop_instance()) in Instance and - just call it from here. -*/ - -int Start_instance::execute_impl(st_net * /* net */, Instance *instance) -{ - if (!instance->is_configured()) - return ER_INSTANCE_MISCONFIGURED; - - if (instance->is_active()) - return ER_INSTANCE_ALREADY_STARTED; - - if (instance->start_mysqld()) - return ER_CANNOT_START_INSTANCE; - - instance->reset_stat(); - instance->set_state(Instance::NOT_STARTED); - - return 0; -} - - -int Start_instance::send_ok_response(st_net *net, ulong connection_id) -{ - if (net_send_ok(net, connection_id, "Instance started")) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation of Stop_instance. -**************************************************************************/ - -Stop_instance::Stop_instance(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of STOP INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - - TODO: as soon as this method operates only with Instance, we probably - should introduce a new method (execute_stop_instance()) in Instance and - just call it from here. -*/ - -int Stop_instance::execute_impl(st_net * /* net */, Instance *instance) -{ - if (!instance->is_active()) - return ER_INSTANCE_IS_NOT_STARTED; - - instance->set_state(Instance::STOPPED); - - return instance->stop_mysqld() ? ER_STOP_INSTANCE : 0; -} - - -int Stop_instance::send_ok_response(st_net *net, ulong connection_id) -{ - if (net_send_ok(net, connection_id, NULL)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Create_instance. -**************************************************************************/ - -Create_instance::Create_instance(const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -/** - This operation initializes Create_instance object. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing instance options. - - RETURN - FALSE On success. - TRUE On error. -*/ - -bool Create_instance::init(const char **text) -{ - return options.init() || parse_args(text); -} - - -/** - This operation parses CREATE INSTANCE options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing instance options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Create_instance::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return FALSE; /* OK: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING option_name; - char *option_name_str; - char *option_value_str= NULL; - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - /* Looking for equal sign. */ - - skip_spaces(text); - - if (**text == '=') - { - ++(*text); /* Skip an equal sign. */ - - /* Looking for option value. */ - - skip_spaces(text); - - if (!**text) - return TRUE; /* Syntax error: EOS when option value expected. */ - - if (**text != '\'' && **text != '"') - { - /* Option value is a simple token. */ - - LEX_STRING option_value; - - get_word(text, &option_value.length, ALPHANUM); - - if (option_value.length == 0) - return TRUE; /* internal parser error. */ - - option_value.str= (char *) *text; - *text+= option_value.length; - - if (!(option_value_str= Named_value::alloc_str(&option_value))) - return TRUE; /* out of memory during parsing. */ - } - else - { - /* Option value is a string. */ - - if (parse_option_value(*text, &len, &option_value_str)) - return TRUE; /* Syntax error: invalid string specification. */ - - *text+= len; - } - } - - if (!option_value_str) - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - return TRUE; /* out of memory during parsing. */ - } - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - { - Named_value::free_str(&option_value_str); - return TRUE; /* out of memory during parsing. */ - } - - { - Named_value option(option_name_str, option_value_str); - - if (options.add_element(&option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); - } -} - - -/** - Implementation of CREATE INSTANCE statement. - - Possible error codes: - ER_MALFORMED_INSTANCE_NAME Instance name is malformed - ER_CREATE_EXISTING_INSTANCE There is an instance with the given name - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Create_instance::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - /* Check that the name is valid and there is no instance with such name. */ - - if (!Instance::is_name_valid(get_instance_name())) - return ER_MALFORMED_INSTANCE_NAME; - - /* - NOTE: In order to prevent race condition, we should perform all operations - on under acquired lock. - */ - - instance_map->lock(); - - if (instance_map->find(get_instance_name())) - { - instance_map->unlock(); - return ER_CREATE_EXISTING_INSTANCE; - } - - if ((err_code= instance_map->create_instance(get_instance_name(), &options))) - { - instance_map->unlock(); - return err_code; - } - - instance= instance_map->find(get_instance_name()); - DBUG_ASSERT(instance); - - if ((err_code= create_instance_in_file(get_instance_name(), &options))) - { - instance_map->remove_instance(instance); /* instance is deleted here. */ - - instance_map->unlock(); - return err_code; - } - - /* - CREATE INSTANCE must not lead to start instance, even if it guarded. - - TODO: The problem however is that if Instance Manager restarts after - creating instance, the instance will be restarted (see also BUG#19718). - */ - - instance->set_state(Instance::STOPPED); - - /* That's all. */ - - instance_map->unlock(); - - /* Send the result. */ - - if (net_send_ok(net, connection_id, NULL)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Drop_instance. -**************************************************************************/ - -Drop_instance::Drop_instance(const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of DROP INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_DROP_ACTIVE_INSTANCE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Drop_instance::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - /* Lock Guardian, then Instance_map. */ - - instance_map->lock(); - - /* Find an instance. */ - - instance= instance_map->find(get_instance_name()); - - if (!instance) - { - instance_map->unlock(); - return ER_BAD_INSTANCE_NAME; - } - - instance->lock(); - - /* Check that the instance is offline. */ - - if (instance->is_active()) - { - instance->unlock(); - instance_map->unlock(); - - return ER_DROP_ACTIVE_INSTANCE; - } - - /* Try to remove instance from the file. */ - - err_code= modify_defaults_file(Options::Main::config_file, NULL, NULL, - get_instance_name()->str, MY_REMOVE_SECTION); - DBUG_ASSERT(err_code >= 0 && err_code <= 2); - - if (err_code) - { - log_error("Can not remove instance '%s' from defaults file (%s). " - "Original error code: %d.", - (const char *) get_instance_name()->str, - (const char *) Options::Main::config_file, - (int) err_code); - - instance->unlock(); - instance_map->unlock(); - - return modify_defaults_to_im_error[err_code]; - } - - /* Unlock the instance before destroy. */ - - instance->unlock(); - - /* - Remove instance from the instance map - (the instance will be also destroyed here). - */ - - instance_map->remove_instance(instance); - - /* Unlock the instance map. */ - - instance_map->unlock(); - - /* That's all: send ok. */ - - if (net_send_ok(net, connection_id, "Instance dropped")) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Show_instance_log. -**************************************************************************/ - -Show_instance_log::Show_instance_log(const LEX_STRING *instance_name_arg, - Log_type log_type_arg, - uint size_arg, uint offset_arg) - :Abstract_instance_cmd(instance_name_arg), - log_type(log_type_arg), - size(size_arg), - offset(offset_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE LOG statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OFFSET_ERROR We were requested to read negative number of - bytes from the log - ER_NO_SUCH_LOG The specified type of log is not available for - the given instance - ER_GUESS_LOGFILE IM wasn't able to figure out the log - placement, while it is enabled. Probably user - should specify the path to the logfile - explicitly. - ER_OPEN_LOGFILE Cannot open the logfile - ER_READ_FILE Cannot read the logfile - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_log::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= check_params(instance))) - return err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_log::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_log::check_params(Instance *instance) -{ - const char *logpath= instance->options.logs[log_type]; - - /* Cannot read negative number of bytes. */ - - if (offset > size) - return ER_OFFSET_ERROR; - - /* Instance has no such log. */ - - if (logpath == NULL) - return ER_NO_SUCH_LOG; - - if (*logpath == '\0') - return ER_GUESS_LOGFILE; - - return 0; -} - - -int Show_instance_log::write_header(st_net *net) -{ - LIST name; - LIST *field_list; - LEX_STRING name_field; - - /* Create list of the fields to be passed to send_fields(). */ - - name_field.str= (char *) "Log"; - name_field.length= DEFAULT_FIELD_LENGTH; - - name.data= &name_field; - - field_list= list_add(NULL, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_log::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - size_t pos= 0; - - const char *logpath= instance->options.logs[log_type]; - File fd; - - size_t buff_size; - size_t read_len; - - MY_STAT file_stat; - Buffer read_buff; - - if ((fd= my_open(logpath, O_RDONLY | O_BINARY, MYF(MY_WME))) <= 0) - return ER_OPEN_LOGFILE; - - /* my_fstat doesn't use the flag parameter */ - if (my_fstat(fd, &file_stat, MYF(0))) - { - close(fd); - return ER_OUT_OF_RESOURCES; - } - - /* calculate buffer size */ - buff_size= (size - offset); - - read_buff.reserve(0, buff_size); - - /* read in one chunk */ - read_len= (int)my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0)); - - if ((read_len= my_read(fd, read_buff.buffer, buff_size, MYF(0))) == - MY_FILE_ERROR) - { - close(fd); - return ER_READ_FILE; - } - - close(fd); - - if (store_to_protocol_packet(&send_buff, (char*) read_buff.buffer, &pos, - read_len) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Show_instance_log_files. -**************************************************************************/ - -Show_instance_log_files::Show_instance_log_files - (const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE LOG FILES statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_log_files::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_log_files::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_log_files::write_header(st_net *net) -{ - LIST name, path, size; - LIST *field_list; - LEX_STRING name_field, path_field, size_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "Logfile"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - path_field.str= (char *) "Path"; - path_field.length= DEFAULT_FIELD_LENGTH; - path.data= &path_field; - - size_field.str= (char *) "File size"; - size_field.length= DEFAULT_FIELD_LENGTH; - size.data= &size_field; - - field_list= list_add(NULL, &size); - field_list= list_add(field_list, &path); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_log_files::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - - /* - We have alike structure in instance_options.cc. We use such to be able - to loop through the options, which we need to handle in some common way. - */ - struct log_files_st - { - const char *name; - const char *value; - } logs[]= - { - {"ERROR LOG", instance->options.logs[IM_LOG_ERROR]}, - {"GENERAL LOG", instance->options.logs[IM_LOG_GENERAL]}, - {"SLOW LOG", instance->options.logs[IM_LOG_SLOW]}, - {NULL, NULL} - }; - struct log_files_st *log_files; - - for (log_files= logs; log_files->name; log_files++) - { - if (!log_files->value) - continue; - - struct stat file_stat; - /* - Save some more space for the log file names. In fact all - we need is strlen("GENERAL_LOG") + 1 - */ - enum { LOG_NAME_BUFFER_SIZE= 20 }; - char buff[LOG_NAME_BUFFER_SIZE]; - - size_t pos= 0; - - const char *log_path= ""; - const char *log_size= "0"; - - if (!stat(log_files->value, &file_stat) && - MY_S_ISREG(file_stat.st_mode)) - { - int10_to_str(file_stat.st_size, buff, 10); - - log_path= log_files->value; - log_size= buff; - } - - if (store_to_protocol_packet(&send_buff, log_files->name, &pos) || - store_to_protocol_packet(&send_buff, log_path, &pos) || - store_to_protocol_packet(&send_buff, log_size, &pos) || - my_net_write(net, send_buff.buffer, pos)) - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Abstract_option_cmd. -**************************************************************************/ - -/** - Instance_options_list -- a data class representing a list of options for - some instance. -*/ - -class Instance_options_list -{ -public: - Instance_options_list(const LEX_STRING *instance_name_arg); - -public: - bool init(); - - const LEX_STRING *get_instance_name() const - { - return instance_name.get_str(); - } - -public: - /* - This member is set and used only in Abstract_option_cmd::execute_impl(). - Normally it is not used (and should not). - - The problem is that construction and execution of commands are made not - in one transaction (not under one lock session). So, we can not initialize - instance in constructor and use it in execution. - */ - Instance *instance; - - Named_value_arr options; - -private: - Instance_name instance_name; -}; - - -/**************************************************************************/ - -Instance_options_list::Instance_options_list( - const LEX_STRING *instance_name_arg) - :instance(NULL), - instance_name(instance_name_arg) -{ -} - - -bool Instance_options_list::init() -{ - return options.init(); -} - - -/**************************************************************************/ - -C_MODE_START - -static uchar* get_item_key(const uchar* item, size_t* len, - my_bool __attribute__((unused)) t) -{ - const Instance_options_list *lst= (const Instance_options_list *) item; - *len= lst->get_instance_name()->length; - return (uchar *) lst->get_instance_name()->str; -} - -static void delete_item(void *item) -{ - delete (Instance_options_list *) item; -} - -C_MODE_END - - -/**************************************************************************/ - -Abstract_option_cmd::Abstract_option_cmd() - :initialized(FALSE) -{ -} - - -Abstract_option_cmd::~Abstract_option_cmd() -{ - if (initialized) - hash_free(&instance_options_map); -} - - -bool Abstract_option_cmd::add_option(const LEX_STRING *instance_name, - Named_value *option) -{ - Instance_options_list *lst= get_instance_options_list(instance_name); - - if (!lst) - return TRUE; - - lst->options.add_element(option); - - return FALSE; -} - - -bool Abstract_option_cmd::init(const char **text) -{ - static const int INITIAL_HASH_SIZE= 16; - - if (hash_init(&instance_options_map, default_charset_info, - INITIAL_HASH_SIZE, 0, 0, get_item_key, delete_item, 0)) - return TRUE; - - if (parse_args(text)) - return TRUE; - - initialized= TRUE; - - return FALSE; -} - - -/** - Correct the option file. The "skip" option is used to remove the found - option. - - SYNOPSIS - Abstract_option_cmd::correct_file() - skip Skip the option, being searched while writing the result file. - That is, to delete it. - - RETURN - 0 Success - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_ACCESS_OPTION_FILE Cannot access the option file -*/ - -int Abstract_option_cmd::correct_file(Instance *instance, Named_value *option, - bool skip) -{ - int err_code= modify_defaults_file(Options::Main::config_file, - option->get_name(), - option->get_value(), - instance->get_name()->str, - skip); - - DBUG_ASSERT(err_code >= 0 && err_code <= 2); - - if (err_code) - { - log_error("Can not modify option (%s) in defaults file (%s). " - "Original error code: %d.", - (const char *) option->get_name(), - (const char *) Options::Main::config_file, - (int) err_code); - } - - return modify_defaults_to_im_error[err_code]; -} - - -/** - Lock Instance Map and call execute_impl(). - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_INCOMPATIBLE_OPTION The specified option can not be set for - mysqld-compatible instance - ER_INSTANCE_IS_ACTIVE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Abstract_option_cmd::execute(st_net *net, ulong connection_id) -{ - int err_code; - - instance_map->lock(); - - err_code= execute_impl(net, connection_id); - - instance_map->unlock(); - - return err_code; -} - - -Instance_options_list * -Abstract_option_cmd::get_instance_options_list(const LEX_STRING *instance_name) -{ - Instance_options_list *lst= - (Instance_options_list *) hash_search(&instance_options_map, - (uchar *) instance_name->str, - instance_name->length); - - if (!lst) - { - lst= new Instance_options_list(instance_name); - - if (!lst) - return NULL; - - if (lst->init() || my_hash_insert(&instance_options_map, (uchar *) lst)) - { - delete lst; - return NULL; - } - } - - return lst; -} - - -/** - Skeleton implementation of option-management command. - - MT-NOTE: Instance Map is locked before calling this operation. -*/ -int Abstract_option_cmd::execute_impl(st_net *net, ulong connection_id) -{ - int err_code= 0; - - /* Check that all the specified instances exist and are offline. */ - - for (uint i= 0; i < instance_options_map.records; ++i) - { - Instance_options_list *lst= - (Instance_options_list *) hash_element(&instance_options_map, i); - - bool instance_is_active; - - lst->instance= instance_map->find(lst->get_instance_name()); - - if (!lst->instance) - return ER_BAD_INSTANCE_NAME; - - lst->instance->lock(); - instance_is_active= lst->instance->is_active(); - lst->instance->unlock(); - - if (instance_is_active) - return ER_INSTANCE_IS_ACTIVE; - } - - /* Perform command-specific (SET/UNSET) actions. */ - - for (uint i= 0; i < instance_options_map.records; ++i) - { - Instance_options_list *lst= - (Instance_options_list *) hash_element(&instance_options_map, i); - - lst->instance->lock(); - - for (int j= 0; j < lst->options.get_size(); ++j) - { - Named_value option= lst->options.get_element(j); - err_code= process_option(lst->instance, &option); - - if (err_code) - break; - } - - lst->instance->unlock(); - - if (err_code) - break; - } - - if (err_code == 0) - net_send_ok(net, connection_id, NULL); - - return err_code; -} - - -/************************************************************************** - Implementation of Set_option. -**************************************************************************/ - -/** - This operation parses SET options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Set_option::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return TRUE; /* Syntax error: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING instance_name; - LEX_STRING option_name; - char *option_name_str; - char *option_value_str= NULL; - - /* Looking for instance name. */ - - get_word(text, &instance_name.length, ALPHANUM); - - if (instance_name.length == 0) - return TRUE; /* Syntax error: instance name expected. */ - - instance_name.str= (char *) *text; - *text+= instance_name.length; - - skip_spaces(text); - - /* Check the the delimiter is a dot. */ - - if (**text != '.') - return TRUE; /* Syntax error: dot expected. */ - - ++(*text); - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - /* Looking for equal sign. */ - - skip_spaces(text); - - if (**text == '=') - { - ++(*text); /* Skip an equal sign. */ - - /* Looking for option value. */ - - skip_spaces(text); - - if (!**text) - return TRUE; /* Syntax error: EOS when option value expected. */ - - if (**text != '\'' && **text != '"') - { - /* Option value is a simple token. */ - - LEX_STRING option_value; - - get_word(text, &option_value.length, ALPHANUM); - - if (option_value.length == 0) - return TRUE; /* internal parser error. */ - - option_value.str= (char *) *text; - *text+= option_value.length; - - if (!(option_value_str= Named_value::alloc_str(&option_value))) - return TRUE; /* out of memory during parsing. */ - } - else - { - /* Option value is a string. */ - - if (parse_option_value(*text, &len, &option_value_str)) - return TRUE; /* Syntax error: invalid string specification. */ - - *text+= len; - } - } - - if (!option_value_str) - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - return TRUE; /* out of memory during parsing. */ - } - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - { - Named_value::free_str(&option_name_str); - return TRUE; /* out of memory during parsing. */ - } - - { - Named_value option(option_name_str, option_value_str); - - if (add_option(&instance_name, &option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); /* Skip a comma. */ - } -} - - -int Set_option::process_option(Instance *instance, Named_value *option) -{ - /* Check that the option is valid. */ - - if (instance->is_mysqld_compatible() && - Instance_options::is_option_im_specific(option->get_name())) - { - log_error("IM-option (%s) can not be used " - "in the configuration of mysqld-compatible instance (%s).", - (const char *) option->get_name(), - (const char *) instance->get_name()->str); - return ER_INCOMPATIBLE_OPTION; - } - - /* Update the configuration file. */ - - int err_code= correct_file(instance, option, FALSE); - - if (err_code) - return err_code; - - /* Update the internal cache. */ - - if (instance->options.set_option(option)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation of Unset_option. -**************************************************************************/ - -/** - This operation parses UNSET options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Unset_option::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return TRUE; /* Syntax error: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING instance_name; - LEX_STRING option_name; - char *option_name_str; - char *option_value_str; - - /* Looking for instance name. */ - - get_word(text, &instance_name.length, ALPHANUM); - - if (instance_name.length == 0) - return TRUE; /* Syntax error: instance name expected. */ - - instance_name.str= (char *) *text; - *text+= instance_name.length; - - skip_spaces(text); - - /* Check the the delimiter is a dot. */ - - if (**text != '.') - return TRUE; /* Syntax error: dot expected. */ - - ++(*text); /* Skip a dot. */ - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - return TRUE; /* out of memory during parsing. */ - - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - { - Named_value::free_str(&option_name_str); - return TRUE; - } - } - - { - Named_value option(option_name_str, option_value_str); - - if (add_option(&instance_name, &option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); /* Skip a comma. */ - } -} - - -/** - Implementation of UNSET statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance name specified is not valid - ER_INSTANCE_IS_ACTIVE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Unset_option::process_option(Instance *instance, Named_value *option) -{ - /* Update the configuration file. */ - - int err_code= correct_file(instance, option, TRUE); - - if (err_code) - return err_code; - - /* Update the internal cache. */ - - instance->options.unset_option(option->get_name()); - - return 0; -} - - -/************************************************************************** - Implementation of Syntax_error. -**************************************************************************/ - -int Syntax_error::execute(st_net * /* net */, ulong /* connection_id */) -{ - return ER_SYNTAX_ERROR; -} |