List:Commits« Previous MessageNext Message »
From:Kristofer Pettersson Date:October 5 2010 12:38pm
Subject:bzr commit into mysql-trunk branch (kristofer.pettersson:3197) Bug#29071
View as plain text  
#At file:///home/thek/bzr/mysql-trunk/ based on revid:dlenev@stripped

 3197 Kristofer Pettersson	2010-10-05
      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 decrease my_file_opened or my_stream_opened if the file
      descriptor was maked as anything but UNOPEN
     @ include/my_global.h
        * In order to be able to map all file descriptors to the minimal requirement of concurrently open files we need to increase MY_NFILE to 256 which also matches the official recommendation better.
     @ mysql-test/t/myisampack.test
        * Add test file to verify that previously working scripts are still working within acceptable limits.
     @ mysys/my_file.c
        * Make sure that the my_file_limit is updated even if the requested number of file descriptors fit into the default static memory allocation.
        * If an allocation fail, make sure the my_file_info pointer is reverted to the default structure.
     @ mysys/my_fopen.c
        * The variable "my_stream_opened" needs to be strongly associated
          with the my_file_info::type attribute.
        * Move the THR_LOCK_open mutex so that we don't hold it while doing system calls.
     @ mysys/my_open.c
        * The variable "my_file_opened" needs to be strongly associated
          with the my_file_info::type attribute.
        * Move the THR_LOCK_open mutex so that we don't hold it while doing system calls.
        * Previously the file descriptor didn't map strictly to the my_file_info array and when very many files were used, the my_file_info array weren't updated.
     @ 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:
      include/my_global.h
      mysql-test/t/myisampack.test
      mysys/my_file.c
      mysys/my_fopen.c
      mysys/my_open.c
      unittest/gunit/CMakeLists.txt
=== modified file 'include/my_global.h'
--- a/include/my_global.h	2010-07-23 20:59:42 +0000
+++ b/include/my_global.h	2010-10-05 12:38:33 +0000
@@ -642,7 +642,7 @@ typedef SOCKET_SIZE_TYPE size_socket;
 #ifdef _WIN32
 #define MY_NFILE (16384 + MY_FILE_MIN)
 #else
-#define MY_NFILE 64
+#define MY_NFILE 256
 #endif
 
 #ifndef OS_FILE_LIMIT

=== modified file 'mysql-test/t/myisampack.test'
--- a/mysql-test/t/myisampack.test	2009-11-26 12:47:55 +0000
+++ b/mysql-test/t/myisampack.test	2010-10-05 12:38:33 +0000
@@ -221,3 +221,61 @@ DROP TABLE t1,t2,t3;
 DROP TABLE mysql_db1.t1;
 DROP DATABASE mysql_db1;
 
+#
+# Bug#29071 invalid Open_files or Slave_open_temp_tables value in show global
+#           status
+#
+let $MYSQLD_DATADIR= `select @@datadir`;
+disable_query_log;
+let $ntables= 64;
+let $i= $ntables;
+let $myisampack_arg=-j $MYSQLD_DATADIR/test/t0;
+while ($i)
+{
+  eval CREATE TABLE t$i(a INT);
+  let $myisampack_arg=$myisampack_arg $MYSQLD_DATADIR/test/t$i;
+  dec $i;
+}
+FLUSH TABLES;
+enable_query_log;
+
+# myisampack
+--exec $MYISAMPACK $myisampack_arg
+
+disable_query_log;
+let $i= $ntables;
+while ($i)
+{
+  eval DROP TABLE t$i;
+  dec $i;
+}
+disable_warnings;
+DROP TABLE IF EXISTS t0;
+enable_warnings;
+enable_query_log;
+
+let $i= $ntables;
+while ($i)
+{
+  connect(con$i,localhost,root,,);
+  dec $i;
+}
+
+disable_query_log;
+CREATE TABLE t1(a INT);
+# mysqltest
+cat_file $MYSQLD_DATADIR/test/t1.MYD;
+
+# libmysqlclient
+eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/test/t1.MYD' INTO TABLE t1;
+DROP TABLE t1;
+enable_query_log;
+
+let $i= $ntables;
+while ($i)
+{
+  disconnect con$i;
+  dec $i;
+}
+
+

