📄 os0file.c
字号:
/******************************************************The interface to the operating system file i/o primitives(c) 1995 Innobase OyCreated 10/21/1995 Heikki Tuuri*******************************************************/#include "os0file.h"#include "os0sync.h"#include "os0thread.h"#include "ut0mem.h"#include "srv0srv.h"#include "srv0start.h"#include "fil0fil.h"#include "buf0buf.h"#if defined(UNIV_HOTBACKUP) && defined(__WIN__)/* Add includes for the _stat() call to compile on Windows */#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#endif /* UNIV_HOTBACKUP */#undef HAVE_FDATASYNC#ifdef POSIX_ASYNC_IO/* We assume in this case that the OS has standard Posix aio (at least SunOS2.6, HP-UX 11i and AIX 4.3 have) */#endif/* This specifies the file permissions InnoDB uses when it creates files inUnix; the value of os_innodb_umask is initialized in ha_innodb.cc tomy_umask */#ifndef __WIN__ulint os_innodb_umask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;#elseulint os_innodb_umask = 0;#endif#ifdef UNIV_DO_FLUSH/* If the following is set to TRUE, we do not call os_file_flush in everyos_file_write. We can set this TRUE when the doublewrite buffer is used. */ibool os_do_not_call_flush_at_each_write = FALSE;#else/* We do not call os_file_flush in every os_file_write. */#endif /* UNIV_DO_FLUSH *//* We use these mutexes to protect lseek + file i/o operation, if theOS does not provide an atomic pread or pwrite, or similar */#define OS_FILE_N_SEEK_MUTEXES 16os_mutex_t os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES];/* In simulated aio, merge at most this many consecutive i/os */#define OS_AIO_MERGE_N_CONSECUTIVE 64/* If this flag is TRUE, then we will use the native aio of theOS (provided we compiled Innobase with it in), otherwise we willuse simulated aio we build below with threads */ibool os_aio_use_native_aio = FALSE;ibool os_aio_print_debug = FALSE;/* The aio array slot structure */typedef struct os_aio_slot_struct os_aio_slot_t;struct os_aio_slot_struct{ ibool is_read; /* TRUE if a read operation */ ulint pos; /* index of the slot in the aio array */ ibool reserved; /* TRUE if this slot is reserved */ time_t reservation_time;/* time when reserved */ ulint len; /* length of the block to read or write */ byte* buf; /* buffer used in i/o */ ulint type; /* OS_FILE_READ or OS_FILE_WRITE */ ulint offset; /* 32 low bits of file offset in bytes */ ulint offset_high; /* 32 high bits of file offset */ os_file_t file; /* file where to read or write */ const char* name; /* file name or path */ ibool io_already_done;/* used only in simulated aio: TRUE if the physical i/o already made and only the slot message needs to be passed to the caller of os_aio_simulated_handle */ fil_node_t* message1; /* message which is given by the */ void* message2; /* the requester of an aio operation 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 */#elif defined(POSIX_ASYNC_IO) struct aiocb control; /* Posix control block for aio request */#endif};/* The aio array structure */typedef struct os_aio_array_struct os_aio_array_t;struct os_aio_array_struct{ os_mutex_t mutex; /* the mutex protecting the aio array */ os_event_t not_full; /* The event which is set to the signaled state when there is space in the aio outside the ibuf segment */ os_event_t is_empty; /* The event which is set to the signaled state when there are no pending i/os in this array */ ulint n_slots; /* Total number of slots in the aio array. This must be divisible by n_threads. */ ulint n_segments;/* Number of segments in the aio array of pending aio requests. A thread can wait separately for any one of the segments. */ ulint n_reserved;/* 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 */os_event_t* os_aio_segment_wait_events = NULL;/* The aio arrays for non-ibuf i/o and ibuf i/o, as well as sync aio. Theseare NULL when the module has not yet been initialized. */static os_aio_array_t* os_aio_read_array = NULL;static os_aio_array_t* os_aio_write_array = NULL;static os_aio_array_t* os_aio_ibuf_array = NULL;static os_aio_array_t* os_aio_log_array = NULL;static os_aio_array_t* os_aio_sync_array = NULL;static ulint os_aio_n_segments = ULINT_UNDEFINED;/* If the following is TRUE, read i/o handler threads try towait until a batch of new read requests have been posted */static ibool os_aio_recommend_sleep_for_read_threads = FALSE;ulint os_n_file_reads = 0;ulint os_bytes_read_since_printout = 0;ulint os_n_file_writes = 0;ulint os_n_fsyncs = 0;ulint os_n_file_reads_old = 0;ulint os_n_file_writes_old = 0;ulint os_n_fsyncs_old = 0;time_t os_last_printout;ibool os_has_said_disk_full = FALSE;/* The mutex protecting the following counts of pending I/O operations */static os_mutex_t os_file_count_mutex;ulint os_file_n_pending_preads = 0;ulint os_file_n_pending_pwrites = 0;ulint os_n_pending_writes = 0;ulint os_n_pending_reads = 0;/***************************************************************************Gets the operating system version. Currently works only on Windows. */ulintos_get_os_version(void)/*===================*/ /* out: OS_WIN95, OS_WIN31, OS_WINNT, OS_WIN2000 */{#ifdef __WIN__ OSVERSIONINFO os_info; os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); ut_a(GetVersionEx(&os_info)); if (os_info.dwPlatformId == VER_PLATFORM_WIN32s) { return(OS_WIN31); } 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); } } else { ut_error; return(0); }#else ut_error; return(0);#endif}/***************************************************************************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 mayoverwrite the error number). If the number is not known to this program,the OS error number + 100 is returned. */ulintos_file_get_last_error(/*===================*/ /* out: error number, or OS error number + 100 */ ibool report_all_errors) /* in: TRUE if we want an error message printed of all errors */{ ulint err;#ifdef __WIN__ err = (ulint) GetLastError(); if (report_all_errors || (err != ERROR_DISK_FULL && err != ERROR_FILE_EXISTS)) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Operating system error number %lu in a file operation.\n", (ulong) err); if (err == ERROR_PATH_NOT_FOUND) { fprintf(stderr, "InnoDB: The error means the system cannot find the path specified.\n"); if (srv_is_being_started) { fprintf(stderr, "InnoDB: If you are installing InnoDB, remember that you must create\n" "InnoDB: directories yourself, InnoDB does not create them.\n"); } } else if (err == ERROR_ACCESS_DENIED) { fprintf(stderr, "InnoDB: The error means mysqld does not have the access rights to\n" "InnoDB: the directory. It may also be you have created a subdirectory\n" "InnoDB: of the same name as a data file.\n"); } else { fprintf(stderr, "InnoDB: Some operating system error numbers are described at\n" "InnoDB: " "http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n"); } } fflush(stderr); if (err == ERROR_FILE_NOT_FOUND) { return(OS_FILE_NOT_FOUND); } else if (err == ERROR_DISK_FULL) { return(OS_FILE_DISK_FULL); } else if (err == ERROR_FILE_EXISTS) { return(OS_FILE_ALREADY_EXISTS); } else { return(100 + err); }#else err = (ulint) errno; if (report_all_errors || (err != ENOSPC && err != EEXIST)) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Operating system error number %lu in a file operation.\n", (ulong) err); if (err == ENOENT) { fprintf(stderr, "InnoDB: The error means the system cannot find the path specified.\n"); if (srv_is_being_started) { fprintf(stderr, "InnoDB: If you are installing InnoDB, remember that you must create\n" "InnoDB: directories yourself, InnoDB does not create them.\n"); } } else if (err == EACCES) { fprintf(stderr, "InnoDB: The error means mysqld does not have the access rights to\n" "InnoDB: the directory.\n"); } else { if (strerror((int)err) != NULL) { fprintf(stderr, "InnoDB: Error number %lu means '%s'.\n", err, strerror((int)err)); } fprintf(stderr, "InnoDB: Some operating system error numbers are described at\n" "InnoDB: " "http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n"); } } fflush(stderr); if (err == ENOSPC ) { return(OS_FILE_DISK_FULL);#ifdef POSIX_ASYNC_IO } else if (err == EAGAIN) { return(OS_FILE_AIO_RESOURCES_RESERVED);#endif } else if (err == ENOENT) { return(OS_FILE_NOT_FOUND); } else if (err == EEXIST) { return(OS_FILE_ALREADY_EXISTS); } else if (err == EXDEV || err == ENOTDIR || err == EISDIR) { return(OS_FILE_PATH_ERROR); } else { return(100 + err); }#endif}/********************************************************************Does error handling when a file operation fails. */staticiboolos_file_handle_error(/*=================*/ /* out: TRUE if we should retry the operation */ const char* name, /* in: name of a file or NULL */ const char* operation)/* in: operation */{ ulint err; err = os_file_get_last_error(FALSE); if (err == OS_FILE_DISK_FULL) { /* We only print a warning about disk full once */ if (os_has_said_disk_full) { return(FALSE); } if (name) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Encountered a problem with file %s\n", name); } ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Disk is full. Try to clean the disk to free space.\n"); os_has_said_disk_full = TRUE; fflush(stderr); return(FALSE); } else if (err == OS_FILE_AIO_RESOURCES_RESERVED) { return(TRUE); } else if (err == OS_FILE_ALREADY_EXISTS || err == OS_FILE_PATH_ERROR) { return(FALSE); } else { if (name) { fprintf(stderr, "InnoDB: File name %s\n", name); } fprintf(stderr, "InnoDB: File operation call: '%s'.\n", operation); fprintf(stderr, "InnoDB: Cannot continue operation.\n"); fflush(stderr); exit(1); } return(FALSE); }#undef USE_FILE_LOCK#define USE_FILE_LOCK#if defined(UNIV_HOTBACKUP) || defined(__WIN__) || defined(__FreeBSD__) || defined(__NETWARE__)/* InnoDB Hot Backup does not lock the data files. * On Windows, mandatory locking is used. * On FreeBSD with LinuxThreads, advisory locking does not work properly. */# undef USE_FILE_LOCK#endif#ifdef USE_FILE_LOCK/********************************************************************Obtain an exclusive lock on a file. */staticintos_file_lock(/*=========*/ /* out: 0 on success */ int fd, /* in: file descriptor */ const char* name) /* in: file name */{ struct flock lk; lk.l_type = F_WRLCK; lk.l_whence = SEEK_SET; lk.l_start = lk.l_len = 0; if (fcntl(fd, F_SETLK, &lk) == -1) { fprintf(stderr, "InnoDB: Unable to lock %s, error: %d\n", name, errno); if (errno == EAGAIN || errno == EACCES) { fprintf(stderr,"InnoDB: Check that you do not already have another mysqld process\n""InnoDB: using the same InnoDB data or log files.\n"); } return(-1); } return(0);}#endif /* USE_FILE_LOCK *//********************************************************************Does error handling when a file operation fails. */staticiboolos_file_handle_error_no_exit(/*=========================*/ /* out: TRUE if we should retry the operation */ const char* name, /* in: name of a file or NULL */ const char* operation)/* in: operation */{ ulint err; err = os_file_get_last_error(FALSE); if (err == OS_FILE_DISK_FULL) { /* We only print a warning about disk full once */ if (os_has_said_disk_full) { return(FALSE); } if (name) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Encountered a problem with file %s\n", name); } ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Disk is full. Try to clean the disk to free space.\n"); os_has_said_disk_full = TRUE; fflush(stderr); return(FALSE); } else if (err == OS_FILE_AIO_RESOURCES_RESERVED) { return(TRUE); } else if (err == OS_FILE_ALREADY_EXISTS || err == OS_FILE_PATH_ERROR) { return(FALSE); } else { if (name) { fprintf(stderr, "InnoDB: File name %s\n", name); } fprintf(stderr, "InnoDB: File operation call: '%s'.\n", operation); return (FALSE); } return(FALSE); /* not reached */}/********************************************************************Creates the seek mutexes used in positioned reads and writes. */voidos_io_init_simple(void)/*===================*/{ ulint i; os_file_count_mutex = os_mutex_create(NULL); for (i = 0; i < OS_FILE_N_SEEK_MUTEXES; i++) { os_file_seek_mutexes[i] = os_mutex_create(NULL); }}#if !defined(UNIV_HOTBACKUP) && !defined(__NETWARE__)/*************************************************************************Creates a temporary file. This function is defined in ha_innodb.cc. */intinnobase_mysql_tmpfile(void);/*========================*/ /* out: temporary file descriptor, or < 0 on error */#endif /* !UNIV_HOTBACKUP && !__NETWARE__ *//***************************************************************************Creates a temporary file. */FILE*os_file_create_tmpfile(void)/*========================*/ /* out: temporary file handle, or NULL on error */{#ifdef __NETWARE__ FILE* file = tmpfile();#else /* __NETWARE__ */ FILE* file = NULL; int fd = -1;# ifdef UNIV_HOTBACKUP int tries; for (tries = 10; tries--; ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -