From: Kristofer Pettersson Date: September 27 2010 1:11pm Subject: bzr commit into mysql-trunk branch (kristofer.pettersson:3197) Bug#29071 List-Archive: http://lists.mysql.com/commits/119172 X-Bug: 29071 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============6171724357012093924==" --===============6171724357012093924== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/thek/bzr/mysql-trunk/ based on revid:dlenev@stripped 3197 Kristofer Pettersson 2010-09-27 Bug#29071 invalid Open_files or Slave_open_temp_tables value in show global status If an error occurred during registration of a file handle, the Open_files counter would show very large numbers. Only decrese my_file_opened or my_stream_opened if the file descriptor was maked as anything but UNOPEN @ mysys/my_fopen.c * The variable "my_stream_opened" needs to be strongly associated with the my_file_info::type attribute. @ mysys/my_open.c * The variable "my_file_opened" needs to be strongly associated with the my_file_info::type attribute. @ unittest/gunit/CMakeLists.txt * Added two test cases my_open-t.cc, my_fopen-t.cc added: unittest/gunit/my_fopen-t.cc unittest/gunit/my_open-t.cc modified: mysys/my_fopen.c mysys/my_open.c unittest/gunit/CMakeLists.txt === modified file 'mysys/my_fopen.c' --- a/mysys/my_fopen.c 2010-07-08 21:20:08 +0000 +++ b/mysys/my_fopen.c 2010-09-27 13:11:49 +0000 @@ -20,18 +20,18 @@ static void make_ftype(char * to,int flag); -/* +/** Open a file as stream - SYNOPSIS - my_fopen() - FileName Path-name of file - Flags Read | write | append | trunc (like for open()) - MyFlags Flags for handling errors - - RETURN - 0 Error - # File handler + @param FileName Path-name of file + @param Flags like for open() + @param MyFlags Flags for handling errors + + @see my_win_fopen() + + @return + @retval 0 Error + @retval # File handler */ FILE *my_fopen(const char *filename, int flags, myf MyFlags) @@ -52,20 +52,27 @@ FILE *my_fopen(const char *filename, int if (fd != 0) { /* - The test works if MY_NFILE < 128. The problem is that fileno() is char - on some OS (SUNOS). Actually the filename save isn't that important - so we can ignore if this doesn't work. + @todo The problem is that fileno() is of type char on some OS (SUNOS). */ int filedesc= my_fileno(fd); + mysql_mutex_lock(&THR_LOCK_open); if ((uint)filedesc >= my_file_limit) { - thread_safe_increment(my_stream_opened,&THR_LOCK_open); - DBUG_RETURN(fd); /* safeguard */ + /* + The number of concurrently opened files exceeds the limits or + the file descriptor can't be mapped to the my_file_info array. + */ + my_errno= EMFILE; +#ifndef _WIN32 + fclose(fd); +#else + my_win_fclose(fd); +#endif + mysql_mutex_unlock(&THR_LOCK_open); + goto err; } - mysql_mutex_lock(&THR_LOCK_open); - if ((my_file_info[filedesc].name= (char*) - my_strdup(filename,MyFlags))) + if ((my_file_info[filedesc].name= (char*) my_strdup(filename,MyFlags))) { my_stream_opened++; my_file_total_opened++; @@ -80,6 +87,8 @@ FILE *my_fopen(const char *filename, int } else my_errno=errno; + +err: DBUG_PRINT("error",("Got error %d on open",my_errno)); if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND : @@ -98,13 +107,25 @@ int my_fclose(FILE *fd, myf MyFlags) DBUG_ENTER("my_fclose"); DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags)); - mysql_mutex_lock(&THR_LOCK_open); + if(fd == 0) + { + /* Function called with wrong parameters */ + DBUG_RETURN(EBADF); + } + file= my_fileno(fd); + if ((uint) file >= my_file_limit) + { + /* Function called with wrong parameters */ + DBUG_RETURN(EBADF); + } + #ifndef _WIN32 err= fclose(fd); #else err= my_win_fclose(fd); #endif + mysql_mutex_lock(&THR_LOCK_open); if(err < 0) { my_errno=errno; @@ -112,12 +133,12 @@ int my_fclose(FILE *fd, myf MyFlags) my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG), my_filename(file),errno); } - else - my_stream_opened--; - if ((uint) file < my_file_limit && my_file_info[file].type != UNOPEN) + + if (my_file_info[file].type != UNOPEN) { my_file_info[file].type = UNOPEN; my_free(my_file_info[file].name); + my_stream_opened--; } mysql_mutex_unlock(&THR_LOCK_open); DBUG_RETURN(err); === modified file 'mysys/my_open.c' --- a/mysys/my_open.c 2010-07-08 21:20:08 +0000 +++ b/mysys/my_open.c 2010-09-27 13:11:49 +0000 @@ -19,17 +19,20 @@ #include -/* +/** Open a file - SYNOPSIS - my_open() - FileName Fully qualified file name - Flags Read | write - MyFlags Special flags - - RETURN VALUE - File descriptor + @param FileName Fully qualified file name + @param Flags Same as for unix system call open(2) + @param MyFlags Special flags + + @note This function encapsluates my_win_open and open(3) calls. + + @see my_win_open + + @return + @retval -1 An error occurred; my_errno has the error code. + @retval # On success a file descriptor is returned. */ File my_open(const char *FileName, int Flags, myf MyFlags) @@ -70,6 +73,11 @@ int my_close(File fd, myf MyFlags) DBUG_ENTER("my_close"); DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags)); + if (fd < 0 || fd >= my_file_limit) + { + /* Function called with wrong parameters */ + DBUG_RETURN(EBADF); + } mysql_mutex_lock(&THR_LOCK_open); #ifndef _WIN32 do @@ -86,15 +94,15 @@ int my_close(File fd, myf MyFlags) if (MyFlags & (MY_FAE | MY_WME)) my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),my_filename(fd),errno); } - if ((uint) fd < my_file_limit && my_file_info[fd].type != UNOPEN) + if (my_file_info[fd].type != UNOPEN) { my_free(my_file_info[fd].name); #if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32) mysql_mutex_destroy(&my_file_info[fd].mutex); #endif my_file_info[fd].type = UNOPEN; + my_file_opened--; } - my_file_opened--; mysql_mutex_unlock(&THR_LOCK_open); DBUG_RETURN(err); } /* my_close */ @@ -103,17 +111,15 @@ int my_close(File fd, myf MyFlags) /* Register file in my_file_info[] - SYNOPSIS - my_register_filename() - fd File number opened, -1 if error on open - FileName File name - type_file_type How file was created - error_message_number Error message number if caller got error (fd == -1) - MyFlags Flags for my_close() - - RETURN - -1 error - # Filenumber + @param fd File number opened, -1 if error on open + @param FileName File name + @param type_file_type How file was created + @param error_message_numbe Error message number if caller got error (fd == -1) + @param MyFlags Flags for my_close() + + @return + @retval -1 An error occurred + @retval # On success the file descriptor is returned. */ @@ -121,41 +127,56 @@ File my_register_filename(File fd, const type_of_file, uint error_message_number, myf MyFlags) { DBUG_ENTER("my_register_filename"); - if ((int) fd >= MY_FILE_MIN) + if (fd < 0) { - if ((uint) fd >= my_file_limit) + /* + The file descriptor indicates that the FileName couldn't be opened + properly; - Report the error. + */ + my_errno= errno; + goto err; + } + + mysql_mutex_lock(&THR_LOCK_open); + if (fd >= my_file_limit) + { + /* + The number of concurrently opened files exceeds the limits or + the file descriptor can't be mapped to the my_file_info array. + */ + my_errno= EMFILE; +#ifndef _WIN32 + int ret; + do { -#if defined(THREAD) && !defined(HAVE_PREAD) - my_errno= EMFILE; + ret= close(fd); + } while (ret == -1 && errno == EINTR); #else - thread_safe_increment(my_file_opened,&THR_LOCK_open); - DBUG_RETURN(fd); /* safeguard */ -#endif - } - else - { - mysql_mutex_lock(&THR_LOCK_open); - if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags))) - { - my_file_opened++; - my_file_total_opened++; - my_file_info[fd].type = type_of_file; -#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32) - mysql_mutex_init(key_my_file_info_mutex, &my_file_info[fd].mutex, - MY_MUTEX_INIT_FAST); + my_win_close(fd); #endif - mysql_mutex_unlock(&THR_LOCK_open); - DBUG_PRINT("exit",("fd: %d",fd)); - DBUG_RETURN(fd); - } - mysql_mutex_unlock(&THR_LOCK_open); - my_errno= ENOMEM; - } - (void) my_close(fd, MyFlags); + mysql_mutex_unlock(&THR_LOCK_open); + goto err; } - else - my_errno= errno; + if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags))) + { + my_file_opened++; + my_file_total_opened++; + my_file_info[fd].type = type_of_file; +#if defined(THREAD) && !defined(_WIN32) && !defined(HAVE_PREAD) + mysql_mutex_init(key_my_file_info_mutex, &my_file_info[fd].mutex, + MY_MUTEX_INIT_FAST); +#endif + mysql_mutex_unlock(&THR_LOCK_open); + DBUG_PRINT("exit",("fd: %d",fd)); + DBUG_RETURN(fd); + } +#if defined(THREAD) + mysql_mutex_unlock(&THR_LOCK_open); +#endif + my_errno= ENOMEM; + +err: DBUG_PRINT("error",("Got error %d on open", my_errno)); if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) { === modified file 'unittest/gunit/CMakeLists.txt' --- a/unittest/gunit/CMakeLists.txt 2010-07-30 08:34:23 +0000 +++ b/unittest/gunit/CMakeLists.txt 2010-09-27 13:11:49 +0000 @@ -207,7 +207,7 @@ IF (CMAKE_CXX_COMPILER_ID STREQUAL "SunP ENDIF() # Add tests (link them with sql library) -SET(TESTS sql_list mdl mdl_mytap my_regex thread_utils) +SET(TESTS sql_list mdl mdl_mytap my_regex thread_utils my_open my_fopen) FOREACH(test ${TESTS}) ADD_EXECUTABLE(${test}-t ${test}-t.cc) TARGET_LINK_LIBRARIES(${test}-t gunit sqlgunitlib strings dbug regex) === added file 'unittest/gunit/my_fopen-t.cc' --- a/unittest/gunit/my_fopen-t.cc 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/my_fopen-t.cc 2010-09-27 13:11:49 +0000 @@ -0,0 +1,191 @@ +/* Copyright (c) 2000, 2010, 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include "my_config.h" +#include +#include "mysqld_error.h" +#include "my_sys.h" + +#define MAX_NUMBER_OF_FILE_DESCRIPTORS (OS_FILE_LIMIT+MY_NFILE+1024) +#define DUMMY_FILE_NAME "successful_open_rdonly.bin" + +struct st_my_file_info my_file_info_default[MY_NFILE]; +class My_open_test : public ::testing::Test +{ +public: + My_open_test() + { + } + + virtual void SetUp() + { + /* set all global variables for each TEST_F. */ + my_thread_basic_global_reinit(); + my_stream_opened= 0; + my_file_total_opened= 0; + my_set_max_open_files(MAX_NUMBER_OF_FILE_DESCRIPTORS); + my_errno= 0; + } + + /** + Set up test case for all tests + */ + static void SetUpTestCase() + { + my_thread_basic_global_init(); + FILE *fp; + fp= my_fopen(DUMMY_FILE_NAME, O_WRONLY | O_CREAT | O_BINARY, MYF(0)); + if (fp == 0) + { + ADD_FAILURE() << "Failed to SetUpTestCase()."; + exit(EXIT_FAILURE); + } + my_fclose(fp, MYF(0)); + } + + static void TearDownTestCase() + { + /* + The std lib routine unlink(3) is considered trusted. + */ + if (unlink(DUMMY_FILE_NAME) > 0) + { + ADD_FAILURE() << "Failed to TearDownTestCase()."; + exit(EXIT_FAILURE); + } + } + +private: + +}; + +TEST_F(My_open_test, EnvironmentCheck) +{ +} + +TEST_F(My_open_test, FailToOpenUnknownFile) +{ + FILE *fp; + fp= my_fopen("/really/unknown/does-not-exist.bin", O_RDONLY | O_BINARY, MYF(0)); + EXPECT_EQ((FILE *)0, fp); + EXPECT_EQ(0, my_stream_opened); + EXPECT_EQ(0, my_file_total_opened); +} + + +TEST_F(My_open_test, SuccessToOpenKnownBinaryFile) +{ + EXPECT_EQ(0, my_stream_opened); + FILE *fp; + fp= my_fopen(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0)); + /* + The file should exist in the test dir and the call to my_open should not + fail under normal circumstances. + */ + EXPECT_NE((FILE *)0, fp); + + /* + The number of currently opened files should have increased + */ + EXPECT_EQ(1, my_stream_opened); + /* + The number of total files should have increased + */ + EXPECT_EQ(1, my_file_total_opened); + + + /* + When the file is closed the number of currently opened files should have + decreased to 0. + */ + my_fclose(fp, MYF(0)); + EXPECT_EQ(0, my_stream_opened); + + /* + But the number of files which has been opened should of course stay the + same. + */ + EXPECT_EQ(1, my_file_total_opened); + + /* + Lets try it again to see if the number of files ever opened in the system + increases to 2 + */ + fp= my_fopen(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0)); + EXPECT_NE((FILE *)0, fp); + EXPECT_EQ(1, my_stream_opened); + EXPECT_EQ(2, my_file_total_opened); + my_fclose(fp, MYF(0)); + EXPECT_EQ(0, my_stream_opened); + EXPECT_EQ(2, my_file_total_opened); + +} + +TEST_F(My_open_test, TooManyOpenFiles) +{ + FILE *fp[MAX_NUMBER_OF_FILE_DESCRIPTORS+1]; + /* + Attempt to open MAX_NUMBER_OF_FILE_DESCRIPTORS number of files. + NOTE: Couting begins at 0 hence we exclude i==MAX_NUMBER_OF_FILE_DESCRIPTORS + */ + int opened_files= 0; + for(unsigned i= 0; i=0; --i) + { + my_fclose(fp[i],MYF(0)); + } + /* + No more files should be opened. + */ + EXPECT_EQ(0, my_stream_opened); + EXPECT_EQ(opened_files, my_file_total_opened); +} + +TEST_F(My_open_test, MultipleClose) +{ + FILE *fp; + fp= my_fopen(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0)); + EXPECT_NE((FILE *)0, fp); + my_fclose(fp, MYF(0)); + my_fclose(fp, MYF(0)); + my_fclose(fp, MYF(0)); + EXPECT_EQ(0, my_stream_opened); + EXPECT_EQ(1, my_file_total_opened); + fp= my_fopen("/really/dont/exist.bin", O_RDONLY | O_BINARY, MYF(0)); + EXPECT_EQ((FILE *)0, fp); + my_fclose(fp, MYF(0)); + my_fclose(fp, MYF(0)); + my_fclose(fp, MYF(0)); + EXPECT_EQ(0, my_stream_opened); + EXPECT_EQ(1, my_file_total_opened); +} + === added file 'unittest/gunit/my_open-t.cc' --- a/unittest/gunit/my_open-t.cc 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/my_open-t.cc 2010-09-27 13:11:49 +0000 @@ -0,0 +1,182 @@ +/* Copyright (c) 2000, 2010, 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include "my_config.h" +#include +#include "mysqld_error.h" +#include "my_sys.h" + +#define MAX_NUMBER_OF_FILE_DESCRIPTORS (OS_FILE_LIMIT+MY_NFILE+1024) +#define DUMMY_FILE_NAME "successful_open_rdonly.bin" + +struct st_my_file_info my_file_info_default[MY_NFILE]; +class My_open_test : public ::testing::Test +{ +public: + My_open_test() + { + } + + virtual void SetUp() + { + /* set all global variables for each TEST_F */ + my_thread_basic_global_reinit(); + my_file_opened= 0; + my_file_total_opened= 0; + my_set_max_open_files(MAX_NUMBER_OF_FILE_DESCRIPTORS); + my_errno= 0; + } + + static void SetUpTestCase() + { + my_thread_basic_global_init(); + File fd; + fd= my_open(DUMMY_FILE_NAME, O_WRONLY | O_CREAT | O_BINARY, MYF(0)); + if (fd == -1) + { + ADD_FAILURE() << "Failed to SetUpTestCase()."; + exit(EXIT_FAILURE); + } + my_close(fd, MYF(0)); + } + + static void TearDownTestCase() + { + /* + The std lib routine unlink(3) is considered trusted. + */ + if (unlink(DUMMY_FILE_NAME) > 0) + { + ADD_FAILURE() << "Failed to TearDownTestCase()."; + exit(EXIT_FAILURE); + } + } + +private: + +}; + +TEST_F(My_open_test, FailToOpenUnknownFile) +{ + File fd; + fd= my_open("/really/unknown/does-not-exist.bin", O_RDONLY | O_BINARY, MYF(0)); + EXPECT_EQ(-1, fd); + EXPECT_EQ(0, my_file_opened); + EXPECT_EQ(0, my_file_total_opened); +} + + +TEST_F(My_open_test, SuccessToOpenKnownBinaryFile) +{ + File fd; + fd= my_open(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0)); + /* + The file should exist in the test dir and the call to my_open should not + fail under normal circumstances. + */ + EXPECT_NE(-1, fd); + + /* + The number of currently opened files should have increased + */ + EXPECT_EQ(1, my_file_opened); + /* + The number of total files should have increased + */ + EXPECT_EQ(1, my_file_total_opened); + + my_close(fd, MYF(0)); + + /* + When the file is closed the number of currently opened files should have + decreased to 0. + */ + EXPECT_EQ(0, my_file_opened); + /* + But the number of files which has been opened should of course stay the + same. + */ + EXPECT_EQ(1, my_file_total_opened); + + /* + Lets try it again to see if the number of files ever opened in the system + increases to 2 + */ + fd= my_open(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0)); + EXPECT_NE(-1, fd); + EXPECT_EQ(1, my_file_opened); + EXPECT_EQ(2, my_file_total_opened); + my_close(fd, MYF(0)); + EXPECT_EQ(0, my_file_opened); + EXPECT_EQ(2, my_file_total_opened); + +} + +TEST_F(My_open_test, TooManyOpenFiles) +{ + File fd[MAX_NUMBER_OF_FILE_DESCRIPTORS+1]; + /* + Attempt to open MAX_NUMBER_OF_FILE_DESCRIPTORS number of files. + NOTE: Couting begins at 0 hence we exclude i==MAX_NUMBER_OF_FILE_DESCRIPTORS + */ + int opened_files= 0; + for(unsigned i= 0; i=0; --i) + { + my_close(fd[i],MYF(0)); + } + /* + No more files should be opened. + */ + EXPECT_EQ(0, my_file_opened); + EXPECT_EQ(opened_files, my_file_total_opened); +} + +TEST_F(My_open_test, MultipleClose) +{ + File fd; + fd= my_open(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0)); + EXPECT_NE(-1, fd); + my_close(fd, MYF(0)); + my_close(fd, MYF(0)); + my_close(fd, MYF(0)); + EXPECT_EQ(0, my_file_opened); + EXPECT_EQ(1, my_file_total_opened); + fd= my_open("/really/dont/exist.bin", O_RDONLY | O_BINARY, MYF(0)); + EXPECT_EQ(-1, fd); + my_close(fd, MYF(0)); + my_close(fd, MYF(0)); + my_close(fd, MYF(0)); + EXPECT_EQ(0, my_file_opened); + EXPECT_EQ(1, my_file_total_opened); +} + --===============6171724357012093924== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/kristofer.pettersson@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: kristofer.pettersson@stripped\ # uezcc29lyxm735cp # target_branch: file:///home/thek/bzr/mysql-trunk/ # testament_sha1: 3b11aceab59e5c25ec5363945dcc5eaad5d300b5 # timestamp: 2010-09-27 15:11:52 +0200 # base_revision_id: dlenev@stripped # # Begin bundle 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 --===============6171724357012093924==--