=== modified file 'mysys/my_file.c'
--- a/mysys/my_file.c	2010-07-08 21:20:08 +0000
+++ b/mysys/my_file.c	2010-10-05 12:38:33 +0000
@@ -83,12 +83,10 @@ static uint set_max_open_files(uint max_
 /*
   Change number of open files
 
-  SYNOPSIS:
-    my_set_max_open_files()
-    files		Number of requested files
+  @param files Number of requested files
 
-  RETURN
-    number of files available for open
+  
+  @return Number of files available for open
 */
 
 uint my_set_max_open_files(uint files)
@@ -100,11 +98,26 @@ uint my_set_max_open_files(uint files)
   files+= MY_FILE_MIN;
   files= set_max_open_files(min(files, OS_FILE_LIMIT));
   if (files <= MY_NFILE)
+  {
+    /*
+      The number of requested file descriptors will fit into the default
+      static allocation.
+    */
+    my_file_info= my_file_info_default;
+    my_file_limit= files;
     DBUG_RETURN(files);
-
+  }
   if (!(tmp= (struct st_my_file_info*) my_malloc(sizeof(*tmp) * files,
 						 MYF(MY_WME))))
+  {
+    /*
+      if allocation failed then revert to the default number of file
+      descriptors.
+    */
+    my_file_info= my_file_info_default;
+    my_file_limit= MY_NFILE;
     DBUG_RETURN(MY_NFILE);
+  }
 
   /* Copy any initialized files */
   memcpy((char*) tmp, (char*) my_file_info,
@@ -126,7 +139,7 @@ void my_free_open_file_info()
   {
     /* Copy data back for my_print_open_files */
     memcpy((char*) my_file_info_default, my_file_info,
-           sizeof(*my_file_info_default)* MY_NFILE);
+           sizeof(my_file_info_default));
     my_free(my_file_info);
     my_file_info= my_file_info_default;
     my_file_limit= MY_NFILE;

=== modified file 'mysys/my_fopen.c'
--- a/mysys/my_fopen.c	2010-07-08 21:20:08 +0000
+++ b/mysys/my_fopen.c	2010-10-05 12:38:33 +0000
@@ -20,18 +20,33 @@
 
 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
+
+ The following global variables are read:
+    struct st_my_file_info *my_file_info
+    my_file_limit
+  
+  The following global variables are written:
+    struct st_my_file_info *my_file_info
+    my_stream_opened
+    my_total_opened  
+    my_errno
+ 
+  This function attempts to acquire the THR_LOCK_open mutex.
+  
+  This function can throw the following SQL errors:
+    EE_FILENOTFOUND
+    EE_CANTCREATEFILE
+    EE_OUT_OF_FILERESOURCES
+ 
+  @return
+    @retval 0 Error
+    @retval # File handler
 */
 
 FILE *my_fopen(const char *filename, int flags, myf MyFlags)
@@ -51,21 +66,23 @@ FILE *my_fopen(const char *filename, int
 #endif
   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.
-    */
-
     int filedesc= my_fileno(fd);
-    if ((uint)filedesc >= my_file_limit)
+    mysql_mutex_lock(&THR_LOCK_open); 
+    if ((uint)filedesc >= (uint)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;
+      fclose(fd);
+#ifdef _WIN32
+      my_file_info[filedesc].fhandle= 0;   
+#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 +97,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 :
@@ -89,22 +108,35 @@ FILE *my_fopen(const char *filename, int
 } /* my_fopen */
 
 
-	/* Close a stream */
+/**
+  Close a stream
+  @param fd A pointer to a stream file descriptor
+  @param MyFlags Flags regulating how errors are treated.
+
+  @note This function must be called with a valid file descriptor or it will
+    crash. A valid fd is defined on the intervall ]-1, my_file_limit[
+  
+  @see my_win_fclose
+ 
+  The following global variables are read:
+    struct st_my_file_info *my_file_info
+
+  The following global variables are written:
+   struct st_my_file_info *my_file_info     
+   my_stream_opened
+   
+  This function can throw the following SQL errors:
+    EE_BADCLOSE
+*/
 
-/* Close a stream */
 int my_fclose(FILE *fd, myf MyFlags)
 {
   int err,file;
   DBUG_ENTER("my_fclose");
   DBUG_PRINT("my",("stream: 0x%lx  MyFlags: %d", (long) fd, MyFlags));
 
-  mysql_mutex_lock(&THR_LOCK_open);
   file= my_fileno(fd);
-#ifndef _WIN32
   err= fclose(fd);
-#else
-  err= my_win_fclose(fd);
-#endif
   if(err < 0)
   {
     my_errno=errno;
@@ -112,12 +144,21 @@ 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)
+  
+  mysql_mutex_lock(&THR_LOCK_open);
+#ifdef _WIN32
+  /*
+    The windows compatibility frame work attaches a handle which needs to be
+    set to 0 when the file is closed.
+    @see my_win_fclose()
+  */
+  my_file_info[file].fhandle= 0;
+#endif
+  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-10-05 12:38:33 +0000
@@ -19,17 +19,37 @@
 #include <errno.h>
 
 
-/*
+/**
   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.
+  
+  The following global variables are read:
+    struct st_my_file_info *my_file_info
+    my_file_limit
+  
+  The following global variables are written:
+    struct st_my_file_info *my_file_info
+    my_file_opened
+    my_total_opened
+    my_errno
+    PSI_mutex_key key_my_file_info_mutex (initialized)
+ 
+  This function attempts to acquire the THR_LOCK_open mutex.
+  
+  This function can throw the following SQL errors:
+    EE_FILENOTFOUND
+    EE_OUT_OF_FILERESOURCES
+ 
+  @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)
@@ -55,13 +75,17 @@ File my_open(const char *FileName, int F
 
 
 /*
-  Close a file
-
-  SYNOPSIS
-    my_close()
-      fd	File sescriptor
-      myf	Special Flags
-
+  Close a file.
+  
+  @param fd File sescriptor
+  @param myf Flags regulating how errors are treated.
+  
+  The following global variables are read:
+    struct st_my_file_info *my_file_info
+    my_file_limit
+    
+  This function can throw the following SQL errors:
+    EE_BADCLOSE
 */
 
 int my_close(File fd, myf MyFlags)
@@ -70,13 +94,25 @@ int my_close(File fd, myf MyFlags)
   DBUG_ENTER("my_close");
   DBUG_PRINT("my",("fd: %d  MyFlags: %d",fd, MyFlags));
 
-  mysql_mutex_lock(&THR_LOCK_open);
+  if (fd < 0 || fd >= my_file_limit)
+  {
+    /* Function called with wrong parameters */
+    DBUG_RETURN(EBADF);  
+  }
+
 #ifndef _WIN32
   do
   {
     err= close(fd);
   } while (err == -1 && errno == EINTR);
-#else
+#endif
+
+  mysql_mutex_lock(&THR_LOCK_open);
+#ifdef _WIN32
+  /*
+    my_win_close() calls invalidate_fd() which in turn modifies the my_file_info
+    structure which must be protected by THR_LOCK_open.
+  */
   err= my_win_close(fd);
 #endif
   if (err)
@@ -86,15 +122,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 +139,17 @@ 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()
+
+  @see my_open
+  
+  @return
+    @retval -1 An error occurred
+    @retval # On success the file descriptor is returned.
 
 */
 
@@ -121,41 +157,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 ((uint)fd >= (uint)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 */
+    my_win_close(fd);
 #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);
-#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))
   {
@@ -190,3 +241,4 @@ void my_print_open_files(void)
 }
 
 #endif
+

=== modified file 'unittest/gunit/CMakeLists.txt'
--- a/unittest/gunit/CMakeLists.txt	2010-07-30 08:34:23 +0000
+++ b/unittest/gunit/CMakeLists.txt	2010-10-05 12:38:33 +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 string)
 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-10-05 12:38:33 +0000
@@ -0,0 +1,174 @@
+/* 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 <gtest/gtest.h>
+#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_file_info= my_file_info_default;
+    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<MAX_NUMBER_OF_FILE_DESCRIPTORS; ++i)
+  {
+    fp[i]= my_fopen(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+    if (fp[i] == 0)
+      break;
+    else
+      ++opened_files;
+  }
+  /*
+    We now have depleted the number of available file descriptors.
+    Next attempt to open a file will fail.
+  */
+  fp[opened_files]= my_fopen(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+  EXPECT_EQ((FILE *)0, fp[opened_files]);
+
+  /*
+    Apply my_fclose() on all file descriptors to make sure all files are closed
+  */
+  for(int i= opened_files-1; i>=0; --i)
+  {
+    if( fp[i] != 0)
+      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);
+}
+

=== 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-10-05 12:38:33 +0000
@@ -0,0 +1,183 @@
+/* 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 <gtest/gtest.h>
+#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_file_info= my_file_info_default;
+    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<MAX_NUMBER_OF_FILE_DESCRIPTORS; ++i)
+  {
+    fd[i]= my_open(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+    if (fd[i] == -1)
+      break;
+    else
+      ++opened_files;
+  }
+  /*
+    We now have depleted the number of available file descriptors.
+    Next attempt to open a file will fail.
+  */
+  fd[opened_files]= my_open(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+  EXPECT_EQ(-1, fd[opened_files]);
+
+  /*
+    Apply my_close() on all file descriptors to make sure all files are closed
+  */
+  for(int i= opened_files; 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);
+}
+


Attachment: [text/bzr-bundle] bzr/kristofer.pettersson@oracle.com-20101005123833-4j4h7mbskixi72ia.bundle
Thread
bzr commit into mysql-trunk branch (kristofer.pettersson:3197) Bug#29071Kristofer Pettersson5 Oct
Re: bzr commit into mysql-trunk branch (kristofer.pettersson:3197)Bug#29071Sergey Vojtovich6 Oct