summaryrefslogtreecommitdiff
path: root/server-tools/instance-manager/commands.cc
diff options
context:
space:
mode:
Diffstat (limited to 'server-tools/instance-manager/commands.cc')
-rw-r--r--server-tools/instance-manager/commands.cc1752
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;
-}