Description of problem: Customer reports that his /etc/my.conf file is being read twice. Because of the double-loading /etc/my.cnf file, every time MySQL restarts the relay file changes and is not an actual file in the /var/run/mysqld directory, nor is it anywhere near numerical order. Here is the problem it causes - mysql> show slave statusG *************************** 1. row *************************** [...] Relay_Log_File: mysqld-relay-bin.000023 Relay_Log_Pos: 185588730 Relay_Master_Log_File: mysql-bin.000044 Slave_IO_Running: No Slave_SQL_Running: No Replicate_Do_DB: cdr,weboffice,cdr,weboffice Replicate_Ignore_DB: [...] 1 row in set (0.00 sec) and the /var/log/mysqld.log file shows repeated instances of: 080903 15:11:59 [ERROR] Could not find target log during relay log initialization 080903 15:11:59 [ERROR] Failed to initialize the master info structure Version-Release number of selected component (if applicable): mysql-5.0.45-7.el5 How reproducible: Every time Steps to Reproduce: 1. service mysqld start or 1. strace -o mysqld-strace.log /usr/libexec/mysqld --basedir=/usr \ --datadir=/var/lib/mysql --user=mysql \ --pid-file=/var/run/mysqld/mysqld.pid --skip-external-locking \ --socket=/var/lib/mysql/mysql.sock & Actual results: /etc/my.cnf is read twice, as evidenced by the following section of mysqld-strace.log: uname({sys="Linux", node="why-it218594.usersys.redhat.com", ...}) = 0 stat("/etc/my.cnf", {st_mode=S_IFREG|0644, st_size=310, ...}) = 0 open("/etc/my.cnf", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=310, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1bbde23000 read(3, "[mysqld]ndatadir=/var/lib/mysqln"..., 4096) = 310 read(3, "", 4096) = 0 close(3) = 0 munmap(0x2b1bbde23000, 4096) = 0 stat("/root/.my.cnf", 0x7fffecc9ba60) = -1 ENOENT (No such file or directory) stat("/etc/my.cnf", {st_mode=S_IFREG|0644, st_size=310, ...}) = 0 open("/etc/my.cnf", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=310, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1bbde23000 read(3, "[mysqld]ndatadir=/var/lib/mysqln"..., 4096) = 310 read(3, "", 4096) = 0 close(3) = 0 munmap(0x2b1bbde23000, 4096) = 0 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=1024}) = 0 Expected results: /etc/my.cnf should only be read once. Additional info: This bug is documented in http://bugs.mysql.com/bug.php?id=20748 "Bug#20748 SQL Config files should not be read more than once"
Created attachment 316912 [details] Proposed patch Adapted from upstream mysql-5.0.67
Hi Dave, The backport was from the latest version of MySQL (version 5.0.67). The change was made to init_default_directories(), which is called by init_defaults(), which is called by a lot of different fiels within the MySQL codebase. It's probably used by the various MySQL programs to load the MySQL configuration files. Since this was taken from a released version of MySQL, it presumably has already undergone code review and some amount of testing by the upstream MySQL community. The root cause of the problem is that init_default_directories() loads the default_directories array with the /etc directory twice. Once as "/etc/" and then once as DEFAULT_SYSCONFDIR (which is #defined to "/etc"). After init_default_directories() is called, default_directories looks like: (gdb) print default_directories $3 = {0x932f84 "/etc/", 0x8f8ea8 "", 0x932f95 "~/", 0x932f98 "/etc", 0x0, 0x0, 0x0, 0x0} The main thing that the proposed patch does is to modify init_default_directories() so that each directories are added by add_directory(). add_directory() first calls normalize_dirname() to change "/etc" into "/etc/", and then calls array_append_string_unique() to add the directory onto the default_directories array only if the directory doesn't already exist in the array. That way, /etc isn't added since /etc/ is already in the array. With the new code, default_directories looks like: (gdb) print default_directories[0] $1 = 0x10832a88 "/etc/" (gdb) print default_directories[1] $2 = 0x10832a90 "" (gdb) print default_directories[2] $3 = 0x10832a98 "~/" (gdb) print default_directories[3] $4 = 0x0 (gdb) print default_directories[4] $5 = 0x0 (gdb) print default_directories[5] $6 = 0x0 (gdb) print default_directories[6] $7 = 0x0 (gdb) print default_directories[7] $8 = 0x0 There may be an simpler way to work around this problem in RHEL. The bit of code where /etc is double-entered into the default_directories array is here (I've snipped all the bits of code that would be #ifdef'd out for RHEL: static void init_default_directories() { const char *env, **ptr= default_directories; #ifdef __WIN__ [...] #elif defined(__NETWARE__) [...] #else #if defined(__EMX__) || defined(OS2) [...] #endif [1] *ptr++= "/etc/"; #endif if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) *ptr++= env; *ptr++= ""; /* Place for defaults_extra_file */ #if !defined(__WIN__) && !defined(__NETWARE__) *ptr++= "~/";; #elif defined(__WIN__) [...] #endif #ifdef DEFAULT_SYSCONFDIR if (DEFAULT_SYSCONFDIR != "") [2] *ptr++= DEFAULT_SYSCONFDIR; #endif *ptr= 0; /* end marker */ } If we were to comment out either the first bit of code[1] that adds "/etc/" to the default_directories array or the bit of code[2] that adds DEFAULT_SYSCONFDIR to the default_directories array, that would achieve the same purpose with only a couple of changed lines -- much less invasive, although more from upstream. ~ Bryan This event sent from IssueTracker by dmaley issue 218594
One other note. There's a _much_ simpler way to test that this issue has been fixed. Running "/usr/libexec/mysqld --help --verbose" lists the default directories. The version already in RHEL reports: # rpm -q mysql-server mysql-server-5.0.45-7.el5.x86_64 # /usr/libexec/mysqld --help --verbose | grep --after=1 '^Default options' Default options are read from the following files in the given order: /etc/my.cnf ~/.my.cnf /etc/my.cnf After applying the proposed patch, mysqld reports: # rpm -q mysql-servermysql-server-5.0.45-7.it218594.5.el5.x86_64 # /usr/libexec/mysqld --help --verbose | grep --after=1 '^Default options' Default options are read from the following files in the given order: /etc/my.cnf ~/.my.cnf ~ Bryan This event sent from IssueTracker by dmaley issue 218594
An advisory has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on therefore solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHSA-2009-1289.html