merge Windows performance patches into 5.3
This commit is contained in:
commit
f9cb1467b8
@ -59,7 +59,7 @@ IF (MSVC_VERSION GREATER 1400)
|
||||
ENDIF()
|
||||
|
||||
|
||||
SET(CMAKE_INSTALL_PREFIX "C:/MariaDB${MYSQL_BASE_VERSION}")
|
||||
SET(CMAKE_INSTALL_PREFIX "C:/MariaDB${MYSQL_BASE_VERSION}" CACHE PATH "Default installation directory")
|
||||
SET(INSTALL_ROOT "${CMAKE_INSTALL_PREFIX}")
|
||||
# Set standard options
|
||||
ADD_DEFINITIONS(-DHAVE_YASSL)
|
||||
|
@ -1,289 +1,2 @@
|
||||
Up-to-date instructions on MariaDB building on Windows can be found in http://kb.askmonty.org/en/building-mariadb-on-windows.
|
||||
|
||||
2.5.10. Installing MySQL from Source on Windows
|
||||
|
||||
These instructions describe how to build binaries from source for
|
||||
MySQL 5.1 on Windows. Instructions are provided for building
|
||||
binaries from a standard source distribution or from the Bazaar
|
||||
tree that contains the latest development source.
|
||||
|
||||
Note
|
||||
|
||||
The instructions here are strictly for users who want to test
|
||||
MySQL on Microsoft Windows from the latest source distribution or
|
||||
from the Bazaar tree. For production use, we do not advise using a
|
||||
MySQL server built by yourself from source. Normally, it is best
|
||||
to use precompiled binary distributions of MySQL that are built
|
||||
specifically for optimal performance on Windows by Oracle
|
||||
Corporation. Instructions for installing binary distributions are
|
||||
available in Section 2.5, "Installing MySQL on Windows."
|
||||
|
||||
To build MySQL on Windows from source, you must satisfy the
|
||||
following system, compiler, and resource requirements:
|
||||
|
||||
* Windows 2000, Windows XP, or newer version.
|
||||
Windows Vista is supported when using Visual Studio 2005
|
||||
provided you have installed the following updates:
|
||||
|
||||
+ Microsoft Visual Studio 2005 Professional Edition - ENU
|
||||
Service Pack 1 (KB926601)
|
||||
(http://support.microsoft.com/?kbid=926601)
|
||||
|
||||
+ Security Update for Microsoft Visual Studio 2005
|
||||
Professional Edition - ENU (KB937061)
|
||||
(http://support.microsoft.com/?kbid=937061)
|
||||
|
||||
+ Update for Microsoft Visual Studio 2005 Professional
|
||||
Edition - ENU (KB932232)
|
||||
(http://support.microsoft.com/?kbid=932232)
|
||||
|
||||
* CMake, which can be downloaded from http://www.cmake.org.
|
||||
After installing, modify your path to include the cmake
|
||||
binary.
|
||||
|
||||
* Microsoft Visual C++ 2005 Express Edition, Visual Studio .Net
|
||||
2003 (7.1), or Visual Studio 2005 (8.0) compiler system.
|
||||
|
||||
* If you are using Visual C++ 2005 Express Edition, you must
|
||||
also install an appropriate Platform SDK. More information and
|
||||
links to downloads for various Windows platforms is available
|
||||
from
|
||||
http://www.microsoft.com/downloads/details.aspx?familyid=0baf2
|
||||
b35-c656-4969-ace8-e4c0c0716adb.
|
||||
|
||||
* If you are compiling from a Bazaar tree or making changes to
|
||||
the parser, you need bison for Windows, which can be
|
||||
downloaded from
|
||||
http://gnuwin32.sourceforge.net/packages/bison.htm. Download
|
||||
the package labeled "Complete package, excluding sources".
|
||||
After installing the package, modify your path to include the
|
||||
bison binary and ensure that this binary is accessible from
|
||||
Visual Studio.
|
||||
|
||||
* Cygwin might be necessary if you want to run the test script
|
||||
or package the compiled binaries and support files into a Zip
|
||||
archive. (Cygwin is needed only to test or package the
|
||||
distribution, not to build it.) Cygwin is available from
|
||||
http://cygwin.com.
|
||||
|
||||
* 3GB to 5GB of disk space.
|
||||
|
||||
The exact system requirements for Visual Studio can be found here:
|
||||
http://msdn.microsoft.com/vstudio/Previous/2003/sysreqs/default.as
|
||||
px and
|
||||
http://msdn.microsoft.com/vstudio/products/sysreqs/default.aspx
|
||||
|
||||
You also need a MySQL source distribution for Windows, which can
|
||||
be obtained two ways:
|
||||
|
||||
* Obtain a source distribution packaged by Oracle Corporation.
|
||||
These are available from http://dev.mysql.com/downloads/.
|
||||
|
||||
* Package a source distribution yourself from the latest Bazaar
|
||||
developer source tree. For instructions on pulling the latest
|
||||
source files, see Section 2.3.3, "Installing from the
|
||||
Development Source Tree."
|
||||
|
||||
If you find something not working as expected, or you have
|
||||
suggestions about ways to improve the current build process on
|
||||
Windows, please send a message to the win32 mailing list. See
|
||||
Section 1.6.1, "MySQL Mailing Lists."
|
||||
|
||||
2.5.10.1. Building MySQL from Source Using CMake and Visual Studio
|
||||
|
||||
You can build MySQL on Windows by using a combination of cmake and
|
||||
Microsoft Visual Studio .NET 2003 (7.1), Microsoft Visual Studio
|
||||
2005 (8.0), Microsoft Visual Studio 2008 (9.0) or Microsoft Visual
|
||||
C++ 2005 Express Edition. You must have the appropriate Microsoft
|
||||
Platform SDK installed.
|
||||
|
||||
Note
|
||||
|
||||
To compile from the source code on Windows you must use the
|
||||
standard source distribution (for example, mysql-5.1.46.tar.gz).
|
||||
You build from the same distribution as used to build MySQL on
|
||||
Unix, Linux and other platforms. Do not use the Windows Source
|
||||
distributions as they do not contain the necessary configuration
|
||||
script and other files.
|
||||
|
||||
Follow this procedure to build MySQL:
|
||||
|
||||
1. If you are installing from a packaged source distribution,
|
||||
create a work directory (for example, C:\workdir), and unpack
|
||||
the source distribution there using WinZip or another Windows
|
||||
tool that can read .zip files. This directory is the work
|
||||
directory in the following instructions.
|
||||
|
||||
Note
|
||||
You must run the commands in the win directory from the
|
||||
top-level source directory. Do not change into the win
|
||||
directory, as the commands will not be executed correctly.
|
||||
|
||||
2. Start a command shell. If you have not configured the PATH and
|
||||
other environment variables for all command shells, you may be
|
||||
able to start a command shell from the Start Menu within the
|
||||
Windows Visual Studio menu that contains the necessary
|
||||
environment changes.
|
||||
|
||||
3. Within the command shell, navigate to the work directory and
|
||||
run the following command:
|
||||
C:\workdir>win\configure.js options
|
||||
If you have associated the .js file extension with an
|
||||
application such as a text editor, then you may need to use
|
||||
the following command to force configure.js to be executed as
|
||||
a script:
|
||||
C:\workdir>cscript win\configure.js options
|
||||
These options are available for configure.js:
|
||||
|
||||
+ WITH_INNOBASE_STORAGE_ENGINE: Enable the InnoDB storage
|
||||
engine.
|
||||
|
||||
+ WITH_PARTITION_STORAGE_ENGINE: Enable user-defined
|
||||
partitioning.
|
||||
|
||||
+ WITH_ARCHIVE_STORAGE_ENGINE: Enable the ARCHIVE storage
|
||||
engine.
|
||||
|
||||
+ WITH_BLACKHOLE_STORAGE_ENGINE: Enable the BLACKHOLE
|
||||
storage engine.
|
||||
|
||||
+ WITH_EXAMPLE_STORAGE_ENGINE: Enable the EXAMPLE storage
|
||||
engine.
|
||||
|
||||
+ WITH_FEDERATED_STORAGE_ENGINE: Enable the FEDERATED
|
||||
storage engine.
|
||||
|
||||
+ WITH_NDBCLUSTER_STORAGE_ENGINE (experimental): Enable the
|
||||
NDBCLUSTER storage engine in the MySQL server; cause
|
||||
binaries for the MySQL Cluster management and data node,
|
||||
management client, and other programs to be built.
|
||||
This option is supported only in MySQL Cluster NDB 7.0
|
||||
(NDBCLUSTER storage engine versions 6.4.0 and later)
|
||||
using the MySQL Cluster sources. It cannot be used to
|
||||
enable clustering support in other MySQL source trees or
|
||||
distributions.
|
||||
|
||||
+ MYSQL_SERVER_SUFFIX=suffix: Server suffix, default none.
|
||||
|
||||
+ COMPILATION_COMMENT=comment: Server comment, default
|
||||
"Source distribution".
|
||||
|
||||
+ MYSQL_TCP_PORT=port: Server port, default 3306.
|
||||
|
||||
+ DISABLE_GRANT_OPTIONS: Disables the --bootstrap,
|
||||
--skip-grant-tables, and --init-file options for mysqld.
|
||||
This option is available as of MySQL 5.1.15.
|
||||
For example (type the command on one line):
|
||||
C:\workdir>win\configure.js WITH_INNOBASE_STORAGE_ENGINE
|
||||
WITH_PARTITION_STORAGE_ENGINE MYSQL_SERVER_SUFFIX=-pro
|
||||
|
||||
4. From the work directory, execute the win\build-vs9.bat
|
||||
(Windows Visual Studio 2008), win\build-vs8.bat (Windows
|
||||
Visual Studio 2005), or win\build-vs71.bat (Windows Visual
|
||||
Stidion 2003) script, depending on the version of Visual
|
||||
Studio you have installed. The script invokes CMake, which
|
||||
generates the mysql.sln solution file.
|
||||
You can also use the corresponding 64-bit file (for example
|
||||
win\build-vs8_x64.bat or win\build-vs9_x64.bat) to build the
|
||||
64-bit version of MySQL. However, you cannot build the 64-bit
|
||||
version with Visual Studio Express Edition. You must use
|
||||
Visual Studio 2005 (8.0) or higher.
|
||||
|
||||
5. From the work directory, open the generated mysql.sln file
|
||||
with Visual Studio and select the proper configuration using
|
||||
the Configuration menu. The menu provides Debug, Release,
|
||||
RelwithDebInfo, MinRelInfo options. Then select Solution >
|
||||
Build to build the solution.
|
||||
Remember the configuration that you use in this step. It is
|
||||
important later when you run the test script because that
|
||||
script needs to know which configuration you used.
|
||||
|
||||
6. Test the server. The server built using the preceding
|
||||
instructions expects that the MySQL base directory and data
|
||||
directory are C:\mysql and C:\mysql\data by default. If you
|
||||
want to test your server using the source tree root directory
|
||||
and its data directory as the base directory and data
|
||||
directory, you need to tell the server their path names. You
|
||||
can either do this on the command line with the --basedir and
|
||||
--datadir options, or by placing appropriate options in an
|
||||
option file. (See Section 4.2.3.3, "Using Option Files.") If
|
||||
you have an existing data directory elsewhere that you want to
|
||||
use, you can specify its path name instead.
|
||||
When the server is running in standalone fashion or as a
|
||||
service based on your configuration, try to connect to it from
|
||||
the mysql interactive command-line utility.
|
||||
You can also run the standard test script, mysql-test-run.pl.
|
||||
This script is written in Perl, so you'll need either Cygwin
|
||||
or ActiveState Perl to run it. You may also need to install
|
||||
the modules required by the script. To run the test script,
|
||||
change location into the mysql-test directory under the work
|
||||
directory, set the MTR_VS_CONFIG environment variable to the
|
||||
configuration you selected earlier (or use the --vs-config
|
||||
option), and invoke mysql-test-run.pl. For example (using
|
||||
Cygwin and the bash shell):
|
||||
shell> cd mysql-test
|
||||
shell> export MTR_VS_CONFIG=debug
|
||||
shell> ./mysql-test-run.pl --force --timer
|
||||
shell> ./mysql-test-run.pl --force --timer --ps-protocol
|
||||
|
||||
When you are satisfied that the programs you have built are
|
||||
working correctly, stop the server. Now you can install the
|
||||
distribution. One way to do this is to use the make_win_bin_dist
|
||||
script in the scripts directory of the MySQL source distribution
|
||||
(see Section 4.4.2, "make_win_bin_dist --- Package MySQL
|
||||
Distribution as ZIP Archive"). This is a shell script, so you must
|
||||
have Cygwin installed if you want to use it. It creates a Zip
|
||||
archive of the built executables and support files that you can
|
||||
unpack in the location at which you want to install MySQL.
|
||||
|
||||
It is also possible to install MySQL by copying directories and
|
||||
files directly:
|
||||
|
||||
1. Create the directories where you want to install MySQL. For
|
||||
example, to install into C:\mysql, use these commands:
|
||||
C:\> mkdir C:\mysql
|
||||
C:\> mkdir C:\mysql\bin
|
||||
C:\> mkdir C:\mysql\data
|
||||
C:\> mkdir C:\mysql\share
|
||||
C:\> mkdir C:\mysql\scripts
|
||||
If you want to compile other clients and link them to MySQL,
|
||||
you should also create several additional directories:
|
||||
C:\> mkdir C:\mysql\include
|
||||
C:\> mkdir C:\mysql\lib
|
||||
C:\> mkdir C:\mysql\lib\debug
|
||||
C:\> mkdir C:\mysql\lib\opt
|
||||
If you want to benchmark MySQL, create this directory:
|
||||
C:\> mkdir C:\mysql\sql-bench
|
||||
Benchmarking requires Perl support. See Section 2.15, "Perl
|
||||
Installation Notes."
|
||||
|
||||
2. From the work directory, copy into the C:\mysql directory the
|
||||
following files and directories:
|
||||
C:\> cd \workdir
|
||||
C:\workdir> mkdir C:\mysql
|
||||
C:\workdir> mkdir C:\mysql\bin
|
||||
C:\workdir> copy client\Release\*.exe C:\mysql\bin
|
||||
C:\workdir> copy sql\Release\mysqld.exe C:\mysql\bin\mysqld.exe
|
||||
C:\workdir> xcopy scripts\*.* C:\mysql\scripts /E
|
||||
C:\workdir> xcopy share\*.* C:\mysql\share /E
|
||||
If you want to compile other clients and link them to MySQL,
|
||||
you should also copy several libraries and header files:
|
||||
C:\workdir> copy lib\Release\mysqlclient.lib C:\mysql\lib\debug
|
||||
C:\workdir> copy lib\Release\libmysql.* C:\mysql\lib\debug
|
||||
C:\workdir> copy lib\Release\zlib.* C:\mysql\lib\debug
|
||||
C:\workdir> copy lib\Release\mysqlclient.lib C:\mysql\lib\opt
|
||||
C:\workdir> copy lib\Release\libmysql.* C:\mysql\lib\opt
|
||||
C:\workdir> copy lib\Release\zlib.* C:\mysql\lib\opt
|
||||
C:\workdir> copy include\*.h C:\mysql\include
|
||||
C:\workdir> copy libmysql\libmysql.def C:\mysql\include
|
||||
|
||||
Note
|
||||
If you have compiled a Debug, rather than Release solution,
|
||||
you can replace Release with Debug in the source file names
|
||||
shown above.
|
||||
If you want to benchmark MySQL, you should also do this:
|
||||
C:\workdir> xcopy sql-bench\*.* C:\mysql\bench /E
|
||||
|
||||
After installation, set up and start the server in the same way as
|
||||
for binary Windows distributions. This includes creating the
|
||||
system tables by running mysql_install_db. For more information,
|
||||
see Section 2.5, "Installing MySQL on Windows."
|
||||
|
@ -2198,7 +2198,7 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
|
||||
return ERROR_STOP;
|
||||
}
|
||||
#endif
|
||||
if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
|
||||
if (init_io_cache(file, my_fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
|
||||
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
|
||||
{
|
||||
error("Failed to init IO cache.");
|
||||
|
@ -1223,7 +1223,7 @@ get_options(int *argc,char ***argv)
|
||||
|
||||
if (opt_csv_str[0] == '-')
|
||||
{
|
||||
csv_file= fileno(stdout);
|
||||
csv_file= my_fileno(stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1382,9 +1382,9 @@ get_options(int *argc,char ***argv)
|
||||
fprintf(stderr,"%s: Could not open create file\n", my_progname);
|
||||
exit(1);
|
||||
}
|
||||
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
|
||||
tmp_string= (char *)my_malloc((size_t)sbuf.st_size + 1,
|
||||
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
|
||||
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
|
||||
my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
|
||||
tmp_string[sbuf.st_size]= '\0';
|
||||
my_close(data_file,MYF(0));
|
||||
parse_delimiter(tmp_string, &create_statements, delimiter[0]);
|
||||
@ -1409,9 +1409,9 @@ get_options(int *argc,char ***argv)
|
||||
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
|
||||
exit(1);
|
||||
}
|
||||
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
|
||||
tmp_string= (char *)my_malloc((size_t)sbuf.st_size + 1,
|
||||
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
|
||||
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
|
||||
my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
|
||||
tmp_string[sbuf.st_size]= '\0';
|
||||
my_close(data_file,MYF(0));
|
||||
if (user_supplied_query)
|
||||
@ -1440,9 +1440,9 @@ get_options(int *argc,char ***argv)
|
||||
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
|
||||
exit(1);
|
||||
}
|
||||
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
|
||||
tmp_string= (char *)my_malloc((size_t)sbuf.st_size + 1,
|
||||
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
|
||||
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
|
||||
my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
|
||||
tmp_string[sbuf.st_size]= '\0';
|
||||
my_close(data_file,MYF(0));
|
||||
if (user_supplied_pre_statements)
|
||||
@ -1471,9 +1471,9 @@ get_options(int *argc,char ***argv)
|
||||
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
|
||||
exit(1);
|
||||
}
|
||||
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
|
||||
tmp_string= (char *)my_malloc((size_t)sbuf.st_size + 1,
|
||||
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
|
||||
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
|
||||
my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
|
||||
tmp_string[sbuf.st_size]= '\0';
|
||||
my_close(data_file,MYF(0));
|
||||
if (user_supplied_post_statements)
|
||||
|
@ -43,7 +43,7 @@ LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file)
|
||||
if (!(line_buff=(LINE_BUFFER*)
|
||||
my_malloc(sizeof(*line_buff),MYF(MY_WME | MY_ZEROFILL))))
|
||||
return 0;
|
||||
if (init_line_buffer(line_buff,fileno(file),IO_SIZE,max_size))
|
||||
if (init_line_buffer(line_buff,my_fileno(file),IO_SIZE,max_size))
|
||||
{
|
||||
my_free(line_buff,MYF(0));
|
||||
return 0;
|
||||
|
@ -66,7 +66,6 @@
|
||||
#endif
|
||||
|
||||
/* File and lock constants */
|
||||
#define O_SHARE 0x1000 /* Open file in sharing mode */
|
||||
#ifdef __BORLANDC__
|
||||
#define F_RDLCK LK_NBLCK /* read lock */
|
||||
#define F_WRLCK LK_NBRLCK /* write lock */
|
||||
@ -373,7 +372,7 @@ inline ulonglong double2ulonglong(double d)
|
||||
#define FN_DEVCHAR ':'
|
||||
#define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */
|
||||
#define FN_NO_CASE_SENCE /* Files are not case-sensitive */
|
||||
#define OS_FILE_LIMIT 2048
|
||||
#define OS_FILE_LIMIT UINT_MAX
|
||||
|
||||
#define DO_NOT_REMOVE_THREAD_WRAPPERS
|
||||
#define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V))
|
||||
|
@ -69,7 +69,11 @@ typedef struct my_stat
|
||||
|
||||
#else
|
||||
|
||||
#if(_MSC_VER)
|
||||
#define MY_STAT struct _stati64 /* 64 bit file size */
|
||||
#else
|
||||
#define MY_STAT struct stat /* Orginal struct have what we need */
|
||||
#endif
|
||||
|
||||
#endif /* USE_MY_STAT_STRUCT */
|
||||
|
||||
|
@ -784,7 +784,41 @@ typedef SOCKET_SIZE_TYPE size_socket;
|
||||
#define FN_DIRSEP "/" /* Valid directory separators */
|
||||
#define FN_ROOTDIR "/"
|
||||
#endif
|
||||
#define MY_NFILE 64 /* This is only used to save filenames */
|
||||
|
||||
/*
|
||||
MY_FILE_MIN is Windows speciality and is used to quickly detect
|
||||
the mismatch of CRT and mysys file IO usage on Windows at runtime.
|
||||
CRT file descriptors can be in the range 0-2047, whereas descriptors returned
|
||||
by my_open() will start with 2048. If a file descriptor with value less then
|
||||
MY_FILE_MIN is passed to mysys IO function, chances are it stemms from
|
||||
open()/fileno() and not my_open()/my_fileno.
|
||||
|
||||
For Posix, mysys functions are light wrappers around libc, and MY_FILE_MIN
|
||||
is logically 0.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MY_FILE_MIN 2048
|
||||
#else
|
||||
#define MY_FILE_MIN 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
MY_NFILE is the default size of my_file_info array.
|
||||
|
||||
It is larger on Windows, because it all file handles are stored in my_file_info
|
||||
Default size is 16384 and this should be enough for most cases.If it is not
|
||||
enough, --max-open-files with larger value can be used.
|
||||
|
||||
For Posix , my_file_info array is only used to store filenames for
|
||||
error reporting and its size is not a limitation for number of open files.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#define MY_NFILE (16384 + MY_FILE_MIN)
|
||||
#else
|
||||
#define MY_NFILE 64
|
||||
#endif
|
||||
|
||||
#ifndef OS_FILE_LIMIT
|
||||
#define OS_FILE_LIMIT UINT_MAX
|
||||
#endif
|
||||
@ -821,9 +855,8 @@ typedef SOCKET_SIZE_TYPE size_socket;
|
||||
/* Some things that this system doesn't have */
|
||||
|
||||
#define NO_HASH /* Not needed anymore */
|
||||
#ifdef __WIN__
|
||||
#define NO_DIR_LIBRARY /* Not standar dir-library */
|
||||
#define USE_MY_STAT_STRUCT /* For my_lib */
|
||||
#ifdef _WIN32
|
||||
#define NO_DIR_LIBRARY /* Not standard dir-library */
|
||||
#endif
|
||||
|
||||
/* Some defines of functions for portability */
|
||||
|
@ -48,19 +48,30 @@ typedef struct st_pthread_link {
|
||||
struct st_pthread_link *next;
|
||||
} pthread_link;
|
||||
|
||||
typedef struct {
|
||||
uint32 waiting;
|
||||
CRITICAL_SECTION lock_waiting;
|
||||
|
||||
enum {
|
||||
SIGNAL= 0,
|
||||
BROADCAST= 1,
|
||||
MAX_EVENTS= 2
|
||||
} EVENTS;
|
||||
|
||||
HANDLE events[MAX_EVENTS];
|
||||
HANDLE broadcast_block_event;
|
||||
/**
|
||||
Implementation of Windows condition variables.
|
||||
We use native conditions on Vista and later, and fallback to own
|
||||
implementation on earlier OS version.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
/* Native condition (used on Vista and later) */
|
||||
CONDITION_VARIABLE native_cond;
|
||||
|
||||
/* Own implementation (used on XP) */
|
||||
struct
|
||||
{
|
||||
uint32 waiting;
|
||||
CRITICAL_SECTION lock_waiting;
|
||||
enum
|
||||
{
|
||||
SIGNAL= 0,
|
||||
BROADCAST= 1,
|
||||
MAX_EVENTS= 2
|
||||
} EVENTS;
|
||||
HANDLE events[MAX_EVENTS];
|
||||
HANDLE broadcast_block_event;
|
||||
};
|
||||
} pthread_cond_t;
|
||||
|
||||
|
||||
@ -605,6 +616,45 @@ int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp);
|
||||
#endif
|
||||
#define my_rwlock_init(A,B) rwlock_init((A),USYNC_THREAD,0)
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
Implementation of Windows rwlock.
|
||||
|
||||
We use native (slim) rwlocks on Win7 and later, and fallback to portable
|
||||
implementation on earlier Windows.
|
||||
|
||||
slim rwlock are also available on Vista/WS2008, but we do not use it
|
||||
("trylock" APIs are missing on Vista)
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
/* Native rwlock (is_srwlock == TRUE) */
|
||||
struct
|
||||
{
|
||||
SRWLOCK srwlock; /* native reader writer lock */
|
||||
BOOL have_exclusive_srwlock; /* used for unlock */
|
||||
};
|
||||
|
||||
/*
|
||||
Portable implementation (is_srwlock == FALSE)
|
||||
Fields are identical with Unix my_rw_lock_t fields.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
pthread_mutex_t lock; /* lock for structure */
|
||||
pthread_cond_t readers; /* waiting readers */
|
||||
pthread_cond_t writers; /* waiting writers */
|
||||
int state; /* -1:writer,0:free,>0:readers */
|
||||
int waiters; /* number of waiting writers */
|
||||
#ifdef SAFE_MUTEX
|
||||
pthread_t write_thread;
|
||||
#endif
|
||||
};
|
||||
} my_rw_lock_t;
|
||||
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
/* Use our own version of read/write locks */
|
||||
typedef struct _my_rw_lock_t {
|
||||
pthread_mutex_t lock; /* lock for structure */
|
||||
@ -614,6 +664,8 @@ typedef struct _my_rw_lock_t {
|
||||
int waiters; /* number of waiting writers */
|
||||
} my_rw_lock_t;
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#define rw_lock_t my_rw_lock_t
|
||||
#define rw_rdlock(A) my_rw_rdlock((A))
|
||||
#define rw_wrlock(A) my_rw_wrlock((A))
|
||||
|
@ -342,11 +342,12 @@ enum file_type
|
||||
|
||||
struct st_my_file_info
|
||||
{
|
||||
char * name;
|
||||
enum file_type type;
|
||||
#if defined(THREAD) && !defined(HAVE_PREAD)
|
||||
pthread_mutex_t mutex;
|
||||
char *name;
|
||||
#ifdef _WIN32
|
||||
HANDLE fhandle; /* win32 file handle */
|
||||
int oflag; /* open flags, e.g O_APPEND */
|
||||
#endif
|
||||
enum file_type type;
|
||||
};
|
||||
|
||||
extern struct st_my_file_info *my_file_info;
|
||||
@ -652,12 +653,12 @@ extern void *my_memmem(const void *haystack, size_t haystacklen,
|
||||
const void *needle, size_t needlelen);
|
||||
|
||||
|
||||
#ifdef __WIN__
|
||||
extern int my_access(const char *path, int amode);
|
||||
extern File my_sopen(const char *path, int oflag, int shflag, int pmode);
|
||||
#ifdef _WIN32
|
||||
extern int my_access(const char *path, int amode);
|
||||
#else
|
||||
#define my_access access
|
||||
#endif
|
||||
|
||||
extern int check_if_legal_filename(const char *path);
|
||||
extern int check_if_legal_tablename(const char *path);
|
||||
|
||||
@ -668,6 +669,13 @@ extern int nt_share_delete(const char *name,myf MyFlags);
|
||||
#define my_delete_allow_opened(fname,flags) my_delete((fname),(flags))
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Windows-only functions (CRT equivalents)*/
|
||||
extern File my_sopen(const char *path, int oflag, int shflag, int pmode);
|
||||
extern HANDLE my_get_osfhandle(File fd);
|
||||
extern void my_osmaperr(unsigned long last_error);
|
||||
#endif
|
||||
|
||||
#ifndef TERMINATE
|
||||
extern void TERMINATE(FILE *file, uint flag);
|
||||
#endif
|
||||
@ -677,6 +685,7 @@ extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags);
|
||||
extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags);
|
||||
extern FILE *my_freopen(const char *path, const char *mode, FILE *stream);
|
||||
extern int my_fclose(FILE *fd,myf MyFlags);
|
||||
extern File my_fileno(FILE *fd);
|
||||
extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags);
|
||||
extern int my_chmod(const char *name, mode_t mode, myf my_flags);
|
||||
extern int my_sync(File fd, myf my_flags);
|
||||
|
@ -89,6 +89,7 @@ SET(CLIENT_SOURCES ../mysys/array.c ../strings/bchange.c ../strings/bmove.c
|
||||
../mysys/ma_dyncol.c
|
||||
../mysys/my_symlink2.c ../mysys/my_thr_init.c ../sql-common/my_time.c
|
||||
../strings/my_vsnprintf.c ../mysys/my_wincond.c ../mysys/my_winthread.c
|
||||
../mysys/my_wincond.c ../mysys/my_winthread.c ../mysys/my_winfile.c ../mysys/my_winerr.c
|
||||
../mysys/my_write.c ../sql/net_serv.cc ../sql-common/pack.c ../sql/password.c
|
||||
../mysys/safemalloc.c ../mysys/sha1.c ../strings/str2int.c
|
||||
../strings/str_alloc.c ../strings/strcend.c ../strings/strcont.c ../strings/strend.c
|
||||
|
@ -38,7 +38,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_
|
||||
my_mkdir.c my_mmap.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c
|
||||
my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_sleep.c
|
||||
my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c
|
||||
my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c
|
||||
my_winerr.c my_winfile.c my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c
|
||||
rijndael.c safemalloc.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c
|
||||
thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c ma_dyncol.c
|
||||
lf_alloc-pin.c lf_dynarray.c lf_hash.c
|
||||
|
@ -74,7 +74,7 @@ endif
|
||||
EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
|
||||
thr_mutex.c thr_rwlock.c waiting_threads.c \
|
||||
CMakeLists.txt mf_soundex.c \
|
||||
my_conio.c my_wincond.c my_winthread.c
|
||||
my_conio.c my_wincond.c my_winthread.c my_winfile.c my_winerr.c
|
||||
# test_dir_DEPENDENCIES= $(LIBRARIES)
|
||||
# testhash_DEPENDENCIES= $(LIBRARIES)
|
||||
# test_charset_DEPENDENCIES= $(LIBRARIES)
|
||||
|
@ -21,7 +21,7 @@
|
||||
#define BUFF_SIZE 1024
|
||||
#define RESERVE 1024 /* Extend buffer with this extent */
|
||||
|
||||
#ifdef __WIN__
|
||||
#ifdef _WIN32
|
||||
#define NEWLINE "\r\n"
|
||||
#define NEWLINE_LEN 2
|
||||
#else
|
||||
@ -78,7 +78,7 @@ int modify_defaults_file(const char *file_location, const char *option,
|
||||
DBUG_RETURN(2);
|
||||
|
||||
/* my_fstat doesn't use the flag parameter */
|
||||
if (my_fstat(fileno(cnf_file), &file_stat, MYF(0)))
|
||||
if (my_fstat(my_fileno(cnf_file), &file_stat, MYF(0)))
|
||||
goto malloc_err;
|
||||
|
||||
if (option && option_value)
|
||||
@ -96,7 +96,7 @@ int modify_defaults_file(const char *file_location, const char *option,
|
||||
NEWLINE_LEN + /* Space for newline */
|
||||
RESERVE); /* Some additional space */
|
||||
|
||||
buffer_size= (file_stat.st_size +
|
||||
buffer_size= (uint)(file_stat.st_size +
|
||||
1); /* The ending zero */
|
||||
|
||||
/*
|
||||
@ -213,7 +213,7 @@ int modify_defaults_file(const char *file_location, const char *option,
|
||||
if (opt_applied)
|
||||
{
|
||||
/* Don't write the file if there are no changes to be made */
|
||||
if (my_chsize(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0,
|
||||
if (my_chsize(my_fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0,
|
||||
MYF(MY_WME)) ||
|
||||
my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) ||
|
||||
my_fwrite(cnf_file, (uchar*) file_buffer, (size_t) (dst_ptr - file_buffer),
|
||||
|
@ -1659,9 +1659,6 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count,
|
||||
Buffer+=length;
|
||||
pos+= length;
|
||||
Count-= length;
|
||||
#ifndef HAVE_PREAD
|
||||
info->seek_not_done=1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if we want to write inside the used part of the buffer.*/
|
||||
|
@ -52,20 +52,13 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
|
||||
|
||||
if (oldsize > newlength)
|
||||
{
|
||||
#if defined(HAVE_SETFILEPOINTER)
|
||||
/* This is for the moment only true on windows */
|
||||
long is_success;
|
||||
HANDLE win_file= (HANDLE) _get_osfhandle(fd);
|
||||
long length_low, length_high;
|
||||
length_low= (long) (ulong) newlength;
|
||||
length_high= (long) ((ulonglong) newlength >> 32);
|
||||
is_success= SetFilePointer(win_file, length_low, &length_high, FILE_BEGIN);
|
||||
if (is_success == -1 && (my_errno= GetLastError()) != NO_ERROR)
|
||||
#ifdef _WIN32
|
||||
if (my_win_chsize(fd, newlength))
|
||||
{
|
||||
my_errno= errno;
|
||||
goto err;
|
||||
if (SetEndOfFile(win_file))
|
||||
DBUG_RETURN(0);
|
||||
my_errno= GetLastError();
|
||||
goto err;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
#elif defined(HAVE_FTRUNCATE)
|
||||
if (ftruncate(fd, (off_t) newlength))
|
||||
{
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "mysys_err.h"
|
||||
#include <errno.h>
|
||||
#include <my_sys.h>
|
||||
#if defined(__WIN__)
|
||||
#if defined(_WIN32)
|
||||
#include <share.h>
|
||||
#endif
|
||||
|
||||
@ -41,16 +41,12 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
|
||||
FileName, CreateFlags, access_flags, MyFlags));
|
||||
|
||||
#if !defined(NO_OPEN_3)
|
||||
fd = open((char *) FileName, access_flags | O_CREAT,
|
||||
fd= open((char *) FileName, access_flags | O_CREAT,
|
||||
CreateFlags ? CreateFlags : my_umask);
|
||||
#elif defined(VMS)
|
||||
fd = open((char *) FileName, access_flags | O_CREAT, 0,
|
||||
"ctx=stm","ctx=bin");
|
||||
#elif defined(__WIN__)
|
||||
fd= my_sopen((char *) FileName, access_flags | O_CREAT | O_BINARY,
|
||||
SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
|
||||
#elif defined(_WIN32)
|
||||
fd= my_win_open(FileName, access_flags | O_CREAT);
|
||||
#else
|
||||
fd = open(FileName, access_flags);
|
||||
fd= open(FileName, access_flags);
|
||||
#endif
|
||||
|
||||
if ((MyFlags & MY_SYNC_DIR) && (fd >=0) &&
|
||||
@ -71,6 +67,7 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
|
||||
if (unlikely(fd >= 0 && rc < 0))
|
||||
{
|
||||
int tmp= my_errno;
|
||||
my_close(fd, MyFlags);
|
||||
my_delete(FileName, MyFlags);
|
||||
my_errno= tmp;
|
||||
}
|
||||
|
@ -29,7 +29,11 @@ File my_dup(File file, myf MyFlags)
|
||||
const char *filename;
|
||||
DBUG_ENTER("my_dup");
|
||||
DBUG_PRINT("my",("file: %d MyFlags: %d", file, MyFlags));
|
||||
fd = dup(file);
|
||||
#ifdef _WIN32
|
||||
fd= my_win_dup(file);
|
||||
#else
|
||||
fd= dup(file);
|
||||
#endif
|
||||
filename= (((uint) file < my_file_limit) ?
|
||||
my_file_info[(int) file].name : "Unknown");
|
||||
DBUG_RETURN(my_register_filename(fd, filename, FILE_BY_DUP,
|
||||
|
@ -97,6 +97,7 @@ uint my_set_max_open_files(uint files)
|
||||
DBUG_ENTER("my_set_max_open_files");
|
||||
DBUG_PRINT("enter",("files: %u my_file_limit: %u", files, my_file_limit));
|
||||
|
||||
files+= MY_FILE_MIN;
|
||||
files= set_max_open_files(min(files, OS_FILE_LIMIT));
|
||||
if (files <= MY_NFILE)
|
||||
DBUG_RETURN(files);
|
||||
|
@ -46,24 +46,14 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
|
||||
DBUG_ENTER("my_fopen");
|
||||
DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d",
|
||||
filename, flags, MyFlags));
|
||||
/*
|
||||
if we are not creating, then we need to use my_access to make sure
|
||||
the file exists since Windows doesn't handle files like "com1.sym"
|
||||
very well
|
||||
*/
|
||||
#ifdef __WIN__
|
||||
if (check_if_legal_filename(filename))
|
||||
{
|
||||
errno= EACCES;
|
||||
fd= 0;
|
||||
}
|
||||
else
|
||||
|
||||
make_ftype(type,flags);
|
||||
|
||||
#ifdef _WIN32
|
||||
fd= my_win_fopen(filename, type);
|
||||
#else
|
||||
fd= fopen(filename, type);
|
||||
#endif
|
||||
{
|
||||
make_ftype(type,flags);
|
||||
fd = fopen(filename, type);
|
||||
}
|
||||
|
||||
if (fd != 0)
|
||||
{
|
||||
/*
|
||||
@ -71,18 +61,20 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
|
||||
on some OS (SUNOS). Actually the filename save isn't that important
|
||||
so we can ignore if this doesn't work.
|
||||
*/
|
||||
if ((uint) fileno(fd) >= my_file_limit)
|
||||
|
||||
int filedesc= my_fileno(fd);
|
||||
if ((uint)filedesc >= my_file_limit)
|
||||
{
|
||||
thread_safe_increment(my_stream_opened,&THR_LOCK_open);
|
||||
DBUG_RETURN(fd); /* safeguard */
|
||||
}
|
||||
pthread_mutex_lock(&THR_LOCK_open);
|
||||
if ((my_file_info[fileno(fd)].name = (char*)
|
||||
if ((my_file_info[filedesc].name= (char*)
|
||||
my_strdup(filename,MyFlags)))
|
||||
{
|
||||
my_stream_opened++;
|
||||
my_file_total_opened++;
|
||||
my_file_info[fileno(fd)].type = STREAM_BY_FOPEN;
|
||||
my_file_info[filedesc].type= STREAM_BY_FOPEN;
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
DBUG_PRINT("exit",("stream: 0x%lx", (long) fd));
|
||||
DBUG_RETURN(fd);
|
||||
@ -240,8 +232,13 @@ int my_fclose(FILE *fd, myf MyFlags)
|
||||
DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags));
|
||||
|
||||
pthread_mutex_lock(&THR_LOCK_open);
|
||||
file=fileno(fd);
|
||||
if ((err = fclose(fd)) < 0)
|
||||
file= my_fileno(fd);
|
||||
#ifndef _WIN32
|
||||
err= fclose(fd);
|
||||
#else
|
||||
err= my_win_fclose(fd);
|
||||
#endif
|
||||
if(err < 0)
|
||||
{
|
||||
my_errno=errno;
|
||||
if (MyFlags & (MY_FAE | MY_WME))
|
||||
@ -272,7 +269,12 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
|
||||
Filedes, Flags, MyFlags));
|
||||
|
||||
make_ftype(type,Flags);
|
||||
if ((fd = fdopen(Filedes, type)) == 0)
|
||||
#ifdef _WIN32
|
||||
fd= my_win_fdopen(Filedes, type);
|
||||
#else
|
||||
fd= fdopen(Filedes, type);
|
||||
#endif
|
||||
if (!fd)
|
||||
{
|
||||
my_errno=errno;
|
||||
if (MyFlags & (MY_FAE | MY_WME))
|
||||
|
@ -56,11 +56,11 @@ size_t my_fread(FILE *stream, uchar *Buffer, size_t Count, myf MyFlags)
|
||||
{
|
||||
if (ferror(stream))
|
||||
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(fileno(stream)),errno);
|
||||
my_filename(my_fileno(stream)),errno);
|
||||
else
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(fileno(stream)),errno);
|
||||
my_filename(my_fileno(stream)),errno);
|
||||
}
|
||||
my_errno=errno ? errno : -1;
|
||||
if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP))
|
||||
@ -142,7 +142,7 @@ size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(fileno(stream)),errno);
|
||||
my_filename(my_fileno(stream)),errno);
|
||||
}
|
||||
writtenbytes= (size_t) -1; /* Return that we got error */
|
||||
break;
|
||||
@ -182,3 +182,14 @@ my_off_t my_ftell(FILE *stream, myf MyFlags __attribute__((unused)))
|
||||
DBUG_PRINT("exit",("ftell: %lu",(ulong) pos));
|
||||
DBUG_RETURN((my_off_t) pos);
|
||||
} /* my_ftell */
|
||||
|
||||
|
||||
/* Get a File corresponding to the stream*/
|
||||
int my_fileno(FILE *f)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return my_win_fileno(f);
|
||||
#else
|
||||
return fileno(f);
|
||||
#endif
|
||||
}
|
||||
|
@ -274,6 +274,7 @@ void my_parameter_handler(const wchar_t * expression, const wchar_t * function,
|
||||
{
|
||||
DBUG_PRINT("my",("Expression: %s function: %s file: %s, line: %d",
|
||||
expression, function, file, line));
|
||||
__debugbreak();
|
||||
}
|
||||
|
||||
|
||||
@ -298,7 +299,7 @@ int handle_rtc_failure(int err_type, const char *file, int line,
|
||||
fprintf(stderr, " At %s:%d\n", file, line);
|
||||
va_end(args);
|
||||
(void) fflush(stderr);
|
||||
|
||||
__debugbreak();
|
||||
return 0; /* Error is handled */
|
||||
}
|
||||
#pragma runtime_checks("", restore)
|
||||
|
@ -35,8 +35,7 @@
|
||||
# if defined(HAVE_NDIR_H)
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
# if defined(__WIN__)
|
||||
# include <dos.h>
|
||||
# if defined(_WIN32)
|
||||
# ifdef __BORLANDC__
|
||||
# include <dir.h>
|
||||
# endif
|
||||
@ -92,7 +91,7 @@ static int comp_names(struct fileinfo *a, struct fileinfo *b)
|
||||
} /* comp_names */
|
||||
|
||||
|
||||
#if !defined(__WIN__)
|
||||
#if !defined(_WIN32)
|
||||
|
||||
MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
{
|
||||
@ -507,19 +506,24 @@ error:
|
||||
DBUG_RETURN((MY_DIR *) NULL);
|
||||
} /* my_dir */
|
||||
|
||||
#endif /* __WIN__ */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/****************************************************************************
|
||||
** File status
|
||||
** Note that MY_STAT is assumed to be same as struct stat
|
||||
****************************************************************************/
|
||||
|
||||
int my_fstat(int Filedes, MY_STAT *stat_area,
|
||||
|
||||
int my_fstat(File Filedes, MY_STAT *stat_area,
|
||||
myf MyFlags __attribute__((unused)))
|
||||
{
|
||||
DBUG_ENTER("my_fstat");
|
||||
DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes, MyFlags));
|
||||
#ifdef _WIN32
|
||||
DBUG_RETURN(my_win_fstat(Filedes, stat_area));
|
||||
#else
|
||||
DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -531,11 +535,15 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
|
||||
(long) stat_area, my_flags));
|
||||
|
||||
if ((m_used= (stat_area == NULL)))
|
||||
if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
|
||||
if (!(stat_area= (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
|
||||
goto error;
|
||||
if (! stat((char *) path, (struct stat *) stat_area) )
|
||||
DBUG_RETURN(stat_area);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (! stat((char *) path, (struct stat *) stat_area) )
|
||||
DBUG_RETURN(stat_area);
|
||||
#else
|
||||
if (! my_win_stat(path, stat_area) )
|
||||
DBUG_RETURN(stat_area);
|
||||
#endif
|
||||
DBUG_PRINT("error",("Got errno: %d from stat", errno));
|
||||
my_errno= errno;
|
||||
if (m_used) /* Free if new area */
|
||||
|
137
mysys/my_lock.c
137
mysys/my_lock.c
@ -22,13 +22,113 @@
|
||||
#undef NO_ALARM_LOOP
|
||||
#endif
|
||||
#include <my_alarm.h>
|
||||
#ifdef __WIN__
|
||||
#include <sys/locking.h>
|
||||
#endif
|
||||
#ifdef __NETWARE__
|
||||
#include <nks/fsio.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN_LOCK_INFINITE -1
|
||||
#define WIN_LOCK_SLEEP_MILLIS 100
|
||||
|
||||
static int win_lock(File fd, int locktype, my_off_t start, my_off_t length,
|
||||
int timeout_sec)
|
||||
{
|
||||
LARGE_INTEGER liOffset,liLength;
|
||||
DWORD dwFlags;
|
||||
OVERLAPPED ov= {0};
|
||||
HANDLE hFile= (HANDLE)my_get_osfhandle(fd);
|
||||
DWORD lastError= 0;
|
||||
int i;
|
||||
int timeout_millis= timeout_sec * 1000;
|
||||
|
||||
DBUG_ENTER("win_lock");
|
||||
|
||||
liOffset.QuadPart= start;
|
||||
liLength.QuadPart= length;
|
||||
|
||||
ov.Offset= liOffset.LowPart;
|
||||
ov.OffsetHigh= liOffset.HighPart;
|
||||
|
||||
if (locktype == F_UNLCK)
|
||||
{
|
||||
if (UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov))
|
||||
DBUG_RETURN(0);
|
||||
/*
|
||||
For compatibility with fcntl implementation, ignore error,
|
||||
if region was not locked
|
||||
*/
|
||||
if (GetLastError() == ERROR_NOT_LOCKED)
|
||||
{
|
||||
SetLastError(0);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
else if (locktype == F_RDLCK)
|
||||
/* read lock is mapped to a shared lock. */
|
||||
dwFlags= 0;
|
||||
else
|
||||
/* write lock is mapped to an exclusive lock. */
|
||||
dwFlags= LOCKFILE_EXCLUSIVE_LOCK;
|
||||
|
||||
/*
|
||||
Drop old lock first to avoid double locking.
|
||||
During analyze of Bug#38133 (Myisamlog test fails on Windows)
|
||||
I met the situation that the program myisamlog locked the file
|
||||
exclusively, then additionally shared, then did one unlock, and
|
||||
then blocked on an attempt to lock it exclusively again.
|
||||
Unlocking before every lock fixed the problem.
|
||||
Note that this introduces a race condition. When the application
|
||||
wants to convert an exclusive lock into a shared one, it will now
|
||||
first unlock the file and then lock it shared. A waiting exclusive
|
||||
lock could step in here. For reasons described in Bug#38133 and
|
||||
Bug#41124 (Server hangs on Windows with --external-locking after
|
||||
INSERT...SELECT) and in the review thread at
|
||||
http://lists.mysql.com/commits/60721 it seems to be the better
|
||||
option than not to unlock here.
|
||||
If one day someone notices a way how to do file lock type changes
|
||||
on Windows without unlocking before taking the new lock, please
|
||||
change this code accordingly to fix the race condition.
|
||||
*/
|
||||
if (!UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov) &&
|
||||
(GetLastError() != ERROR_NOT_LOCKED))
|
||||
goto error;
|
||||
|
||||
if (timeout_sec == WIN_LOCK_INFINITE)
|
||||
{
|
||||
if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov))
|
||||
DBUG_RETURN(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dwFlags|= LOCKFILE_FAIL_IMMEDIATELY;
|
||||
timeout_millis= timeout_sec * 1000;
|
||||
/* Try lock in a loop, until the lock is acquired or timeout happens */
|
||||
for(i= 0; ;i+= WIN_LOCK_SLEEP_MILLIS)
|
||||
{
|
||||
if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov))
|
||||
DBUG_RETURN(0);
|
||||
|
||||
if (GetLastError() != ERROR_LOCK_VIOLATION)
|
||||
goto error;
|
||||
|
||||
if (i >= timeout_millis)
|
||||
break;
|
||||
Sleep(WIN_LOCK_SLEEP_MILLIS);
|
||||
}
|
||||
|
||||
/* timeout */
|
||||
errno= EAGAIN;
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
error:
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Lock a part of a file
|
||||
|
||||
@ -97,29 +197,16 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_LOCKING)
|
||||
/* Windows */
|
||||
#elif defined(_WIN32)
|
||||
{
|
||||
my_bool error= FALSE;
|
||||
pthread_mutex_lock(&my_file_info[fd].mutex);
|
||||
if (MyFlags & MY_SEEK_NOT_DONE)
|
||||
{
|
||||
if( my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))
|
||||
== MY_FILEPOS_ERROR )
|
||||
{
|
||||
/*
|
||||
If my_seek fails my_errno will already contain an error code;
|
||||
just unlock and return error code.
|
||||
*/
|
||||
DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno));
|
||||
pthread_mutex_unlock(&my_file_info[fd].mutex);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
error= locking(fd,locktype,(ulong) length) && errno != EINVAL;
|
||||
pthread_mutex_unlock(&my_file_info[fd].mutex);
|
||||
if (!error)
|
||||
DBUG_RETURN(0);
|
||||
int timeout_sec;
|
||||
if (MyFlags & MY_NO_WAIT)
|
||||
timeout_sec= 0;
|
||||
else
|
||||
timeout_sec= WIN_LOCK_INFINITE;
|
||||
|
||||
if(win_lock(fd, locktype, start, length, timeout_sec) == 0)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#else
|
||||
#if defined(HAVE_FCNTL)
|
||||
|
@ -27,17 +27,17 @@ int my_msync(int fd, void *addr, size_t len, int flags)
|
||||
return my_sync(fd, MYF(0));
|
||||
}
|
||||
|
||||
#elif defined(__WIN__)
|
||||
#elif defined(_WIN32)
|
||||
|
||||
static SECURITY_ATTRIBUTES mmap_security_attributes=
|
||||
{sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
|
||||
|
||||
void *my_mmap(void *addr, size_t len, int prot,
|
||||
int flags, int fd, my_off_t offset)
|
||||
int flags, File fd, my_off_t offset)
|
||||
{
|
||||
HANDLE hFileMap;
|
||||
LPVOID ptr;
|
||||
HANDLE hFile= (HANDLE)_get_osfhandle(fd);
|
||||
HANDLE hFile= (HANDLE)my_get_osfhandle(fd);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return MAP_FAILED;
|
||||
|
||||
|
227
mysys/my_open.c
227
mysys/my_open.c
@ -17,9 +17,7 @@
|
||||
#include "mysys_err.h"
|
||||
#include <my_dir.h>
|
||||
#include <errno.h>
|
||||
#if defined(__WIN__)
|
||||
#include <share.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Open a file
|
||||
@ -43,29 +41,8 @@ File my_open(const char *FileName, int Flags, myf MyFlags)
|
||||
DBUG_ENTER("my_open");
|
||||
DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
|
||||
FileName, Flags, MyFlags));
|
||||
#if defined(__WIN__)
|
||||
/*
|
||||
Check that we don't try to open or create a file name that may
|
||||
cause problems for us in the future (like PRN)
|
||||
*/
|
||||
if (check_if_legal_filename(FileName))
|
||||
{
|
||||
errno= EACCES;
|
||||
DBUG_RETURN(my_register_filename(-1, FileName, FILE_BY_OPEN,
|
||||
EE_FILENOTFOUND, MyFlags));
|
||||
}
|
||||
#ifndef __WIN__
|
||||
if (Flags & O_SHARE)
|
||||
fd = sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
|
||||
MY_S_IREAD | MY_S_IWRITE);
|
||||
else
|
||||
fd = open((char *) FileName, Flags | O_BINARY,
|
||||
MY_S_IREAD | MY_S_IWRITE);
|
||||
#else
|
||||
fd= my_sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
|
||||
MY_S_IREAD | MY_S_IWRITE);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
fd= my_win_open(FileName, Flags);
|
||||
#elif !defined(NO_OPEN_3)
|
||||
fd = open(FileName, Flags, my_umask); /* Normal unix */
|
||||
#else
|
||||
@ -94,11 +71,14 @@ int my_close(File fd, myf MyFlags)
|
||||
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
|
||||
|
||||
pthread_mutex_lock(&THR_LOCK_open);
|
||||
#ifndef _WIN32
|
||||
do
|
||||
{
|
||||
err= close(fd);
|
||||
} while (err == -1 && errno == EINTR);
|
||||
|
||||
#else
|
||||
err= my_win_close(fd);
|
||||
#endif
|
||||
if (err)
|
||||
{
|
||||
DBUG_PRINT("error",("Got error %d on close",err));
|
||||
@ -109,9 +89,6 @@ int my_close(File fd, myf MyFlags)
|
||||
if ((uint) fd < my_file_limit && my_file_info[fd].type != UNOPEN)
|
||||
{
|
||||
my_free(my_file_info[fd].name, MYF(0));
|
||||
#if defined(THREAD) && !defined(HAVE_PREAD)
|
||||
pthread_mutex_destroy(&my_file_info[fd].mutex);
|
||||
#endif
|
||||
my_file_info[fd].type = UNOPEN;
|
||||
}
|
||||
my_file_opened--;
|
||||
@ -141,16 +118,12 @@ File my_register_filename(File fd, const char *FileName, enum file_type
|
||||
type_of_file, uint error_message_number, myf MyFlags)
|
||||
{
|
||||
DBUG_ENTER("my_register_filename");
|
||||
if ((int) fd >= 0)
|
||||
if ((int) fd >= MY_FILE_MIN)
|
||||
{
|
||||
if ((uint) fd >= my_file_limit)
|
||||
{
|
||||
#if defined(THREAD) && !defined(HAVE_PREAD)
|
||||
my_errno= EMFILE;
|
||||
#else
|
||||
thread_safe_increment(my_file_opened,&THR_LOCK_open);
|
||||
DBUG_RETURN(fd); /* safeguard */
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -160,9 +133,6 @@ File my_register_filename(File fd, const char *FileName, enum file_type
|
||||
my_file_opened++;
|
||||
my_file_total_opened++;
|
||||
my_file_info[fd].type = type_of_file;
|
||||
#if defined(THREAD) && !defined(HAVE_PREAD)
|
||||
pthread_mutex_init(&my_file_info[fd].mutex,MY_MUTEX_INIT_FAST);
|
||||
#endif
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
DBUG_PRINT("exit",("fd: %d",fd));
|
||||
DBUG_RETURN(fd);
|
||||
@ -187,188 +157,7 @@ File my_register_filename(File fd, const char *FileName, enum file_type
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
#ifdef __WIN__
|
||||
|
||||
extern void __cdecl _dosmaperr(unsigned long);
|
||||
|
||||
/*
|
||||
Open a file with sharing. Similar to _sopen() from libc, but allows managing
|
||||
share delete on win32
|
||||
|
||||
SYNOPSIS
|
||||
my_sopen()
|
||||
path fully qualified file name
|
||||
oflag operation flags
|
||||
shflag share flag
|
||||
pmode permission flags
|
||||
|
||||
RETURN VALUE
|
||||
File descriptor of opened file if success
|
||||
-1 and sets errno if fails.
|
||||
*/
|
||||
|
||||
File my_sopen(const char *path, int oflag, int shflag, int pmode)
|
||||
{
|
||||
int fh; /* handle of opened file */
|
||||
int mask;
|
||||
HANDLE osfh; /* OS handle of opened file */
|
||||
DWORD fileaccess; /* OS file access (requested) */
|
||||
DWORD fileshare; /* OS file sharing mode */
|
||||
DWORD filecreate; /* OS method of opening/creating */
|
||||
DWORD fileattrib; /* OS file attribute flags */
|
||||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
|
||||
SecurityAttributes.nLength= sizeof(SecurityAttributes);
|
||||
SecurityAttributes.lpSecurityDescriptor= NULL;
|
||||
SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
|
||||
|
||||
/*
|
||||
* decode the access flags
|
||||
*/
|
||||
switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
|
||||
case _O_RDONLY: /* read access */
|
||||
fileaccess= GENERIC_READ;
|
||||
break;
|
||||
case _O_WRONLY: /* write access */
|
||||
fileaccess= GENERIC_WRITE;
|
||||
break;
|
||||
case _O_RDWR: /* read and write access */
|
||||
fileaccess= GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
default: /* error, bad oflag */
|
||||
errno= EINVAL;
|
||||
_doserrno= 0L; /* not an OS error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode sharing flags
|
||||
*/
|
||||
switch (shflag) {
|
||||
case _SH_DENYRW: /* exclusive access except delete */
|
||||
fileshare= FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYWR: /* share read and delete access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYRD: /* share write and delete access */
|
||||
fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYNO: /* share read, write and delete access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYRWD: /* exclusive access */
|
||||
fileshare= 0L;
|
||||
break;
|
||||
case _SH_DENYWRD: /* share read access */
|
||||
fileshare= FILE_SHARE_READ;
|
||||
break;
|
||||
case _SH_DENYRDD: /* share write access */
|
||||
fileshare= FILE_SHARE_WRITE;
|
||||
break;
|
||||
case _SH_DENYDEL: /* share read and write access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
break;
|
||||
default: /* error, bad shflag */
|
||||
errno= EINVAL;
|
||||
_doserrno= 0L; /* not an OS error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode open/create method flags
|
||||
*/
|
||||
switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
|
||||
case 0:
|
||||
case _O_EXCL: /* ignore EXCL w/o CREAT */
|
||||
filecreate= OPEN_EXISTING;
|
||||
break;
|
||||
|
||||
case _O_CREAT:
|
||||
filecreate= OPEN_ALWAYS;
|
||||
break;
|
||||
|
||||
case _O_CREAT | _O_EXCL:
|
||||
case _O_CREAT | _O_TRUNC | _O_EXCL:
|
||||
filecreate= CREATE_NEW;
|
||||
break;
|
||||
|
||||
case _O_TRUNC:
|
||||
case _O_TRUNC | _O_EXCL: /* ignore EXCL w/o CREAT */
|
||||
filecreate= TRUNCATE_EXISTING;
|
||||
break;
|
||||
|
||||
case _O_CREAT | _O_TRUNC:
|
||||
filecreate= CREATE_ALWAYS;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* this can't happen ... all cases are covered */
|
||||
errno= EINVAL;
|
||||
_doserrno= 0L;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode file attribute flags if _O_CREAT was specified
|
||||
*/
|
||||
fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */
|
||||
if (oflag & _O_CREAT)
|
||||
{
|
||||
_umask((mask= _umask(0)));
|
||||
|
||||
if (!((pmode & ~mask) & _S_IWRITE))
|
||||
fileattrib= FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set temporary file (delete-on-close) attribute if requested.
|
||||
*/
|
||||
if (oflag & _O_TEMPORARY)
|
||||
{
|
||||
fileattrib|= FILE_FLAG_DELETE_ON_CLOSE;
|
||||
fileaccess|= DELETE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set temporary file (delay-flush-to-disk) attribute if requested.
|
||||
*/
|
||||
if (oflag & _O_SHORT_LIVED)
|
||||
fileattrib|= FILE_ATTRIBUTE_TEMPORARY;
|
||||
|
||||
/*
|
||||
* Set sequential or random access attribute if requested.
|
||||
*/
|
||||
if (oflag & _O_SEQUENTIAL)
|
||||
fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN;
|
||||
else if (oflag & _O_RANDOM)
|
||||
fileattrib|= FILE_FLAG_RANDOM_ACCESS;
|
||||
|
||||
/*
|
||||
* try to open/create the file
|
||||
*/
|
||||
if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
|
||||
filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/*
|
||||
* OS call to open/create file failed! map the error, release
|
||||
* the lock, and return -1. note that it's not necessary to
|
||||
* call _free_osfhnd (it hasn't been used yet).
|
||||
*/
|
||||
_dosmaperr(GetLastError()); /* map error */
|
||||
return -1; /* return error to caller */
|
||||
}
|
||||
|
||||
if ((fh= _open_osfhandle((intptr_t)osfh,
|
||||
oflag & (_O_APPEND | _O_RDONLY | _O_TEXT))) == -1)
|
||||
{
|
||||
_dosmaperr(GetLastError()); /* map error */
|
||||
CloseHandle(osfh);
|
||||
}
|
||||
|
||||
return fh; /* return handle */
|
||||
}
|
||||
#endif /* __WIN__ */
|
||||
|
||||
|
||||
#ifdef EXTRA_DEBUG
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "my_base.h"
|
||||
#include <m_string.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_PREAD
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
@ -48,9 +48,7 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
|
||||
{
|
||||
size_t readbytes;
|
||||
int error= 0;
|
||||
#ifndef HAVE_PREAD
|
||||
int save_errno;
|
||||
#endif
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
char llbuf[22];
|
||||
DBUG_ENTER("my_pread");
|
||||
@ -61,20 +59,15 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
|
||||
for (;;)
|
||||
{
|
||||
errno= 0; /* Linux, Windows don't reset this on EOF/success */
|
||||
#ifndef HAVE_PREAD
|
||||
pthread_mutex_lock(&my_file_info[Filedes].mutex);
|
||||
readbytes= (uint) -1;
|
||||
error= (lseek(Filedes, offset, MY_SEEK_SET) == (my_off_t) -1 ||
|
||||
(readbytes= read(Filedes, Buffer, (uint) Count)) != Count);
|
||||
save_errno= errno;
|
||||
pthread_mutex_unlock(&my_file_info[Filedes].mutex);
|
||||
#ifdef _WIN32
|
||||
readbytes= my_win_pread(Filedes, Buffer, Count, offset);
|
||||
#else
|
||||
readbytes= pread(Filedes, Buffer, Count, offset);
|
||||
#endif
|
||||
error = (readbytes != Count);
|
||||
|
||||
if (error)
|
||||
{
|
||||
errno= save_errno;
|
||||
#else
|
||||
if ((error= ((readbytes= pread(Filedes, Buffer, Count, offset)) != Count)))
|
||||
{
|
||||
#endif
|
||||
my_errno= errno ? errno : -1;
|
||||
if (errno == 0 || (readbytes != (size_t) -1 &&
|
||||
(MyFlags & (MY_NABP | MY_FNABP))))
|
||||
@ -91,19 +84,19 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
|
||||
#endif
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
if (readbytes == (size_t) -1)
|
||||
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
else if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
if (readbytes == (size_t) -1)
|
||||
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
else if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
}
|
||||
if (readbytes == (size_t) -1 || (MyFlags & (MY_FNABP | MY_NABP)))
|
||||
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
|
||||
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
|
||||
}
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
DBUG_RETURN(0); /* Read went ok; Return 0 */
|
||||
DBUG_RETURN(readbytes); /* purecov: inspected */
|
||||
DBUG_RETURN(0); /* Read went ok; Return 0 */
|
||||
DBUG_RETURN(readbytes); /* purecov: inspected */
|
||||
}
|
||||
} /* my_pread */
|
||||
|
||||
@ -132,7 +125,7 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
|
||||
size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
|
||||
my_off_t offset, myf MyFlags)
|
||||
{
|
||||
size_t writenbytes, written;
|
||||
size_t writtenbytes, written;
|
||||
uint errors;
|
||||
#ifndef DBUG_OFF
|
||||
char llbuf[22];
|
||||
@ -146,28 +139,22 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
|
||||
|
||||
for (;;)
|
||||
{
|
||||
#ifndef HAVE_PREAD
|
||||
int error;
|
||||
writenbytes= (size_t) -1;
|
||||
pthread_mutex_lock(&my_file_info[Filedes].mutex);
|
||||
error= (lseek(Filedes, offset, MY_SEEK_SET) != (my_off_t) -1 &&
|
||||
(writenbytes = write(Filedes, Buffer, (uint) Count)) == Count);
|
||||
pthread_mutex_unlock(&my_file_info[Filedes].mutex);
|
||||
if (error)
|
||||
break;
|
||||
#ifdef _WIN32
|
||||
writtenbytes= my_win_pwrite(Filedes, Buffer, Count,offset);
|
||||
#else
|
||||
if ((writenbytes= pwrite(Filedes, Buffer, Count,offset)) == Count)
|
||||
writtenbytes= pwrite(Filedes, Buffer, Count, offset);
|
||||
#endif
|
||||
if (writtenbytes == Count)
|
||||
break;
|
||||
my_errno= errno;
|
||||
#endif
|
||||
if (writenbytes != (size_t) -1)
|
||||
if (writtenbytes != (size_t) -1)
|
||||
{ /* Safegueard */
|
||||
written+=writenbytes;
|
||||
Buffer+=writenbytes;
|
||||
Count-=writenbytes;
|
||||
offset+=writenbytes;
|
||||
written+=writtenbytes;
|
||||
Buffer+=writtenbytes;
|
||||
Count-=writtenbytes;
|
||||
offset+=writtenbytes;
|
||||
}
|
||||
DBUG_PRINT("error",("Write only %u bytes", (uint) writenbytes));
|
||||
DBUG_PRINT("error",("Write only %u bytes", (uint) writtenbytes));
|
||||
#ifndef NO_BACKGROUND
|
||||
#ifdef THREAD
|
||||
if (my_thread_var->abort)
|
||||
@ -180,15 +167,15 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
if ((writenbytes && writenbytes != (size_t) -1) || my_errno == EINTR)
|
||||
if ((writtenbytes && writtenbytes != (size_t) -1) || my_errno == EINTR)
|
||||
continue; /* Retry */
|
||||
#endif
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
{
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
}
|
||||
DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
|
||||
}
|
||||
@ -198,5 +185,5 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
|
||||
DBUG_EXECUTE_IF("check", my_seek(Filedes, -1, SEEK_SET, MYF(0)););
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
DBUG_RETURN(0); /* Want only errors */
|
||||
DBUG_RETURN(writenbytes+written); /* purecov: inspected */
|
||||
DBUG_RETURN(writtenbytes+written); /* purecov: inspected */
|
||||
} /* my_pwrite */
|
||||
|
@ -19,11 +19,19 @@
|
||||
#include "my_nosys.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
extern size_t my_win_read(File Filedes,uchar *Buffer,size_t Count);
|
||||
#endif
|
||||
|
||||
size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags)
|
||||
{
|
||||
size_t readbytes;
|
||||
|
||||
if ((readbytes = read(Filedes, Buffer, (uint) Count)) != Count)
|
||||
#ifdef _WIN32
|
||||
readbytes= my_win_read(Filedes, Buffer, Count);
|
||||
#else
|
||||
readbytes= read(Filedes, Buffer, Count);
|
||||
#endif
|
||||
if(readbytes != Count)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
if ((readbytes == 0 || readbytes == (size_t) -1) && errno == EINTR)
|
||||
@ -40,8 +48,13 @@ size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags)
|
||||
}
|
||||
|
||||
|
||||
size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count)
|
||||
|
||||
size_t my_quick_write(File Filedes, const uchar *Buffer, size_t Count)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return my_win_write(Filedes, Buffer, Count);
|
||||
#else
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
size_t writtenbytes;
|
||||
#endif
|
||||
@ -50,7 +63,7 @@ size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count)
|
||||
#ifndef DBUG_OFF
|
||||
writtenbytes =
|
||||
#endif
|
||||
(size_t) write(Filedes,Buffer, (uint) Count)) != Count)
|
||||
(size_t) write(Filedes,Buffer,Count)) != Count)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
if ((writtenbytes == 0 || writtenbytes == (size_t) -1) && errno == EINTR)
|
||||
@ -64,4 +77,5 @@ size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count)
|
||||
return (size_t) -1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -44,7 +44,12 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
|
||||
for (;;)
|
||||
{
|
||||
errno= 0; /* Linux, Windows don't reset this on EOF/success */
|
||||
if ((readbytes= read(Filedes, Buffer, (uint) Count)) != Count)
|
||||
#ifdef _WIN32
|
||||
readbytes= my_win_read(Filedes, Buffer, Count);
|
||||
#else
|
||||
readbytes= read(Filedes, Buffer, Count);
|
||||
#endif
|
||||
if (readbytes != Count)
|
||||
{
|
||||
my_errno= errno;
|
||||
if (errno == 0 || (readbytes != (size_t) -1 &&
|
||||
|
@ -56,16 +56,11 @@ my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags)
|
||||
Make sure we are using a valid file descriptor!
|
||||
*/
|
||||
DBUG_ASSERT(fd != -1);
|
||||
#if defined(THREAD) && !defined(HAVE_PREAD)
|
||||
if (MyFlags & MY_THREADSAFE)
|
||||
{
|
||||
pthread_mutex_lock(&my_file_info[fd].mutex);
|
||||
newpos= lseek(fd, pos, whence);
|
||||
pthread_mutex_unlock(&my_file_info[fd].mutex);
|
||||
}
|
||||
else
|
||||
#ifdef _WIN32
|
||||
newpos= my_win_lseek(fd, pos, whence);
|
||||
#else
|
||||
newpos= lseek(fd, pos, whence);
|
||||
#endif
|
||||
newpos= lseek(fd, pos, whence);
|
||||
if (newpos == (os_off_t) -1)
|
||||
{
|
||||
my_errno= errno;
|
||||
@ -91,7 +86,9 @@ my_off_t my_tell(File fd, myf MyFlags)
|
||||
DBUG_ENTER("my_tell");
|
||||
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
|
||||
DBUG_ASSERT(fd >= 0);
|
||||
#ifdef HAVE_TELL
|
||||
#ifdef _WIN32
|
||||
pos= my_seek(fd, 0, MY_SEEK_CUR,0);
|
||||
#elif defined(HAVE_TELL)
|
||||
pos=tell(fd);
|
||||
#else
|
||||
pos=lseek(fd, 0L, MY_SEEK_CUR);
|
||||
|
@ -35,7 +35,7 @@ int NEAR my_umask=0664, NEAR my_umask_dir=0777;
|
||||
#ifndef THREAD
|
||||
int NEAR my_errno=0;
|
||||
#endif
|
||||
struct st_my_file_info my_file_info_default[MY_NFILE]= {{0,UNOPEN}};
|
||||
struct st_my_file_info my_file_info_default[MY_NFILE];
|
||||
uint my_file_limit= MY_NFILE;
|
||||
struct st_my_file_info *my_file_info= my_file_info_default;
|
||||
|
||||
|
@ -71,7 +71,7 @@ int my_sync(File fd, myf my_flags)
|
||||
if (res == -1 && errno == ENOLCK)
|
||||
res= 0; /* Result Bug in Old FreeBSD */
|
||||
#elif defined(__WIN__)
|
||||
res= _commit(fd);
|
||||
res= my_win_fsync(fd);
|
||||
#else
|
||||
#error Cannot find a way to sync a file, durability in danger
|
||||
res= 0; /* No sync (strange OS) */
|
||||
|
@ -26,7 +26,92 @@
|
||||
#include <process.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
|
||||
|
||||
/*
|
||||
Windows native condition variables. We use runtime loading / function
|
||||
pointers, because they are not available on XP
|
||||
*/
|
||||
|
||||
/* Prototypes and function pointers for condition variable functions */
|
||||
typedef void (WINAPI * InitializeConditionVariableProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
|
||||
typedef BOOL (WINAPI * SleepConditionVariableCSProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable,
|
||||
PCRITICAL_SECTION CriticalSection,
|
||||
DWORD dwMilliseconds);
|
||||
|
||||
typedef void (WINAPI * WakeAllConditionVariableProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
|
||||
typedef void (WINAPI * WakeConditionVariableProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
|
||||
static InitializeConditionVariableProc my_InitializeConditionVariable;
|
||||
static SleepConditionVariableCSProc my_SleepConditionVariableCS;
|
||||
static WakeAllConditionVariableProc my_WakeAllConditionVariable;
|
||||
static WakeConditionVariableProc my_WakeConditionVariable;
|
||||
|
||||
|
||||
/**
|
||||
Indicates if we have native condition variables,
|
||||
initialized first time pthread_cond_init is called.
|
||||
*/
|
||||
|
||||
static BOOL have_native_conditions= FALSE;
|
||||
|
||||
|
||||
/**
|
||||
Check if native conditions can be used, load function pointers
|
||||
*/
|
||||
|
||||
static void check_native_cond_availability(void)
|
||||
{
|
||||
HMODULE module= GetModuleHandle("kernel32");
|
||||
|
||||
my_InitializeConditionVariable= (InitializeConditionVariableProc)
|
||||
GetProcAddress(module, "InitializeConditionVariable");
|
||||
my_SleepConditionVariableCS= (SleepConditionVariableCSProc)
|
||||
GetProcAddress(module, "SleepConditionVariableCS");
|
||||
my_WakeAllConditionVariable= (WakeAllConditionVariableProc)
|
||||
GetProcAddress(module, "WakeAllConditionVariable");
|
||||
my_WakeConditionVariable= (WakeConditionVariableProc)
|
||||
GetProcAddress(module, "WakeConditionVariable");
|
||||
|
||||
if (my_InitializeConditionVariable)
|
||||
have_native_conditions= TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Convert abstime to milliseconds
|
||||
*/
|
||||
|
||||
static DWORD get_milliseconds(const struct timespec *abstime)
|
||||
{
|
||||
struct timespec current_time;
|
||||
long long ms;
|
||||
|
||||
if (abstime == NULL)
|
||||
return INFINITE;
|
||||
|
||||
set_timespec_nsec(current_time, 0);
|
||||
ms= (abstime->tv_sec - current_time.tv_sec)*1000LL +
|
||||
(abstime->tv_nsec - current_time.tv_nsec)/1000000LL;
|
||||
if(ms < 0 )
|
||||
ms= 0;
|
||||
if(ms > UINT_MAX)
|
||||
ms= INFINITE;
|
||||
return (DWORD)ms;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Old (pre-vista) implementation using events
|
||||
*/
|
||||
|
||||
static int legacy_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
|
||||
{
|
||||
cond->waiting= 0;
|
||||
InitializeCriticalSection(&cond->lock_waiting);
|
||||
@ -55,7 +140,8 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
|
||||
static int legacy_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
DeleteCriticalSection(&cond->lock_waiting);
|
||||
|
||||
@ -67,13 +153,7 @@ int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
{
|
||||
return pthread_cond_timedwait(cond,mutex,NULL);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
static int legacy_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
struct timespec *abstime)
|
||||
{
|
||||
int result;
|
||||
@ -135,7 +215,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
|
||||
}
|
||||
|
||||
int pthread_cond_signal(pthread_cond_t *cond)
|
||||
static int legacy_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
EnterCriticalSection(&cond->lock_waiting);
|
||||
|
||||
@ -148,7 +228,7 @@ int pthread_cond_signal(pthread_cond_t *cond)
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
static int legacy_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
EnterCriticalSection(&cond->lock_waiting);
|
||||
/*
|
||||
@ -170,6 +250,87 @@ int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Posix API functions. Just choose between native and legacy implementation.
|
||||
*/
|
||||
|
||||
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
|
||||
{
|
||||
/*
|
||||
Once initialization is used here rather than in my_init(), to
|
||||
1) avoid my_init() pitfalls- undefined order in which initialization should
|
||||
run
|
||||
2) be potentially useful C++ (in static constructors that run before main())
|
||||
3) just to simplify the API.
|
||||
Also, the overhead of my_pthread_once is very small.
|
||||
*/
|
||||
static my_pthread_once_t once_control= MY_PTHREAD_ONCE_INIT;
|
||||
my_pthread_once(&once_control, check_native_cond_availability);
|
||||
|
||||
if (have_native_conditions)
|
||||
{
|
||||
my_InitializeConditionVariable(&cond->native_cond);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return legacy_cond_init(cond, attr);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
if (have_native_conditions)
|
||||
return 0; /* no destroy function */
|
||||
else
|
||||
return legacy_cond_destroy(cond);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
if (have_native_conditions)
|
||||
{
|
||||
my_WakeAllConditionVariable(&cond->native_cond);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return legacy_cond_broadcast(cond);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
if (have_native_conditions)
|
||||
{
|
||||
my_WakeConditionVariable(&cond->native_cond);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return legacy_cond_signal(cond);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
struct timespec *abstime)
|
||||
{
|
||||
if (have_native_conditions)
|
||||
{
|
||||
DWORD timeout= get_milliseconds(abstime);
|
||||
if (!my_SleepConditionVariableCS(&cond->native_cond, mutex, timeout))
|
||||
return ETIMEDOUT;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return legacy_cond_timedwait(cond, mutex, abstime);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
{
|
||||
return pthread_cond_timedwait(cond, mutex, NULL);
|
||||
}
|
||||
|
||||
|
||||
int pthread_attr_init(pthread_attr_t *connect_att)
|
||||
{
|
||||
connect_att->dwStackSize = 0;
|
||||
|
123
mysys/my_winerr.c
Normal file
123
mysys/my_winerr.c
Normal file
@ -0,0 +1,123 @@
|
||||
/* Copyright (C) 2008 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 */
|
||||
|
||||
/*
|
||||
Convert Windows API error (GetLastError() to Posix equivalent (errno)
|
||||
The exported function my_osmaperr() is modelled after and borrows
|
||||
heavily from undocumented _dosmaperr()(found of the static Microsoft C runtime).
|
||||
*/
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
|
||||
|
||||
struct errentry
|
||||
{
|
||||
unsigned long oscode; /* OS return value */
|
||||
int sysv_errno; /* System V error code */
|
||||
};
|
||||
|
||||
static struct errentry errtable[]= {
|
||||
{ ERROR_INVALID_FUNCTION, EINVAL }, /* 1 */
|
||||
{ ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 */
|
||||
{ ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 */
|
||||
{ ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 */
|
||||
{ ERROR_ACCESS_DENIED, EACCES }, /* 5 */
|
||||
{ ERROR_INVALID_HANDLE, EBADF }, /* 6 */
|
||||
{ ERROR_ARENA_TRASHED, ENOMEM }, /* 7 */
|
||||
{ ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 */
|
||||
{ ERROR_INVALID_BLOCK, ENOMEM }, /* 9 */
|
||||
{ ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 */
|
||||
{ ERROR_BAD_FORMAT, ENOEXEC }, /* 11 */
|
||||
{ ERROR_INVALID_ACCESS, EINVAL }, /* 12 */
|
||||
{ ERROR_INVALID_DATA, EINVAL }, /* 13 */
|
||||
{ ERROR_INVALID_DRIVE, ENOENT }, /* 15 */
|
||||
{ ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */
|
||||
{ ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */
|
||||
{ ERROR_NO_MORE_FILES, ENOENT }, /* 18 */
|
||||
{ ERROR_LOCK_VIOLATION, EACCES }, /* 33 */
|
||||
{ ERROR_BAD_NETPATH, ENOENT }, /* 53 */
|
||||
{ ERROR_NETWORK_ACCESS_DENIED, EACCES }, /* 65 */
|
||||
{ ERROR_BAD_NET_NAME, ENOENT }, /* 67 */
|
||||
{ ERROR_FILE_EXISTS, EEXIST }, /* 80 */
|
||||
{ ERROR_CANNOT_MAKE, EACCES }, /* 82 */
|
||||
{ ERROR_FAIL_I24, EACCES }, /* 83 */
|
||||
{ ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */
|
||||
{ ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */
|
||||
{ ERROR_DRIVE_LOCKED, EACCES }, /* 108 */
|
||||
{ ERROR_BROKEN_PIPE, EPIPE }, /* 109 */
|
||||
{ ERROR_DISK_FULL, ENOSPC }, /* 112 */
|
||||
{ ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */
|
||||
{ ERROR_INVALID_HANDLE, EINVAL }, /* 124 */
|
||||
{ ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */
|
||||
{ ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */
|
||||
{ ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */
|
||||
{ ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */
|
||||
{ ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */
|
||||
{ ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */
|
||||
{ ERROR_NOT_LOCKED, EACCES }, /* 158 */
|
||||
{ ERROR_BAD_PATHNAME, ENOENT }, /* 161 */
|
||||
{ ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */
|
||||
{ ERROR_LOCK_FAILED, EACCES }, /* 167 */
|
||||
{ ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */
|
||||
{ ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */
|
||||
{ ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */
|
||||
{ ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */
|
||||
};
|
||||
|
||||
/* size of the table */
|
||||
#define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0]))
|
||||
|
||||
/* The following two constants must be the minimum and maximum
|
||||
values in the (contiguous) range of Exec Failure errors. */
|
||||
#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
|
||||
#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
|
||||
|
||||
/* These are the low and high value in the range of errors that are
|
||||
access violations */
|
||||
#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
|
||||
#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
|
||||
|
||||
|
||||
static int get_errno_from_oserr(unsigned long oserrno)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* check the table for the OS error code */
|
||||
for (i= 0; i < ERRTABLESIZE; ++i)
|
||||
{
|
||||
if (oserrno == errtable[i].oscode)
|
||||
{
|
||||
return errtable[i].sysv_errno;
|
||||
}
|
||||
}
|
||||
|
||||
/* The error code wasn't in the table. We check for a range of */
|
||||
/* EACCES errors or exec failure errors (ENOEXEC). Otherwise */
|
||||
/* EINVAL is returned. */
|
||||
|
||||
if (oserrno >= MIN_EACCES_RANGE && oserrno <= MAX_EACCES_RANGE)
|
||||
return EACCES;
|
||||
else if (oserrno >= MIN_EXEC_ERROR && oserrno <= MAX_EXEC_ERROR)
|
||||
return ENOEXEC;
|
||||
else
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Set errno corresponsing to GetLastError() value */
|
||||
void my_osmaperr ( unsigned long oserrno)
|
||||
{
|
||||
errno= get_errno_from_oserr(oserrno);
|
||||
}
|
681
mysys/my_winfile.c
Normal file
681
mysys/my_winfile.c
Normal file
@ -0,0 +1,681 @@
|
||||
/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
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 */
|
||||
|
||||
/*
|
||||
The purpose of this file is to provide implementation of file IO routines on
|
||||
Windows that can be thought as drop-in replacement for corresponding C runtime
|
||||
functionality.
|
||||
|
||||
Compared to Windows CRT, this one
|
||||
- does not have the same file descriptor
|
||||
limitation (default is 16384 and can be increased further, whereas CRT poses
|
||||
a hard limit of 2048 file descriptors)
|
||||
- the file operations are not serialized
|
||||
- positional IO pread/pwrite is ported here.
|
||||
- no text mode for files, all IO is "binary"
|
||||
|
||||
Naming convention:
|
||||
All routines are prefixed with my_win_, e.g Posix open() is implemented with
|
||||
my_win_open()
|
||||
|
||||
Implemented are
|
||||
- POSIX routines(e.g open, read, lseek ...)
|
||||
- Some ANSI C stream routines (fopen, fdopen, fileno, fclose)
|
||||
- Windows CRT equvalients (my_get_osfhandle, open_osfhandle)
|
||||
|
||||
Worth to note:
|
||||
- File descriptors used here are located in a range that is not compatible
|
||||
with CRT on purpose. Attempt to use a file descriptor from Windows CRT library
|
||||
range in my_win_* function will be punished with DBUG_ASSERT()
|
||||
|
||||
- File streams (FILE *) are actually from the C runtime. The routines provided
|
||||
here are useful only in scernarios that use low-level IO with my_win_fileno()
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <share.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* Associates a file descriptor with an existing operating-system file handle.*/
|
||||
File my_open_osfhandle(HANDLE handle, int oflag)
|
||||
{
|
||||
int offset= -1;
|
||||
uint i;
|
||||
DBUG_ENTER("my_open_osfhandle");
|
||||
|
||||
pthread_mutex_lock(&THR_LOCK_open);
|
||||
for(i= MY_FILE_MIN; i < my_file_limit;i++)
|
||||
{
|
||||
if(my_file_info[i].fhandle == 0)
|
||||
{
|
||||
struct st_my_file_info *finfo= &(my_file_info[i]);
|
||||
finfo->type= FILE_BY_OPEN;
|
||||
finfo->fhandle= handle;
|
||||
finfo->oflag= oflag;
|
||||
offset= i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
if(offset == -1)
|
||||
errno= EMFILE; /* to many file handles open */
|
||||
DBUG_RETURN(offset);
|
||||
}
|
||||
|
||||
|
||||
static void invalidate_fd(File fd)
|
||||
{
|
||||
DBUG_ENTER("invalidate_fd");
|
||||
DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
|
||||
my_file_info[fd].fhandle= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/* Get Windows handle for a file descriptor */
|
||||
HANDLE my_get_osfhandle(File fd)
|
||||
{
|
||||
DBUG_ENTER("my_get_osfhandle");
|
||||
DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
|
||||
DBUG_RETURN(my_file_info[fd].fhandle);
|
||||
}
|
||||
|
||||
|
||||
static int my_get_open_flags(File fd)
|
||||
{
|
||||
DBUG_ENTER("my_get_open_flags");
|
||||
DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
|
||||
DBUG_RETURN(my_file_info[fd].oflag);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open a file with sharing. Similar to _sopen() from libc, but allows managing
|
||||
share delete on win32
|
||||
|
||||
SYNOPSIS
|
||||
my_win_sopen()
|
||||
path file name
|
||||
oflag operation flags
|
||||
shflag share flag
|
||||
pmode permission flags
|
||||
|
||||
RETURN VALUE
|
||||
File descriptor of opened file if success
|
||||
-1 and sets errno if fails.
|
||||
*/
|
||||
|
||||
File my_win_sopen(const char *path, int oflag, int shflag, int pmode)
|
||||
{
|
||||
int fh; /* handle of opened file */
|
||||
int mask;
|
||||
HANDLE osfh; /* OS handle of opened file */
|
||||
DWORD fileaccess; /* OS file access (requested) */
|
||||
DWORD fileshare; /* OS file sharing mode */
|
||||
DWORD filecreate; /* OS method of opening/creating */
|
||||
DWORD fileattrib; /* OS file attribute flags */
|
||||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
|
||||
DBUG_ENTER("my_win_sopen");
|
||||
|
||||
if (check_if_legal_filename(path))
|
||||
{
|
||||
errno= EACCES;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
SecurityAttributes.nLength= sizeof(SecurityAttributes);
|
||||
SecurityAttributes.lpSecurityDescriptor= NULL;
|
||||
SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
|
||||
|
||||
/* decode the access flags */
|
||||
switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
|
||||
case _O_RDONLY: /* read access */
|
||||
fileaccess= GENERIC_READ;
|
||||
break;
|
||||
case _O_WRONLY: /* write access */
|
||||
fileaccess= GENERIC_WRITE;
|
||||
break;
|
||||
case _O_RDWR: /* read and write access */
|
||||
fileaccess= GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
default: /* error, bad oflag */
|
||||
errno= EINVAL;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
/* decode sharing flags */
|
||||
switch (shflag) {
|
||||
case _SH_DENYRW: /* exclusive access except delete */
|
||||
fileshare= FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYWR: /* share read and delete access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYRD: /* share write and delete access */
|
||||
fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYNO: /* share read, write and delete access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYRWD: /* exclusive access */
|
||||
fileshare= 0L;
|
||||
break;
|
||||
case _SH_DENYWRD: /* share read access */
|
||||
fileshare= FILE_SHARE_READ;
|
||||
break;
|
||||
case _SH_DENYRDD: /* share write access */
|
||||
fileshare= FILE_SHARE_WRITE;
|
||||
break;
|
||||
case _SH_DENYDEL: /* share read and write access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
break;
|
||||
default: /* error, bad shflag */
|
||||
errno= EINVAL;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
/* decode open/create method flags */
|
||||
switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
|
||||
case 0:
|
||||
case _O_EXCL: /* ignore EXCL w/o CREAT */
|
||||
filecreate= OPEN_EXISTING;
|
||||
break;
|
||||
|
||||
case _O_CREAT:
|
||||
filecreate= OPEN_ALWAYS;
|
||||
break;
|
||||
|
||||
case _O_CREAT | _O_EXCL:
|
||||
case _O_CREAT | _O_TRUNC | _O_EXCL:
|
||||
filecreate= CREATE_NEW;
|
||||
break;
|
||||
|
||||
case _O_TRUNC:
|
||||
case _O_TRUNC | _O_EXCL: /* ignore EXCL w/o CREAT */
|
||||
filecreate= TRUNCATE_EXISTING;
|
||||
break;
|
||||
|
||||
case _O_CREAT | _O_TRUNC:
|
||||
filecreate= CREATE_ALWAYS;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* this can't happen ... all cases are covered */
|
||||
errno= EINVAL;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
/* decode file attribute flags if _O_CREAT was specified */
|
||||
fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */
|
||||
if (oflag & _O_CREAT)
|
||||
{
|
||||
_umask((mask= _umask(0)));
|
||||
|
||||
if (!((pmode & ~mask) & _S_IWRITE))
|
||||
fileattrib= FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
/* Set temporary file (delete-on-close) attribute if requested. */
|
||||
if (oflag & _O_TEMPORARY)
|
||||
{
|
||||
fileattrib|= FILE_FLAG_DELETE_ON_CLOSE;
|
||||
fileaccess|= DELETE;
|
||||
}
|
||||
|
||||
/* Set temporary file (delay-flush-to-disk) attribute if requested.*/
|
||||
if (oflag & _O_SHORT_LIVED)
|
||||
fileattrib|= FILE_ATTRIBUTE_TEMPORARY;
|
||||
|
||||
/* Set sequential or random access attribute if requested. */
|
||||
if (oflag & _O_SEQUENTIAL)
|
||||
fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN;
|
||||
else if (oflag & _O_RANDOM)
|
||||
fileattrib|= FILE_FLAG_RANDOM_ACCESS;
|
||||
|
||||
/* try to open/create the file */
|
||||
if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
|
||||
filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/*
|
||||
OS call to open/create file failed! map the error, release
|
||||
the lock, and return -1. note that it's not necessary to
|
||||
call _free_osfhnd (it hasn't been used yet).
|
||||
*/
|
||||
my_osmaperr(GetLastError()); /* map error */
|
||||
DBUG_RETURN(-1); /* return error to caller */
|
||||
}
|
||||
|
||||
if ((fh= my_open_osfhandle(osfh,
|
||||
oflag & (_O_APPEND | _O_RDONLY | _O_TEXT))) == -1)
|
||||
{
|
||||
CloseHandle(osfh);
|
||||
}
|
||||
|
||||
DBUG_RETURN(fh); /* return handle */
|
||||
}
|
||||
|
||||
|
||||
File my_win_open(const char *path, int flags)
|
||||
{
|
||||
DBUG_ENTER("my_win_open");
|
||||
DBUG_RETURN(my_win_sopen((char *) path, flags | _O_BINARY, _SH_DENYNO,
|
||||
_S_IREAD | S_IWRITE));
|
||||
}
|
||||
|
||||
|
||||
int my_win_close(File fd)
|
||||
{
|
||||
DBUG_ENTER("my_win_close");
|
||||
if(CloseHandle(my_get_osfhandle(fd)))
|
||||
{
|
||||
invalidate_fd(fd);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
size_t my_win_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset)
|
||||
{
|
||||
DWORD nBytesRead;
|
||||
HANDLE hFile;
|
||||
OVERLAPPED ov= {0};
|
||||
LARGE_INTEGER li;
|
||||
|
||||
DBUG_ENTER("my_win_pread");
|
||||
|
||||
if(!Count)
|
||||
DBUG_RETURN(0);
|
||||
#ifdef _WIN64
|
||||
if(Count > UINT_MAX)
|
||||
Count= UINT_MAX;
|
||||
#endif
|
||||
|
||||
hFile= (HANDLE)my_get_osfhandle(Filedes);
|
||||
li.QuadPart= offset;
|
||||
ov.Offset= li.LowPart;
|
||||
ov.OffsetHigh= li.HighPart;
|
||||
|
||||
if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, &ov))
|
||||
{
|
||||
DWORD lastError= GetLastError();
|
||||
/*
|
||||
ERROR_BROKEN_PIPE is returned when no more data coming
|
||||
through e.g. a command pipe in windows : see MSDN on ReadFile.
|
||||
*/
|
||||
if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE)
|
||||
DBUG_RETURN(0); /*return 0 at EOF*/
|
||||
my_osmaperr(lastError);
|
||||
DBUG_RETURN((size_t)-1);
|
||||
}
|
||||
DBUG_RETURN(nBytesRead);
|
||||
}
|
||||
|
||||
|
||||
size_t my_win_read(File Filedes, uchar *Buffer, size_t Count)
|
||||
{
|
||||
DWORD nBytesRead;
|
||||
HANDLE hFile;
|
||||
|
||||
DBUG_ENTER("my_win_read");
|
||||
if(!Count)
|
||||
DBUG_RETURN(0);
|
||||
#ifdef _WIN64
|
||||
if(Count > UINT_MAX)
|
||||
Count= UINT_MAX;
|
||||
#endif
|
||||
|
||||
hFile= (HANDLE)my_get_osfhandle(Filedes);
|
||||
|
||||
if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, NULL))
|
||||
{
|
||||
DWORD lastError= GetLastError();
|
||||
/*
|
||||
ERROR_BROKEN_PIPE is returned when no more data coming
|
||||
through e.g. a command pipe in windows : see MSDN on ReadFile.
|
||||
*/
|
||||
if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE)
|
||||
DBUG_RETURN(0); /*return 0 at EOF*/
|
||||
my_osmaperr(lastError);
|
||||
DBUG_RETURN((size_t)-1);
|
||||
}
|
||||
DBUG_RETURN(nBytesRead);
|
||||
}
|
||||
|
||||
|
||||
size_t my_win_pwrite(File Filedes, const uchar *Buffer, size_t Count,
|
||||
my_off_t offset)
|
||||
{
|
||||
DWORD nBytesWritten;
|
||||
HANDLE hFile;
|
||||
OVERLAPPED ov= {0};
|
||||
LARGE_INTEGER li;
|
||||
|
||||
DBUG_ENTER("my_win_pwrite");
|
||||
DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count: %llu, offset: %llu",
|
||||
Filedes, Buffer, (ulonglong)Count, (ulonglong)offset));
|
||||
|
||||
if(!Count)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
#ifdef _WIN64
|
||||
if(Count > UINT_MAX)
|
||||
Count= UINT_MAX;
|
||||
#endif
|
||||
|
||||
hFile= (HANDLE)my_get_osfhandle(Filedes);
|
||||
li.QuadPart= offset;
|
||||
ov.Offset= li.LowPart;
|
||||
ov.OffsetHigh= li.HighPart;
|
||||
|
||||
if(!WriteFile(hFile, Buffer, (DWORD)Count, &nBytesWritten, &ov))
|
||||
{
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN((size_t)-1);
|
||||
}
|
||||
else
|
||||
DBUG_RETURN(nBytesWritten);
|
||||
}
|
||||
|
||||
|
||||
my_off_t my_win_lseek(File fd, my_off_t pos, int whence)
|
||||
{
|
||||
LARGE_INTEGER offset;
|
||||
LARGE_INTEGER newpos;
|
||||
|
||||
DBUG_ENTER("my_win_lseek");
|
||||
|
||||
/* Check compatibility of Windows and Posix seek constants */
|
||||
compile_time_assert(FILE_BEGIN == SEEK_SET && FILE_CURRENT == SEEK_CUR
|
||||
&& FILE_END == SEEK_END);
|
||||
|
||||
offset.QuadPart= pos;
|
||||
if(!SetFilePointerEx(my_get_osfhandle(fd), offset, &newpos, whence))
|
||||
{
|
||||
my_osmaperr(GetLastError());
|
||||
newpos.QuadPart= -1;
|
||||
}
|
||||
DBUG_RETURN(newpos.QuadPart);
|
||||
}
|
||||
|
||||
|
||||
#ifndef FILE_WRITE_TO_END_OF_FILE
|
||||
#define FILE_WRITE_TO_END_OF_FILE 0xffffffff
|
||||
#endif
|
||||
size_t my_win_write(File fd, const uchar *Buffer, size_t Count)
|
||||
{
|
||||
DWORD nWritten;
|
||||
OVERLAPPED ov;
|
||||
OVERLAPPED *pov= NULL;
|
||||
HANDLE hFile;
|
||||
|
||||
DBUG_ENTER("my_win_write");
|
||||
DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count %llu", fd, Buffer,
|
||||
(ulonglong)Count));
|
||||
|
||||
if(!Count)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
#ifdef _WIN64
|
||||
if(Count > UINT_MAX)
|
||||
Count= UINT_MAX;
|
||||
#endif
|
||||
|
||||
if(my_get_open_flags(fd) & _O_APPEND)
|
||||
{
|
||||
/*
|
||||
Atomic append to the end of file is is done by special initialization of
|
||||
the OVERLAPPED structure. See MSDN WriteFile documentation for more info.
|
||||
*/
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
ov.Offset= FILE_WRITE_TO_END_OF_FILE;
|
||||
ov.OffsetHigh= -1;
|
||||
pov= &ov;
|
||||
}
|
||||
|
||||
hFile= my_get_osfhandle(fd);
|
||||
if(!WriteFile(hFile, Buffer, (DWORD)Count, &nWritten, pov))
|
||||
{
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN((size_t)-1);
|
||||
}
|
||||
DBUG_RETURN(nWritten);
|
||||
}
|
||||
|
||||
|
||||
int my_win_chsize(File fd, my_off_t newlength)
|
||||
{
|
||||
HANDLE hFile;
|
||||
LARGE_INTEGER length;
|
||||
DBUG_ENTER("my_win_chsize");
|
||||
|
||||
hFile= (HANDLE) my_get_osfhandle(fd);
|
||||
length.QuadPart= newlength;
|
||||
if (!SetFilePointerEx(hFile, length , NULL , FILE_BEGIN))
|
||||
goto err;
|
||||
if (!SetEndOfFile(hFile))
|
||||
goto err;
|
||||
DBUG_RETURN(0);
|
||||
err:
|
||||
my_osmaperr(GetLastError());
|
||||
my_errno= errno;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
/* Get the file descriptor for stdin,stdout or stderr */
|
||||
static File my_get_stdfile_descriptor(FILE *stream)
|
||||
{
|
||||
HANDLE hFile;
|
||||
DWORD nStdHandle;
|
||||
DBUG_ENTER("my_get_stdfile_descriptor");
|
||||
|
||||
if(stream == stdin)
|
||||
nStdHandle= STD_INPUT_HANDLE;
|
||||
else if(stream == stdout)
|
||||
nStdHandle= STD_OUTPUT_HANDLE;
|
||||
else if(stream == stderr)
|
||||
nStdHandle= STD_ERROR_HANDLE;
|
||||
else
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
hFile= GetStdHandle(nStdHandle);
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
DBUG_RETURN(my_open_osfhandle(hFile, 0));
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
File my_win_fileno(FILE *file)
|
||||
{
|
||||
HANDLE hFile= (HANDLE)_get_osfhandle(fileno(file));
|
||||
int retval= -1;
|
||||
uint i;
|
||||
|
||||
DBUG_ENTER("my_win_fileno");
|
||||
|
||||
for(i= MY_FILE_MIN; i < my_file_limit; i++)
|
||||
{
|
||||
if(my_file_info[i].fhandle == hFile)
|
||||
{
|
||||
retval= i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(retval == -1)
|
||||
/* try std stream */
|
||||
DBUG_RETURN(my_get_stdfile_descriptor(file));
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
|
||||
|
||||
FILE *my_win_fopen(const char *filename, const char *type)
|
||||
{
|
||||
FILE *file;
|
||||
int flags= 0;
|
||||
DBUG_ENTER("my_win_open");
|
||||
|
||||
/*
|
||||
If we are not creating, then we need to use my_access to make sure
|
||||
the file exists since Windows doesn't handle files like "com1.sym"
|
||||
very well
|
||||
*/
|
||||
if (check_if_legal_filename(filename))
|
||||
{
|
||||
errno= EACCES;
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
file= fopen(filename, type);
|
||||
if(!file)
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
if(strchr(type,'a') != NULL)
|
||||
flags= O_APPEND;
|
||||
|
||||
/*
|
||||
Register file handle in my_table_info.
|
||||
Necessary for my_fileno()
|
||||
*/
|
||||
if(my_open_osfhandle((HANDLE)_get_osfhandle(fileno(file)), flags) < 0)
|
||||
{
|
||||
fclose(file);
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
DBUG_RETURN(file);
|
||||
}
|
||||
|
||||
|
||||
FILE * my_win_fdopen(File fd, const char *type)
|
||||
{
|
||||
FILE *file;
|
||||
int crt_fd;
|
||||
int flags= 0;
|
||||
|
||||
DBUG_ENTER("my_win_fdopen");
|
||||
|
||||
if(strchr(type,'a') != NULL)
|
||||
flags= O_APPEND;
|
||||
/* Convert OS file handle to CRT file descriptor and then call fdopen*/
|
||||
crt_fd= _open_osfhandle((intptr_t)my_get_osfhandle(fd), flags);
|
||||
if(crt_fd < 0)
|
||||
file= NULL;
|
||||
else
|
||||
file= fdopen(crt_fd, type);
|
||||
DBUG_RETURN(file);
|
||||
}
|
||||
|
||||
|
||||
int my_win_fclose(FILE *file)
|
||||
{
|
||||
File fd;
|
||||
|
||||
DBUG_ENTER("my_win_close");
|
||||
fd= my_fileno(file);
|
||||
if(fd < 0)
|
||||
DBUG_RETURN(-1);
|
||||
if(fclose(file) < 0)
|
||||
DBUG_RETURN(-1);
|
||||
invalidate_fd(fd);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Quick and dirty my_fstat() implementation for Windows.
|
||||
Use CRT fstat on temporarily allocated file descriptor.
|
||||
Patch file size, because size that fstat returns is not
|
||||
reliable (may be outdated)
|
||||
*/
|
||||
int my_win_fstat(File fd, struct _stati64 *buf)
|
||||
{
|
||||
int crt_fd;
|
||||
int retval;
|
||||
HANDLE hFile, hDup;
|
||||
|
||||
DBUG_ENTER("my_win_fstat");
|
||||
|
||||
hFile= my_get_osfhandle(fd);
|
||||
if(!DuplicateHandle( GetCurrentProcess(), hFile, GetCurrentProcess(),
|
||||
&hDup ,0,FALSE,DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if ((crt_fd= _open_osfhandle((intptr_t)hDup,0)) < 0)
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
retval= _fstati64(crt_fd, buf);
|
||||
if(retval == 0)
|
||||
{
|
||||
/* File size returned by stat is not accurate (may be outdated), fix it*/
|
||||
GetFileSizeEx(hDup, (PLARGE_INTEGER) (&(buf->st_size)));
|
||||
}
|
||||
_close(crt_fd);
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int my_win_stat( const char *path, struct _stati64 *buf)
|
||||
{
|
||||
DBUG_ENTER("my_win_stat");
|
||||
if(_stati64( path, buf) == 0)
|
||||
{
|
||||
/* File size returned by stat is not accurate (may be outdated), fix it*/
|
||||
WIN32_FILE_ATTRIBUTE_DATA data;
|
||||
if (GetFileAttributesEx(path, GetFileExInfoStandard, &data))
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
li.LowPart= data.nFileSizeLow;
|
||||
li.HighPart= data.nFileSizeHigh;
|
||||
buf->st_size= li.QuadPart;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int my_win_fsync(File fd)
|
||||
{
|
||||
DBUG_ENTER("my_win_fsync");
|
||||
if(FlushFileBuffers(my_get_osfhandle(fd)))
|
||||
DBUG_RETURN(0);
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int my_win_dup(File fd)
|
||||
{
|
||||
HANDLE hDup;
|
||||
DBUG_ENTER("my_win_dup");
|
||||
if (DuplicateHandle(GetCurrentProcess(), my_get_osfhandle(fd),
|
||||
GetCurrentProcess(), &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
DBUG_RETURN(my_open_osfhandle(hDup, my_get_open_flags(fd)));
|
||||
}
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
#endif /*_WIN32*/
|
@ -156,8 +156,19 @@ int win_pthread_setspecific(void *a,void *b,uint length)
|
||||
int my_pthread_once(my_pthread_once_t *once_control,
|
||||
void (*init_routine)(void))
|
||||
{
|
||||
LONG state= InterlockedCompareExchange(once_control, MY_PTHREAD_ONCE_INPROGRESS,
|
||||
MY_PTHREAD_ONCE_INIT);
|
||||
LONG state;
|
||||
|
||||
/*
|
||||
Do "dirty" read to find out if initialization is already done, to
|
||||
save an interlocked operation in common case. Memory barriers are ensured by
|
||||
Visual C++ volatile implementation.
|
||||
*/
|
||||
if (*once_control == MY_PTHREAD_ONCE_DONE)
|
||||
return 0;
|
||||
|
||||
state= InterlockedCompareExchange(once_control, MY_PTHREAD_ONCE_INPROGRESS,
|
||||
MY_PTHREAD_ONCE_INIT);
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case MY_PTHREAD_ONCE_INIT:
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
{
|
||||
size_t writenbytes, written;
|
||||
size_t writtenbytes, written;
|
||||
uint errors;
|
||||
DBUG_ENTER("my_write");
|
||||
DBUG_PRINT("my",("fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
|
||||
@ -35,17 +35,27 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if ((writenbytes= write(Filedes, Buffer, Count)) == Count)
|
||||
break;
|
||||
if (writenbytes != (size_t) -1)
|
||||
{ /* Safeguard */
|
||||
written+=writenbytes;
|
||||
Buffer+=writenbytes;
|
||||
Count-=writenbytes;
|
||||
#ifdef _WIN32
|
||||
if(Filedes < 0)
|
||||
{
|
||||
my_errno= errno= EBADF;
|
||||
DBUG_RETURN((size_t)-1);
|
||||
}
|
||||
my_errno=errno;
|
||||
writtenbytes= my_win_write(Filedes, Buffer, Count);
|
||||
#else
|
||||
writtenbytes= write(Filedes, Buffer, Count);
|
||||
#endif
|
||||
if (writtenbytes == Count)
|
||||
break;
|
||||
if (writtenbytes != (size_t) -1)
|
||||
{ /* Safeguard */
|
||||
written+= writtenbytes;
|
||||
Buffer+= writtenbytes;
|
||||
Count-= writtenbytes;
|
||||
}
|
||||
my_errno= errno;
|
||||
DBUG_PRINT("error",("Write only %ld bytes, error: %d",
|
||||
(long) writenbytes, my_errno));
|
||||
(long) writtenbytes, my_errno));
|
||||
#ifndef NO_BACKGROUND
|
||||
#ifdef THREAD
|
||||
if (my_thread_var->abort)
|
||||
@ -59,19 +69,19 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((writenbytes == 0 || writenbytes == (size_t) -1))
|
||||
if ((writtenbytes == 0 || writtenbytes == (size_t) -1))
|
||||
{
|
||||
if (my_errno == EINTR)
|
||||
{
|
||||
DBUG_PRINT("debug", ("my_write() was interrupted and returned %ld",
|
||||
(long) writenbytes));
|
||||
(long) writtenbytes));
|
||||
continue; /* Interrupted */
|
||||
}
|
||||
|
||||
if (!writenbytes && !errors++) /* Retry once */
|
||||
if (!writtenbytes && !errors++) /* Retry once */
|
||||
{
|
||||
/* We may come here if the file quota is exeeded */
|
||||
errno=EFBIG; /* Assume this is the error */
|
||||
errno= EFBIG; /* Assume this is the error */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -92,5 +102,5 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
}
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
DBUG_RETURN(0); /* Want only errors */
|
||||
DBUG_RETURN(writenbytes+written);
|
||||
DBUG_RETURN(writtenbytes+written);
|
||||
} /* my_write */
|
||||
|
@ -45,3 +45,27 @@ extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time;
|
||||
void my_error_unregister_all(void);
|
||||
void my_thread_destroy_mutex(void);
|
||||
my_bool my_wait_for_other_threads_to_die(uint number_of_threads);
|
||||
|
||||
#ifdef _WIN32
|
||||
/* my_winfile.c exports, should not be used outside mysys */
|
||||
extern File my_win_open(const char *path, int oflag);
|
||||
extern int my_win_close(File fd);
|
||||
extern size_t my_win_read(File fd, uchar *buffer, size_t count);
|
||||
extern size_t my_win_write(File fd, const uchar *buffer, size_t count);
|
||||
extern size_t my_win_pread(File fd, uchar *buffer, size_t count,
|
||||
my_off_t offset);
|
||||
extern size_t my_win_pwrite(File fd, const uchar *buffer, size_t count,
|
||||
my_off_t offset);
|
||||
extern my_off_t my_win_lseek(File fd, my_off_t pos, int whence);
|
||||
extern int my_win_chsize(File fd, my_off_t newlength);
|
||||
extern FILE* my_win_fopen(const char *filename, const char *type);
|
||||
extern File my_win_fclose(FILE *file);
|
||||
extern File my_win_fileno(FILE *file);
|
||||
extern FILE* my_win_fdopen(File Filedes, const char *type);
|
||||
extern int my_win_stat(const char *path, struct _stat64 *buf);
|
||||
extern int my_win_fstat(File fd, struct _stat64 *buf);
|
||||
extern int my_win_fsync(File fd);
|
||||
extern File my_win_dup(File fd);
|
||||
extern File my_win_sopen(const char *path, int oflag, int shflag, int perm);
|
||||
extern File my_open_osfhandle(HANDLE handle, int oflag);
|
||||
#endif
|
||||
|
@ -19,6 +19,119 @@
|
||||
#if defined(THREAD) && !defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && !defined(HAVE_RWLOCK_INIT)
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static BOOL have_srwlock= FALSE;
|
||||
/* Prototypes and function pointers for windows functions */
|
||||
typedef VOID (WINAPI* srw_func) (PSRWLOCK SRWLock);
|
||||
typedef BOOL (WINAPI* srw_bool_func) (PSRWLOCK SRWLock);
|
||||
|
||||
static srw_func my_InitializeSRWLock;
|
||||
static srw_func my_AcquireSRWLockExclusive;
|
||||
static srw_func my_ReleaseSRWLockExclusive;
|
||||
static srw_func my_AcquireSRWLockShared;
|
||||
static srw_func my_ReleaseSRWLockShared;
|
||||
|
||||
static srw_bool_func my_TryAcquireSRWLockExclusive;
|
||||
static srw_bool_func my_TryAcquireSRWLockShared;
|
||||
|
||||
/**
|
||||
Check for presence of Windows slim reader writer lock function.
|
||||
Load function pointers.
|
||||
*/
|
||||
|
||||
static void check_srwlock_availability(void)
|
||||
{
|
||||
HMODULE module= GetModuleHandle("kernel32");
|
||||
|
||||
my_InitializeSRWLock= (srw_func) GetProcAddress(module,
|
||||
"InitializeSRWLock");
|
||||
my_AcquireSRWLockExclusive= (srw_func) GetProcAddress(module,
|
||||
"AcquireSRWLockExclusive");
|
||||
my_AcquireSRWLockShared= (srw_func) GetProcAddress(module,
|
||||
"AcquireSRWLockShared");
|
||||
my_ReleaseSRWLockExclusive= (srw_func) GetProcAddress(module,
|
||||
"ReleaseSRWLockExclusive");
|
||||
my_ReleaseSRWLockShared= (srw_func) GetProcAddress(module,
|
||||
"ReleaseSRWLockShared");
|
||||
my_TryAcquireSRWLockExclusive= (srw_bool_func) GetProcAddress(module,
|
||||
"TryAcquireSRWLockExclusive");
|
||||
my_TryAcquireSRWLockShared= (srw_bool_func) GetProcAddress(module,
|
||||
"TryAcquireSRWLockShared");
|
||||
|
||||
/*
|
||||
We currently require TryAcquireSRWLockExclusive. This API is missing on
|
||||
Vista, this means SRWLock are only used starting with Win7.
|
||||
|
||||
If "trylock" usage for rwlocks is eliminated from server codebase (it is used
|
||||
in a single place currently, in query cache), then SRWLock can be enabled on
|
||||
Vista too. In this case condition below needs to be changed to e.g check
|
||||
for my_InitializeSRWLock.
|
||||
*/
|
||||
|
||||
if (my_TryAcquireSRWLockExclusive)
|
||||
have_srwlock= TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int srw_init(my_rw_lock_t *rwp)
|
||||
{
|
||||
my_InitializeSRWLock(&rwp->srwlock);
|
||||
rwp->have_exclusive_srwlock = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int srw_rdlock(my_rw_lock_t *rwp)
|
||||
{
|
||||
my_AcquireSRWLockShared(&rwp->srwlock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int srw_tryrdlock(my_rw_lock_t *rwp)
|
||||
{
|
||||
|
||||
if (!my_TryAcquireSRWLockShared(&rwp->srwlock))
|
||||
return EBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int srw_wrlock(my_rw_lock_t *rwp)
|
||||
{
|
||||
my_AcquireSRWLockExclusive(&rwp->srwlock);
|
||||
rwp->have_exclusive_srwlock= TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int srw_trywrlock(my_rw_lock_t *rwp)
|
||||
{
|
||||
if (!my_TryAcquireSRWLockExclusive(&rwp->srwlock))
|
||||
return EBUSY;
|
||||
rwp->have_exclusive_srwlock= TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int srw_unlock(my_rw_lock_t *rwp)
|
||||
{
|
||||
if (rwp->have_exclusive_srwlock)
|
||||
{
|
||||
rwp->have_exclusive_srwlock= FALSE;
|
||||
my_ReleaseSRWLockExclusive(&rwp->srwlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
my_ReleaseSRWLockShared(&rwp->srwlock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /*_WIN32 */
|
||||
|
||||
/*
|
||||
Source base from Sun Microsystems SPILT, simplified for MySQL use
|
||||
-- Joshua Chamas
|
||||
@ -62,6 +175,22 @@ int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused)))
|
||||
{
|
||||
pthread_condattr_t cond_attr;
|
||||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
Once initialization is used here rather than in my_init(), in order to
|
||||
- avoid my_init() pitfalls- (undefined order in which initialization should
|
||||
run)
|
||||
- be potentially useful C++ (static constructors)
|
||||
- just to simplify the API.
|
||||
Also, the overhead is of my_pthread_once is very small.
|
||||
*/
|
||||
static my_pthread_once_t once_control= MY_PTHREAD_ONCE_INIT;
|
||||
my_pthread_once(&once_control, check_srwlock_availability);
|
||||
|
||||
if (have_srwlock)
|
||||
return srw_init(rwp);
|
||||
#endif
|
||||
|
||||
pthread_mutex_init( &rwp->lock, MY_MUTEX_INIT_FAST);
|
||||
pthread_condattr_init( &cond_attr );
|
||||
pthread_cond_init( &rwp->readers, &cond_attr );
|
||||
@ -77,6 +206,10 @@ int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused)))
|
||||
|
||||
int my_rwlock_destroy(rw_lock_t *rwp)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (have_srwlock)
|
||||
return 0; /* no destroy function */
|
||||
#endif
|
||||
pthread_mutex_destroy( &rwp->lock );
|
||||
pthread_cond_destroy( &rwp->readers );
|
||||
pthread_cond_destroy( &rwp->writers );
|
||||
@ -86,6 +219,11 @@ int my_rwlock_destroy(rw_lock_t *rwp)
|
||||
|
||||
int my_rw_rdlock(rw_lock_t *rwp)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (have_srwlock)
|
||||
return srw_rdlock(rwp);
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&rwp->lock);
|
||||
|
||||
/* active or queued writers */
|
||||
@ -100,6 +238,12 @@ int my_rw_rdlock(rw_lock_t *rwp)
|
||||
int my_rw_tryrdlock(rw_lock_t *rwp)
|
||||
{
|
||||
int res;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (have_srwlock)
|
||||
return srw_tryrdlock(rwp);
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&rwp->lock);
|
||||
if ((rwp->state < 0 ) || rwp->waiters)
|
||||
res= EBUSY; /* Can't get lock */
|
||||
@ -115,6 +259,11 @@ int my_rw_tryrdlock(rw_lock_t *rwp)
|
||||
|
||||
int my_rw_wrlock(rw_lock_t *rwp)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (have_srwlock)
|
||||
return srw_wrlock(rwp);
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&rwp->lock);
|
||||
rwp->waiters++; /* another writer queued */
|
||||
|
||||
@ -130,6 +279,12 @@ int my_rw_wrlock(rw_lock_t *rwp)
|
||||
int my_rw_trywrlock(rw_lock_t *rwp)
|
||||
{
|
||||
int res;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (have_srwlock)
|
||||
return srw_trywrlock(rwp);
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&rwp->lock);
|
||||
if (rwp->state)
|
||||
res= EBUSY; /* Can't get lock */
|
||||
@ -145,6 +300,11 @@ int my_rw_trywrlock(rw_lock_t *rwp)
|
||||
|
||||
int my_rw_unlock(rw_lock_t *rwp)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (have_srwlock)
|
||||
return srw_unlock(rwp);
|
||||
#endif
|
||||
|
||||
DBUG_PRINT("rw_unlock",
|
||||
("state: %d waiters: %d", rwp->state, rwp->waiters));
|
||||
pthread_mutex_lock(&rwp->lock);
|
||||
|
@ -67,7 +67,7 @@ int readfrm(const char *name, uchar **frmdata, size_t *len)
|
||||
error= 2;
|
||||
if (my_fstat(file, &state, MYF(0)))
|
||||
goto err;
|
||||
read_len= state.st_size;
|
||||
read_len= (size_t)state.st_size;
|
||||
|
||||
// Read whole frm file
|
||||
error= 3;
|
||||
|
@ -3026,16 +3026,16 @@ String *Item_load_file::val_str(String *str)
|
||||
func_name(), current_thd->variables.max_allowed_packet);
|
||||
goto err;
|
||||
}
|
||||
if (tmp_value.alloc(stat_info.st_size))
|
||||
if (tmp_value.alloc((size_t)stat_info.st_size))
|
||||
goto err;
|
||||
if ((file = my_open(file_name->ptr(), O_RDONLY, MYF(0))) < 0)
|
||||
goto err;
|
||||
if (my_read(file, (uchar*) tmp_value.ptr(), stat_info.st_size, MYF(MY_NABP)))
|
||||
if (my_read(file, (uchar*) tmp_value.ptr(), (size_t)stat_info.st_size, MYF(MY_NABP)))
|
||||
{
|
||||
my_close(file, MYF(0));
|
||||
goto err;
|
||||
}
|
||||
tmp_value.length(stat_info.st_size);
|
||||
tmp_value.length((uint32)stat_info.st_size);
|
||||
my_close(file, MYF(0));
|
||||
null_value = 0;
|
||||
DBUG_RETURN(&tmp_value);
|
||||
|
@ -413,7 +413,6 @@ protected:
|
||||
#define DELAYED_LIMIT 100 /**< pause after xxx inserts */
|
||||
#define DELAYED_QUEUE_SIZE 1000
|
||||
#define DELAYED_WAIT_TIMEOUT 5*60 /**< Wait for delayed insert */
|
||||
#define FLUSH_TIME 0 /**< Don't flush tables */
|
||||
#define MAX_CONNECT_ERRORS 10 ///< errors before disabling host
|
||||
|
||||
#ifdef __NETWARE__
|
||||
@ -423,8 +422,6 @@ protected:
|
||||
#endif
|
||||
|
||||
#if defined(__WIN__)
|
||||
#undef FLUSH_TIME
|
||||
#define FLUSH_TIME 1800 /**< Flush every half hour */
|
||||
|
||||
#define INTERRUPT_PRIOR -2
|
||||
#define CONNECT_PRIOR -1
|
||||
|
@ -7215,7 +7215,7 @@ each time the SQL thread starts.",
|
||||
{ "flush_time", OPT_FLUSH_TIME,
|
||||
"A dedicated thread is created to flush all tables at the given interval.",
|
||||
&flush_time, &flush_time, 0, GET_ULONG, REQUIRED_ARG,
|
||||
FLUSH_TIME, 0, LONG_TIMEOUT, 0, 1, 0},
|
||||
0 , 0, LONG_TIMEOUT, 0, 1, 0},
|
||||
{ "ft_boolean_syntax", OPT_FT_BOOLEAN_SYNTAX,
|
||||
"List of operators for MATCH ... AGAINST ( ... IN BOOLEAN MODE).",
|
||||
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
|
@ -684,11 +684,11 @@ int ha_archive::create(const char *name, TABLE *table_arg,
|
||||
{
|
||||
if (!my_fstat(frm_file, &file_stat, MYF(MY_WME)))
|
||||
{
|
||||
frm_ptr= (uchar *)my_malloc(sizeof(uchar) * file_stat.st_size, MYF(0));
|
||||
frm_ptr= (uchar *)my_malloc(sizeof(uchar) * (size_t)file_stat.st_size, MYF(0));
|
||||
if (frm_ptr)
|
||||
{
|
||||
my_read(frm_file, frm_ptr, file_stat.st_size, MYF(0));
|
||||
azwrite_frm(&create_stream, (char *)frm_ptr, file_stat.st_size);
|
||||
my_read(frm_file, frm_ptr, (size_t)file_stat.st_size, MYF(0));
|
||||
azwrite_frm(&create_stream, (char *)frm_ptr, (size_t)file_stat.st_size);
|
||||
my_free((uchar*)frm_ptr, MYF(0));
|
||||
}
|
||||
}
|
||||
|
@ -1061,7 +1061,29 @@ innobase_mysql_tmpfile(void)
|
||||
will be passed to fdopen(), it will be closed by invoking
|
||||
fclose(), which in turn will invoke close() instead of
|
||||
my_close(). */
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Note that on Windows, the integer returned by mysql_tmpfile
|
||||
has no relation to C runtime file descriptor. Here, we need
|
||||
to call my_get_osfhandle to get the HANDLE and then convert it
|
||||
to C runtime filedescriptor. */
|
||||
{
|
||||
HANDLE hFile = my_get_osfhandle(fd);
|
||||
HANDLE hDup;
|
||||
BOOL bOK =
|
||||
DuplicateHandle(GetCurrentProcess(), hFile, GetCurrentProcess(),
|
||||
&hDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
if(bOK) {
|
||||
fd2 = _open_osfhandle((intptr_t)hDup,0);
|
||||
}
|
||||
else {
|
||||
my_osmaperr(GetLastError());
|
||||
fd2 = -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
fd2 = dup(fd);
|
||||
#endif
|
||||
if (fd2 < 0) {
|
||||
DBUG_PRINT("error",("Got error %d on dup",fd2));
|
||||
my_errno=errno;
|
||||
|
@ -49,7 +49,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <m_ctype.h>
|
||||
#include <mysys_err.h>
|
||||
#include <mysql/plugin.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
/** @file ha_innodb.cc */
|
||||
|
||||
/* Include necessary InnoDB headers */
|
||||
@ -1172,7 +1174,28 @@ innobase_mysql_tmpfile(void)
|
||||
will be passed to fdopen(), it will be closed by invoking
|
||||
fclose(), which in turn will invoke close() instead of
|
||||
my_close(). */
|
||||
#ifdef _WIN32
|
||||
/* Note that on Windows, the integer returned by mysql_tmpfile
|
||||
has no relation to C runtime file descriptor. Here, we need
|
||||
to call my_get_osfhandle to get the HANDLE and then convert it
|
||||
to C runtime filedescriptor. */
|
||||
{
|
||||
HANDLE hFile = my_get_osfhandle(fd);
|
||||
HANDLE hDup;
|
||||
BOOL bOK =
|
||||
DuplicateHandle(GetCurrentProcess(), hFile, GetCurrentProcess(),
|
||||
&hDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
if(bOK) {
|
||||
fd2 = _open_osfhandle((intptr_t)hDup,0);
|
||||
}
|
||||
else {
|
||||
my_osmaperr(GetLastError());
|
||||
fd2 = -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
fd2 = dup(fd);
|
||||
#endif
|
||||
if (fd2 < 0) {
|
||||
DBUG_PRINT("error",("Got error %d on dup",fd2));
|
||||
my_errno=errno;
|
||||
|
@ -415,9 +415,8 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
|
||||
if (!share->temporary)
|
||||
error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
|
||||
FLUSH_KEEP, FLUSH_KEEP);
|
||||
#ifdef HAVE_PREAD
|
||||
|
||||
_ma_decrement_open_count(info, 1);
|
||||
#endif
|
||||
if (share->not_flushed)
|
||||
{
|
||||
share->not_flushed= 0;
|
||||
|
@ -239,7 +239,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
|
||||
break; /* Impossible */
|
||||
}
|
||||
}
|
||||
#ifdef __WIN__
|
||||
#ifdef _WIN32
|
||||
else
|
||||
{
|
||||
/*
|
||||
@ -521,11 +521,11 @@ int _mi_writeinfo(register MI_INFO *info, uint operation)
|
||||
share->state.update_count= info->last_loop= ++info->this_loop;
|
||||
if ((error=mi_state_info_write(share->kfile, &share->state, 1)))
|
||||
olderror=my_errno;
|
||||
#ifdef __WIN__
|
||||
#ifdef _WIN32
|
||||
if (myisam_flush)
|
||||
{
|
||||
_commit(share->kfile);
|
||||
_commit(info->dfile);
|
||||
my_sync(share->kfile,0);
|
||||
my_sync(info->dfile,0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -15,20 +15,10 @@
|
||||
|
||||
# This is the CMakeLists for InnoDB Plugin
|
||||
|
||||
|
||||
|
||||
# Starting at 5.1.38, MySQL CMake files are simplified. But the plugin
|
||||
# CMakeLists.txt still needs to work with previous versions of MySQL.
|
||||
IF (MYSQL_VERSION_ID GREATER "50137")
|
||||
INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake")
|
||||
ENDIF (MYSQL_VERSION_ID GREATER "50137")
|
||||
|
||||
IF (CMAKE_SIZEOF_VOID_P MATCHES 8)
|
||||
SET(WIN64 TRUE)
|
||||
ENDIF (CMAKE_SIZEOF_VOID_P MATCHES 8)
|
||||
|
||||
ADD_DEFINITIONS(-D_WIN32 -D_LIB -DMYSQL_SERVER)
|
||||
|
||||
# Include directories under xtradb
|
||||
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/xtradb/include
|
||||
${CMAKE_SOURCE_DIR}/storage/xtradb/handler)
|
||||
@ -89,9 +79,6 @@ SET(XTRADB_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c
|
||||
usr/usr0sess.c
|
||||
ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rbt.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c
|
||||
ut/ut0list.c ut/ut0wqueue.c)
|
||||
# Windows atomics do not perform well. Disable Windows atomics by default.
|
||||
# See bug#52102 for details.
|
||||
#ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DINNODB_RW_LOCKS_USE_ATOMICS -DHAVE_IB_PAUSE_INSTRUCTION)
|
||||
ADD_DEFINITIONS(-DHAVE_IB_PAUSE_INSTRUCTION)
|
||||
|
||||
|
||||
MYSQL_STORAGE_ENGINE(XTRADB)
|
||||
|
@ -56,7 +56,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <m_ctype.h>
|
||||
#include <mysys_err.h>
|
||||
#include <mysql/plugin.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
/** @file ha_innodb.cc */
|
||||
|
||||
/* Include necessary InnoDB headers */
|
||||
@ -1239,7 +1241,28 @@ innobase_mysql_tmpfile(void)
|
||||
will be passed to fdopen(), it will be closed by invoking
|
||||
fclose(), which in turn will invoke close() instead of
|
||||
my_close(). */
|
||||
#ifdef _WIN32
|
||||
/* Note that on Windows, the integer returned by mysql_tmpfile
|
||||
has no relation to C runtime file descriptor. Here, we need
|
||||
to call my_get_osfhandle to get the HANDLE and then convert it
|
||||
to C runtime filedescriptor. */
|
||||
{
|
||||
HANDLE hFile = my_get_osfhandle(fd);
|
||||
HANDLE hDup;
|
||||
BOOL bOK =
|
||||
DuplicateHandle(GetCurrentProcess(), hFile, GetCurrentProcess(),
|
||||
&hDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
if(bOK) {
|
||||
fd2 = _open_osfhandle((intptr_t)hDup,0);
|
||||
}
|
||||
else {
|
||||
my_osmaperr(GetLastError());
|
||||
fd2 = -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
fd2 = dup(fd);
|
||||
#endif
|
||||
if (fd2 < 0) {
|
||||
DBUG_PRINT("error",("Got error %d on dup",fd2));
|
||||
my_errno=errno;
|
||||
|
@ -152,8 +152,8 @@ log. */
|
||||
#define OS_FILE_LOG 256 /* This can be ORed to type */
|
||||
/* @} */
|
||||
|
||||
#define OS_AIO_N_PENDING_IOS_PER_THREAD 32 /*!< Win NT does not allow more
|
||||
than 64 */
|
||||
#define OS_AIO_N_PENDING_IOS_PER_THREAD 256 /*!< Windows might be able to handle
|
||||
more */
|
||||
|
||||
/** Modes for aio operations @{ */
|
||||
#define OS_AIO_NORMAL 21 /*!< Normal asynchronous i/o not for ibuf
|
||||
@ -183,6 +183,10 @@ log. */
|
||||
#define OS_WIN95 2 /*!< Microsoft Windows 95 */
|
||||
#define OS_WINNT 3 /*!< Microsoft Windows NT 3.x */
|
||||
#define OS_WIN2000 4 /*!< Microsoft Windows 2000 */
|
||||
#define OS_WINXP 5 /*!< Microsoft Windows XP */
|
||||
#define OS_WINVISTA 6 /*!< Microsoft Windows Vista */
|
||||
#define OS_WIN7 7 /*!< Microsoft Windows 7 */
|
||||
|
||||
|
||||
extern ulint os_n_file_reads;
|
||||
extern ulint os_n_file_writes;
|
||||
|
@ -37,29 +37,19 @@ Created 9/6/1995 Heikki Tuuri
|
||||
#include "univ.i"
|
||||
#include "ut0lst.h"
|
||||
|
||||
#ifdef __WIN__
|
||||
|
||||
#ifdef _WIN32
|
||||
/** Native event (slow)*/
|
||||
typedef HANDLE os_native_event_t;
|
||||
/** Native mutex */
|
||||
#define os_fast_mutex_t CRITICAL_SECTION
|
||||
|
||||
/** Native event */
|
||||
typedef HANDLE os_native_event_t;
|
||||
|
||||
/** Operating system event */
|
||||
typedef struct os_event_struct os_event_struct_t;
|
||||
/** Operating system event handle */
|
||||
typedef os_event_struct_t* os_event_t;
|
||||
|
||||
/** An asynchronous signal sent between threads */
|
||||
struct os_event_struct {
|
||||
os_native_event_t handle;
|
||||
/*!< Windows event */
|
||||
UT_LIST_NODE_T(os_event_struct_t) os_event_list;
|
||||
/*!< list of all created events */
|
||||
};
|
||||
typedef CRITICAL_SECTION os_fast_mutex_t;
|
||||
/** Native condition variable */
|
||||
typedef CONDITION_VARIABLE os_cond_t;
|
||||
#else
|
||||
/** Native mutex */
|
||||
typedef pthread_mutex_t os_fast_mutex_t;
|
||||
/** Native condition variable */
|
||||
typedef pthread_cond_t os_cond_t;
|
||||
#endif
|
||||
|
||||
/** Operating system event */
|
||||
typedef struct os_event_struct os_event_struct_t;
|
||||
@ -68,6 +58,9 @@ typedef os_event_struct_t* os_event_t;
|
||||
|
||||
/** An asynchronous signal sent between threads */
|
||||
struct os_event_struct {
|
||||
#ifdef _WIN32
|
||||
HANDLE handle; /*!< kernel event object, slow, used on older Windows */
|
||||
#endif
|
||||
os_fast_mutex_t os_mutex; /*!< this mutex protects the next
|
||||
fields */
|
||||
ibool is_set; /*!< this is TRUE when the event is
|
||||
@ -76,12 +69,14 @@ struct os_event_struct {
|
||||
this event */
|
||||
ib_int64_t signal_count; /*!< this is incremented each time
|
||||
the event becomes signaled */
|
||||
pthread_cond_t cond_var; /*!< condition variable is used in
|
||||
os_cond_t cond_var; /*!< condition variable is used in
|
||||
waiting for the event */
|
||||
UT_LIST_NODE_T(os_event_struct_t) os_event_list;
|
||||
/*!< list of all created events */
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/** Operating system mutex */
|
||||
typedef struct os_mutex_struct os_mutex_str_t;
|
||||
@ -186,33 +181,23 @@ os_event_wait_low(
|
||||
os_event_reset(). */
|
||||
|
||||
#define os_event_wait(event) os_event_wait_low(event, 0)
|
||||
|
||||
#define os_event_wait_time(event, t) os_event_wait_time_low(event, t, 0)
|
||||
/**********************************************************//**
|
||||
Waits for an event object until it is in the signaled state or
|
||||
a timeout is exceeded.
|
||||
a timeout is exceeded. In Unix the timeout is always infinite.
|
||||
@return 0 if success, OS_SYNC_TIME_EXCEEDED if timeout was exceeded */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
os_event_wait_time(
|
||||
/*===============*/
|
||||
os_event_t event, /*!< in: event to wait */
|
||||
ulint wtime); /*!< in: timeout in microseconds, or
|
||||
OS_SYNC_INFINITE_TIME */
|
||||
#ifdef __WIN__
|
||||
/**********************************************************//**
|
||||
Waits for any event in an OS native event array. Returns if even a single
|
||||
one is signaled or becomes signaled.
|
||||
@return index of the event which was signaled */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
os_event_wait_multiple(
|
||||
os_event_wait_time_low(
|
||||
/*===================*/
|
||||
ulint n, /*!< in: number of events in the
|
||||
array */
|
||||
os_native_event_t* native_event_array);
|
||||
/*!< in: pointer to an array of event
|
||||
handles */
|
||||
#endif
|
||||
os_event_t event, /*!< in: event to wait */
|
||||
ulint time_in_usec, /*!< in: timeout in
|
||||
microseconds, or
|
||||
OS_SYNC_INFINITE_TIME */
|
||||
ib_int64_t reset_sig_count); /*!< in: zero or the value
|
||||
returned by previous call of
|
||||
os_event_reset(). */
|
||||
|
||||
/*********************************************************//**
|
||||
Creates an operating system mutex semaphore. Because these are slow, the
|
||||
mutex semaphore of InnoDB itself (mutex_t) should be used where possible.
|
||||
@ -385,7 +370,7 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
|
||||
# define os_atomic_test_and_set_byte(ptr, new_val) \
|
||||
atomic_swap_uchar(ptr, new_val)
|
||||
|
||||
#elif defined(HAVE_WINDOWS_ATOMICS)
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#define HAVE_ATOMIC_BUILTINS
|
||||
|
||||
|
@ -28,8 +28,7 @@ Created 9/6/1995 Heikki Tuuri
|
||||
#endif
|
||||
|
||||
/**********************************************************//**
|
||||
Acquires ownership of a fast mutex. Currently in Windows this is the same
|
||||
as os_fast_mutex_lock!
|
||||
Acquires ownership of a fast mutex.
|
||||
@return 0 if success, != 0 if was reserved by another thread */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
@ -38,9 +37,9 @@ os_fast_mutex_trylock(
|
||||
os_fast_mutex_t* fast_mutex) /*!< in: mutex to acquire */
|
||||
{
|
||||
#ifdef __WIN__
|
||||
EnterCriticalSection(fast_mutex);
|
||||
|
||||
return(0);
|
||||
if (TryEnterCriticalSection(fast_mutex))
|
||||
return 0;
|
||||
return(1);
|
||||
#else
|
||||
/* NOTE that the MySQL my_pthread.h redefines pthread_mutex_trylock
|
||||
so that it returns 0 on success. In the operating system
|
||||
|
@ -112,7 +112,9 @@ extern ulint srv_check_file_format_at_startup;
|
||||
on duplicate key checking and foreign key checking */
|
||||
extern ibool srv_locks_unsafe_for_binlog;
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
#ifdef __WIN__
|
||||
extern ibool srv_use_native_conditions;
|
||||
#endif
|
||||
extern ulint srv_n_data_files;
|
||||
extern char** srv_data_file_names;
|
||||
extern ulint* srv_data_file_sizes;
|
||||
|
@ -45,7 +45,7 @@ Created 9/5/1995 Heikki Tuuri
|
||||
extern my_bool timed_mutexes;
|
||||
#endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
|
||||
|
||||
#ifdef HAVE_WINDOWS_ATOMICS
|
||||
#ifdef _WIN32
|
||||
typedef LONG lock_word_t; /*!< On Windows, InterlockedExchange operates
|
||||
on LONG variable */
|
||||
#else
|
||||
|
@ -121,6 +121,12 @@ typedef struct os_aio_slot_struct os_aio_slot_t;
|
||||
|
||||
/** The asynchronous i/o array slot structure */
|
||||
struct os_aio_slot_struct{
|
||||
#ifdef WIN_ASYNC_IO
|
||||
OVERLAPPED control; /*!< Windows control block for the
|
||||
aio request, MUST be first element in the structure*/
|
||||
void *arr; /*!< Array this slot belongs to*/
|
||||
#endif
|
||||
|
||||
ibool is_read; /*!< TRUE if a read operation */
|
||||
ulint pos; /*!< index of the slot in the aio
|
||||
array */
|
||||
@ -148,12 +154,6 @@ struct os_aio_slot_struct{
|
||||
and which can be used to identify
|
||||
which pending aio operation was
|
||||
completed */
|
||||
#ifdef WIN_ASYNC_IO
|
||||
os_event_t event; /*!< event object we need in the
|
||||
OVERLAPPED struct */
|
||||
OVERLAPPED control; /*!< Windows control block for the
|
||||
aio request */
|
||||
#endif
|
||||
};
|
||||
|
||||
/** The asynchronous i/o array structure */
|
||||
@ -182,15 +182,6 @@ struct os_aio_array_struct{
|
||||
/*!< Number of reserved slots in the
|
||||
aio array outside the ibuf segment */
|
||||
os_aio_slot_t* slots; /*!< Pointer to the slots in the array */
|
||||
#ifdef __WIN__
|
||||
os_native_event_t* native_events;
|
||||
/*!< Pointer to an array of OS native
|
||||
event handles where we copied the
|
||||
handles from slots, in the same
|
||||
order. This can be used in
|
||||
WaitForMultipleObjects; used only in
|
||||
Windows */
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Array of events used in simulated aio */
|
||||
@ -250,6 +241,14 @@ UNIV_INTERN ulint os_n_pending_writes = 0;
|
||||
/** Number of pending read operations */
|
||||
UNIV_INTERN ulint os_n_pending_reads = 0;
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
/** IO completion port used by background io threads */
|
||||
static HANDLE completion_port;
|
||||
/** Thread local storage index for the per-thread event used for synchronous IO */
|
||||
static DWORD tls_sync_io = TLS_OUT_OF_INDEXES;
|
||||
#endif
|
||||
|
||||
/***********************************************************************//**
|
||||
Gets the operating system version. Currently works only on Windows.
|
||||
@return OS_WIN95, OS_WIN31, OS_WINNT, OS_WIN2000 */
|
||||
@ -270,10 +269,16 @@ os_get_os_version(void)
|
||||
} else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
|
||||
return(OS_WIN95);
|
||||
} else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
|
||||
if (os_info.dwMajorVersion <= 4) {
|
||||
return(OS_WINNT);
|
||||
} else {
|
||||
return(OS_WIN2000);
|
||||
switch(os_info.dwMajorVersion){
|
||||
case 3:
|
||||
case 4:
|
||||
return OS_WINNT;
|
||||
case 5:
|
||||
return (os_info.dwMinorVersion == 0)?OS_WIN2000 : OS_WINXP;
|
||||
case 6:
|
||||
return (os_info.dwMinorVersion == 0)?OS_WINVISTA : OS_WIN7;
|
||||
default:
|
||||
return OS_WIN7;
|
||||
}
|
||||
} else {
|
||||
ut_error;
|
||||
@ -286,6 +291,86 @@ os_get_os_version(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
Windows : Handling synchronous IO on files opened asynchronously.
|
||||
|
||||
If file is opened for asynchronous IO (FILE_FLAG_OVERLAPPED) and also bound to
|
||||
a completion port, then every IO on this file would normally be enqueued to the
|
||||
completion port. Sometimes however we would like to do a synchronous IO. This is
|
||||
possible if we initialitze have overlapped.hEvent with a valid event and set its
|
||||
lowest order bit to 1 (see MSDN ReadFile and WriteFile description for more info)
|
||||
|
||||
We'll create this special event once for each thread and store in thread local
|
||||
storage.
|
||||
*/
|
||||
|
||||
|
||||
/***********************************************************************//**
|
||||
Initialize tls index.for event handle used for synchronized IO on files that
|
||||
might be opened with FILE_FLAG_OVERLAPPED.
|
||||
*/
|
||||
static void win_init_syncio_event()
|
||||
{
|
||||
tls_sync_io = TlsAlloc();
|
||||
ut_a(tls_sync_io != TLS_OUT_OF_INDEXES);
|
||||
}
|
||||
|
||||
/***********************************************************************//**
|
||||
Retrieve per-thread event for doing synchronous io on asyncronously opened files
|
||||
*/
|
||||
static HANDLE win_get_syncio_event()
|
||||
{
|
||||
HANDLE h;
|
||||
if(tls_sync_io == TLS_OUT_OF_INDEXES){
|
||||
win_init_syncio_event();
|
||||
}
|
||||
|
||||
h = (HANDLE)TlsGetValue(tls_sync_io);
|
||||
if (h)
|
||||
return h;
|
||||
h = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
ut_a(h);
|
||||
h = (HANDLE)((uintptr_t)h | 1);
|
||||
TlsSetValue(tls_sync_io, h);
|
||||
return h;
|
||||
}
|
||||
|
||||
/*
|
||||
TLS destructor, inspired by Chromium code
|
||||
http://src.chromium.org/svn/trunk/src/base/threading/thread_local_storage_win.cc
|
||||
*/
|
||||
|
||||
static void win_free_syncio_event()
|
||||
{
|
||||
HANDLE h = win_get_syncio_event();
|
||||
if (h) {
|
||||
CloseHandle(h);
|
||||
}
|
||||
}
|
||||
|
||||
static void NTAPI win_tls_thread_exit(PVOID module, DWORD reason, PVOID reserved) {
|
||||
if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason)
|
||||
win_free_syncio_event();
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
#pragma comment(linker, "/INCLUDE:_tls_used")
|
||||
#pragma comment(linker, "/INCLUDE:p_thread_callback_base")
|
||||
#pragma const_seg(".CRT$XLB")
|
||||
extern const PIMAGE_TLS_CALLBACK p_thread_callback_base;
|
||||
const PIMAGE_TLS_CALLBACK p_thread_callback_base = win_tls_thread_exit;
|
||||
#pragma data_seg()
|
||||
#else
|
||||
#pragma comment(linker, "/INCLUDE:__tls_used")
|
||||
#pragma comment(linker, "/INCLUDE:_p_thread_callback_base")
|
||||
#pragma data_seg(".CRT$XLB")
|
||||
PIMAGE_TLS_CALLBACK p_thread_callback_base = win_tls_thread_exit;
|
||||
#pragma data_seg()
|
||||
#endif
|
||||
#endif /*_WIN32 */
|
||||
|
||||
/***********************************************************************//**
|
||||
Retrieves the last error number if an error occurs in a file io function.
|
||||
The number should be retrieved before any other OS calls (because they may
|
||||
@ -611,6 +696,9 @@ os_io_init_simple(void)
|
||||
for (i = 0; i < OS_FILE_N_SEEK_MUTEXES; i++) {
|
||||
os_file_seek_mutexes[i] = os_mutex_create(NULL);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
win_init_syncio_event();
|
||||
#endif
|
||||
}
|
||||
|
||||
/***********************************************************************//**
|
||||
@ -1358,6 +1446,16 @@ try_again:
|
||||
ut_error;
|
||||
}
|
||||
|
||||
if (type == OS_LOG_FILE) {
|
||||
if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) {
|
||||
/* Map O_DSYNC to WRITE_THROUGH */
|
||||
attributes |= FILE_FLAG_WRITE_THROUGH;
|
||||
} else if (srv_unix_file_flush_method == SRV_UNIX_ALL_O_DIRECT) {
|
||||
/* Open log file without buffering */
|
||||
attributes |= FILE_FLAG_NO_BUFFERING;
|
||||
}
|
||||
}
|
||||
|
||||
file = CreateFile((LPCTSTR) name,
|
||||
GENERIC_READ | GENERIC_WRITE, /* read and write
|
||||
access */
|
||||
@ -1402,6 +1500,9 @@ try_again:
|
||||
}
|
||||
} else {
|
||||
*success = TRUE;
|
||||
if (os_aio_use_native_aio && ((attributes & FILE_FLAG_OVERLAPPED) != 0)) {
|
||||
ut_a(CreateIoCompletionPort(file, completion_port, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
return(file);
|
||||
@ -2350,13 +2451,9 @@ _os_file_read(
|
||||
#ifdef __WIN__
|
||||
BOOL ret;
|
||||
DWORD len;
|
||||
DWORD ret2;
|
||||
DWORD low;
|
||||
DWORD high;
|
||||
ibool retry;
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
ulint i;
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
OVERLAPPED overlapped;
|
||||
|
||||
|
||||
/* On 64-bit Windows, ulint is 64 bits. But offset and n should be
|
||||
no more than 32 bits. */
|
||||
@ -2371,41 +2468,21 @@ try_again:
|
||||
ut_ad(buf);
|
||||
ut_ad(n > 0);
|
||||
|
||||
low = (DWORD) offset;
|
||||
high = (DWORD) offset_high;
|
||||
|
||||
os_mutex_enter(os_file_count_mutex);
|
||||
os_n_pending_reads++;
|
||||
os_mutex_exit(os_file_count_mutex);
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
/* Protect the seek / read operation with a mutex */
|
||||
i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
|
||||
|
||||
os_mutex_enter(os_file_seek_mutexes[i]);
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
|
||||
|
||||
if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
os_mutex_exit(os_file_seek_mutexes[i]);
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
os_mutex_enter(os_file_count_mutex);
|
||||
os_n_pending_reads--;
|
||||
os_mutex_exit(os_file_count_mutex);
|
||||
|
||||
goto error_handling;
|
||||
memset (&overlapped, 0, sizeof (overlapped));
|
||||
overlapped.Offset = (DWORD)offset;
|
||||
overlapped.OffsetHigh = (DWORD)offset_high;
|
||||
overlapped.hEvent = win_get_syncio_event();
|
||||
ret = ReadFile(file, buf, n, NULL, &overlapped);
|
||||
if (ret) {
|
||||
ret = GetOverlappedResult(file, &overlapped, (DWORD *)&len, FALSE);
|
||||
}
|
||||
|
||||
ret = ReadFile(file, buf, (DWORD) n, &len, NULL);
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
os_mutex_exit(os_file_seek_mutexes[i]);
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
else if(GetLastError() == ERROR_IO_PENDING) {
|
||||
ret = GetOverlappedResult(file, &overlapped, (DWORD *)&len, TRUE);
|
||||
}
|
||||
os_mutex_enter(os_file_count_mutex);
|
||||
os_n_pending_reads--;
|
||||
os_mutex_exit(os_file_count_mutex);
|
||||
@ -2433,9 +2510,6 @@ try_again:
|
||||
(ulong)n, (ulong)offset_high,
|
||||
(ulong)offset, (long)ret);
|
||||
#endif /* __WIN__ */
|
||||
#ifdef __WIN__
|
||||
error_handling:
|
||||
#endif
|
||||
retry = os_file_handle_error(NULL, "read");
|
||||
|
||||
if (retry) {
|
||||
@ -2477,13 +2551,11 @@ os_file_read_no_error_handling(
|
||||
#ifdef __WIN__
|
||||
BOOL ret;
|
||||
DWORD len;
|
||||
DWORD ret2;
|
||||
DWORD low;
|
||||
DWORD high;
|
||||
ibool retry;
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
ulint i;
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
OVERLAPPED overlapped;
|
||||
overlapped.Offset = (DWORD)offset;
|
||||
overlapped.OffsetHigh = (DWORD)offset_high;
|
||||
|
||||
|
||||
/* On 64-bit Windows, ulint is 64 bits. But offset and n should be
|
||||
no more than 32 bits. */
|
||||
@ -2498,41 +2570,21 @@ try_again:
|
||||
ut_ad(buf);
|
||||
ut_ad(n > 0);
|
||||
|
||||
low = (DWORD) offset;
|
||||
high = (DWORD) offset_high;
|
||||
|
||||
os_mutex_enter(os_file_count_mutex);
|
||||
os_n_pending_reads++;
|
||||
os_mutex_exit(os_file_count_mutex);
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
/* Protect the seek / read operation with a mutex */
|
||||
i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
|
||||
|
||||
os_mutex_enter(os_file_seek_mutexes[i]);
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
|
||||
|
||||
if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
os_mutex_exit(os_file_seek_mutexes[i]);
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
os_mutex_enter(os_file_count_mutex);
|
||||
os_n_pending_reads--;
|
||||
os_mutex_exit(os_file_count_mutex);
|
||||
|
||||
goto error_handling;
|
||||
memset (&overlapped, 0, sizeof (overlapped));
|
||||
overlapped.Offset = (DWORD)offset;
|
||||
overlapped.OffsetHigh = (DWORD)offset_high;
|
||||
overlapped.hEvent = win_get_syncio_event();
|
||||
ret = ReadFile(file, buf, n, NULL, &overlapped);
|
||||
if (ret) {
|
||||
ret = GetOverlappedResult(file, &overlapped, (DWORD *)&len, FALSE);
|
||||
}
|
||||
|
||||
ret = ReadFile(file, buf, (DWORD) n, &len, NULL);
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
os_mutex_exit(os_file_seek_mutexes[i]);
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
else if(GetLastError() == ERROR_IO_PENDING) {
|
||||
ret = GetOverlappedResult(file, &overlapped, (DWORD *)&len, TRUE);
|
||||
}
|
||||
os_mutex_enter(os_file_count_mutex);
|
||||
os_n_pending_reads--;
|
||||
os_mutex_exit(os_file_count_mutex);
|
||||
@ -2554,9 +2606,6 @@ try_again:
|
||||
return(TRUE);
|
||||
}
|
||||
#endif /* __WIN__ */
|
||||
#ifdef __WIN__
|
||||
error_handling:
|
||||
#endif
|
||||
retry = os_file_handle_error_no_exit(NULL, "read");
|
||||
|
||||
if (retry) {
|
||||
@ -2609,14 +2658,9 @@ os_file_write(
|
||||
#ifdef __WIN__
|
||||
BOOL ret;
|
||||
DWORD len;
|
||||
DWORD ret2;
|
||||
DWORD low;
|
||||
DWORD high;
|
||||
ulint n_retries = 0;
|
||||
ulint err;
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
ulint i;
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
OVERLAPPED overlapped;
|
||||
|
||||
/* On 64-bit Windows, ulint is 64 bits. But offset and n should be
|
||||
no more than 32 bits. */
|
||||
@ -2629,64 +2673,23 @@ os_file_write(
|
||||
ut_ad(buf);
|
||||
ut_ad(n > 0);
|
||||
retry:
|
||||
low = (DWORD) offset;
|
||||
high = (DWORD) offset_high;
|
||||
|
||||
os_mutex_enter(os_file_count_mutex);
|
||||
os_n_pending_writes++;
|
||||
os_mutex_exit(os_file_count_mutex);
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
/* Protect the seek / write operation with a mutex */
|
||||
i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
|
||||
memset (&overlapped, 0, sizeof (overlapped));
|
||||
overlapped.Offset = (DWORD)offset;
|
||||
overlapped.OffsetHigh = (DWORD)offset_high;
|
||||
|
||||
os_mutex_enter(os_file_seek_mutexes[i]);
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
|
||||
|
||||
if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
os_mutex_exit(os_file_seek_mutexes[i]);
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
os_mutex_enter(os_file_count_mutex);
|
||||
os_n_pending_writes--;
|
||||
os_mutex_exit(os_file_count_mutex);
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
fprintf(stderr,
|
||||
" InnoDB: Error: File pointer positioning to"
|
||||
" file %s failed at\n"
|
||||
"InnoDB: offset %lu %lu. Operating system"
|
||||
" error number %lu.\n"
|
||||
"InnoDB: Some operating system error numbers"
|
||||
" are described at\n"
|
||||
"InnoDB: "
|
||||
REFMAN "operating-system-error-codes.html\n",
|
||||
name, (ulong) offset_high, (ulong) offset,
|
||||
(ulong) GetLastError());
|
||||
|
||||
return(FALSE);
|
||||
overlapped.hEvent = win_get_syncio_event();
|
||||
ret = WriteFile(file, buf, n, NULL, &overlapped);
|
||||
if (ret) {
|
||||
ret = GetOverlappedResult(file, &overlapped, (DWORD *)&len, FALSE);
|
||||
}
|
||||
|
||||
ret = WriteFile(file, buf, (DWORD) n, &len, NULL);
|
||||
|
||||
/* Always do fsync to reduce the probability that when the OS crashes,
|
||||
a database page is only partially physically written to disk. */
|
||||
|
||||
# ifdef UNIV_DO_FLUSH
|
||||
if (!os_do_not_call_flush_at_each_write) {
|
||||
ut_a(TRUE == os_file_flush(file));
|
||||
else if(GetLastError() == ERROR_IO_PENDING) {
|
||||
ret = GetOverlappedResult(file, &overlapped, (DWORD *)&len, TRUE);
|
||||
}
|
||||
# endif /* UNIV_DO_FLUSH */
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
os_mutex_exit(os_file_seek_mutexes[i]);
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
os_mutex_enter(os_file_count_mutex);
|
||||
os_n_pending_writes--;
|
||||
os_mutex_exit(os_file_count_mutex);
|
||||
@ -3071,9 +3074,6 @@ os_aio_array_create(
|
||||
os_aio_array_t* array;
|
||||
ulint i;
|
||||
os_aio_slot_t* slot;
|
||||
#ifdef WIN_ASYNC_IO
|
||||
OVERLAPPED* over;
|
||||
#endif
|
||||
ut_a(n > 0);
|
||||
ut_a(n_segments > 0);
|
||||
|
||||
@ -3089,23 +3089,12 @@ os_aio_array_create(
|
||||
array->n_segments = n_segments;
|
||||
array->n_reserved = 0;
|
||||
array->slots = ut_malloc(n * sizeof(os_aio_slot_t));
|
||||
#ifdef __WIN__
|
||||
array->native_events = ut_malloc(n * sizeof(os_native_event_t));
|
||||
#endif
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
slot = os_aio_array_get_nth_slot(array, i);
|
||||
|
||||
slot->pos = i;
|
||||
slot->reserved = FALSE;
|
||||
#ifdef WIN_ASYNC_IO
|
||||
slot->event = os_event_create(NULL);
|
||||
|
||||
over = &(slot->control);
|
||||
|
||||
over->hEvent = slot->event->handle;
|
||||
|
||||
*((array->native_events) + i) = over->hEvent;
|
||||
#endif
|
||||
}
|
||||
|
||||
return(array);
|
||||
@ -3119,18 +3108,7 @@ os_aio_array_free(
|
||||
/*==============*/
|
||||
os_aio_array_t* array) /*!< in, own: array to free */
|
||||
{
|
||||
#ifdef WIN_ASYNC_IO
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < array->n_slots; i++) {
|
||||
os_aio_slot_t* slot = os_aio_array_get_nth_slot(array, i);
|
||||
os_event_free(slot->event);
|
||||
}
|
||||
#endif /* WIN_ASYNC_IO */
|
||||
|
||||
#ifdef __WIN__
|
||||
ut_free(array->native_events);
|
||||
#endif /* __WIN__ */
|
||||
os_mutex_free(array->mutex);
|
||||
os_event_free(array->not_full);
|
||||
os_event_free(array->is_empty);
|
||||
@ -3209,7 +3187,11 @@ os_aio_init(
|
||||
}
|
||||
|
||||
os_last_printout = time(NULL);
|
||||
|
||||
#ifdef _WIN32
|
||||
ut_a(completion_port == 0);
|
||||
completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
|
||||
ut_a(completion_port);
|
||||
#endif
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
@ -3251,11 +3233,11 @@ os_aio_array_wake_win_aio_at_shutdown(
|
||||
/*==================================*/
|
||||
os_aio_array_t* array) /*!< in: aio array */
|
||||
{
|
||||
ulint i;
|
||||
if(completion_port)
|
||||
{
|
||||
ut_a(CloseHandle(completion_port));
|
||||
completion_port = 0;
|
||||
|
||||
for (i = 0; i < array->n_slots; i++) {
|
||||
|
||||
os_event_set((array->slots + i)->event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -3480,7 +3462,8 @@ found:
|
||||
control = &(slot->control);
|
||||
control->Offset = (DWORD)offset;
|
||||
control->OffsetHigh = (DWORD)offset_high;
|
||||
os_event_reset(slot->event);
|
||||
control->hEvent = 0;
|
||||
slot->arr = array;
|
||||
#endif
|
||||
|
||||
os_mutex_exit(array->mutex);
|
||||
@ -3517,9 +3500,6 @@ os_aio_array_free_slot(
|
||||
os_event_set(array->is_empty);
|
||||
}
|
||||
|
||||
#ifdef WIN_ASYNC_IO
|
||||
os_event_reset(slot->event);
|
||||
#endif
|
||||
os_mutex_exit(array->mutex);
|
||||
}
|
||||
|
||||
@ -3689,12 +3669,8 @@ os_aio(
|
||||
os_aio_array_t* array;
|
||||
os_aio_slot_t* slot;
|
||||
#ifdef WIN_ASYNC_IO
|
||||
ibool retval;
|
||||
BOOL ret = TRUE;
|
||||
DWORD len = (DWORD) n;
|
||||
struct fil_node_struct * dummy_mess1;
|
||||
void* dummy_mess2;
|
||||
ulint dummy_type;
|
||||
BOOL ret;
|
||||
#endif
|
||||
ulint err = 0;
|
||||
ibool retry;
|
||||
@ -3713,26 +3689,23 @@ os_aio(
|
||||
wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
|
||||
mode = mode & (~OS_AIO_SIMULATED_WAKE_LATER);
|
||||
|
||||
if (mode == OS_AIO_SYNC
|
||||
#ifdef WIN_ASYNC_IO
|
||||
&& !os_aio_use_native_aio
|
||||
#endif
|
||||
) {
|
||||
if (mode == OS_AIO_SYNC)
|
||||
{
|
||||
ibool ret;
|
||||
/* This is actually an ordinary synchronous read or write:
|
||||
no need to use an i/o-handler thread. NOTE that if we use
|
||||
Windows async i/o, Windows does not allow us to use
|
||||
ordinary synchronous os_file_read etc. on the same file,
|
||||
therefore we have built a special mechanism for synchronous
|
||||
wait in the Windows case. */
|
||||
no need to use an i/o-handler thread */
|
||||
|
||||
if (type == OS_FILE_READ) {
|
||||
return(_os_file_read(file, buf, offset,
|
||||
offset_high, n, trx));
|
||||
ret = _os_file_read(file, buf, offset,
|
||||
offset_high, n, trx);
|
||||
}
|
||||
else {
|
||||
ut_a(type == OS_FILE_WRITE);
|
||||
|
||||
ut_a(type == OS_FILE_WRITE);
|
||||
|
||||
return(os_file_write(name, file, buf, offset, offset_high, n));
|
||||
ret = os_file_write(name, file, buf, offset, offset_high, n);
|
||||
}
|
||||
ut_a(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
try_again:
|
||||
@ -3775,6 +3748,8 @@ try_again:
|
||||
|
||||
ret = ReadFile(file, buf, (DWORD)n, &len,
|
||||
&(slot->control));
|
||||
if(!ret && GetLastError() != ERROR_IO_PENDING)
|
||||
err = 1;
|
||||
#endif
|
||||
} else {
|
||||
if (!wake_later) {
|
||||
@ -3789,6 +3764,8 @@ try_again:
|
||||
os_n_file_writes++;
|
||||
ret = WriteFile(file, buf, (DWORD)n, &len,
|
||||
&(slot->control));
|
||||
if(!ret && GetLastError() != ERROR_IO_PENDING)
|
||||
err = 1;
|
||||
#endif
|
||||
} else {
|
||||
if (!wake_later) {
|
||||
@ -3801,34 +3778,7 @@ try_again:
|
||||
ut_error;
|
||||
}
|
||||
|
||||
#ifdef WIN_ASYNC_IO
|
||||
if (os_aio_use_native_aio) {
|
||||
if ((ret && len == n)
|
||||
|| (!ret && GetLastError() == ERROR_IO_PENDING)) {
|
||||
/* aio was queued successfully! */
|
||||
|
||||
if (mode == OS_AIO_SYNC) {
|
||||
/* We want a synchronous i/o operation on a
|
||||
file where we also use async i/o: in Windows
|
||||
we must use the same wait mechanism as for
|
||||
async i/o */
|
||||
|
||||
retval = os_aio_windows_handle(ULINT_UNDEFINED,
|
||||
slot->pos,
|
||||
&dummy_mess1,
|
||||
&dummy_mess2,
|
||||
&dummy_type,
|
||||
&space_id);
|
||||
|
||||
return(retval);
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
err = 1; /* Fall through the next if */
|
||||
}
|
||||
#endif
|
||||
if (err == 0) {
|
||||
/* aio was queued successfully! */
|
||||
|
||||
@ -3881,52 +3831,20 @@ os_aio_windows_handle(
|
||||
ulint* space_id)
|
||||
{
|
||||
ulint orig_seg = segment;
|
||||
os_aio_array_t* array;
|
||||
os_aio_slot_t* slot;
|
||||
ulint n;
|
||||
ulint i;
|
||||
ibool ret_val;
|
||||
BOOL ret;
|
||||
DWORD len;
|
||||
BOOL retry = FALSE;
|
||||
ULONG_PTR dummy_key;
|
||||
|
||||
if (segment == ULINT_UNDEFINED) {
|
||||
array = os_aio_sync_array;
|
||||
segment = 0;
|
||||
} else {
|
||||
segment = os_aio_get_array_and_local_segment(&array, segment);
|
||||
ret = GetQueuedCompletionStatus(completion_port, &len, &dummy_key,
|
||||
(OVERLAPPED **)&slot, INFINITE);
|
||||
|
||||
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
|
||||
os_thread_exit(NULL);
|
||||
}
|
||||
|
||||
/* NOTE! We only access constant fields in os_aio_array. Therefore
|
||||
we do not have to acquire the protecting mutex yet */
|
||||
|
||||
ut_ad(os_aio_validate());
|
||||
ut_ad(segment < array->n_segments);
|
||||
|
||||
n = array->n_slots;
|
||||
|
||||
if (array == os_aio_sync_array) {
|
||||
os_event_wait(os_aio_array_get_nth_slot(array, pos)->event);
|
||||
i = pos;
|
||||
} else {
|
||||
srv_set_io_thread_op_info(orig_seg, "wait Windows aio");
|
||||
i = os_event_wait_multiple(n,
|
||||
(array->native_events)
|
||||
);
|
||||
}
|
||||
|
||||
os_mutex_enter(array->mutex);
|
||||
|
||||
slot = os_aio_array_get_nth_slot(array, i);
|
||||
|
||||
ut_a(slot->reserved);
|
||||
|
||||
if (orig_seg != ULINT_UNDEFINED) {
|
||||
srv_set_io_thread_op_info(orig_seg,
|
||||
"get windows aio return value");
|
||||
}
|
||||
|
||||
ret = GetOverlappedResult(slot->file, &(slot->control), &len, TRUE);
|
||||
|
||||
*message1 = slot->message1;
|
||||
*message2 = slot->message2;
|
||||
@ -3951,8 +3869,6 @@ os_aio_windows_handle(
|
||||
ret_val = FALSE;
|
||||
}
|
||||
|
||||
os_mutex_exit(array->mutex);
|
||||
|
||||
if (retry) {
|
||||
/* retry failed read/write operation synchronously.
|
||||
No need to hold array->mutex. */
|
||||
@ -3961,37 +3877,19 @@ os_aio_windows_handle(
|
||||
|
||||
switch (slot->type) {
|
||||
case OS_FILE_WRITE:
|
||||
ret = WriteFile(slot->file, slot->buf,
|
||||
(DWORD) slot->len, &len,
|
||||
&(slot->control));
|
||||
|
||||
ret_val = os_file_write(slot->name, slot->file, slot->buf,
|
||||
slot->control.Offset, slot->control.OffsetHigh, slot->len);
|
||||
break;
|
||||
case OS_FILE_READ:
|
||||
ret = ReadFile(slot->file, slot->buf,
|
||||
(DWORD) slot->len, &len,
|
||||
&(slot->control));
|
||||
|
||||
ret_val = os_file_read(slot->file, slot->buf,
|
||||
slot->control.Offset, slot->control.OffsetHigh, slot->len);
|
||||
break;
|
||||
default:
|
||||
ut_error;
|
||||
}
|
||||
|
||||
if (!ret && GetLastError() == ERROR_IO_PENDING) {
|
||||
/* aio was queued successfully!
|
||||
We want a synchronous i/o operation on a
|
||||
file where we also use async i/o: in Windows
|
||||
we must use the same wait mechanism as for
|
||||
async i/o */
|
||||
|
||||
ret = GetOverlappedResult(slot->file,
|
||||
&(slot->control),
|
||||
&len, TRUE);
|
||||
}
|
||||
|
||||
ret_val = ret && len == slot->len;
|
||||
}
|
||||
|
||||
os_aio_array_free_slot(array, slot);
|
||||
os_aio_array_free_slot((os_aio_array_t *)slot->arr, slot);
|
||||
|
||||
return(ret_val);
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ Created 9/6/1995 Heikki Tuuri
|
||||
|
||||
#include "ut0mem.h"
|
||||
#include "srv0start.h"
|
||||
#include "srv0srv.h"
|
||||
|
||||
/* Type definition for an operating system mutex struct */
|
||||
struct os_mutex_struct{
|
||||
@ -74,11 +75,225 @@ UNIV_INTERN ulint os_event_count = 0;
|
||||
UNIV_INTERN ulint os_mutex_count = 0;
|
||||
UNIV_INTERN ulint os_fast_mutex_count = 0;
|
||||
|
||||
/* The number of microsecnds in a second. */
|
||||
static const ulint MICROSECS_IN_A_SECOND = 1000000;
|
||||
|
||||
/* Because a mutex is embedded inside an event and there is an
|
||||
event embedded inside a mutex, on free, this generates a recursive call.
|
||||
This version of the free event function doesn't acquire the global lock */
|
||||
static void os_event_free_internal(os_event_t event);
|
||||
|
||||
/* On Windows (Vista and later), load function pointers for condition
|
||||
variable handling. Those functions are not available in prior versions,
|
||||
so we have to use them via runtime loading, as long as we support XP. */
|
||||
static void os_cond_module_init(void);
|
||||
|
||||
#ifdef __WIN__
|
||||
/* Prototypes and function pointers for condition variable functions */
|
||||
typedef VOID (WINAPI* InitializeConditionVariableProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
static InitializeConditionVariableProc initialize_condition_variable;
|
||||
|
||||
typedef BOOL (WINAPI* SleepConditionVariableCSProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable,
|
||||
PCRITICAL_SECTION CriticalSection,
|
||||
DWORD dwMilliseconds);
|
||||
static SleepConditionVariableCSProc sleep_condition_variable;
|
||||
|
||||
typedef VOID (WINAPI* WakeAllConditionVariableProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
static WakeAllConditionVariableProc wake_all_condition_variable;
|
||||
|
||||
typedef VOID (WINAPI* WakeConditionVariableProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
static WakeConditionVariableProc wake_condition_variable;
|
||||
#endif
|
||||
|
||||
/*********************************************************//**
|
||||
Initialitze condition variable */
|
||||
UNIV_INLINE
|
||||
void
|
||||
os_cond_init(
|
||||
/*=========*/
|
||||
os_cond_t* cond) /*!< in: condition variable. */
|
||||
{
|
||||
ut_a(cond);
|
||||
|
||||
#ifdef __WIN__
|
||||
ut_a(initialize_condition_variable != NULL);
|
||||
initialize_condition_variable(cond);
|
||||
#else
|
||||
ut_a(pthread_cond_init(cond, NULL) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************************************************//**
|
||||
Do a timed wait on condition variable.
|
||||
@return TRUE if timed out, FALSE otherwise */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
os_cond_wait_timed(
|
||||
/*===============*/
|
||||
os_cond_t* cond, /*!< in: condition variable. */
|
||||
os_fast_mutex_t* mutex, /*!< in: fast mutex */
|
||||
#ifndef __WIN__
|
||||
const struct timespec* abstime /*!< in: timeout */
|
||||
#else
|
||||
DWORD time_in_ms /*!< in: timeout in
|
||||
milliseconds*/
|
||||
#endif /* !__WIN__ */
|
||||
)
|
||||
{
|
||||
#ifdef __WIN__
|
||||
BOOL ret;
|
||||
DWORD err;
|
||||
|
||||
ut_a(sleep_condition_variable != NULL);
|
||||
|
||||
ret = sleep_condition_variable(cond, mutex, time_in_ms);
|
||||
|
||||
if (!ret) {
|
||||
err = GetLastError();
|
||||
/* From http://msdn.microsoft.com/en-us/library/ms686301%28VS.85%29.aspx,
|
||||
"Condition variables are subject to spurious wakeups
|
||||
(those not associated with an explicit wake) and stolen wakeups
|
||||
(another thread manages to run before the woken thread)."
|
||||
Check for both types of timeouts.
|
||||
Conditions are checked by the caller.*/
|
||||
if ((err == WAIT_TIMEOUT) || (err == ERROR_TIMEOUT)) {
|
||||
return(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
ut_a(ret);
|
||||
|
||||
return(FALSE);
|
||||
#else
|
||||
int ret;
|
||||
|
||||
ret = pthread_cond_timedwait(cond, mutex, abstime);
|
||||
|
||||
switch (ret) {
|
||||
case 0:
|
||||
case ETIMEDOUT:
|
||||
/* We play it safe by checking for EINTR even though
|
||||
according to the POSIX documentation it can't return EINTR. */
|
||||
case EINTR:
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, " InnoDB: pthread_cond_timedwait() returned: "
|
||||
"%d: abstime={%lu,%lu}\n",
|
||||
ret, (ulong) abstime->tv_sec, (ulong) abstime->tv_nsec);
|
||||
ut_error;
|
||||
}
|
||||
|
||||
return(ret == ETIMEDOUT);
|
||||
#endif
|
||||
}
|
||||
/*********************************************************//**
|
||||
Wait on condition variable */
|
||||
UNIV_INLINE
|
||||
void
|
||||
os_cond_wait(
|
||||
/*=========*/
|
||||
os_cond_t* cond, /*!< in: condition variable. */
|
||||
os_fast_mutex_t* mutex) /*!< in: fast mutex */
|
||||
{
|
||||
ut_a(cond);
|
||||
ut_a(mutex);
|
||||
|
||||
#ifdef __WIN__
|
||||
ut_a(sleep_condition_variable != NULL);
|
||||
ut_a(sleep_condition_variable(cond, mutex, INFINITE));
|
||||
#else
|
||||
ut_a(pthread_cond_wait(cond, mutex) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************************************************//**
|
||||
Wakes all threads waiting for condition variable */
|
||||
UNIV_INLINE
|
||||
void
|
||||
os_cond_broadcast(
|
||||
/*==============*/
|
||||
os_cond_t* cond) /*!< in: condition variable. */
|
||||
{
|
||||
ut_a(cond);
|
||||
|
||||
#ifdef __WIN__
|
||||
ut_a(wake_all_condition_variable != NULL);
|
||||
wake_all_condition_variable(cond);
|
||||
#else
|
||||
ut_a(pthread_cond_broadcast(cond) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************************************************//**
|
||||
Wakes one thread waiting for condition variable */
|
||||
UNIV_INLINE
|
||||
void
|
||||
os_cond_signal(
|
||||
/*==========*/
|
||||
os_cond_t* cond) /*!< in: condition variable. */
|
||||
{
|
||||
ut_a(cond);
|
||||
|
||||
#ifdef __WIN__
|
||||
ut_a(wake_condition_variable != NULL);
|
||||
wake_condition_variable(cond);
|
||||
#else
|
||||
ut_a(pthread_cond_signal(cond) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************************************************//**
|
||||
Destroys condition variable */
|
||||
UNIV_INLINE
|
||||
void
|
||||
os_cond_destroy(
|
||||
/*============*/
|
||||
os_cond_t* cond) /*!< in: condition variable. */
|
||||
{
|
||||
#ifdef __WIN__
|
||||
/* Do nothing */
|
||||
#else
|
||||
ut_a(pthread_cond_destroy(cond) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************************************************//**
|
||||
On Windows (Vista and later), load function pointers for condition variable
|
||||
handling. Those functions are not available in prior versions, so we have to
|
||||
use them via runtime loading, as long as we support XP. */
|
||||
static
|
||||
void
|
||||
os_cond_module_init(void)
|
||||
/*=====================*/
|
||||
{
|
||||
#ifdef __WIN__
|
||||
HMODULE h_dll;
|
||||
|
||||
|
||||
h_dll = GetModuleHandle("kernel32");
|
||||
|
||||
initialize_condition_variable = (InitializeConditionVariableProc)
|
||||
GetProcAddress(h_dll, "InitializeConditionVariable");
|
||||
sleep_condition_variable = (SleepConditionVariableCSProc)
|
||||
GetProcAddress(h_dll, "SleepConditionVariableCS");
|
||||
wake_all_condition_variable = (WakeAllConditionVariableProc)
|
||||
GetProcAddress(h_dll, "WakeAllConditionVariable");
|
||||
wake_condition_variable = (WakeConditionVariableProc)
|
||||
GetProcAddress(h_dll, "WakeConditionVariable");
|
||||
|
||||
/* When using native condition variables, check function pointers */
|
||||
ut_a(initialize_condition_variable);
|
||||
ut_a(sleep_condition_variable);
|
||||
ut_a(wake_all_condition_variable);
|
||||
ut_a(wake_condition_variable);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************************************************//**
|
||||
Initializes global event and OS 'slow' mutex lists. */
|
||||
UNIV_INTERN
|
||||
@ -92,6 +307,9 @@ os_sync_init(void)
|
||||
os_sync_mutex = NULL;
|
||||
os_sync_mutex_inited = FALSE;
|
||||
|
||||
/* Now for Windows only */
|
||||
os_cond_module_init();
|
||||
|
||||
os_sync_mutex = os_mutex_create(NULL);
|
||||
|
||||
os_sync_mutex_inited = TRUE;
|
||||
@ -146,42 +364,45 @@ os_event_create(
|
||||
const char* name) /*!< in: the name of the event, if NULL
|
||||
the event is created without a name */
|
||||
{
|
||||
#ifdef __WIN__
|
||||
os_event_t event;
|
||||
|
||||
event = ut_malloc(sizeof(struct os_event_struct));
|
||||
|
||||
event->handle = CreateEvent(NULL, /* No security attributes */
|
||||
TRUE, /* Manual reset */
|
||||
FALSE, /* Initial state nonsignaled */
|
||||
(LPCTSTR) name);
|
||||
if (!event->handle) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Could not create a Windows event semaphore;"
|
||||
" Windows error %lu\n",
|
||||
(ulong) GetLastError());
|
||||
}
|
||||
#else /* Unix */
|
||||
os_event_t event;
|
||||
|
||||
UT_NOT_USED(name);
|
||||
#ifdef __WIN__
|
||||
if(!srv_use_native_conditions) {
|
||||
|
||||
event = ut_malloc(sizeof(struct os_event_struct));
|
||||
event = ut_malloc(sizeof(struct os_event_struct));
|
||||
|
||||
os_fast_mutex_init(&(event->os_mutex));
|
||||
event->handle = CreateEvent(NULL,
|
||||
TRUE,
|
||||
FALSE,
|
||||
(LPCTSTR) name);
|
||||
if (!event->handle) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Could not create a Windows event"
|
||||
" semaphore; Windows error %lu\n",
|
||||
(ulong) GetLastError());
|
||||
}
|
||||
} else /* Windows with condition variables */
|
||||
#endif
|
||||
|
||||
ut_a(0 == pthread_cond_init(&(event->cond_var), NULL));
|
||||
{
|
||||
UT_NOT_USED(name);
|
||||
|
||||
event->is_set = FALSE;
|
||||
event = ut_malloc(sizeof(struct os_event_struct));
|
||||
|
||||
/* We return this value in os_event_reset(), which can then be
|
||||
be used to pass to the os_event_wait_low(). The value of zero
|
||||
is reserved in os_event_wait_low() for the case when the
|
||||
caller does not want to pass any signal_count value. To
|
||||
distinguish between the two cases we initialize signal_count
|
||||
to 1 here. */
|
||||
event->signal_count = 1;
|
||||
#endif /* __WIN__ */
|
||||
os_fast_mutex_init(&(event->os_mutex));
|
||||
|
||||
os_cond_init(&(event->cond_var));
|
||||
|
||||
event->is_set = FALSE;
|
||||
|
||||
/* We return this value in os_event_reset(), which can then be
|
||||
be used to pass to the os_event_wait_low(). The value of zero
|
||||
is reserved in os_event_wait_low() for the case when the
|
||||
caller does not want to pass any signal_count value. To
|
||||
distinguish between the two cases we initialize signal_count
|
||||
to 1 here. */
|
||||
event->signal_count = 1;
|
||||
}
|
||||
|
||||
/* The os_sync_mutex can be NULL because during startup an event
|
||||
can be created [ because it's embedded in the mutex/rwlock ] before
|
||||
@ -211,10 +432,15 @@ os_event_set(
|
||||
/*=========*/
|
||||
os_event_t event) /*!< in: event to set */
|
||||
{
|
||||
#ifdef __WIN__
|
||||
ut_a(event);
|
||||
ut_a(SetEvent(event->handle));
|
||||
#else
|
||||
|
||||
#ifdef __WIN__
|
||||
if (!srv_use_native_conditions) {
|
||||
ut_a(SetEvent(event->handle));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ut_a(event);
|
||||
|
||||
os_fast_mutex_lock(&(event->os_mutex));
|
||||
@ -224,11 +450,10 @@ os_event_set(
|
||||
} else {
|
||||
event->is_set = TRUE;
|
||||
event->signal_count += 1;
|
||||
ut_a(0 == pthread_cond_broadcast(&(event->cond_var)));
|
||||
os_cond_broadcast(&(event->cond_var));
|
||||
}
|
||||
|
||||
os_fast_mutex_unlock(&(event->os_mutex));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**********************************************************//**
|
||||
@ -247,12 +472,14 @@ os_event_reset(
|
||||
{
|
||||
ib_int64_t ret = 0;
|
||||
|
||||
#ifdef __WIN__
|
||||
ut_a(event);
|
||||
|
||||
ut_a(ResetEvent(event->handle));
|
||||
#else
|
||||
ut_a(event);
|
||||
#ifdef __WIN__
|
||||
if(!srv_use_native_conditions) {
|
||||
ut_a(ResetEvent(event->handle));
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
os_fast_mutex_lock(&(event->os_mutex));
|
||||
|
||||
@ -264,7 +491,6 @@ os_event_reset(
|
||||
ret = event->signal_count;
|
||||
|
||||
os_fast_mutex_unlock(&(event->os_mutex));
|
||||
#endif
|
||||
return(ret);
|
||||
}
|
||||
|
||||
@ -277,17 +503,20 @@ os_event_free_internal(
|
||||
os_event_t event) /*!< in: event to free */
|
||||
{
|
||||
#ifdef __WIN__
|
||||
ut_a(event);
|
||||
|
||||
ut_a(CloseHandle(event->handle));
|
||||
#else
|
||||
ut_a(event);
|
||||
|
||||
/* This is to avoid freeing the mutex twice */
|
||||
os_fast_mutex_free(&(event->os_mutex));
|
||||
|
||||
ut_a(0 == pthread_cond_destroy(&(event->cond_var)));
|
||||
if(!srv_use_native_conditions) {
|
||||
ut_a(event);
|
||||
ut_a(CloseHandle(event->handle));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ut_a(event);
|
||||
|
||||
/* This is to avoid freeing the mutex twice */
|
||||
os_fast_mutex_free(&(event->os_mutex));
|
||||
|
||||
os_cond_destroy(&(event->cond_var));
|
||||
}
|
||||
|
||||
/* Remove from the list of events */
|
||||
|
||||
UT_LIST_REMOVE(os_event_list, os_event_list, event);
|
||||
@ -306,16 +535,18 @@ os_event_free(
|
||||
os_event_t event) /*!< in: event to free */
|
||||
|
||||
{
|
||||
ut_a(event);
|
||||
#ifdef __WIN__
|
||||
ut_a(event);
|
||||
|
||||
ut_a(CloseHandle(event->handle));
|
||||
#else
|
||||
ut_a(event);
|
||||
|
||||
os_fast_mutex_free(&(event->os_mutex));
|
||||
ut_a(0 == pthread_cond_destroy(&(event->cond_var)));
|
||||
if(!srv_use_native_conditions){
|
||||
ut_a(CloseHandle(event->handle));
|
||||
} else /*Windows with condition variables */
|
||||
#endif
|
||||
{
|
||||
os_fast_mutex_free(&(event->os_mutex));
|
||||
|
||||
os_cond_destroy(&(event->cond_var));
|
||||
}
|
||||
|
||||
/* Remove from the list of events */
|
||||
|
||||
os_mutex_enter(os_sync_mutex);
|
||||
@ -358,24 +589,25 @@ os_event_wait_low(
|
||||
returned by previous call of
|
||||
os_event_reset(). */
|
||||
{
|
||||
#ifdef __WIN__
|
||||
DWORD err;
|
||||
|
||||
ut_a(event);
|
||||
|
||||
UT_NOT_USED(reset_sig_count);
|
||||
|
||||
/* Specify an infinite time limit for waiting */
|
||||
err = WaitForSingleObject(event->handle, INFINITE);
|
||||
|
||||
ut_a(err == WAIT_OBJECT_0);
|
||||
|
||||
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
|
||||
os_thread_exit(NULL);
|
||||
}
|
||||
#else
|
||||
|
||||
ib_int64_t old_signal_count;
|
||||
|
||||
#ifdef __WIN__
|
||||
if(!srv_use_native_conditions) {
|
||||
DWORD err;
|
||||
|
||||
ut_a(event);
|
||||
|
||||
UT_NOT_USED(reset_sig_count);
|
||||
|
||||
/* Specify an infinite wait */
|
||||
err = WaitForSingleObject(event->handle, INFINITE);
|
||||
|
||||
ut_a(err == WAIT_OBJECT_0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
os_fast_mutex_lock(&(event->os_mutex));
|
||||
|
||||
if (reset_sig_count) {
|
||||
@ -399,13 +631,12 @@ os_event_wait_low(
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_cond_wait(&(event->cond_var), &(event->os_mutex));
|
||||
os_cond_wait(&(event->cond_var), &(event->os_mutex));
|
||||
|
||||
/* Solaris manual said that spurious wakeups may occur: we
|
||||
have to check if the event really has been signaled after
|
||||
we came here to wait */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**********************************************************//**
|
||||
@ -414,112 +645,112 @@ a timeout is exceeded.
|
||||
@return 0 if success, OS_SYNC_TIME_EXCEEDED if timeout was exceeded */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
os_event_wait_time(
|
||||
/*===============*/
|
||||
os_event_t event, /*!< in: event to wait */
|
||||
ulint wtime) /*!< in: timeout in microseconds, or
|
||||
OS_SYNC_INFINITE_TIME */
|
||||
os_event_wait_time_low(
|
||||
/*===================*/
|
||||
os_event_t event, /*!< in: event to wait */
|
||||
ulint time_in_usec, /*!< in: timeout in
|
||||
microseconds, or
|
||||
OS_SYNC_INFINITE_TIME */
|
||||
ib_int64_t reset_sig_count) /*!< in: zero or the value
|
||||
returned by previous call of
|
||||
os_event_reset(). */
|
||||
|
||||
{
|
||||
ibool timed_out = FALSE;
|
||||
|
||||
#ifdef __WIN__
|
||||
DWORD err;
|
||||
DWORD time_in_ms;
|
||||
|
||||
ut_a(event);
|
||||
if (!srv_use_native_conditions) {
|
||||
DWORD err;
|
||||
|
||||
if (wtime != OS_SYNC_INFINITE_TIME) {
|
||||
err = WaitForSingleObject(event->handle, (DWORD) wtime / 1000);
|
||||
} else {
|
||||
err = WaitForSingleObject(event->handle, INFINITE);
|
||||
}
|
||||
ut_a(event);
|
||||
|
||||
if (err == WAIT_OBJECT_0) {
|
||||
if (time_in_usec != OS_SYNC_INFINITE_TIME) {
|
||||
time_in_ms = time_in_usec / 1000;
|
||||
err = WaitForSingleObject(event->handle, time_in_ms);
|
||||
} else {
|
||||
err = WaitForSingleObject(event->handle, INFINITE);
|
||||
}
|
||||
|
||||
return(0);
|
||||
} else if (err == WAIT_TIMEOUT) {
|
||||
if (err == WAIT_OBJECT_0) {
|
||||
return(0);
|
||||
} else if ((err == WAIT_TIMEOUT) || (err == ERROR_TIMEOUT)) {
|
||||
return(OS_SYNC_TIME_EXCEEDED);
|
||||
}
|
||||
|
||||
return(OS_SYNC_TIME_EXCEEDED);
|
||||
} else {
|
||||
ut_error;
|
||||
return(1000000); /* dummy value to eliminate compiler warn. */
|
||||
}
|
||||
#else
|
||||
int err;
|
||||
int ret = 0;
|
||||
ulint tmp;
|
||||
ib_int64_t old_count;
|
||||
struct timeval tv_start;
|
||||
struct timespec timeout;
|
||||
/* Dummy value to eliminate compiler warning. */
|
||||
return(42);
|
||||
} else {
|
||||
ut_a(sleep_condition_variable != NULL);
|
||||
|
||||
if (wtime == OS_SYNC_INFINITE_TIME) {
|
||||
os_event_wait(event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute the absolute point in time at which to time out. */
|
||||
gettimeofday(&tv_start, NULL);
|
||||
tmp = tv_start.tv_usec + wtime;
|
||||
timeout.tv_sec = tv_start.tv_sec + (tmp / 1000000);
|
||||
timeout.tv_nsec = (tmp % 1000000) * 1000;
|
||||
|
||||
os_fast_mutex_lock(&(event->os_mutex));
|
||||
old_count = event->signal_count;
|
||||
|
||||
for (;;) {
|
||||
if (event->is_set == TRUE || event->signal_count != old_count)
|
||||
break;
|
||||
|
||||
err = pthread_cond_timedwait(&(event->cond_var),
|
||||
&(event->os_mutex), &timeout);
|
||||
if (err == ETIMEDOUT) {
|
||||
ret = OS_SYNC_TIME_EXCEEDED;
|
||||
break;
|
||||
if (time_in_usec != OS_SYNC_INFINITE_TIME) {
|
||||
time_in_ms = time_in_usec / 1000;
|
||||
} else {
|
||||
time_in_ms = INFINITE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct timespec abstime;
|
||||
|
||||
os_fast_mutex_unlock(&(event->os_mutex));
|
||||
if (time_in_usec != OS_SYNC_INFINITE_TIME) {
|
||||
struct timeval tv;
|
||||
int ret;
|
||||
ulint sec;
|
||||
ulint usec;
|
||||
|
||||
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
|
||||
ret = ut_usectime(&sec, &usec);
|
||||
ut_a(ret == 0);
|
||||
|
||||
os_thread_exit(NULL);
|
||||
tv.tv_sec = sec;
|
||||
tv.tv_usec = usec;
|
||||
|
||||
tv.tv_usec += time_in_usec;
|
||||
|
||||
if ((ulint) tv.tv_usec >= MICROSECS_IN_A_SECOND) {
|
||||
tv.tv_sec += time_in_usec / MICROSECS_IN_A_SECOND;
|
||||
tv.tv_usec %= MICROSECS_IN_A_SECOND;
|
||||
}
|
||||
|
||||
abstime.tv_sec = tv.tv_sec;
|
||||
abstime.tv_nsec = tv.tv_usec * 1000;
|
||||
} else {
|
||||
abstime.tv_nsec = 999999999;
|
||||
abstime.tv_sec = (time_t) ULINT_MAX;
|
||||
}
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
ut_a(abstime.tv_nsec <= 999999999);
|
||||
|
||||
#ifdef __WIN__
|
||||
/**********************************************************//**
|
||||
Waits for any event in an OS native event array. Returns if even a single
|
||||
one is signaled or becomes signaled.
|
||||
@return index of the event which was signaled */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
os_event_wait_multiple(
|
||||
/*===================*/
|
||||
ulint n, /*!< in: number of events in the
|
||||
array */
|
||||
os_native_event_t* native_event_array)
|
||||
/*!< in: pointer to an array of event
|
||||
handles */
|
||||
{
|
||||
DWORD index;
|
||||
#endif /* __WIN__ */
|
||||
|
||||
ut_a(native_event_array);
|
||||
ut_a(n > 0);
|
||||
os_fast_mutex_lock(&event->os_mutex);
|
||||
|
||||
index = WaitForMultipleObjects((DWORD) n, native_event_array,
|
||||
FALSE, /* Wait for any 1 event */
|
||||
INFINITE); /* Infinite wait time
|
||||
limit */
|
||||
ut_a(index >= WAIT_OBJECT_0); /* NOTE: Pointless comparison */
|
||||
ut_a(index < WAIT_OBJECT_0 + n);
|
||||
|
||||
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
|
||||
os_thread_exit(NULL);
|
||||
if (!reset_sig_count) {
|
||||
reset_sig_count = event->signal_count;
|
||||
}
|
||||
|
||||
return(index - WAIT_OBJECT_0);
|
||||
do {
|
||||
if (event->is_set || event->signal_count != reset_sig_count) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
timed_out = os_cond_wait_timed(
|
||||
&event->cond_var, &event->os_mutex,
|
||||
#ifndef __WIN__
|
||||
&abstime
|
||||
#else
|
||||
time_in_ms
|
||||
#endif /* !__WIN__ */
|
||||
);
|
||||
|
||||
} while (!timed_out);
|
||||
|
||||
os_fast_mutex_unlock(&event->os_mutex);
|
||||
|
||||
return(timed_out ? OS_SYNC_TIME_EXCEEDED : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************//**
|
||||
Creates an operating system mutex semaphore. Because these are slow, the
|
||||
@ -532,15 +763,6 @@ os_mutex_create(
|
||||
const char* name) /*!< in: the name of the mutex, if NULL
|
||||
the mutex is created without a name */
|
||||
{
|
||||
#ifdef __WIN__
|
||||
HANDLE mutex;
|
||||
os_mutex_t mutex_str;
|
||||
|
||||
mutex = CreateMutex(NULL, /* No security attributes */
|
||||
FALSE, /* Initial state: no owner */
|
||||
(LPCTSTR) name);
|
||||
ut_a(mutex);
|
||||
#else
|
||||
os_fast_mutex_t* mutex;
|
||||
os_mutex_t mutex_str;
|
||||
|
||||
@ -549,7 +771,6 @@ os_mutex_create(
|
||||
mutex = ut_malloc(sizeof(os_fast_mutex_t));
|
||||
|
||||
os_fast_mutex_init(mutex);
|
||||
#endif
|
||||
mutex_str = ut_malloc(sizeof(os_mutex_str_t));
|
||||
|
||||
mutex_str->handle = mutex;
|
||||
@ -580,25 +801,11 @@ os_mutex_enter(
|
||||
/*===========*/
|
||||
os_mutex_t mutex) /*!< in: mutex to acquire */
|
||||
{
|
||||
#ifdef __WIN__
|
||||
DWORD err;
|
||||
|
||||
ut_a(mutex);
|
||||
|
||||
/* Specify infinite time limit for waiting */
|
||||
err = WaitForSingleObject(mutex->handle, INFINITE);
|
||||
|
||||
ut_a(err == WAIT_OBJECT_0);
|
||||
|
||||
(mutex->count)++;
|
||||
ut_a(mutex->count == 1);
|
||||
#else
|
||||
os_fast_mutex_lock(mutex->handle);
|
||||
|
||||
(mutex->count)++;
|
||||
|
||||
ut_a(mutex->count == 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**********************************************************//**
|
||||
@ -614,11 +821,7 @@ os_mutex_exit(
|
||||
ut_a(mutex->count == 1);
|
||||
|
||||
(mutex->count)--;
|
||||
#ifdef __WIN__
|
||||
ut_a(ReleaseMutex(mutex->handle));
|
||||
#else
|
||||
os_fast_mutex_unlock(mutex->handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**********************************************************//**
|
||||
@ -647,15 +850,9 @@ os_mutex_free(
|
||||
os_mutex_exit(os_sync_mutex);
|
||||
}
|
||||
|
||||
#ifdef __WIN__
|
||||
ut_a(CloseHandle(mutex->handle));
|
||||
|
||||
ut_free(mutex);
|
||||
#else
|
||||
os_fast_mutex_free(mutex->handle);
|
||||
ut_free(mutex->handle);
|
||||
ut_free(mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************************************************//**
|
||||
|
@ -139,6 +139,20 @@ UNIV_INTERN ulint srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX;
|
||||
/** Place locks to records only i.e. do not use next-key locking except
|
||||
on duplicate key checking and foreign key checking */
|
||||
UNIV_INTERN ibool srv_locks_unsafe_for_binlog = FALSE;
|
||||
#ifdef __WIN__
|
||||
/* Windows native condition variables. We use runtime loading / function
|
||||
pointers, because they are not available on Windows Server 2003 and
|
||||
Windows XP/2000.
|
||||
|
||||
We use condition for events on Windows if possible, even if os_event
|
||||
resembles Windows kernel event object well API-wise. The reason is
|
||||
performance, kernel objects are heavyweights and WaitForSingleObject() is a
|
||||
performance killer causing calling thread to context switch. Besides, Innodb
|
||||
is preallocating large number (often millions) of os_events. With kernel event
|
||||
objects it takes a big chunk out of non-paged pool, which is better suited
|
||||
for tasks like IO than for storing idle event objects. */
|
||||
UNIV_INTERN ibool srv_use_native_conditions = FALSE;
|
||||
#endif /* __WIN__ */
|
||||
|
||||
UNIV_INTERN ulint srv_n_data_files = 0;
|
||||
UNIV_INTERN char** srv_data_file_names = NULL;
|
||||
|
@ -1265,6 +1265,7 @@ innobase_start_or_create_for_mysql(void)
|
||||
case OS_WIN95:
|
||||
case OS_WIN31:
|
||||
case OS_WINNT:
|
||||
srv_use_native_conditions = FALSE;
|
||||
/* On Win 95, 98, ME, Win32 subsystem for Windows 3.1,
|
||||
and NT use simulated aio. In NT Windows provides async i/o,
|
||||
but when run in conjunction with InnoDB Hot Backup, it seemed
|
||||
@ -1272,24 +1273,26 @@ innobase_start_or_create_for_mysql(void)
|
||||
|
||||
os_aio_use_native_aio = FALSE;
|
||||
break;
|
||||
default:
|
||||
/* On Win 2000 and XP use async i/o */
|
||||
//os_aio_use_native_aio = TRUE;
|
||||
os_aio_use_native_aio = FALSE;
|
||||
fprintf(stderr,
|
||||
"InnoDB: Windows native async i/o is disabled as default.\n"
|
||||
"InnoDB: It is not applicable for the current"
|
||||
" multi io threads implementation.\n");
|
||||
break;
|
||||
|
||||
case OS_WIN2000:
|
||||
case OS_WINXP:
|
||||
/* On 2000 and XP, async IO is available, but no condition variables. */
|
||||
os_aio_use_native_aio = TRUE;
|
||||
srv_use_native_conditions = FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
os_aio_use_native_aio = TRUE;
|
||||
srv_use_native_conditions = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (srv_file_flush_method_str == NULL) {
|
||||
/* These are the default options */
|
||||
|
||||
srv_unix_file_flush_method = SRV_UNIX_FSYNC;
|
||||
|
||||
srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
|
||||
#ifndef __WIN__
|
||||
} else if (0 == ut_strcmp(srv_file_flush_method_str, "fsync")) {
|
||||
srv_unix_file_flush_method = SRV_UNIX_FSYNC;
|
||||
|
||||
@ -1307,7 +1310,7 @@ innobase_start_or_create_for_mysql(void)
|
||||
|
||||
} else if (0 == ut_strcmp(srv_file_flush_method_str, "nosync")) {
|
||||
srv_unix_file_flush_method = SRV_UNIX_NOSYNC;
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
} else if (0 == ut_strcmp(srv_file_flush_method_str, "normal")) {
|
||||
srv_win_file_flush_method = SRV_WIN_IO_NORMAL;
|
||||
os_aio_use_native_aio = FALSE;
|
||||
@ -1315,16 +1318,10 @@ innobase_start_or_create_for_mysql(void)
|
||||
} else if (0 == ut_strcmp(srv_file_flush_method_str, "unbuffered")) {
|
||||
srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
|
||||
os_aio_use_native_aio = FALSE;
|
||||
|
||||
} else if (0 == ut_strcmp(srv_file_flush_method_str,
|
||||
"async_unbuffered")) {
|
||||
srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
|
||||
os_aio_use_native_aio = TRUE;
|
||||
srv_n_read_io_threads = srv_n_write_io_threads = 1;
|
||||
fprintf(stderr,
|
||||
"InnoDB: 'async_unbuffered' was detected as innodb_flush_method.\n"
|
||||
"InnoDB: Windows native async i/o is enabled.\n"
|
||||
"InnoDB: And io threads are restricted.\n");
|
||||
#endif
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
|
Loading…
x
Reference in New Issue
Block a user