669 lines
18 KiB
C++
669 lines
18 KiB
C++
|
|
/* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
|
|||
|
|
|
|||
|
|
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|||
|
|
|
|||
|
|
#include "rpl_info_file.h"
|
|||
|
|
|
|||
|
|
#include "my_dir.h" // MY_STAT
|
|||
|
|
#include "my_thread_local.h" // my_errno
|
|||
|
|
#include "dynamic_ids.h" // Server_ids
|
|||
|
|
#include "log.h" // sql_print_error
|
|||
|
|
|
|||
|
|
|
|||
|
|
int init_ulongvar_from_file(ulong* var, IO_CACHE* f, ulong default_val);
|
|||
|
|
int init_strvar_from_file(char *var, size_t max_size, IO_CACHE *f,
|
|||
|
|
const char *default_val);
|
|||
|
|
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
|
|||
|
|
int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val);
|
|||
|
|
bool init_dynarray_intvar_from_file(char *buffer, size_t size,
|
|||
|
|
char **buffer_act, IO_CACHE* f);
|
|||
|
|
|
|||
|
|
Rpl_info_file::Rpl_info_file(const int nparam,
|
|||
|
|
const char* param_pattern_fname,
|
|||
|
|
const char* param_info_fname,
|
|||
|
|
bool indexed_arg)
|
|||
|
|
:Rpl_info_handler(nparam), info_fd(-1), name_indexed(indexed_arg)
|
|||
|
|
{
|
|||
|
|
DBUG_ENTER("Rpl_info_file::Rpl_info_file");
|
|||
|
|
|
|||
|
|
memset(&info_file, 0, sizeof(info_file));
|
|||
|
|
fn_format(pattern_fname, param_pattern_fname, mysql_data_home, "", 4 + 32);
|
|||
|
|
fn_format(info_fname, param_info_fname, mysql_data_home, "", 4 + 32);
|
|||
|
|
|
|||
|
|
DBUG_VOID_RETURN;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Rpl_info_file::~Rpl_info_file()
|
|||
|
|
{
|
|||
|
|
DBUG_ENTER("Rpl_info_file::~Rpl_info_file");
|
|||
|
|
|
|||
|
|
do_end_info();
|
|||
|
|
|
|||
|
|
DBUG_VOID_RETURN;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int Rpl_info_file::do_init_info(uint instance)
|
|||
|
|
{
|
|||
|
|
DBUG_ENTER("Rpl_info_file::do_init_info(uint)");
|
|||
|
|
|
|||
|
|
char fname_local[FN_REFLEN];
|
|||
|
|
char *pos= my_stpcpy(fname_local, pattern_fname);
|
|||
|
|
if (name_indexed)
|
|||
|
|
sprintf(pos, "%u", instance);
|
|||
|
|
|
|||
|
|
fn_format(info_fname, fname_local, mysql_data_home, "", 4 + 32);
|
|||
|
|
DBUG_RETURN(do_init_info());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int Rpl_info_file::do_init_info()
|
|||
|
|
{
|
|||
|
|
int error= 0;
|
|||
|
|
DBUG_ENTER("Rpl_info_file::do_init_info");
|
|||
|
|
|
|||
|
|
/* does info file exist ? */
|
|||
|
|
enum_return_check ret_check= do_check_info();
|
|||
|
|
if (ret_check == REPOSITORY_DOES_NOT_EXIST)
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
If someone removed the file from underneath our feet, just close
|
|||
|
|
the old descriptor and re-create the old file
|
|||
|
|
*/
|
|||
|
|
if (info_fd >= 0)
|
|||
|
|
{
|
|||
|
|
if (my_b_inited(&info_file))
|
|||
|
|
end_io_cache(&info_file);
|
|||
|
|
my_close(info_fd, MYF(MY_WME));
|
|||
|
|
}
|
|||
|
|
if ((info_fd = my_open(info_fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
|
|||
|
|
{
|
|||
|
|
sql_print_error("Failed to create a new info file (\
|
|||
|
|
file '%s', errno %d)", info_fname, my_errno());
|
|||
|
|
error= 1;
|
|||
|
|
}
|
|||
|
|
else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
|
|||
|
|
MYF(MY_WME)))
|
|||
|
|
{
|
|||
|
|
sql_print_error("Failed to create a cache on info file (\
|
|||
|
|
file '%s')", info_fname);
|
|||
|
|
error= 1;
|
|||
|
|
}
|
|||
|
|
if (error)
|
|||
|
|
{
|
|||
|
|
if (info_fd >= 0)
|
|||
|
|
my_close(info_fd, MYF(0));
|
|||
|
|
info_fd= -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/* file exists */
|
|||
|
|
else if (ret_check == REPOSITORY_EXISTS)
|
|||
|
|
{
|
|||
|
|
if (info_fd >= 0)
|
|||
|
|
reinit_io_cache(&info_file, READ_CACHE, 0L,0,0);
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if ((info_fd = my_open(info_fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
|
|||
|
|
{
|
|||
|
|
sql_print_error("Failed to open the existing info file (\
|
|||
|
|
file '%s', errno %d)", info_fname, my_errno());
|
|||
|
|
error= 1;
|
|||
|
|
}
|
|||
|
|
else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,
|
|||
|
|
0, MYF(MY_WME)))
|
|||
|
|
{
|
|||
|
|
sql_print_error("Failed to create a cache on info file (\
|
|||
|
|
file '%s')", info_fname);
|
|||
|
|
error= 1;
|
|||
|
|
}
|
|||
|
|
if (error)
|
|||
|
|
{
|
|||
|
|
if (info_fd >= 0)
|
|||
|
|
my_close(info_fd, MYF(0));
|
|||
|
|
info_fd= -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
error= 1;
|
|||
|
|
DBUG_RETURN(error);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int Rpl_info_file::do_prepare_info_for_read()
|
|||
|
|
{
|
|||
|
|
cursor= 0;
|
|||
|
|
prv_error= FALSE;
|
|||
|
|
return (reinit_io_cache(&info_file, READ_CACHE, 0L, 0, 0));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int Rpl_info_file::do_prepare_info_for_write()
|
|||
|
|
{
|
|||
|
|
cursor= 0;
|
|||
|
|
prv_error= FALSE;
|
|||
|
|
return (reinit_io_cache(&info_file, WRITE_CACHE, 0L, 0, 1));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inline enum_return_check do_check_repository_file(const char *fname)
|
|||
|
|
{
|
|||
|
|
if (my_access(fname, F_OK))
|
|||
|
|
return REPOSITORY_DOES_NOT_EXIST;
|
|||
|
|
|
|||
|
|
if (my_access(fname, F_OK | R_OK | W_OK))
|
|||
|
|
return ERROR_CHECKING_REPOSITORY;
|
|||
|
|
|
|||
|
|
return REPOSITORY_EXISTS;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
The method verifies existence of an instance of the repository.
|
|||
|
|
|
|||
|
|
@param instance an index in the repository
|
|||
|
|
@retval REPOSITORY_EXISTS when the check is successful
|
|||
|
|
@retval REPOSITORY_DOES_NOT_EXIST otherwise
|
|||
|
|
|
|||
|
|
@note This method also verifies overall integrity
|
|||
|
|
of the repositories to make sure they are indexed without any gaps.
|
|||
|
|
*/
|
|||
|
|
enum_return_check Rpl_info_file::do_check_info(uint instance)
|
|||
|
|
{
|
|||
|
|
uint i;
|
|||
|
|
enum_return_check last_check= REPOSITORY_EXISTS;
|
|||
|
|
char fname_local[FN_REFLEN];
|
|||
|
|
char *pos= NULL;
|
|||
|
|
|
|||
|
|
for (i= 1; i <= instance && last_check == REPOSITORY_EXISTS; i++)
|
|||
|
|
{
|
|||
|
|
pos= my_stpcpy(fname_local, pattern_fname);
|
|||
|
|
if (name_indexed)
|
|||
|
|
sprintf(pos, "%u", i);
|
|||
|
|
fn_format(fname_local, fname_local, mysql_data_home, "", 4 + 32);
|
|||
|
|
last_check= do_check_repository_file(fname_local);
|
|||
|
|
}
|
|||
|
|
return last_check;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
enum_return_check Rpl_info_file::do_check_info()
|
|||
|
|
{
|
|||
|
|
return do_check_repository_file(info_fname);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
The function counts number of files in a range starting
|
|||
|
|
from one. The range degenerates into one item when @c indexed is false.
|
|||
|
|
Scanning ends once the next indexed file is not found.
|
|||
|
|
|
|||
|
|
@param nparam Number of fields
|
|||
|
|
@param param_pattern
|
|||
|
|
a string pattern to generate
|
|||
|
|
the actual file name
|
|||
|
|
@param indexed indicates whether the file is indexed and if so
|
|||
|
|
there is a range to count in.
|
|||
|
|
@param[out] counter the number of discovered instances before the first
|
|||
|
|
unsuccess in locating the next file.
|
|||
|
|
|
|||
|
|
@retval false All OK
|
|||
|
|
@retval true An error
|
|||
|
|
*/
|
|||
|
|
bool Rpl_info_file::do_count_info(const int nparam,
|
|||
|
|
const char* param_pattern,
|
|||
|
|
bool indexed,
|
|||
|
|
uint* counter)
|
|||
|
|
{
|
|||
|
|
uint i= 0;
|
|||
|
|
Rpl_info_file* info= NULL;
|
|||
|
|
|
|||
|
|
char fname_local[FN_REFLEN];
|
|||
|
|
char *pos= NULL;
|
|||
|
|
enum_return_check last_check= REPOSITORY_EXISTS;
|
|||
|
|
|
|||
|
|
DBUG_ENTER("Rpl_info_file::do_count_info");
|
|||
|
|
|
|||
|
|
if (!(info= new Rpl_info_file(nparam, param_pattern, "", indexed)))
|
|||
|
|
DBUG_RETURN(true);
|
|||
|
|
|
|||
|
|
for (i= 1; last_check == REPOSITORY_EXISTS; i++)
|
|||
|
|
{
|
|||
|
|
pos= my_stpcpy(fname_local, param_pattern);
|
|||
|
|
if (indexed)
|
|||
|
|
{
|
|||
|
|
sprintf(pos, "%u", i);
|
|||
|
|
}
|
|||
|
|
fn_format(fname_local, fname_local, mysql_data_home, "", 4 + 32);
|
|||
|
|
if ((last_check= do_check_repository_file(fname_local)) == REPOSITORY_EXISTS)
|
|||
|
|
(*counter)++;
|
|||
|
|
// just one loop pass for MI and RLI file
|
|||
|
|
if (!indexed)
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
delete info;
|
|||
|
|
|
|||
|
|
DBUG_RETURN(false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int Rpl_info_file::do_flush_info(const bool force)
|
|||
|
|
{
|
|||
|
|
int error= 0;
|
|||
|
|
|
|||
|
|
DBUG_ENTER("Rpl_info_file::do_flush_info");
|
|||
|
|
|
|||
|
|
if (flush_io_cache(&info_file))
|
|||
|
|
error= 1;
|
|||
|
|
if (!error && (force ||
|
|||
|
|
(sync_period &&
|
|||
|
|
++(sync_counter) >= sync_period)))
|
|||
|
|
{
|
|||
|
|
if (my_sync(info_fd, MYF(MY_WME)))
|
|||
|
|
error= 1;
|
|||
|
|
sync_counter= 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
DBUG_RETURN(error);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Rpl_info_file::do_end_info()
|
|||
|
|
{
|
|||
|
|
DBUG_ENTER("Rpl_info_file::do_end_info");
|
|||
|
|
|
|||
|
|
if (info_fd >= 0)
|
|||
|
|
{
|
|||
|
|
if (my_b_inited(&info_file))
|
|||
|
|
end_io_cache(&info_file);
|
|||
|
|
my_close(info_fd, MYF(MY_WME));
|
|||
|
|
info_fd = -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
DBUG_VOID_RETURN;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int Rpl_info_file::do_remove_info()
|
|||
|
|
{
|
|||
|
|
MY_STAT stat_area;
|
|||
|
|
int error= 0;
|
|||
|
|
|
|||
|
|
DBUG_ENTER("Rpl_info_file::do_remove_info");
|
|||
|
|
|
|||
|
|
if (my_stat(info_fname, &stat_area, MYF(0)) && my_delete(info_fname, MYF(MY_WME)))
|
|||
|
|
error= 1;
|
|||
|
|
|
|||
|
|
DBUG_RETURN(error);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int Rpl_info_file::do_clean_info()
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
There is nothing to do here. Maybe we can truncate the
|
|||
|
|
file in the future. Howerver, for now, there is no need.
|
|||
|
|
*/
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int Rpl_info_file::do_reset_info(const int nparam,
|
|||
|
|
const char* param_pattern,
|
|||
|
|
bool indexed)
|
|||
|
|
{
|
|||
|
|
int error= false;
|
|||
|
|
uint i= 0;
|
|||
|
|
Rpl_info_file* info= NULL;
|
|||
|
|
char fname_local[FN_REFLEN];
|
|||
|
|
char *pos= NULL;
|
|||
|
|
enum_return_check last_check= REPOSITORY_EXISTS;
|
|||
|
|
|
|||
|
|
DBUG_ENTER("Rpl_info_file::do_count_info");
|
|||
|
|
|
|||
|
|
if (!(info= new Rpl_info_file(nparam, param_pattern, "", indexed)))
|
|||
|
|
DBUG_RETURN(true);
|
|||
|
|
|
|||
|
|
for (i= 1; last_check == REPOSITORY_EXISTS; i++)
|
|||
|
|
{
|
|||
|
|
pos= my_stpcpy(fname_local, param_pattern);
|
|||
|
|
if (indexed)
|
|||
|
|
{
|
|||
|
|
sprintf(pos, "%u", i);
|
|||
|
|
}
|
|||
|
|
fn_format(fname_local, fname_local, mysql_data_home, "", 4 + 32);
|
|||
|
|
if ((last_check= do_check_repository_file(fname_local)) == REPOSITORY_EXISTS)
|
|||
|
|
if (my_delete(fname_local, MYF(MY_WME)))
|
|||
|
|
error= true;
|
|||
|
|
// just one loop pass for MI and RLI file
|
|||
|
|
if (!indexed)
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
delete info;
|
|||
|
|
|
|||
|
|
DBUG_RETURN(error);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_set_info(const int pos, const char *value)
|
|||
|
|
{
|
|||
|
|
return (my_b_printf(&info_file, "%s\n", value) > (size_t) 0 ?
|
|||
|
|
FALSE : TRUE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_set_info(const int pos, const uchar *value,
|
|||
|
|
const size_t size)
|
|||
|
|
{
|
|||
|
|
return (my_b_write(&info_file, value, size));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_set_info(const int pos, const ulong value)
|
|||
|
|
{
|
|||
|
|
return (my_b_printf(&info_file, "%lu\n", value) > (size_t) 0 ?
|
|||
|
|
FALSE : TRUE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_set_info(const int pos, const int value)
|
|||
|
|
{
|
|||
|
|
return (my_b_printf(&info_file, "%d\n", value) > (size_t) 0 ?
|
|||
|
|
FALSE : TRUE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_set_info(const int pos, const float value)
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
64 bytes provide enough space considering that the precision is 3
|
|||
|
|
bytes (See the appropriate set funciton):
|
|||
|
|
|
|||
|
|
FLT_MAX The value of this macro is the maximum number representable
|
|||
|
|
in type float. It is supposed to be at least 1E+37.
|
|||
|
|
FLT_MIN Similar to the FLT_MAX, we have 1E-37.
|
|||
|
|
|
|||
|
|
If a file is manually and not properly changed, this function may
|
|||
|
|
crash the server.
|
|||
|
|
*/
|
|||
|
|
char buffer[64];
|
|||
|
|
|
|||
|
|
sprintf(buffer, "%.3f", value);
|
|||
|
|
|
|||
|
|
return (my_b_printf(&info_file, "%s\n", buffer) > (size_t) 0 ?
|
|||
|
|
FALSE : TRUE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_set_info(const int pos, const Server_ids *value)
|
|||
|
|
{
|
|||
|
|
bool error= TRUE;
|
|||
|
|
String buffer;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
This produces a line listing the total number and all the server_ids.
|
|||
|
|
*/
|
|||
|
|
if (const_cast<Server_ids*>(value)->pack_dynamic_ids(&buffer))
|
|||
|
|
goto err;
|
|||
|
|
|
|||
|
|
error= (my_b_printf(&info_file, "%s\n", buffer.c_ptr_safe()) >
|
|||
|
|
(size_t) 0 ? FALSE : TRUE);
|
|||
|
|
err:
|
|||
|
|
return error;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_get_info(const int pos, char *value, const size_t size,
|
|||
|
|
const char *default_value)
|
|||
|
|
{
|
|||
|
|
return (init_strvar_from_file(value, size, &info_file,
|
|||
|
|
default_value));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_get_info(const int pos, uchar *value, const size_t size,
|
|||
|
|
const uchar *default_value)
|
|||
|
|
{
|
|||
|
|
return(my_b_read(&info_file, value, size));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_get_info(const int pos, ulong *value,
|
|||
|
|
const ulong default_value)
|
|||
|
|
{
|
|||
|
|
return (init_ulongvar_from_file(value, &info_file,
|
|||
|
|
default_value));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_get_info(const int pos, int *value,
|
|||
|
|
const int default_value)
|
|||
|
|
{
|
|||
|
|
return (init_intvar_from_file(value, &info_file,
|
|||
|
|
(int) default_value));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_get_info(const int pos, float *value,
|
|||
|
|
const float default_value)
|
|||
|
|
{
|
|||
|
|
return (init_floatvar_from_file(value, &info_file,
|
|||
|
|
default_value));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_get_info(const int pos, Server_ids *value,
|
|||
|
|
const Server_ids *default_value MY_ATTRIBUTE((unused)))
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
Static buffer to use most of the times. However, if it is not big
|
|||
|
|
enough to accommodate the server ids, a new buffer is allocated.
|
|||
|
|
*/
|
|||
|
|
const int array_size= 16 * (sizeof(long) * 3 + 1);
|
|||
|
|
char buffer[array_size];
|
|||
|
|
char *buffer_act= buffer;
|
|||
|
|
|
|||
|
|
bool error= init_dynarray_intvar_from_file(buffer, sizeof(buffer),
|
|||
|
|
&buffer_act,
|
|||
|
|
&info_file);
|
|||
|
|
if (!error)
|
|||
|
|
value->unpack_dynamic_ids(buffer_act);
|
|||
|
|
|
|||
|
|
if (buffer != buffer_act)
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
Release the buffer allocated while reading the server ids
|
|||
|
|
from the file.
|
|||
|
|
*/
|
|||
|
|
my_free(buffer_act);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return error;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
char* Rpl_info_file::do_get_description_info()
|
|||
|
|
{
|
|||
|
|
return info_fname;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_is_transactional()
|
|||
|
|
{
|
|||
|
|
return FALSE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Rpl_info_file::do_update_is_transactional()
|
|||
|
|
{
|
|||
|
|
DBUG_EXECUTE_IF("simulate_update_is_transactional_error",
|
|||
|
|
{
|
|||
|
|
return TRUE;
|
|||
|
|
});
|
|||
|
|
return FALSE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint Rpl_info_file::do_get_rpl_info_type()
|
|||
|
|
{
|
|||
|
|
return INFO_REPOSITORY_FILE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int init_strvar_from_file(char *var, size_t max_size, IO_CACHE *f,
|
|||
|
|
const char *default_val)
|
|||
|
|
{
|
|||
|
|
size_t length;
|
|||
|
|
DBUG_ENTER("init_strvar_from_file");
|
|||
|
|
|
|||
|
|
if ((length=my_b_gets(f,var, max_size)))
|
|||
|
|
{
|
|||
|
|
char* last_p = var + length -1;
|
|||
|
|
if (*last_p == '\n')
|
|||
|
|
*last_p = 0; // if we stopped on newline, kill it
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
If we truncated a line or stopped on last char, remove all chars
|
|||
|
|
up to and including newline.
|
|||
|
|
*/
|
|||
|
|
int c;
|
|||
|
|
while (((c=my_b_get(f)) != '\n' && c != my_b_EOF)) ;
|
|||
|
|
}
|
|||
|
|
DBUG_RETURN(0);
|
|||
|
|
}
|
|||
|
|
else if (default_val)
|
|||
|
|
{
|
|||
|
|
strmake(var, default_val, max_size-1);
|
|||
|
|
DBUG_RETURN(0);
|
|||
|
|
}
|
|||
|
|
DBUG_RETURN(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
32 bytes provide enough space:
|
|||
|
|
|
|||
|
|
INT_MIN –2,147,483,648
|
|||
|
|
INT_MAX +2,147,483,647
|
|||
|
|
*/
|
|||
|
|
char buf[32];
|
|||
|
|
DBUG_ENTER("init_intvar_from_file");
|
|||
|
|
|
|||
|
|
if (my_b_gets(f, buf, sizeof(buf)))
|
|||
|
|
{
|
|||
|
|
*var = atoi(buf);
|
|||
|
|
DBUG_RETURN(0);
|
|||
|
|
}
|
|||
|
|
else if (default_val)
|
|||
|
|
{
|
|||
|
|
*var = default_val;
|
|||
|
|
DBUG_RETURN(0);
|
|||
|
|
}
|
|||
|
|
DBUG_RETURN(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int init_ulongvar_from_file(ulong* var, IO_CACHE* f, ulong default_val)
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
32 bytes provide enough space:
|
|||
|
|
|
|||
|
|
ULONG_MAX 32 bit compiler +4,294,967,295
|
|||
|
|
64 bit compiler +18,446,744,073,709,551,615
|
|||
|
|
*/
|
|||
|
|
char buf[32];
|
|||
|
|
DBUG_ENTER("init_ulongvar_from_file");
|
|||
|
|
|
|||
|
|
if (my_b_gets(f, buf, sizeof(buf)))
|
|||
|
|
{
|
|||
|
|
*var = strtoul(buf, 0, 10);
|
|||
|
|
DBUG_RETURN(0);
|
|||
|
|
}
|
|||
|
|
else if (default_val)
|
|||
|
|
{
|
|||
|
|
*var = default_val;
|
|||
|
|
DBUG_RETURN(0);
|
|||
|
|
}
|
|||
|
|
DBUG_RETURN(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val)
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
64 bytes provide enough space considering that the precision is 3
|
|||
|
|
bytes (See the appropriate set funciton):
|
|||
|
|
|
|||
|
|
FLT_MAX The value of this macro is the maximum number representable
|
|||
|
|
in type float. It is supposed to be at least 1E+37.
|
|||
|
|
FLT_MIN Similar to the FLT_MAX, we have 1E-37.
|
|||
|
|
|
|||
|
|
If a file is manually and not properly changed, this function may
|
|||
|
|
crash the server.
|
|||
|
|
*/
|
|||
|
|
char buf[64];
|
|||
|
|
DBUG_ENTER("init_floatvar_from_file");
|
|||
|
|
|
|||
|
|
if (my_b_gets(f, buf, sizeof(buf)))
|
|||
|
|
{
|
|||
|
|
if (sscanf(buf, "%f", var) != 1)
|
|||
|
|
DBUG_RETURN(1);
|
|||
|
|
else
|
|||
|
|
DBUG_RETURN(0);
|
|||
|
|
}
|
|||
|
|
else if (default_val != 0.0)
|
|||
|
|
{
|
|||
|
|
*var = default_val;
|
|||
|
|
DBUG_RETURN(0);
|
|||
|
|
}
|
|||
|
|
DBUG_RETURN(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
TODO - Improve this function to use String and avoid this weird computation
|
|||
|
|
to calculate the size of the buffers.
|
|||
|
|
|
|||
|
|
Particularly, this function is responsible for restoring IGNORE_SERVER_IDS
|
|||
|
|
list of servers whose events the slave is going to ignore (to not log them
|
|||
|
|
in the relay log).
|
|||
|
|
|
|||
|
|
Items being read are supposed to be decimal output of values of a type
|
|||
|
|
shorter or equal of @c long and separated by the single space.
|
|||
|
|
|
|||
|
|
@param buffer Put the read values in this static buffer
|
|||
|
|
@param buffer Size of the static buffer
|
|||
|
|
@param buffer_act Points to the final buffer as dynamic buffer may
|
|||
|
|
be used if the static buffer is not big enough.
|
|||
|
|
|
|||
|
|
@retval 0 All OK
|
|||
|
|
@retval non-zero An error
|
|||
|
|
*/
|
|||
|
|
bool init_dynarray_intvar_from_file(char *buffer, size_t size,
|
|||
|
|
char **buffer_act, IO_CACHE* f)
|
|||
|
|
{
|
|||
|
|
char *buf= buffer; // actual buffer can be dynamic if static is short
|
|||
|
|
char *buf_act= buffer;
|
|||
|
|
char *last;
|
|||
|
|
uint num_items; // number of items of `arr'
|
|||
|
|
size_t read_size;
|
|||
|
|
|
|||
|
|
DBUG_ENTER("init_dynarray_intvar_from_file");
|
|||
|
|
|
|||
|
|
if ((read_size= my_b_gets(f, buf_act, size)) == 0)
|
|||
|
|
{
|
|||
|
|
DBUG_RETURN(FALSE); // no line in master.info
|
|||
|
|
}
|
|||
|
|
if (read_size + 1 == size && buf[size - 2] != '\n')
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
short read happend; allocate sufficient memory and make the 2nd read
|
|||
|
|
*/
|
|||
|
|
char buf_work[(sizeof(long) * 3 + 1) * 16];
|
|||
|
|
memcpy(buf_work, buf, sizeof(buf_work));
|
|||
|
|
num_items= atoi(my_strtok_r(buf_work, " ", &last));
|
|||
|
|
size_t snd_size;
|
|||
|
|
/*
|
|||
|
|
max size upper bound approximate estimation bases on the formula:
|
|||
|
|
(the items number + items themselves) *
|
|||
|
|
(decimal size + space) - 1 + `\n' + '\0'
|
|||
|
|
*/
|
|||
|
|
size_t max_size= (1 + num_items) * (sizeof(long) * 3 + 1) + 1;
|
|||
|
|
if (! (buf_act= (char*) my_malloc(key_memory_Rpl_info_file_buffer,
|
|||
|
|
max_size, MYF(MY_WME))))
|
|||
|
|
DBUG_RETURN(TRUE);
|
|||
|
|
*buffer_act= buf_act;
|
|||
|
|
memcpy(buf_act, buf, read_size);
|
|||
|
|
snd_size= my_b_gets(f, buf_act + read_size, max_size - read_size);
|
|||
|
|
if (snd_size == 0 ||
|
|||
|
|
((snd_size + 1 == max_size - read_size) && buf[max_size - 2] != '\n'))
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
failure to make the 2nd read or short read again
|
|||
|
|
*/
|
|||
|
|
DBUG_RETURN(TRUE);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
DBUG_RETURN(FALSE);
|
|||
|
|
}
|