Drizzled Public API Documentation

os0file.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1995, 2010, Innobase Oy. All Rights Reserved.
00004 Copyright (C) 2009, Percona Inc.
00005 
00006 Portions of this file contain modifications contributed and copyrighted
00007 by Percona Inc.. Those modifications are
00008 gratefully acknowledged and are described briefly in the InnoDB
00009 documentation. The contributions by Percona Inc. are incorporated with
00010 their permission, and subject to the conditions contained in the file
00011 COPYING.Percona.
00012 
00013 This program is free software; you can redistribute it and/or modify it under
00014 the terms of the GNU General Public License as published by the Free Software
00015 Foundation; version 2 of the License.
00016 
00017 This program is distributed in the hope that it will be useful, but WITHOUT
00018 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00019 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License along with
00022 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00023 St, Fifth Floor, Boston, MA 02110-1301 USA
00024 
00025 *****************************************************************************/
00026 
00027 /**************************************************/
00034 #include "os0file.h"
00035 
00036 #ifdef UNIV_NONINL
00037 #include "os0file.ic"
00038 #endif
00039 
00040 #include "ut0mem.h"
00041 #include "srv0srv.h"
00042 #include "srv0start.h"
00043 #include "fil0fil.h"
00044 #include "buf0buf.h"
00045 #include <errno.h>
00046 #include <fcntl.h>
00047 #include <limits.h>
00048 #include <unistd.h>
00049 #ifndef UNIV_HOTBACKUP
00050 # include "os0sync.h"
00051 # include "os0thread.h"
00052 #else /* !UNIV_HOTBACKUP */
00053 # ifdef __WIN__
00054 /* Add includes for the _stat() call to compile on Windows */
00055 #  include <sys/types.h>
00056 #  include <sys/stat.h>
00057 # endif /* __WIN__ */
00058 #endif /* !UNIV_HOTBACKUP */
00059 
00060 #if defined(LINUX_NATIVE_AIO)
00061 #include <libaio.h>
00062 #endif
00063 
00064 /* This specifies the file permissions InnoDB uses when it creates files in
00065 Unix; the value of os_innodb_umask is initialized in ha_innodb.cc to
00066 my_umask */
00067 
00068 #ifndef __WIN__
00069 
00070 UNIV_INTERN ulint os_innodb_umask
00071       = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
00072 #else
00073 
00074 UNIV_INTERN ulint os_innodb_umask   = 0;
00075 #endif
00076 
00077 #ifdef UNIV_DO_FLUSH
00078 /* If the following is set to TRUE, we do not call os_file_flush in every
00079 os_file_write. We can set this TRUE when the doublewrite buffer is used. */
00080 UNIV_INTERN ibool os_do_not_call_flush_at_each_write  = FALSE;
00081 #else
00082 /* We do not call os_file_flush in every os_file_write. */
00083 #endif /* UNIV_DO_FLUSH */
00084 
00085 #ifndef UNIV_HOTBACKUP
00086 /* We use these mutexes to protect lseek + file i/o operation, if the
00087 OS does not provide an atomic pread or pwrite, or similar */
00088 #define OS_FILE_N_SEEK_MUTEXES  16
00089 UNIV_INTERN os_mutex_t  os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES];
00090 
00091 /* In simulated aio, merge at most this many consecutive i/os */
00092 #define OS_AIO_MERGE_N_CONSECUTIVE  64
00093 
00094 /**********************************************************************
00095 
00096 InnoDB AIO Implementation:
00097 =========================
00098 
00099 We support native AIO for windows and linux. For rest of the platforms
00100 we simulate AIO by special io-threads servicing the IO-requests.
00101 
00102 Simulated AIO:
00103 ==============
00104 
00105 In platforms where we 'simulate' AIO following is a rough explanation
00106 of the high level design.
00107 There are four io-threads (for ibuf, log, read, write).
00108 All synchronous IO requests are serviced by the calling thread using
00109 os_file_write/os_file_read. The Asynchronous requests are queued up
00110 in an array (there are four such arrays) by the calling thread. 
00111 Later these requests are picked up by the io-thread and are serviced
00112 synchronously.
00113 
00114 Windows native AIO:
00115 ==================
00116 
00117 If srv_use_native_aio is not set then windows follow the same
00118 code as simulated AIO. If the flag is set then native AIO interface
00119 is used. On windows, one of the limitation is that if a file is opened
00120 for AIO no synchronous IO can be done on it. Therefore we have an
00121 extra fifth array to queue up synchronous IO requests.
00122 There are innodb_file_io_threads helper threads. These threads work
00123 on the four arrays mentioned above in Simulated AIO. No thread is
00124 required for the sync array.
00125 If a synchronous IO request is made, it is first queued in the sync
00126 array. Then the calling thread itself waits on the request, thus
00127 making the call synchronous.
00128 If an AIO request is made the calling thread not only queues it in the
00129 array but also submits the requests. The helper thread then collects
00130 the completed IO request and calls completion routine on it.
00131 
00132 Linux native AIO:
00133 =================
00134 
00135 If we have libaio installed on the system and innodb_use_native_aio
00136 is set to TRUE we follow the code path of native AIO, otherwise we
00137 do simulated AIO.
00138 There are innodb_file_io_threads helper threads. These threads work
00139 on the four arrays mentioned above in Simulated AIO.
00140 If a synchronous IO request is made, it is handled by calling
00141 os_file_write/os_file_read.
00142 If an AIO request is made the calling thread not only queues it in the
00143 array but also submits the requests. The helper thread then collects
00144 the completed IO request and calls completion routine on it.
00145 
00146 **********************************************************************/
00147 
00149 UNIV_INTERN ibool os_aio_print_debug  = FALSE;
00150 
00151 #ifdef UNIV_PFS_IO
00152 /* Keys to register InnoDB I/O with performance schema */
00153 UNIV_INTERN mysql_pfs_key_t  innodb_file_data_key;
00154 UNIV_INTERN mysql_pfs_key_t  innodb_file_log_key;
00155 UNIV_INTERN mysql_pfs_key_t  innodb_file_temp_key;
00156 #endif /* UNIV_PFS_IO */
00157 
00159 typedef struct os_aio_slot_struct os_aio_slot_t;
00160 
00162 struct os_aio_slot_struct{
00163   ibool   is_read;  
00164   ulint   pos;    
00166   ibool   reserved; 
00167   time_t    reservation_time;
00168   ulint   len;    
00170   byte*   buf;    
00171   ulint   type;   
00172   ulint   offset;   
00174   ulint   offset_high;  
00175   os_file_t file;   
00176   const char* name;   
00177   ibool   io_already_done;
00182   fil_node_t* message1; 
00183   void*   message2; 
00187 #ifdef WIN_ASYNC_IO
00188   HANDLE    handle;   
00190   OVERLAPPED  control;  
00192 #elif defined(LINUX_NATIVE_AIO)
00193   struct iocb control;  /* Linux control block for aio */
00194   int   n_bytes;  /* bytes written/read. */
00195   int   ret;    /* AIO return code */
00196 #endif
00197 };
00198 
00200 typedef struct os_aio_array_struct  os_aio_array_t;
00201 
00203 struct os_aio_array_struct{
00204   os_mutex_t  mutex;  
00205   os_event_t  not_full;
00209   os_event_t  is_empty;
00213   ulint   n_slots;
00216   ulint   n_segments;
00221   ulint   cur_seg;
00225   ulint   n_reserved;
00228   os_aio_slot_t*  slots;  
00229 #ifdef __WIN__
00230   HANDLE*   handles;
00237 #endif
00238 
00239 #if defined(LINUX_NATIVE_AIO)
00240   io_context_t*   aio_ctx;
00241         /* completion queue for IO. There is 
00242         one such queue per segment. Each thread
00243         will work on one ctx exclusively. */
00244   struct io_event*  aio_events;
00245         /* The array to collect completed IOs.
00246         There is one such event for each
00247         possible pending IO. The size of the
00248         array is equal to n_slots. */
00249 #endif
00250 };
00251 
00252 #if defined(LINUX_NATIVE_AIO)
00253 
00254 #define OS_AIO_REAP_TIMEOUT (500000000UL)
00255 
00257 #define OS_AIO_IO_SETUP_RETRY_SLEEP (500000UL)
00258 
00260 #define OS_AIO_IO_SETUP_RETRY_ATTEMPTS  5
00261 #endif
00262 
00264 static os_event_t*  os_aio_segment_wait_events  = NULL;
00265 
00268 static os_aio_array_t*  os_aio_read_array = NULL; 
00269 static os_aio_array_t*  os_aio_write_array  = NULL; 
00270 static os_aio_array_t*  os_aio_ibuf_array = NULL; 
00271 static os_aio_array_t*  os_aio_log_array  = NULL; 
00272 static os_aio_array_t*  os_aio_sync_array = NULL; 
00273 /* @} */
00274 
00276 static ulint  os_aio_n_segments = ULINT_UNDEFINED;
00277 
00280 static ibool  os_aio_recommend_sleep_for_read_threads = FALSE;
00281 #endif /* !UNIV_HOTBACKUP */
00282 
00283 UNIV_INTERN ulint os_n_file_reads   = 0;
00284 UNIV_INTERN ulint os_bytes_read_since_printout = 0;
00285 UNIV_INTERN ulint os_n_file_writes  = 0;
00286 UNIV_INTERN ulint os_n_fsyncs   = 0;
00287 UNIV_INTERN ulint os_n_file_reads_old = 0;
00288 UNIV_INTERN ulint os_n_file_writes_old  = 0;
00289 UNIV_INTERN ulint os_n_fsyncs_old   = 0;
00290 UNIV_INTERN time_t  os_last_printout;
00291 
00292 UNIV_INTERN ibool os_has_said_disk_full = FALSE;
00293 
00294 #ifndef UNIV_HOTBACKUP
00295 
00296 static os_mutex_t os_file_count_mutex;
00297 #endif /* !UNIV_HOTBACKUP */
00298 
00299 UNIV_INTERN ulint os_file_n_pending_preads  = 0;
00301 UNIV_INTERN ulint os_file_n_pending_pwrites = 0;
00303 UNIV_INTERN ulint os_n_pending_writes = 0;
00305 UNIV_INTERN ulint os_n_pending_reads = 0;
00306 
00307 /***********************************************************************/
00311 UNIV_INTERN
00312 ulint
00313 os_get_os_version(void)
00314 /*===================*/
00315 {
00316 #ifdef __WIN__
00317   OSVERSIONINFO   os_info;
00318 
00319   os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
00320 
00321   ut_a(GetVersionEx(&os_info));
00322 
00323   if (os_info.dwPlatformId == VER_PLATFORM_WIN32s) {
00324     return(OS_WIN31);
00325   } else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
00326     return(OS_WIN95);
00327   } else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
00328     switch (os_info.dwMajorVersion) {
00329     case 3:
00330     case 4:
00331       return OS_WINNT;
00332     case 5:
00333       return (os_info.dwMinorVersion == 0) ? OS_WIN2000
00334                    : OS_WINXP;
00335     case 6:
00336       return (os_info.dwMinorVersion == 0) ? OS_WINVISTA
00337                    : OS_WIN7;
00338     default:
00339       return OS_WIN7;
00340     }
00341   } else {
00342     ut_error;
00343     return(0);
00344   }
00345 #else
00346   ut_error;
00347 
00348   return(0);
00349 #endif
00350 }
00351 
00352 /***********************************************************************/
00358 UNIV_INTERN
00359 ulint
00360 os_file_get_last_error(
00361 /*===================*/
00362   ibool report_all_errors)  
00364 {
00365   ulint err;
00366 
00367 #ifdef __WIN__
00368 
00369   err = (ulint) GetLastError();
00370 
00371   if (report_all_errors
00372       || (err != ERROR_DISK_FULL && err != ERROR_FILE_EXISTS)) {
00373 
00374     ut_print_timestamp(stderr);
00375     fprintf(stderr,
00376       "  InnoDB: Operating system error number %lu"
00377       " in a file operation.\n", (ulong) err);
00378 
00379     if (err == ERROR_PATH_NOT_FOUND) {
00380       fprintf(stderr,
00381         "InnoDB: The error means the system"
00382         " cannot find the path specified.\n");
00383 
00384       if (srv_is_being_started) {
00385         fprintf(stderr,
00386           "InnoDB: If you are installing InnoDB,"
00387           " remember that you must create\n"
00388           "InnoDB: directories yourself, InnoDB"
00389           " does not create them.\n");
00390       }
00391     } else if (err == ERROR_ACCESS_DENIED) {
00392       fprintf(stderr,
00393         "InnoDB: The error means mysqld does not have"
00394         " the access rights to\n"
00395         "InnoDB: the directory. It may also be"
00396         " you have created a subdirectory\n"
00397         "InnoDB: of the same name as a data file.\n");
00398     } else if (err == ERROR_SHARING_VIOLATION
00399          || err == ERROR_LOCK_VIOLATION) {
00400       fprintf(stderr,
00401         "InnoDB: The error means that another program"
00402         " is using InnoDB's files.\n"
00403         "InnoDB: This might be a backup or antivirus"
00404         " software or another instance\n"
00405         "InnoDB: of MySQL."
00406         " Please close it to get rid of this error.\n");
00407     } else if (err == ERROR_WORKING_SET_QUOTA
00408          || err == ERROR_NO_SYSTEM_RESOURCES) {
00409       fprintf(stderr,
00410         "InnoDB: The error means that there are no"
00411         " sufficient system resources or quota to"
00412         " complete the operation.\n");
00413     } else if (err == ERROR_OPERATION_ABORTED) {
00414       fprintf(stderr,
00415         "InnoDB: The error means that the I/O"
00416         " operation has been aborted\n"
00417         "InnoDB: because of either a thread exit"
00418         " or an application request.\n"
00419         "InnoDB: Retry attempt is made.\n");
00420     } else {
00421       fprintf(stderr,
00422         "InnoDB: Some operating system error numbers"
00423         " are described at\n"
00424         "InnoDB: "
00425         REFMAN
00426         "operating-system-error-codes.html\n");
00427     }
00428   }
00429 
00430   fflush(stderr);
00431 
00432   if (err == ERROR_FILE_NOT_FOUND) {
00433     return(OS_FILE_NOT_FOUND);
00434   } else if (err == ERROR_DISK_FULL) {
00435     return(OS_FILE_DISK_FULL);
00436   } else if (err == ERROR_FILE_EXISTS) {
00437     return(OS_FILE_ALREADY_EXISTS);
00438   } else if (err == ERROR_SHARING_VIOLATION
00439        || err == ERROR_LOCK_VIOLATION) {
00440     return(OS_FILE_SHARING_VIOLATION);
00441   } else if (err == ERROR_WORKING_SET_QUOTA
00442        || err == ERROR_NO_SYSTEM_RESOURCES) {
00443     return(OS_FILE_INSUFFICIENT_RESOURCE);
00444   } else if (err == ERROR_OPERATION_ABORTED) {
00445     return(OS_FILE_OPERATION_ABORTED);
00446   } else {
00447     return(100 + err);
00448   }
00449 #else
00450   err = (ulint) errno;
00451 
00452   if (report_all_errors
00453       || (err != ENOSPC && err != EEXIST)) {
00454 
00455     ut_print_timestamp(stderr);
00456     fprintf(stderr,
00457       "  InnoDB: Operating system error number %lu"
00458       " in a file operation.\n", (ulong) err);
00459 
00460     if (err == ENOENT) {
00461       fprintf(stderr,
00462         "InnoDB: The error means the system"
00463         " cannot find the path specified.\n");
00464 
00465       if (srv_is_being_started) {
00466         fprintf(stderr,
00467           "InnoDB: If you are installing InnoDB,"
00468           " remember that you must create\n"
00469           "InnoDB: directories yourself, InnoDB"
00470           " does not create them.\n");
00471       }
00472     } else if (err == EACCES) {
00473       fprintf(stderr,
00474         "InnoDB: The error means mysqld does not have"
00475         " the access rights to\n"
00476         "InnoDB: the directory.\n");
00477     } else {
00478       if (strerror((int)err) != NULL) {
00479         fprintf(stderr,
00480           "InnoDB: Error number %lu"
00481           " means '%s'.\n",
00482           err, strerror((int)err));
00483       }
00484 
00485       fprintf(stderr,
00486         "InnoDB: Some operating system"
00487         " error numbers are described at\n"
00488         "InnoDB: "
00489         REFMAN
00490         "operating-system-error-codes.html\n");
00491     }
00492   }
00493 
00494   fflush(stderr);
00495 
00496   switch (err) {
00497   case ENOSPC:
00498     return(OS_FILE_DISK_FULL);
00499   case ENOENT:
00500     return(OS_FILE_NOT_FOUND);
00501   case EEXIST:
00502     return(OS_FILE_ALREADY_EXISTS);
00503   case EXDEV:
00504   case ENOTDIR:
00505   case EISDIR:
00506     return(OS_FILE_PATH_ERROR);
00507   case EAGAIN:
00508     if (srv_use_native_aio) {
00509       return(OS_FILE_AIO_RESOURCES_RESERVED);
00510     }
00511     break;
00512   case EINTR:
00513     if (srv_use_native_aio) {
00514       return(OS_FILE_AIO_INTERRUPTED);
00515     }
00516     break;
00517   }
00518   return(100 + err);
00519 #endif
00520 }
00521 
00522 /****************************************************************/
00527 static
00528 ibool
00529 os_file_handle_error_cond_exit(
00530 /*===========================*/
00531   const char* name,   
00532   const char* operation,  
00533   ibool   should_exit)  
00535 {
00536   ulint err;
00537 
00538   err = os_file_get_last_error(FALSE);
00539 
00540   if (err == OS_FILE_DISK_FULL) {
00541     /* We only print a warning about disk full once */
00542 
00543     if (os_has_said_disk_full) {
00544 
00545       return(FALSE);
00546     }
00547 
00548     if (name) {
00549       ut_print_timestamp(stderr);
00550       fprintf(stderr,
00551         "  InnoDB: Encountered a problem with"
00552         " file %s\n", name);
00553     }
00554 
00555     ut_print_timestamp(stderr);
00556     fprintf(stderr,
00557       "  InnoDB: Disk is full. Try to clean the disk"
00558       " to free space.\n");
00559 
00560     os_has_said_disk_full = TRUE;
00561 
00562     fflush(stderr);
00563 
00564     return(FALSE);
00565   } else if (err == OS_FILE_AIO_RESOURCES_RESERVED) {
00566 
00567     return(TRUE);
00568   } else if (err == OS_FILE_AIO_INTERRUPTED) {
00569 
00570     return(TRUE);
00571   } else if (err == OS_FILE_ALREADY_EXISTS
00572        || err == OS_FILE_PATH_ERROR) {
00573 
00574     return(FALSE);
00575   } else if (err == OS_FILE_SHARING_VIOLATION) {
00576 
00577     os_thread_sleep(10000000);  /* 10 sec */
00578     return(TRUE);
00579   } else if (err == OS_FILE_INSUFFICIENT_RESOURCE) {
00580 
00581     os_thread_sleep(100000);  /* 100 ms */
00582     return(TRUE);
00583   } else if (err == OS_FILE_OPERATION_ABORTED) {
00584 
00585     os_thread_sleep(100000);  /* 100 ms */
00586     return(TRUE);
00587   } else {
00588     if (name) {
00589       fprintf(stderr, "InnoDB: File name %s\n", name);
00590     }
00591 
00592     fprintf(stderr, "InnoDB: File operation call: '%s'.\n",
00593       operation);
00594 
00595     if (should_exit) {
00596       fprintf(stderr, "InnoDB: Cannot continue operation.\n");
00597 
00598       fflush(stderr);
00599 
00600       exit(1);
00601     }
00602   }
00603 
00604   return(FALSE);
00605 }
00606 
00607 /****************************************************************/
00610 static
00611 ibool
00612 os_file_handle_error(
00613 /*=================*/
00614   const char* name, 
00615   const char* operation)
00616 {
00617   /* exit in case of unknown error */
00618   return(os_file_handle_error_cond_exit(name, operation, TRUE));
00619 }
00620 
00621 /****************************************************************/
00624 static
00625 ibool
00626 os_file_handle_error_no_exit(
00627 /*=========================*/
00628   const char* name, 
00629   const char* operation)
00630 {
00631   /* don't exit in case of unknown error */
00632   return(os_file_handle_error_cond_exit(name, operation, FALSE));
00633 }
00634 
00635 #undef USE_FILE_LOCK
00636 #define USE_FILE_LOCK
00637 #if defined(UNIV_HOTBACKUP) || defined(__WIN__)
00638 /* InnoDB Hot Backup does not lock the data files.
00639  * On Windows, mandatory locking is used.
00640  */
00641 # undef USE_FILE_LOCK
00642 #endif
00643 #ifdef USE_FILE_LOCK
00644 /****************************************************************/
00647 static
00648 int
00649 os_file_lock(
00650 /*=========*/
00651   int   fd, 
00652   const char* name) 
00653 {
00654   struct flock lk;
00655 
00656         if (srv_read_only)
00657           return 0;
00658 
00659   lk.l_type = F_WRLCK;
00660   lk.l_whence = SEEK_SET;
00661   lk.l_start = lk.l_len = 0;
00662   if (fcntl(fd, F_SETLK, &lk) == -1) {
00663     fprintf(stderr,
00664       "InnoDB: Unable to lock %s, error: %d\n", name, errno);
00665 
00666     if (errno == EAGAIN || errno == EACCES) {
00667       fprintf(stderr,
00668         "InnoDB: Check that you do not already have"
00669         " another drizzled process\n"
00670         "InnoDB: using the same InnoDB data"
00671         " or log files.\n");
00672     }
00673 
00674     return(-1);
00675   }
00676 
00677   return(0);
00678 }
00679 #endif /* USE_FILE_LOCK */
00680 
00681 #ifndef UNIV_HOTBACKUP
00682 /****************************************************************/
00684 UNIV_INTERN
00685 void
00686 os_io_init_simple(void)
00687 /*===================*/
00688 {
00689   ulint i;
00690 
00691   os_file_count_mutex = os_mutex_create();
00692 
00693   for (i = 0; i < OS_FILE_N_SEEK_MUTEXES; i++) {
00694     os_file_seek_mutexes[i] = os_mutex_create();
00695   }
00696 }
00697 
00698 /***********************************************************************/
00702 UNIV_INTERN
00703 FILE*
00704 os_file_create_tmpfile(void)
00705 /*========================*/
00706 {
00707   FILE* file  = NULL;
00708   int fd  = innobase_mysql_tmpfile();
00709 
00710   if (fd >= 0) {
00711     file = fdopen(fd, "w+b");
00712   }
00713 
00714   if (!file) {
00715     ut_print_timestamp(stderr);
00716     fprintf(stderr,
00717       "  InnoDB: Error: unable to create temporary file;"
00718       " errno: %d\n", errno);
00719     if (fd >= 0) {
00720       close(fd);
00721     }
00722   }
00723 
00724   return(file);
00725 }
00726 #endif /* !UNIV_HOTBACKUP */
00727 
00728 /***********************************************************************/
00734 UNIV_INTERN
00735 os_file_dir_t
00736 os_file_opendir(
00737 /*============*/
00738   const char* dirname,  
00740   ibool   error_is_fatal) 
00745 {
00746   os_file_dir_t   dir;
00747 #ifdef __WIN__
00748   LPWIN32_FIND_DATA lpFindFileData;
00749   char      path[OS_FILE_MAX_PATH + 3];
00750 
00751   ut_a(strlen(dirname) < OS_FILE_MAX_PATH);
00752 
00753   strcpy(path, dirname);
00754   strcpy(path + strlen(path), "\\*");
00755 
00756   /* Note that in Windows opening the 'directory stream' also retrieves
00757   the first entry in the directory. Since it is '.', that is no problem,
00758   as we will skip over the '.' and '..' entries anyway. */
00759 
00760   lpFindFileData = ut_malloc(sizeof(WIN32_FIND_DATA));
00761 
00762   dir = FindFirstFile((LPCTSTR) path, lpFindFileData);
00763 
00764   ut_free(lpFindFileData);
00765 
00766   if (dir == INVALID_HANDLE_VALUE) {
00767 
00768     if (error_is_fatal) {
00769       os_file_handle_error(dirname, "opendir");
00770     }
00771 
00772     return(NULL);
00773   }
00774 
00775   return(dir);
00776 #else
00777   dir = opendir(dirname);
00778 
00779   if (dir == NULL && error_is_fatal) {
00780     os_file_handle_error(dirname, "opendir");
00781   }
00782 
00783   return(dir);
00784 #endif
00785 }
00786 
00787 /***********************************************************************/
00790 UNIV_INTERN
00791 int
00792 os_file_closedir(
00793 /*=============*/
00794   os_file_dir_t dir)  
00795 {
00796 #ifdef __WIN__
00797   BOOL    ret;
00798 
00799   ret = FindClose(dir);
00800 
00801   if (!ret) {
00802     os_file_handle_error_no_exit(NULL, "closedir");
00803 
00804     return(-1);
00805   }
00806 
00807   return(0);
00808 #else
00809   int ret;
00810 
00811   ret = closedir(dir);
00812 
00813   if (ret) {
00814     os_file_handle_error_no_exit(NULL, "closedir");
00815   }
00816 
00817   return(ret);
00818 #endif
00819 }
00820 
00821 /***********************************************************************/
00825 UNIV_INTERN
00826 int
00827 os_file_readdir_next_file(
00828 /*======================*/
00829   const char* dirname,
00830   os_file_dir_t dir,  
00831   os_file_stat_t* info) 
00832 {
00833 #ifdef __WIN__
00834   LPWIN32_FIND_DATA lpFindFileData;
00835   BOOL      ret;
00836 
00837   lpFindFileData = ut_malloc(sizeof(WIN32_FIND_DATA));
00838 next_file:
00839   ret = FindNextFile(dir, lpFindFileData);
00840 
00841   if (ret) {
00842     ut_a(strlen((char *) lpFindFileData->cFileName)
00843          < OS_FILE_MAX_PATH);
00844 
00845     if (strcmp((char *) lpFindFileData->cFileName, ".") == 0
00846         || strcmp((char *) lpFindFileData->cFileName, "..") == 0) {
00847 
00848       goto next_file;
00849     }
00850 
00851     strcpy(info->name, (char *) lpFindFileData->cFileName);
00852 
00853     info->size = (ib_int64_t)(lpFindFileData->nFileSizeLow)
00854       + (((ib_int64_t)(lpFindFileData->nFileSizeHigh))
00855          << 32);
00856 
00857     if (lpFindFileData->dwFileAttributes
00858         & FILE_ATTRIBUTE_REPARSE_POINT) {
00859       /* TODO: test Windows symlinks */
00860       /* TODO: MySQL has apparently its own symlink
00861       implementation in Windows, dbname.sym can
00862       redirect a database directory:
00863       REFMAN "windows-symbolic-links.html" */
00864       info->type = OS_FILE_TYPE_LINK;
00865     } else if (lpFindFileData->dwFileAttributes
00866          & FILE_ATTRIBUTE_DIRECTORY) {
00867       info->type = OS_FILE_TYPE_DIR;
00868     } else {
00869       /* It is probably safest to assume that all other
00870       file types are normal. Better to check them rather
00871       than blindly skip them. */
00872 
00873       info->type = OS_FILE_TYPE_FILE;
00874     }
00875   }
00876 
00877   ut_free(lpFindFileData);
00878 
00879   if (ret) {
00880     return(0);
00881   } else if (GetLastError() == ERROR_NO_MORE_FILES) {
00882 
00883     return(1);
00884   } else {
00885     os_file_handle_error_no_exit(dirname,
00886                "readdir_next_file");
00887     return(-1);
00888   }
00889 #else
00890   struct dirent*  ent;
00891   char*   full_path;
00892   int   ret;
00893   struct stat statinfo;
00894 #ifdef HAVE_READDIR_R
00895   char    dirent_buf[sizeof(struct dirent)
00896            + _POSIX_PATH_MAX + 100];
00897   /* In /mysys/my_lib.c, _POSIX_PATH_MAX + 1 is used as
00898   the max file name len; but in most standards, the
00899   length is NAME_MAX; we add 100 to be even safer */
00900 #endif
00901 
00902 next_file:
00903 
00904 #ifdef HAVE_READDIR_R
00905   ret = readdir_r(dir, (struct dirent*)dirent_buf, &ent);
00906 
00907   if (ret != 0
00908 #ifdef UNIV_AIX
00909       /* On AIX, only if we got non-NULL 'ent' (result) value and
00910       a non-zero 'ret' (return) value, it indicates a failed
00911       readdir_r() call. An NULL 'ent' with an non-zero 'ret'
00912       would indicate the "end of the directory" is reached. */
00913       && ent != NULL
00914 #endif
00915      ) {
00916     fprintf(stderr,
00917       "InnoDB: cannot read directory %s, error %lu\n",
00918       dirname, (ulong)ret);
00919 
00920     return(-1);
00921   }
00922 
00923   if (ent == NULL) {
00924     /* End of directory */
00925 
00926     return(1);
00927   }
00928 
00929   ut_a(strlen(ent->d_name) < _POSIX_PATH_MAX + 100 - 1);
00930 #else
00931   ent = readdir(dir);
00932 
00933   if (ent == NULL) {
00934 
00935     return(1);
00936   }
00937 #endif
00938   ut_a(strlen(ent->d_name) < OS_FILE_MAX_PATH);
00939 
00940   if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
00941 
00942     goto next_file;
00943   }
00944 
00945   strcpy(info->name, ent->d_name);
00946 
00947   full_path = static_cast<char* >(ut_malloc(strlen(dirname) + strlen(ent->d_name) + 10));
00948 
00949   sprintf(full_path, "%s/%s", dirname, ent->d_name);
00950 
00951   ret = stat(full_path, &statinfo);
00952 
00953   if (ret) {
00954 
00955     if (errno == ENOENT) {
00956       /* readdir() returned a file that does not exist,
00957       it must have been deleted in the meantime. Do what
00958       would have happened if the file was deleted before
00959       readdir() - ignore and go to the next entry.
00960       If this is the last entry then info->name will still
00961       contain the name of the deleted file when this
00962       function returns, but this is not an issue since the
00963       caller shouldn't be looking at info when end of
00964       directory is returned. */
00965 
00966       ut_free(full_path);
00967 
00968       goto next_file;
00969     }
00970 
00971     os_file_handle_error_no_exit(full_path, "stat");
00972 
00973     ut_free(full_path);
00974 
00975     return(-1);
00976   }
00977 
00978   info->size = (ib_int64_t)statinfo.st_size;
00979 
00980   if (S_ISDIR(statinfo.st_mode)) {
00981     info->type = OS_FILE_TYPE_DIR;
00982   } else if (S_ISLNK(statinfo.st_mode)) {
00983     info->type = OS_FILE_TYPE_LINK;
00984   } else if (S_ISREG(statinfo.st_mode)) {
00985     info->type = OS_FILE_TYPE_FILE;
00986   } else {
00987     info->type = OS_FILE_TYPE_UNKNOWN;
00988   }
00989 
00990   ut_free(full_path);
00991 
00992   return(0);
00993 #endif
00994 }
00995 
00996 /*****************************************************************/
01002 UNIV_INTERN
01003 ibool
01004 os_file_create_directory(
01005 /*=====================*/
01006   const char* pathname, 
01008   ibool   fail_if_exists) 
01010 {
01011 #ifdef __WIN__
01012   BOOL  rcode;
01013 
01014   rcode = CreateDirectory((LPCTSTR) pathname, NULL);
01015   if (!(rcode != 0
01016         || (GetLastError() == ERROR_ALREADY_EXISTS
01017       && !fail_if_exists))) {
01018     /* failure */
01019     os_file_handle_error(pathname, "CreateDirectory");
01020 
01021     return(FALSE);
01022   }
01023 
01024   return (TRUE);
01025 #else
01026   int rcode;
01027 
01028   rcode = mkdir(pathname, 0770);
01029 
01030   if (!(rcode == 0 || (errno == EEXIST && !fail_if_exists))) {
01031     /* failure */
01032     os_file_handle_error(pathname, "mkdir");
01033 
01034     return(FALSE);
01035   }
01036 
01037   return (TRUE);
01038 #endif
01039 }
01040 
01041 /****************************************************************/
01047 UNIV_INTERN
01048 os_file_t
01049 os_file_create_simple_func(
01050 /*=======================*/
01051   const char* name, 
01053   ulint   create_mode,
01060   ulint   access_type,
01062   ibool*    success)
01063 {
01064 #ifdef __WIN__
01065   os_file_t file;
01066   DWORD   create_flag;
01067   DWORD   access;
01068   DWORD   attributes  = 0;
01069   ibool   retry;
01070 
01071 try_again:
01072   ut_a(name);
01073 
01074   if (create_mode == OS_FILE_OPEN) {
01075     create_flag = OPEN_EXISTING;
01076   } else if (create_mode == OS_FILE_CREATE) {
01077     create_flag = CREATE_NEW;
01078   } else if (create_mode == OS_FILE_CREATE_PATH) {
01079     /* create subdirs along the path if needed  */
01080     *success = os_file_create_subdirs_if_needed(name);
01081     if (!*success) {
01082       ut_error;
01083     }
01084     create_flag = CREATE_NEW;
01085     create_mode = OS_FILE_CREATE;
01086   } else {
01087     create_flag = 0;
01088     ut_error;
01089   }
01090 
01091   if (access_type == OS_FILE_READ_ONLY) {
01092     access = GENERIC_READ;
01093   } else if (access_type == OS_FILE_READ_WRITE) {
01094     access = GENERIC_READ | GENERIC_WRITE;
01095   } else {
01096     access = 0;
01097     ut_error;
01098   }
01099 
01100   file = CreateFile((LPCTSTR) name,
01101         access,
01102         FILE_SHARE_READ | FILE_SHARE_WRITE,
01103         /* file can be read and written also
01104         by other processes */
01105         NULL, /* default security attributes */
01106         create_flag,
01107         attributes,
01108         NULL);  
01110   if (file == INVALID_HANDLE_VALUE) {
01111     *success = FALSE;
01112 
01113     retry = os_file_handle_error(name,
01114                create_mode == OS_FILE_OPEN ?
01115                "open" : "create");
01116     if (retry) {
01117       goto try_again;
01118     }
01119   } else {
01120     *success = TRUE;
01121   }
01122 
01123   return(file);
01124 #else /* __WIN__ */
01125   os_file_t file;
01126   int   create_flag;
01127   ibool   retry;
01128 
01129 try_again:
01130   ut_a(name);
01131 
01132   if (create_mode == OS_FILE_OPEN) {
01133     if (access_type == OS_FILE_READ_ONLY) {
01134       create_flag = O_RDONLY;
01135     } else {
01136       create_flag = O_RDWR;
01137     }
01138   } else if (create_mode == OS_FILE_CREATE) {
01139     create_flag = O_RDWR | O_CREAT | O_EXCL;
01140   } else if (create_mode == OS_FILE_CREATE_PATH) {
01141     /* create subdirs along the path if needed  */
01142     *success = os_file_create_subdirs_if_needed(name);
01143     if (!*success) {
01144       return (-1);
01145     }
01146     create_flag = O_RDWR | O_CREAT | O_EXCL;
01147     create_mode = OS_FILE_CREATE;
01148   } else {
01149     create_flag = 0;
01150     ut_error;
01151   }
01152 
01153   if (create_mode == OS_FILE_CREATE) {
01154     file = open(name, create_flag, S_IRUSR | S_IWUSR
01155           | S_IRGRP | S_IWGRP);
01156   } else {
01157     file = open(name, create_flag);
01158   }
01159 
01160   if (file == -1) {
01161     *success = FALSE;
01162 
01163     retry = os_file_handle_error(name,
01164                create_mode == OS_FILE_OPEN ?
01165                "open" : "create");
01166     if (retry) {
01167       goto try_again;
01168     }
01169 #ifdef USE_FILE_LOCK
01170   } else if (access_type == OS_FILE_READ_WRITE
01171        && os_file_lock(file, name)) {
01172     *success = FALSE;
01173     close(file);
01174     file = -1;
01175 #endif
01176   } else {
01177     *success = TRUE;
01178   }
01179 
01180   return(file);
01181 #endif /* __WIN__ */
01182 }
01183 
01184 /****************************************************************/
01190 UNIV_INTERN
01191 os_file_t
01192 os_file_create_simple_no_error_handling_func(
01193 /*=========================================*/
01194   const char* name, 
01196   ulint   create_mode,
01200   ulint   access_type,
01204   ibool*    success)
01205 {
01206 #ifdef __WIN__
01207   os_file_t file;
01208   DWORD   create_flag;
01209   DWORD   access;
01210   DWORD   attributes  = 0;
01211   DWORD   share_mode  = FILE_SHARE_READ | FILE_SHARE_WRITE;
01212 
01213   ut_a(name);
01214 
01215   if (create_mode == OS_FILE_OPEN) {
01216     create_flag = OPEN_EXISTING;
01217   } else if (create_mode == OS_FILE_CREATE) {
01218     create_flag = CREATE_NEW;
01219   } else {
01220     create_flag = 0;
01221     ut_error;
01222   }
01223 
01224   if (access_type == OS_FILE_READ_ONLY) {
01225     access = GENERIC_READ;
01226   } else if (access_type == OS_FILE_READ_WRITE) {
01227     access = GENERIC_READ | GENERIC_WRITE;
01228   } else if (access_type == OS_FILE_READ_ALLOW_DELETE) {
01229     access = GENERIC_READ;
01230     share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ
01231       | FILE_SHARE_WRITE; 
01235   } else {
01236     access = 0;
01237     ut_error;
01238   }
01239 
01240   file = CreateFile((LPCTSTR) name,
01241         access,
01242         share_mode,
01243         NULL, /* default security attributes */
01244         create_flag,
01245         attributes,
01246         NULL);  
01248   if (file == INVALID_HANDLE_VALUE) {
01249     *success = FALSE;
01250   } else {
01251     *success = TRUE;
01252   }
01253 
01254   return(file);
01255 #else /* __WIN__ */
01256   os_file_t file;
01257   int   create_flag;
01258 
01259   ut_a(name);
01260 
01261   if (create_mode == OS_FILE_OPEN) {
01262     if (access_type == OS_FILE_READ_ONLY) {
01263       create_flag = O_RDONLY;
01264     } else {
01265       create_flag = O_RDWR;
01266     }
01267   } else if (create_mode == OS_FILE_CREATE) {
01268     create_flag = O_RDWR | O_CREAT | O_EXCL;
01269   } else {
01270     create_flag = 0;
01271     ut_error;
01272   }
01273 
01274   if (create_mode == OS_FILE_CREATE) {
01275     file = open(name, create_flag, S_IRUSR | S_IWUSR
01276           | S_IRGRP | S_IWGRP);
01277   } else {
01278     file = open(name, create_flag);
01279   }
01280 
01281   if (file == -1) {
01282     *success = FALSE;
01283 #ifdef USE_FILE_LOCK
01284   } else if (access_type == OS_FILE_READ_WRITE
01285        && os_file_lock(file, name)) {
01286     *success = FALSE;
01287     close(file);
01288     file = -1;
01289 #endif
01290   } else {
01291     *success = TRUE;
01292   }
01293 
01294   return(file);
01295 #endif /* __WIN__ */
01296 }
01297 
01298 /****************************************************************/
01300 UNIV_INTERN
01301 void
01302 os_file_set_nocache(
01303 /*================*/
01304   int   fd,   
01305   const char* file_name,  
01306   const char* operation_name)
01309 {
01310   /* some versions of Solaris may not have DIRECTIO_ON */
01311 #if defined(UNIV_SOLARIS) && defined(DIRECTIO_ON)
01312   if (directio(fd, DIRECTIO_ON) == -1) {
01313     int errno_save;
01314     errno_save = (int)errno;
01315     ut_print_timestamp(stderr);
01316     fprintf(stderr,
01317       "  InnoDB: Failed to set DIRECTIO_ON "
01318       "on file %s: %s: %s, continuing anyway\n",
01319       file_name, operation_name, strerror(errno_save));
01320   }
01321 #elif defined(O_DIRECT)
01322   if (fcntl(fd, F_SETFL, O_DIRECT) == -1) {
01323     int errno_save;
01324     errno_save = (int)errno;
01325     ut_print_timestamp(stderr);
01326     fprintf(stderr,
01327       "  InnoDB: Failed to set O_DIRECT "
01328       "on file %s: %s: %s, continuing anyway\n",
01329       file_name, operation_name, strerror(errno_save));
01330     if (errno_save == EINVAL) {
01331       ut_print_timestamp(stderr);
01332       fprintf(stderr,
01333         "  InnoDB: O_DIRECT is known to result in "
01334         "'Invalid argument' on Linux on tmpfs, "
01335         "see MySQL Bug#26662\n");
01336     }
01337   }
01338 #else /* Required for OSX */
01339         (void)fd;
01340         (void)file_name;
01341         (void)operation_name;
01342 #endif
01343 }
01344 
01345 /****************************************************************/
01351 UNIV_INTERN
01352 os_file_t
01353 os_file_create_func(
01354 /*================*/
01355   const char* name, 
01357   ulint   create_mode,
01365   ulint   purpose,
01372   ulint   type, 
01373   ibool*    success)
01374 {
01375 #ifdef __WIN__
01376   os_file_t file;
01377   DWORD   share_mode  = FILE_SHARE_READ;
01378   DWORD   create_flag;
01379   DWORD   attributes;
01380   ibool   retry;
01381 try_again:
01382   ut_a(name);
01383 
01384   if (create_mode == OS_FILE_OPEN_RAW) {
01385     create_flag = OPEN_EXISTING;
01386     share_mode = FILE_SHARE_WRITE;
01387   } else if (create_mode == OS_FILE_OPEN
01388        || create_mode == OS_FILE_OPEN_RETRY) {
01389     create_flag = OPEN_EXISTING;
01390   } else if (create_mode == OS_FILE_CREATE) {
01391     create_flag = CREATE_NEW;
01392   } else if (create_mode == OS_FILE_OVERWRITE) {
01393     create_flag = CREATE_ALWAYS;
01394   } else {
01395     create_flag = 0;
01396     ut_error;
01397   }
01398 
01399   if (purpose == OS_FILE_AIO) {
01400     /* If specified, use asynchronous (overlapped) io and no
01401     buffering of writes in the OS */
01402     attributes = 0;
01403 #ifdef WIN_ASYNC_IO
01404     if (srv_use_native_aio) {
01405       attributes = attributes | FILE_FLAG_OVERLAPPED;
01406     }
01407 #endif
01408 #ifdef UNIV_NON_BUFFERED_IO
01409 # ifndef UNIV_HOTBACKUP
01410     if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) {
01411       /* Do not use unbuffered i/o to log files because
01412       value 2 denotes that we do not flush the log at every
01413       commit, but only once per second */
01414     } else if (srv_win_file_flush_method
01415          == SRV_WIN_IO_UNBUFFERED) {
01416       attributes = attributes | FILE_FLAG_NO_BUFFERING;
01417     }
01418 # else /* !UNIV_HOTBACKUP */
01419     attributes = attributes | FILE_FLAG_NO_BUFFERING;
01420 # endif /* !UNIV_HOTBACKUP */
01421 #endif /* UNIV_NON_BUFFERED_IO */
01422   } else if (purpose == OS_FILE_NORMAL) {
01423     attributes = 0;
01424 #ifdef UNIV_NON_BUFFERED_IO
01425 # ifndef UNIV_HOTBACKUP
01426     if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) {
01427       /* Do not use unbuffered i/o to log files because
01428       value 2 denotes that we do not flush the log at every
01429       commit, but only once per second */
01430     } else if (srv_win_file_flush_method
01431          == SRV_WIN_IO_UNBUFFERED) {
01432       attributes = attributes | FILE_FLAG_NO_BUFFERING;
01433     }
01434 # else /* !UNIV_HOTBACKUP */
01435     attributes = attributes | FILE_FLAG_NO_BUFFERING;
01436 # endif /* !UNIV_HOTBACKUP */
01437 #endif /* UNIV_NON_BUFFERED_IO */
01438   } else {
01439     attributes = 0;
01440     ut_error;
01441   }
01442 
01443   file = CreateFile((LPCTSTR) name,
01444         GENERIC_READ | GENERIC_WRITE, /* read and write
01445               access */
01446         share_mode, /* File can be read also by other
01447           processes; we must give the read
01448           permission because of ibbackup. We do
01449           not give the write permission to
01450           others because if one would succeed to
01451           start 2 instances of mysqld on the
01452           SAME files, that could cause severe
01453           database corruption! When opening
01454           raw disk partitions, Microsoft manuals
01455           say that we must give also the write
01456           permission. */
01457         NULL, /* default security attributes */
01458         create_flag,
01459         attributes,
01460         NULL);  
01462   if (file == INVALID_HANDLE_VALUE) {
01463     *success = FALSE;
01464 
01465     /* When srv_file_per_table is on, file creation failure may not
01466     be critical to the whole instance. Do not crash the server in
01467     case of unknown errors.
01468     Please note "srv_file_per_table" is a global variable with
01469     no explicit synchronization protection. It could be
01470     changed during this execution path. It might not have the
01471     same value as the one when building the table definition */
01472     if (srv_file_per_table) {
01473       retry = os_file_handle_error_no_exit(name,
01474             create_mode == OS_FILE_CREATE ?
01475             "create" : "open");
01476     } else {
01477       retry = os_file_handle_error(name,
01478             create_mode == OS_FILE_CREATE ?
01479             "create" : "open");
01480     }
01481 
01482     if (retry) {
01483       goto try_again;
01484     }
01485   } else {
01486     *success = TRUE;
01487   }
01488 
01489   return(file);
01490 #else /* __WIN__ */
01491   os_file_t file;
01492   int   create_flag;
01493   ibool   retry;
01494   const char* mode_str  = NULL;
01495 
01496 try_again:
01497   ut_a(name);
01498 
01499   if (create_mode == OS_FILE_OPEN || create_mode == OS_FILE_OPEN_RAW
01500       || create_mode == OS_FILE_OPEN_RETRY) {
01501     mode_str = "OPEN";
01502     if (srv_read_only)
01503                   create_flag = O_RDONLY;
01504                 else
01505                   create_flag = O_RDWR;
01506   } else if (create_mode == OS_FILE_CREATE) {
01507     mode_str = "CREATE";
01508     create_flag = O_RDWR | O_CREAT | O_EXCL;
01509   } else if (create_mode == OS_FILE_OVERWRITE) {
01510     mode_str = "OVERWRITE";
01511     create_flag = O_RDWR | O_CREAT | O_TRUNC;
01512   } else {
01513     create_flag = 0;
01514     ut_error;
01515   }
01516 
01517   ut_a(type == OS_LOG_FILE || type == OS_DATA_FILE);
01518   ut_a(purpose == OS_FILE_AIO || purpose == OS_FILE_NORMAL);
01519 
01520 #ifdef O_SYNC
01521   /* We let O_SYNC only affect log files; note that we map O_DSYNC to
01522   O_SYNC because the datasync options seemed to corrupt files in 2001
01523   in both Linux and Solaris */
01524   if (type == OS_LOG_FILE
01525       && srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) {
01526 
01527 # if 0
01528     fprintf(stderr, "Using O_SYNC for file %s\n", name);
01529 # endif
01530 
01531     create_flag = create_flag | O_SYNC;
01532   }
01533 #endif /* O_SYNC */
01534 
01535   file = open(name, create_flag, os_innodb_umask);
01536 
01537   if (file == -1) {
01538     *success = FALSE;
01539 
01540     /* When srv_file_per_table is on, file creation failure may not
01541     be critical to the whole instance. Do not crash the server in
01542     case of unknown errors.
01543     Please note "srv_file_per_table" is a global variable with
01544     no explicit synchronization protection. It could be
01545     changed during this execution path. It might not have the
01546     same value as the one when building the table definition */
01547     if (srv_file_per_table) {
01548       retry = os_file_handle_error_no_exit(name,
01549             create_mode == OS_FILE_CREATE ?
01550             "create" : "open");
01551     } else {
01552       retry = os_file_handle_error(name,
01553             create_mode == OS_FILE_CREATE ?
01554             "create" : "open");
01555     }
01556 
01557     if (retry) {
01558       goto try_again;
01559     } else {
01560       return(file /* -1 */);
01561     }
01562   }
01563   /* else */
01564 
01565   *success = TRUE;
01566 
01567   /* We disable OS caching (O_DIRECT) only on data files */
01568   if (type != OS_LOG_FILE
01569       && srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
01570     
01571     os_file_set_nocache(file, name, mode_str);
01572   }
01573 
01574   /* With ALL_O_DIRECT we disable OS caching for trx log file too */
01575   if (srv_unix_file_flush_method == SRV_UNIX_ALL_O_DIRECT) {
01576     os_file_set_nocache(file, name, mode_str);
01577   }
01578 
01579 #ifdef USE_FILE_LOCK
01580   if (create_mode != OS_FILE_OPEN_RAW && os_file_lock(file, name)) {
01581 
01582     if (create_mode == OS_FILE_OPEN_RETRY) {
01583       int i;
01584       ut_print_timestamp(stderr);
01585       fputs("  InnoDB: Retrying to lock"
01586             " the first data file\n",
01587             stderr);
01588       for (i = 0; i < 100; i++) {
01589         os_thread_sleep(1000000);
01590         if (!os_file_lock(file, name)) {
01591           *success = TRUE;
01592           return(file);
01593         }
01594       }
01595       ut_print_timestamp(stderr);
01596       fputs("  InnoDB: Unable to open the first data file\n",
01597             stderr);
01598     }
01599 
01600     *success = FALSE;
01601     close(file);
01602     file = -1;
01603   }
01604 #endif /* USE_FILE_LOCK */
01605 
01606   return(file);
01607 #endif /* __WIN__ */
01608 }
01609 
01610 /***********************************************************************/
01613 UNIV_INTERN
01614 ibool
01615 os_file_delete_if_exists(
01616 /*=====================*/
01617   const char* name) 
01618 {
01619 #ifdef __WIN__
01620   BOOL  ret;
01621   ulint count = 0;
01622 loop:
01623   /* In Windows, deleting an .ibd file may fail if ibbackup is copying
01624   it */
01625 
01626   ret = DeleteFile((LPCTSTR)name);
01627 
01628   if (ret) {
01629     return(TRUE);
01630   }
01631 
01632   if (GetLastError() == ERROR_FILE_NOT_FOUND) {
01633     /* the file does not exist, this not an error */
01634 
01635     return(TRUE);
01636   }
01637 
01638   count++;
01639 
01640   if (count > 100 && 0 == (count % 10)) {
01641     fprintf(stderr,
01642       "InnoDB: Warning: cannot delete file %s\n"
01643       "InnoDB: Are you running ibbackup"
01644       " to back up the file?\n", name);
01645 
01646     os_file_get_last_error(TRUE); /* print error information */
01647   }
01648 
01649   os_thread_sleep(1000000); /* sleep for a second */
01650 
01651   if (count > 2000) {
01652 
01653     return(FALSE);
01654   }
01655 
01656   goto loop;
01657 #else
01658   int ret;
01659 
01660   ret = unlink(name);
01661 
01662   if (ret != 0 && errno != ENOENT) {
01663     os_file_handle_error_no_exit(name, "delete");
01664 
01665     return(FALSE);
01666   }
01667 
01668   return(TRUE);
01669 #endif
01670 }
01671 
01672 /***********************************************************************/
01675 UNIV_INTERN
01676 ibool
01677 os_file_delete(
01678 /*===========*/
01679   const char* name) 
01680 {
01681 #ifdef __WIN__
01682   BOOL  ret;
01683   ulint count = 0;
01684 loop:
01685   /* In Windows, deleting an .ibd file may fail if ibbackup is copying
01686   it */
01687 
01688   ret = DeleteFile((LPCTSTR)name);
01689 
01690   if (ret) {
01691     return(TRUE);
01692   }
01693 
01694   if (GetLastError() == ERROR_FILE_NOT_FOUND) {
01695     /* If the file does not exist, we classify this as a 'mild'
01696     error and return */
01697 
01698     return(FALSE);
01699   }
01700 
01701   count++;
01702 
01703   if (count > 100 && 0 == (count % 10)) {
01704     fprintf(stderr,
01705       "InnoDB: Warning: cannot delete file %s\n"
01706       "InnoDB: Are you running ibbackup"
01707       " to back up the file?\n", name);
01708 
01709     os_file_get_last_error(TRUE); /* print error information */
01710   }
01711 
01712   os_thread_sleep(1000000); /* sleep for a second */
01713 
01714   if (count > 2000) {
01715 
01716     return(FALSE);
01717   }
01718 
01719   goto loop;
01720 #else
01721   int ret;
01722 
01723   ret = unlink(name);
01724 
01725   if (ret != 0) {
01726     os_file_handle_error_no_exit(name, "delete");
01727 
01728     return(FALSE);
01729   }
01730 
01731   return(TRUE);
01732 #endif
01733 }
01734 
01735 /***********************************************************************/
01740 UNIV_INTERN
01741 ibool
01742 os_file_rename_func(
01743 /*================*/
01744   const char* oldpath,
01746   const char* newpath)
01747 {
01748 #ifdef __WIN__
01749   BOOL  ret;
01750 
01751   ret = MoveFile((LPCTSTR)oldpath, (LPCTSTR)newpath);
01752 
01753   if (ret) {
01754     return(TRUE);
01755   }
01756 
01757   os_file_handle_error_no_exit(oldpath, "rename");
01758 
01759   return(FALSE);
01760 #else
01761   int ret;
01762 
01763   ret = rename(oldpath, newpath);
01764 
01765   if (ret != 0) {
01766     os_file_handle_error_no_exit(oldpath, "rename");
01767 
01768     return(FALSE);
01769   }
01770 
01771   return(TRUE);
01772 #endif
01773 }
01774 
01775 /***********************************************************************/
01780 UNIV_INTERN
01781 ibool
01782 os_file_close_func(
01783 /*===============*/
01784   os_file_t file) 
01785 {
01786 #ifdef __WIN__
01787   BOOL  ret;
01788 
01789   ut_a(file);
01790 
01791   ret = CloseHandle(file);
01792 
01793   if (ret) {
01794     return(TRUE);
01795   }
01796 
01797   os_file_handle_error(NULL, "close");
01798 
01799   return(FALSE);
01800 #else
01801   int ret;
01802 
01803   ret = close(file);
01804 
01805   if (ret == -1) {
01806     os_file_handle_error(NULL, "close");
01807 
01808     return(FALSE);
01809   }
01810 
01811   return(TRUE);
01812 #endif
01813 }
01814 
01815 #ifdef UNIV_HOTBACKUP
01816 /***********************************************************************/
01819 UNIV_INTERN
01820 ibool
01821 os_file_close_no_error_handling(
01822 /*============================*/
01823   os_file_t file) 
01824 {
01825 #ifdef __WIN__
01826   BOOL  ret;
01827 
01828   ut_a(file);
01829 
01830   ret = CloseHandle(file);
01831 
01832   if (ret) {
01833     return(TRUE);
01834   }
01835 
01836   return(FALSE);
01837 #else
01838   int ret;
01839 
01840   ret = close(file);
01841 
01842   if (ret == -1) {
01843 
01844     return(FALSE);
01845   }
01846 
01847   return(TRUE);
01848 #endif
01849 }
01850 #endif /* UNIV_HOTBACKUP */
01851 
01852 /***********************************************************************/
01855 UNIV_INTERN
01856 ibool
01857 os_file_get_size(
01858 /*=============*/
01859   os_file_t file, 
01860   ulint*    size, 
01862   ulint*    size_high)
01863 {
01864 #ifdef __WIN__
01865   DWORD high;
01866   DWORD low;
01867 
01868   low = GetFileSize(file, &high);
01869 
01870   if ((low == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) {
01871     return(FALSE);
01872   }
01873 
01874   *size = low;
01875   *size_high = high;
01876 
01877   return(TRUE);
01878 #else
01879   off_t offs;
01880 
01881   offs = lseek(file, 0, SEEK_END);
01882 
01883   if (offs == ((off_t)-1)) {
01884 
01885     return(FALSE);
01886   }
01887 
01888   if (sizeof(off_t) > 4) {
01889     *size = (ulint)(offs & 0xFFFFFFFFUL);
01890     *size_high = (ulint)(offs >> 32);
01891   } else {
01892     *size = (ulint) offs;
01893     *size_high = 0;
01894   }
01895 
01896   return(TRUE);
01897 #endif
01898 }
01899 
01900 /***********************************************************************/
01903 UNIV_INTERN
01904 ib_int64_t
01905 os_file_get_size_as_iblonglong(
01906 /*===========================*/
01907   os_file_t file) 
01908 {
01909   ulint size;
01910   ulint size_high;
01911   ibool success;
01912 
01913   success = os_file_get_size(file, &size, &size_high);
01914 
01915   if (!success) {
01916 
01917     return(-1);
01918   }
01919 
01920   return((((ib_int64_t)size_high) << 32) + (ib_int64_t)size);
01921 }
01922 
01923 /***********************************************************************/
01926 UNIV_INTERN
01927 ibool
01928 os_file_set_size(
01929 /*=============*/
01930   const char* name, 
01932   os_file_t file, 
01933   ulint   size, 
01935   ulint   size_high)
01936 {
01937   ib_int64_t  current_size;
01938   ib_int64_t  desired_size;
01939   ibool   ret;
01940   byte*   buf;
01941   byte*   buf2;
01942   ulint   buf_size;
01943 
01944   ut_a(size == (size & 0xFFFFFFFF));
01945 
01946   current_size = 0;
01947   desired_size = (ib_int64_t)size + (((ib_int64_t)size_high) << 32);
01948 
01949   /* Write up to 1 megabyte at a time. */
01950   buf_size = ut_min(64, (ulint) (desired_size / UNIV_PAGE_SIZE))
01951     * UNIV_PAGE_SIZE;
01952   buf2 = static_cast<unsigned char *>(ut_malloc(buf_size + UNIV_PAGE_SIZE));
01953 
01954   /* Align the buffer for possible raw i/o */
01955   buf = static_cast<unsigned char *>(ut_align(buf2, UNIV_PAGE_SIZE));
01956 
01957   /* Write buffer full of zeros */
01958   memset(buf, 0, buf_size);
01959 
01960   if (desired_size >= (ib_int64_t)(100 * 1024 * 1024)) {
01961 
01962     fprintf(stderr, "InnoDB: Progress in MB:");
01963   }
01964 
01965   while (current_size < desired_size) {
01966     ulint n_bytes;
01967 
01968     if (desired_size - current_size < (ib_int64_t) buf_size) {
01969       n_bytes = (ulint) (desired_size - current_size);
01970     } else {
01971       n_bytes = buf_size;
01972     }
01973 
01974     ret = os_file_write(name, file, buf,
01975             (ulint)(current_size & 0xFFFFFFFF),
01976             (ulint)(current_size >> 32),
01977             n_bytes);
01978     if (!ret) {
01979       ut_free(buf2);
01980       goto error_handling;
01981     }
01982 
01983     /* Print about progress for each 100 MB written */
01984     if ((ib_int64_t) (current_size + n_bytes) / (ib_int64_t)(100 * 1024 * 1024)
01985         != current_size / (ib_int64_t)(100 * 1024 * 1024)) {
01986 
01987       fprintf(stderr, " %lu00",
01988         (ulong) ((current_size + n_bytes)
01989            / (ib_int64_t)(100 * 1024 * 1024)));
01990     }
01991 
01992     current_size += n_bytes;
01993   }
01994 
01995   if (desired_size >= (ib_int64_t)(100 * 1024 * 1024)) {
01996 
01997     fprintf(stderr, "\n");
01998   }
01999 
02000   ut_free(buf2);
02001 
02002   ret = os_file_flush(file);
02003 
02004   if (ret) {
02005     return(TRUE);
02006   }
02007 
02008 error_handling:
02009   return(FALSE);
02010 }
02011 
02012 /***********************************************************************/
02015 UNIV_INTERN
02016 ibool
02017 os_file_set_eof(
02018 /*============*/
02019   FILE*   file) 
02020 {
02021 #ifdef __WIN__
02022   HANDLE h = (HANDLE) _get_osfhandle(fileno(file));
02023   return(SetEndOfFile(h));
02024 #else /* __WIN__ */
02025   return(!ftruncate(fileno(file), ftell(file)));
02026 #endif /* __WIN__ */
02027 }
02028 
02029 #ifndef __WIN__
02030 /***********************************************************************/
02036 static
02037 int
02038 os_file_fsync(
02039 /*==========*/
02040   os_file_t file) 
02041 {
02042   int ret;
02043   int failures;
02044   ibool retry;
02045 
02046   failures = 0;
02047 
02048   do {
02049     ret = fsync(file);
02050 
02051     os_n_fsyncs++;
02052 
02053     if (ret == -1 && errno == ENOLCK) {
02054 
02055       if (failures % 100 == 0) {
02056 
02057         ut_print_timestamp(stderr);
02058         fprintf(stderr,
02059           "  InnoDB: fsync(): "
02060           "No locks available; retrying\n");
02061       }
02062 
02063       os_thread_sleep(200000 /* 0.2 sec */);
02064 
02065       failures++;
02066 
02067       retry = TRUE;
02068     } else {
02069 
02070       retry = FALSE;
02071     }
02072   } while (retry);
02073 
02074   return(ret);
02075 }
02076 #endif /* !__WIN__ */
02077 
02078 /***********************************************************************/
02082 UNIV_INTERN
02083 ibool
02084 os_file_flush_func(
02085 /*===============*/
02086   os_file_t file) 
02087 {
02088 #ifdef __WIN__
02089   BOOL  ret;
02090 
02091   ut_a(file);
02092 
02093   os_n_fsyncs++;
02094 
02095   ret = FlushFileBuffers(file);
02096 
02097   if (ret) {
02098     return(TRUE);
02099   }
02100 
02101   /* Since Windows returns ERROR_INVALID_FUNCTION if the 'file' is
02102   actually a raw device, we choose to ignore that error if we are using
02103   raw disks */
02104 
02105   if (srv_start_raw_disk_in_use && GetLastError()
02106       == ERROR_INVALID_FUNCTION) {
02107     return(TRUE);
02108   }
02109 
02110   os_file_handle_error(NULL, "flush");
02111 
02112   /* It is a fatal error if a file flush does not succeed, because then
02113   the database can get corrupt on disk */
02114   ut_error;
02115 
02116   return(FALSE);
02117 #else
02118   int ret;
02119 
02120 #if defined(HAVE_DARWIN_THREADS)
02121 # ifndef F_FULLFSYNC
02122   /* The following definition is from the Mac OS X 10.3 <sys/fcntl.h> */
02123 #  define F_FULLFSYNC 51 /* fsync + ask the drive to flush to the media */
02124 # elif F_FULLFSYNC != 51
02125 #  error "F_FULLFSYNC != 51: ABI incompatibility with Mac OS X 10.3"
02126 # endif
02127   /* Apple has disabled fsync() for internal disk drives in OS X. That
02128   caused corruption for a user when he tested a power outage. Let us in
02129   OS X use a nonstandard flush method recommended by an Apple
02130   engineer. */
02131 
02132   if (!srv_have_fullfsync) {
02133     /* If we are not on an operating system that supports this,
02134     then fall back to a plain fsync. */
02135 
02136     ret = os_file_fsync(file);
02137   } else {
02138     ret = fcntl(file, F_FULLFSYNC, NULL);
02139 
02140     if (ret) {
02141       /* If we are not on a file system that supports this,
02142       then fall back to a plain fsync. */
02143       ret = os_file_fsync(file);
02144     }
02145   }
02146 #else
02147   ret = os_file_fsync(file);
02148 #endif
02149 
02150   if (ret == 0) {
02151     return(TRUE);
02152   }
02153 
02154   /* Since Linux returns EINVAL if the 'file' is actually a raw device,
02155   we choose to ignore that error if we are using raw disks */
02156 
02157   if (srv_start_raw_disk_in_use && errno == EINVAL) {
02158 
02159     return(TRUE);
02160   }
02161 
02162   ut_print_timestamp(stderr);
02163 
02164   fprintf(stderr,
02165     "  InnoDB: Error: the OS said file flush did not succeed\n");
02166 
02167   os_file_handle_error(NULL, "flush");
02168 
02169   /* It is a fatal error if a file flush does not succeed, because then
02170   the database can get corrupt on disk */
02171   ut_error;
02172 
02173   return(FALSE);
02174 #endif
02175 }
02176 
02177 #ifndef __WIN__
02178 /*******************************************************************/
02181 static
02182 ssize_t
02183 os_file_pread(
02184 /*==========*/
02185   os_file_t file, 
02186   void*   buf,  
02187   ulint   n,  
02188   ulint   offset, 
02190   ulint   offset_high) 
02192 {
02193   off_t offs;
02194 #if defined(HAVE_PREAD) && !defined(HAVE_BROKEN_PREAD)
02195   ssize_t n_bytes;
02196 #endif /* HAVE_PREAD && !HAVE_BROKEN_PREAD */
02197 
02198   ut_a((offset & 0xFFFFFFFFUL) == offset);
02199 
02200   /* If off_t is > 4 bytes in size, then we assume we can pass a
02201   64-bit address */
02202 
02203   if (sizeof(off_t) > 4) {
02204     offs = (off_t)offset + (((off_t)offset_high) << 32);
02205 
02206   } else {
02207     offs = (off_t)offset;
02208 
02209     if (offset_high > 0) {
02210       fprintf(stderr,
02211         "InnoDB: Error: file read at offset > 4 GB\n");
02212     }
02213   }
02214 
02215   os_n_file_reads++;
02216 
02217 #if defined(HAVE_PREAD) && !defined(HAVE_BROKEN_PREAD)
02218   os_mutex_enter(os_file_count_mutex);
02219   os_file_n_pending_preads++;
02220   os_n_pending_reads++;
02221   os_mutex_exit(os_file_count_mutex);
02222 
02223   n_bytes = pread(file, buf, (ssize_t)n, offs);
02224 
02225   os_mutex_enter(os_file_count_mutex);
02226   os_file_n_pending_preads--;
02227   os_n_pending_reads--;
02228   os_mutex_exit(os_file_count_mutex);
02229 
02230   return(n_bytes);
02231 #else
02232   {
02233     off_t ret_offset;
02234     ssize_t ret;
02235 #ifndef UNIV_HOTBACKUP
02236     ulint i;
02237 #endif /* !UNIV_HOTBACKUP */
02238 
02239     os_mutex_enter(os_file_count_mutex);
02240     os_n_pending_reads++;
02241     os_mutex_exit(os_file_count_mutex);
02242 
02243 #ifndef UNIV_HOTBACKUP
02244     /* Protect the seek / read operation with a mutex */
02245     i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
02246 
02247     os_mutex_enter(os_file_seek_mutexes[i]);
02248 #endif /* !UNIV_HOTBACKUP */
02249 
02250     ret_offset = lseek(file, offs, SEEK_SET);
02251 
02252     if (ret_offset < 0) {
02253       ret = -1;
02254     } else {
02255       ret = read(file, buf, (ssize_t)n);
02256     }
02257 
02258 #ifndef UNIV_HOTBACKUP
02259     os_mutex_exit(os_file_seek_mutexes[i]);
02260 #endif /* !UNIV_HOTBACKUP */
02261 
02262     os_mutex_enter(os_file_count_mutex);
02263     os_n_pending_reads--;
02264     os_mutex_exit(os_file_count_mutex);
02265 
02266     return(ret);
02267   }
02268 #endif
02269 }
02270 
02271 /*******************************************************************/
02274 static
02275 ssize_t
02276 os_file_pwrite(
02277 /*===========*/
02278   os_file_t file, 
02279   const void* buf,  
02280   ulint   n,  
02281   ulint   offset, 
02283   ulint   offset_high) 
02285 {
02286   ssize_t ret;
02287   off_t offs;
02288 
02289   ut_a((offset & 0xFFFFFFFFUL) == offset);
02290 
02291   /* If off_t is > 4 bytes in size, then we assume we can pass a
02292   64-bit address */
02293 
02294   if (sizeof(off_t) > 4) {
02295     offs = (off_t)offset + (((off_t)offset_high) << 32);
02296   } else {
02297     offs = (off_t)offset;
02298 
02299     if (offset_high > 0) {
02300       fprintf(stderr,
02301         "InnoDB: Error: file write"
02302         " at offset > 4 GB\n");
02303     }
02304   }
02305 
02306         if (srv_fake_write)
02307           return(TRUE);
02308 
02309   os_n_file_writes++;
02310 
02311 #if defined(HAVE_PWRITE) && !defined(HAVE_BROKEN_PREAD)
02312   os_mutex_enter(os_file_count_mutex);
02313   os_file_n_pending_pwrites++;
02314   os_n_pending_writes++;
02315   os_mutex_exit(os_file_count_mutex);
02316 
02317   ret = pwrite(file, buf, (ssize_t)n, offs);
02318 
02319   os_mutex_enter(os_file_count_mutex);
02320   os_file_n_pending_pwrites--;
02321   os_n_pending_writes--;
02322   os_mutex_exit(os_file_count_mutex);
02323 
02324 # ifdef UNIV_DO_FLUSH
02325   if (srv_unix_file_flush_method != SRV_UNIX_LITTLESYNC
02326       && srv_unix_file_flush_method != SRV_UNIX_NOSYNC
02327       && !os_do_not_call_flush_at_each_write) {
02328 
02329     /* Always do fsync to reduce the probability that when
02330     the OS crashes, a database page is only partially
02331     physically written to disk. */
02332 
02333     ut_a(TRUE == os_file_flush(file));
02334   }
02335 # endif /* UNIV_DO_FLUSH */
02336 
02337   return(ret);
02338 #else
02339   {
02340     off_t ret_offset;
02341 # ifndef UNIV_HOTBACKUP
02342     ulint i;
02343 # endif /* !UNIV_HOTBACKUP */
02344 
02345     os_mutex_enter(os_file_count_mutex);
02346     os_n_pending_writes++;
02347     os_mutex_exit(os_file_count_mutex);
02348 
02349 # ifndef UNIV_HOTBACKUP
02350     /* Protect the seek / write operation with a mutex */
02351     i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
02352 
02353     os_mutex_enter(os_file_seek_mutexes[i]);
02354 # endif /* UNIV_HOTBACKUP */
02355 
02356     ret_offset = lseek(file, offs, SEEK_SET);
02357 
02358     if (ret_offset < 0) {
02359       ret = -1;
02360 
02361       goto func_exit;
02362     }
02363 
02364     ret = write(file, buf, (ssize_t)n);
02365 
02366 # ifdef UNIV_DO_FLUSH
02367     if (srv_unix_file_flush_method != SRV_UNIX_LITTLESYNC
02368         && srv_unix_file_flush_method != SRV_UNIX_NOSYNC
02369         && !os_do_not_call_flush_at_each_write) {
02370 
02371       /* Always do fsync to reduce the probability that when
02372       the OS crashes, a database page is only partially
02373       physically written to disk. */
02374 
02375       ut_a(TRUE == os_file_flush(file));
02376     }
02377 # endif /* UNIV_DO_FLUSH */
02378 
02379 func_exit:
02380 # ifndef UNIV_HOTBACKUP
02381     os_mutex_exit(os_file_seek_mutexes[i]);
02382 # endif /* !UNIV_HOTBACKUP */
02383 
02384     os_mutex_enter(os_file_count_mutex);
02385     os_n_pending_writes--;
02386     os_mutex_exit(os_file_count_mutex);
02387 
02388     return(ret);
02389   }
02390 #endif
02391 }
02392 #endif
02393 
02394 /*******************************************************************/
02399 UNIV_INTERN
02400 ibool
02401 os_file_read_func(
02402 /*==============*/
02403   os_file_t file, 
02404   void*   buf,  
02405   ulint   offset, 
02407   ulint   offset_high, 
02409   ulint   n)  
02410 {
02411 #ifdef __WIN__
02412   BOOL    ret;
02413   DWORD   len;
02414   DWORD   ret2;
02415   DWORD   low;
02416   DWORD   high;
02417   ibool   retry;
02418 #ifndef UNIV_HOTBACKUP
02419   ulint   i;
02420 #endif /* !UNIV_HOTBACKUP */
02421 
02422   /* On 64-bit Windows, ulint is 64 bits. But offset and n should be
02423   no more than 32 bits. */
02424   ut_a((offset & 0xFFFFFFFFUL) == offset);
02425   ut_a((n & 0xFFFFFFFFUL) == n);
02426 
02427   os_n_file_reads++;
02428   os_bytes_read_since_printout += n;
02429 
02430 try_again:
02431   ut_ad(file);
02432   ut_ad(buf);
02433   ut_ad(n > 0);
02434 
02435   low = (DWORD) offset;
02436   high = (DWORD) offset_high;
02437 
02438   os_mutex_enter(os_file_count_mutex);
02439   os_n_pending_reads++;
02440   os_mutex_exit(os_file_count_mutex);
02441 
02442 #ifndef UNIV_HOTBACKUP
02443   /* Protect the seek / read operation with a mutex */
02444   i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
02445 
02446   os_mutex_enter(os_file_seek_mutexes[i]);
02447 #endif /* !UNIV_HOTBACKUP */
02448 
02449   ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
02450 
02451   if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
02452 
02453 #ifndef UNIV_HOTBACKUP
02454     os_mutex_exit(os_file_seek_mutexes[i]);
02455 #endif /* !UNIV_HOTBACKUP */
02456 
02457     os_mutex_enter(os_file_count_mutex);
02458     os_n_pending_reads--;
02459     os_mutex_exit(os_file_count_mutex);
02460 
02461     goto error_handling;
02462   }
02463 
02464   ret = ReadFile(file, buf, (DWORD) n, &len, NULL);
02465 
02466 #ifndef UNIV_HOTBACKUP
02467   os_mutex_exit(os_file_seek_mutexes[i]);
02468 #endif /* !UNIV_HOTBACKUP */
02469 
02470   os_mutex_enter(os_file_count_mutex);
02471   os_n_pending_reads--;
02472   os_mutex_exit(os_file_count_mutex);
02473 
02474   if (ret && len == n) {
02475     return(TRUE);
02476   }
02477 #else /* __WIN__ */
02478   ibool retry;
02479   ssize_t ret;
02480 
02481   os_bytes_read_since_printout += n;
02482 
02483 try_again:
02484   ret = os_file_pread(file, buf, n, offset, offset_high);
02485 
02486   if ((ulint)ret == n) {
02487 
02488     return(TRUE);
02489   }
02490 
02491   fprintf(stderr,
02492     "InnoDB: Error: tried to read %lu bytes at offset %lu %lu.\n"
02493     "InnoDB: Was only able to read %ld.\n",
02494     (ulong)n, (ulong)offset_high,
02495     (ulong)offset, (long)ret);
02496 #endif /* __WIN__ */
02497 #ifdef __WIN__
02498 error_handling:
02499 #endif
02500   retry = os_file_handle_error(NULL, "read");
02501 
02502   if (retry) {
02503     goto try_again;
02504   }
02505 
02506   fprintf(stderr,
02507     "InnoDB: Fatal error: cannot read from file."
02508     " OS error number %lu.\n",
02509 #ifdef __WIN__
02510     (ulong) GetLastError()
02511 #else
02512     (ulong) errno
02513 #endif
02514     );
02515   fflush(stderr);
02516 
02517   ut_error;
02518 
02519   return(FALSE);
02520 }
02521 
02522 /*******************************************************************/
02528 UNIV_INTERN
02529 ibool
02530 os_file_read_no_error_handling_func(
02531 /*================================*/
02532   os_file_t file, 
02533   void*   buf,  
02534   ulint   offset, 
02536   ulint   offset_high, 
02538   ulint   n)  
02539 {
02540 #ifdef __WIN__
02541   BOOL    ret;
02542   DWORD   len;
02543   DWORD   ret2;
02544   DWORD   low;
02545   DWORD   high;
02546   ibool   retry;
02547 #ifndef UNIV_HOTBACKUP
02548   ulint   i;
02549 #endif /* !UNIV_HOTBACKUP */
02550 
02551   /* On 64-bit Windows, ulint is 64 bits. But offset and n should be
02552   no more than 32 bits. */
02553   ut_a((offset & 0xFFFFFFFFUL) == offset);
02554   ut_a((n & 0xFFFFFFFFUL) == n);
02555 
02556   os_n_file_reads++;
02557   os_bytes_read_since_printout += n;
02558 
02559 try_again:
02560   ut_ad(file);
02561   ut_ad(buf);
02562   ut_ad(n > 0);
02563 
02564   low = (DWORD) offset;
02565   high = (DWORD) offset_high;
02566 
02567   os_mutex_enter(os_file_count_mutex);
02568   os_n_pending_reads++;
02569   os_mutex_exit(os_file_count_mutex);
02570 
02571 #ifndef UNIV_HOTBACKUP
02572   /* Protect the seek / read operation with a mutex */
02573   i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
02574 
02575   os_mutex_enter(os_file_seek_mutexes[i]);
02576 #endif /* !UNIV_HOTBACKUP */
02577 
02578   ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
02579 
02580   if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
02581 
02582 #ifndef UNIV_HOTBACKUP
02583     os_mutex_exit(os_file_seek_mutexes[i]);
02584 #endif /* !UNIV_HOTBACKUP */
02585 
02586     os_mutex_enter(os_file_count_mutex);
02587     os_n_pending_reads--;
02588     os_mutex_exit(os_file_count_mutex);
02589 
02590     goto error_handling;
02591   }
02592 
02593   ret = ReadFile(file, buf, (DWORD) n, &len, NULL);
02594 
02595 #ifndef UNIV_HOTBACKUP
02596   os_mutex_exit(os_file_seek_mutexes[i]);
02597 #endif /* !UNIV_HOTBACKUP */
02598 
02599   os_mutex_enter(os_file_count_mutex);
02600   os_n_pending_reads--;
02601   os_mutex_exit(os_file_count_mutex);
02602 
02603   if (ret && len == n) {
02604     return(TRUE);
02605   }
02606 #else /* __WIN__ */
02607   ibool retry;
02608   ssize_t ret;
02609 
02610   os_bytes_read_since_printout += n;
02611 
02612 try_again:
02613   ret = os_file_pread(file, buf, n, offset, offset_high);
02614 
02615   if ((ulint)ret == n) {
02616 
02617     return(TRUE);
02618   }
02619 #endif /* __WIN__ */
02620 #ifdef __WIN__
02621 error_handling:
02622 #endif
02623   retry = os_file_handle_error_no_exit(NULL, "read");
02624 
02625   if (retry) {
02626     goto try_again;
02627   }
02628 
02629   return(FALSE);
02630 }
02631 
02632 /*******************************************************************/
02636 UNIV_INTERN
02637 void
02638 os_file_read_string(
02639 /*================*/
02640   FILE* file, 
02641   char* str,  
02642   ulint size) 
02643 {
02644   size_t  flen;
02645 
02646   if (size == 0) {
02647     return;
02648   }
02649 
02650   rewind(file);
02651   flen = fread(str, 1, size - 1, file);
02652   str[flen] = '\0';
02653 }
02654 
02655 /*******************************************************************/
02660 UNIV_INTERN
02661 ibool
02662 os_file_write_func(
02663 /*===============*/
02664   const char* name, 
02666   os_file_t file, 
02667   const void* buf,  
02668   ulint   offset, 
02670   ulint   offset_high, 
02672   ulint   n)  
02673 {
02674 #ifdef __WIN__
02675   BOOL    ret;
02676   DWORD   len;
02677   DWORD   ret2;
02678   DWORD   low;
02679   DWORD   high;
02680   ulint   n_retries = 0;
02681   ulint   err;
02682 #ifndef UNIV_HOTBACKUP
02683   ulint   i;
02684 #endif /* !UNIV_HOTBACKUP */
02685 
02686   /* On 64-bit Windows, ulint is 64 bits. But offset and n should be
02687   no more than 32 bits. */
02688   ut_a((offset & 0xFFFFFFFFUL) == offset);
02689   ut_a((n & 0xFFFFFFFFUL) == n);
02690 
02691         if (srv_fake_write)
02692           return(TRUE);
02693 
02694   os_n_file_writes++;
02695 
02696   ut_ad(file);
02697   ut_ad(buf);
02698   ut_ad(n > 0);
02699 retry:
02700   low = (DWORD) offset;
02701   high = (DWORD) offset_high;
02702 
02703   os_mutex_enter(os_file_count_mutex);
02704   os_n_pending_writes++;
02705   os_mutex_exit(os_file_count_mutex);
02706 
02707 #ifndef UNIV_HOTBACKUP
02708   /* Protect the seek / write operation with a mutex */
02709   i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
02710 
02711   os_mutex_enter(os_file_seek_mutexes[i]);
02712 #endif /* !UNIV_HOTBACKUP */
02713 
02714   ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
02715 
02716   if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
02717 
02718 #ifndef UNIV_HOTBACKUP
02719     os_mutex_exit(os_file_seek_mutexes[i]);
02720 #endif /* !UNIV_HOTBACKUP */
02721 
02722     os_mutex_enter(os_file_count_mutex);
02723     os_n_pending_writes--;
02724     os_mutex_exit(os_file_count_mutex);
02725 
02726     ut_print_timestamp(stderr);
02727 
02728     fprintf(stderr,
02729       "  InnoDB: Error: File pointer positioning to"
02730       " file %s failed at\n"
02731       "InnoDB: offset %lu %lu. Operating system"
02732       " error number %lu.\n"
02733       "InnoDB: Some operating system error numbers"
02734       " are described at\n"
02735       "InnoDB: "
02736       REFMAN "operating-system-error-codes.html\n",
02737       name, (ulong) offset_high, (ulong) offset,
02738       (ulong) GetLastError());
02739 
02740     return(FALSE);
02741   }
02742 
02743   ret = WriteFile(file, buf, (DWORD) n, &len, NULL);
02744 
02745   /* Always do fsync to reduce the probability that when the OS crashes,
02746   a database page is only partially physically written to disk. */
02747 
02748 # ifdef UNIV_DO_FLUSH
02749   if (!os_do_not_call_flush_at_each_write) {
02750     ut_a(TRUE == os_file_flush(file));
02751   }
02752 # endif /* UNIV_DO_FLUSH */
02753 
02754 #ifndef UNIV_HOTBACKUP
02755   os_mutex_exit(os_file_seek_mutexes[i]);
02756 #endif /* !UNIV_HOTBACKUP */
02757 
02758   os_mutex_enter(os_file_count_mutex);
02759   os_n_pending_writes--;
02760   os_mutex_exit(os_file_count_mutex);
02761 
02762   if (ret && len == n) {
02763 
02764     return(TRUE);
02765   }
02766 
02767   /* If some background file system backup tool is running, then, at
02768   least in Windows 2000, we may get here a specific error. Let us
02769   retry the operation 100 times, with 1 second waits. */
02770 
02771   if (GetLastError() == ERROR_LOCK_VIOLATION && n_retries < 100) {
02772 
02773     os_thread_sleep(1000000);
02774 
02775     n_retries++;
02776 
02777     goto retry;
02778   }
02779 
02780   if (!os_has_said_disk_full) {
02781 
02782     err = (ulint)GetLastError();
02783 
02784     ut_print_timestamp(stderr);
02785 
02786     fprintf(stderr,
02787       "  InnoDB: Error: Write to file %s failed"
02788       " at offset %lu %lu.\n"
02789       "InnoDB: %lu bytes should have been written,"
02790       " only %lu were written.\n"
02791       "InnoDB: Operating system error number %lu.\n"
02792       "InnoDB: Check that your OS and file system"
02793       " support files of this size.\n"
02794       "InnoDB: Check also that the disk is not full"
02795       " or a disk quota exceeded.\n",
02796       name, (ulong) offset_high, (ulong) offset,
02797       (ulong) n, (ulong) len, (ulong) err);
02798 
02799     if (strerror((int)err) != NULL) {
02800       fprintf(stderr,
02801         "InnoDB: Error number %lu means '%s'.\n",
02802         (ulong) err, strerror((int)err));
02803     }
02804 
02805     fprintf(stderr,
02806       "InnoDB: Some operating system error numbers"
02807       " are described at\n"
02808       "InnoDB: "
02809       REFMAN "operating-system-error-codes.html\n");
02810 
02811     os_has_said_disk_full = TRUE;
02812   }
02813 
02814   return(FALSE);
02815 #else
02816   ssize_t ret;
02817 
02818   ret = os_file_pwrite(file, buf, n, offset, offset_high);
02819 
02820   if ((ulint)ret == n) {
02821 
02822     return(TRUE);
02823   }
02824 
02825   if (!os_has_said_disk_full) {
02826 
02827     ut_print_timestamp(stderr);
02828 
02829     fprintf(stderr,
02830       "  InnoDB: Error: Write to file %s failed"
02831       " at offset %lu %lu.\n"
02832       "InnoDB: %lu bytes should have been written,"
02833       " only %ld were written.\n"
02834       "InnoDB: Operating system error number %lu.\n"
02835       "InnoDB: Check that your OS and file system"
02836       " support files of this size.\n"
02837       "InnoDB: Check also that the disk is not full"
02838       " or a disk quota exceeded.\n",
02839       name, offset_high, offset, n, (long int)ret,
02840       (ulint)errno);
02841     if (strerror(errno) != NULL) {
02842       fprintf(stderr,
02843         "InnoDB: Error number %lu means '%s'.\n",
02844         (ulint)errno, strerror(errno));
02845     }
02846 
02847     fprintf(stderr,
02848       "InnoDB: Some operating system error numbers"
02849       " are described at\n"
02850       "InnoDB: "
02851       REFMAN "operating-system-error-codes.html\n");
02852 
02853     os_has_said_disk_full = TRUE;
02854   }
02855 
02856   return(FALSE);
02857 #endif
02858 }
02859 
02860 /*******************************************************************/
02863 UNIV_INTERN
02864 ibool
02865 os_file_status(
02866 /*===========*/
02867   const char* path, 
02868   ibool*    exists, 
02869   os_file_type_t* type) 
02870 {
02871 #ifdef __WIN__
02872   int   ret;
02873   struct _stat  statinfo;
02874 
02875   ret = _stat(path, &statinfo);
02876   if (ret && (errno == ENOENT || errno == ENOTDIR)) {
02877     /* file does not exist */
02878     *exists = FALSE;
02879     return(TRUE);
02880   } else if (ret) {
02881     /* file exists, but stat call failed */
02882 
02883     os_file_handle_error_no_exit(path, "stat");
02884 
02885     return(FALSE);
02886   }
02887 
02888   if (_S_IFDIR & statinfo.st_mode) {
02889     *type = OS_FILE_TYPE_DIR;
02890   } else if (_S_IFREG & statinfo.st_mode) {
02891     *type = OS_FILE_TYPE_FILE;
02892   } else {
02893     *type = OS_FILE_TYPE_UNKNOWN;
02894   }
02895 
02896   *exists = TRUE;
02897 
02898   return(TRUE);
02899 #else
02900   int   ret;
02901   struct stat statinfo;
02902 
02903   ret = stat(path, &statinfo);
02904   if (ret && (errno == ENOENT || errno == ENOTDIR)) {
02905     /* file does not exist */
02906     *exists = FALSE;
02907     return(TRUE);
02908   } else if (ret) {
02909     /* file exists, but stat call failed */
02910 
02911     os_file_handle_error_no_exit(path, "stat");
02912 
02913     return(FALSE);
02914   }
02915 
02916   if (S_ISDIR(statinfo.st_mode)) {
02917     *type = OS_FILE_TYPE_DIR;
02918   } else if (S_ISLNK(statinfo.st_mode)) {
02919     *type = OS_FILE_TYPE_LINK;
02920   } else if (S_ISREG(statinfo.st_mode)) {
02921     *type = OS_FILE_TYPE_FILE;
02922   } else {
02923     *type = OS_FILE_TYPE_UNKNOWN;
02924   }
02925 
02926   *exists = TRUE;
02927 
02928   return(TRUE);
02929 #endif
02930 }
02931 
02932 /*******************************************************************/
02935 UNIV_INTERN
02936 ibool
02937 os_file_get_status(
02938 /*===============*/
02939   const char* path,   
02940   os_file_stat_t* stat_info)  
02942 {
02943 #ifdef __WIN__
02944   int   ret;
02945   struct _stat  statinfo;
02946 
02947   ret = _stat(path, &statinfo);
02948   if (ret && (errno == ENOENT || errno == ENOTDIR)) {
02949     /* file does not exist */
02950 
02951     return(FALSE);
02952   } else if (ret) {
02953     /* file exists, but stat call failed */
02954 
02955     os_file_handle_error_no_exit(path, "stat");
02956 
02957     return(FALSE);
02958   }
02959   if (_S_IFDIR & statinfo.st_mode) {
02960     stat_info->type = OS_FILE_TYPE_DIR;
02961   } else if (_S_IFREG & statinfo.st_mode) {
02962     stat_info->type = OS_FILE_TYPE_FILE;
02963   } else {
02964     stat_info->type = OS_FILE_TYPE_UNKNOWN;
02965   }
02966 
02967   stat_info->ctime = statinfo.st_ctime;
02968   stat_info->atime = statinfo.st_atime;
02969   stat_info->mtime = statinfo.st_mtime;
02970   stat_info->size  = statinfo.st_size;
02971 
02972   return(TRUE);
02973 #else
02974   int   ret;
02975   struct stat statinfo;
02976 
02977   ret = stat(path, &statinfo);
02978 
02979   if (ret && (errno == ENOENT || errno == ENOTDIR)) {
02980     /* file does not exist */
02981 
02982     return(FALSE);
02983   } else if (ret) {
02984     /* file exists, but stat call failed */
02985 
02986     os_file_handle_error_no_exit(path, "stat");
02987 
02988     return(FALSE);
02989   }
02990 
02991   if (S_ISDIR(statinfo.st_mode)) {
02992     stat_info->type = OS_FILE_TYPE_DIR;
02993   } else if (S_ISLNK(statinfo.st_mode)) {
02994     stat_info->type = OS_FILE_TYPE_LINK;
02995   } else if (S_ISREG(statinfo.st_mode)) {
02996     stat_info->type = OS_FILE_TYPE_FILE;
02997   } else {
02998     stat_info->type = OS_FILE_TYPE_UNKNOWN;
02999   }
03000 
03001   stat_info->ctime = statinfo.st_ctime;
03002   stat_info->atime = statinfo.st_atime;
03003   stat_info->mtime = statinfo.st_mtime;
03004   stat_info->size  = statinfo.st_size;
03005 
03006   return(TRUE);
03007 #endif
03008 }
03009 
03010 /* path name separator character */
03011 #ifdef __WIN__
03012 #  define OS_FILE_PATH_SEPARATOR  '\\'
03013 #else
03014 #  define OS_FILE_PATH_SEPARATOR  '/'
03015 #endif
03016 
03017 /****************************************************************/
03045 UNIV_INTERN
03046 char*
03047 os_file_dirname(
03048 /*============*/
03049   const char* path) 
03050 {
03051   /* Find the offset of the last slash */
03052   const char* last_slash = strrchr(path, OS_FILE_PATH_SEPARATOR);
03053   if (!last_slash) {
03054     /* No slash in the path, return "." */
03055 
03056     return(mem_strdup("."));
03057   }
03058 
03059   /* Ok, there is a slash */
03060 
03061   if (last_slash == path) {
03062     /* last slash is the first char of the path */
03063 
03064     return(mem_strdup("/"));
03065   }
03066 
03067   /* Non-trivial directory component */
03068 
03069   return(mem_strdupl(path, last_slash - path));
03070 }
03071 
03072 /****************************************************************/
03075 UNIV_INTERN
03076 ibool
03077 os_file_create_subdirs_if_needed(
03078 /*=============================*/
03079   const char* path) 
03080 {
03081   char*   subdir;
03082   ibool   success, subdir_exists;
03083   os_file_type_t  type;
03084 
03085   subdir = os_file_dirname(path);
03086   if (strlen(subdir) == 1
03087       && (*subdir == OS_FILE_PATH_SEPARATOR || *subdir == '.')) {
03088     /* subdir is root or cwd, nothing to do */
03089     mem_free(subdir);
03090 
03091     return(TRUE);
03092   }
03093 
03094   /* Test if subdir exists */
03095   success = os_file_status(subdir, &subdir_exists, &type);
03096   if (success && !subdir_exists) {
03097     /* subdir does not exist, create it */
03098     success = os_file_create_subdirs_if_needed(subdir);
03099     if (!success) {
03100       mem_free(subdir);
03101 
03102       return(FALSE);
03103     }
03104     success = os_file_create_directory(subdir, FALSE);
03105   }
03106 
03107   mem_free(subdir);
03108 
03109   return(success);
03110 }
03111 
03112 #ifndef UNIV_HOTBACKUP
03113 /****************************************************************/
03116 static
03117 os_aio_slot_t*
03118 os_aio_array_get_nth_slot(
03119 /*======================*/
03120   os_aio_array_t*   array,  
03121   ulint     index)  
03122 {
03123   ut_a(index < array->n_slots);
03124 
03125   return((array->slots) + index);
03126 }
03127 
03128 #if defined(LINUX_NATIVE_AIO)
03129 /******************************************************************/
03132 static
03133 ibool
03134 os_aio_linux_create_io_ctx(
03135 /*=======================*/
03136   ulint   max_events, 
03137   io_context_t* io_ctx)   
03138 {
03139   int ret;
03140   ulint retries = 0;
03141 
03142 retry:
03143   memset(io_ctx, 0x0, sizeof(*io_ctx));
03144 
03145   /* Initialize the io_ctx. Tell it how many pending
03146   IO requests this context will handle. */
03147 
03148   ret = io_setup(max_events, io_ctx);
03149   if (ret == 0) {
03150 #if defined(UNIV_AIO_DEBUG)
03151     fprintf(stderr,
03152       "InnoDB: Linux native AIO:"
03153       " initialized io_ctx for segment\n");
03154 #endif
03155     /* Success. Return now. */
03156     return(TRUE);
03157   }
03158 
03159   /* If we hit EAGAIN we'll make a few attempts before failing. */
03160 
03161   switch (ret) {
03162   case -EAGAIN:
03163     if (retries == 0) {
03164       /* First time around. */
03165       ut_print_timestamp(stderr);
03166       fprintf(stderr,
03167         "  InnoDB: Warning: io_setup() failed"
03168         " with EAGAIN. Will make %d attempts"
03169         " before giving up.\n",
03170         OS_AIO_IO_SETUP_RETRY_ATTEMPTS);
03171     }
03172 
03173     if (retries < OS_AIO_IO_SETUP_RETRY_ATTEMPTS) {
03174       ++retries;
03175       fprintf(stderr,
03176         "InnoDB: Warning: io_setup() attempt"
03177         " %lu failed.\n",
03178         retries);
03179       os_thread_sleep(OS_AIO_IO_SETUP_RETRY_SLEEP);
03180       goto retry;
03181     }
03182 
03183     /* Have tried enough. Better call it a day. */
03184     ut_print_timestamp(stderr);
03185     fprintf(stderr,
03186       "  InnoDB: Error: io_setup() failed"
03187       " with EAGAIN after %d attempts.\n",
03188       OS_AIO_IO_SETUP_RETRY_ATTEMPTS);
03189     break;
03190 
03191   case -ENOSYS:
03192     ut_print_timestamp(stderr);
03193     fprintf(stderr,
03194       "  InnoDB: Error: Linux Native AIO interface"
03195       " is not supported on this platform. Please"
03196       " check your OS documentation and install"
03197       " appropriate binary of InnoDB.\n");
03198 
03199     break;
03200 
03201   default:
03202     ut_print_timestamp(stderr);
03203     fprintf(stderr,
03204       "  InnoDB: Error: Linux Native AIO setup"
03205       " returned following error[%d]\n", -ret);
03206     break;
03207   }
03208 
03209   fprintf(stderr,
03210     "InnoDB: You can disable Linux Native AIO by"
03211     " setting innodb_native_aio = off in my.cnf\n");
03212   return(FALSE);
03213 }
03214 #endif /* LINUX_NATIVE_AIO */
03215 
03216 /******************************************************************/
03221 static
03222 os_aio_array_t*
03223 os_aio_array_create(
03224 /*================*/
03225   ulint n,    
03228   ulint n_segments) 
03229 {
03230   os_aio_array_t* array;
03231   ulint   i;
03232   os_aio_slot_t*  slot;
03233 #ifdef WIN_ASYNC_IO
03234   OVERLAPPED* over;
03235 #elif defined(LINUX_NATIVE_AIO)
03236   struct io_event*  aio_event = NULL;
03237 #endif
03238   ut_a(n > 0);
03239   ut_a(n_segments > 0);
03240 
03241   array = static_cast<os_aio_array_t *>(ut_malloc(sizeof(os_aio_array_t)));
03242 
03243   array->mutex    = os_mutex_create();
03244   array->not_full   = os_event_create(NULL);
03245   array->is_empty   = os_event_create(NULL);
03246 
03247   os_event_set(array->is_empty);
03248 
03249   array->n_slots    = n;
03250   array->n_segments = n_segments;
03251   array->n_reserved = 0;
03252   array->cur_seg    = 0;
03253   array->slots    = static_cast<os_aio_slot_t *>(ut_malloc(n * sizeof(os_aio_slot_t)));
03254 #ifdef __WIN__
03255   array->handles    = ut_malloc(n * sizeof(HANDLE));
03256 #endif
03257 
03258 #if defined(LINUX_NATIVE_AIO)
03259   array->aio_ctx = NULL;
03260   array->aio_events = NULL;
03261 
03262   /* If we are not using native aio interface then skip this
03263   part of initialization. */
03264   if (!srv_use_native_aio) {
03265     goto skip_native_aio;
03266   }
03267 
03268   /* Initialize the io_context array. One io_context
03269   per segment in the array. */
03270 
03271   array->aio_ctx = (io_context**) ut_malloc(n_segments *
03272            sizeof(*array->aio_ctx));
03273   for (i = 0; i < n_segments; ++i) {
03274     if (!os_aio_linux_create_io_ctx(n/n_segments,
03275              &array->aio_ctx[i])) {
03276       /* If something bad happened during aio setup
03277       we should call it a day and return right away.
03278       We don't care about any leaks because a failure
03279       to initialize the io subsystem means that the
03280       server (or atleast the innodb storage engine)
03281       is not going to startup. */
03282       return(NULL);
03283     }
03284   }
03285 
03286   /* Initialize the event array. One event per slot. */
03287   aio_event = (io_event*) ut_malloc(n * sizeof(io_event));
03288   memset(aio_event, 0x0, sizeof(io_event) * n);
03289   array->aio_events = aio_event;
03290 
03291 skip_native_aio:
03292 #endif /* LINUX_NATIVE_AIO */
03293   for (i = 0; i < n; i++) {
03294     slot = os_aio_array_get_nth_slot(array, i);
03295 
03296     slot->pos = i;
03297     slot->reserved = FALSE;
03298 #ifdef WIN_ASYNC_IO
03299     slot->handle = CreateEvent(NULL,TRUE, FALSE, NULL);
03300 
03301     over = &(slot->control);
03302 
03303     over->hEvent = slot->handle;
03304 
03305     *((array->handles) + i) = over->hEvent;
03306 
03307 #elif defined(LINUX_NATIVE_AIO)
03308 
03309     memset(&slot->control, 0x0, sizeof(slot->control));
03310     slot->n_bytes = 0;
03311     slot->ret = 0;
03312 #endif
03313   }
03314 
03315   return(array);
03316 }
03317 
03318 /************************************************************************/
03320 static
03321 void
03322 os_aio_array_free(
03323 /*==============*/
03324   os_aio_array_t* array)  
03325 {
03326 #ifdef WIN_ASYNC_IO
03327   ulint i;
03328 
03329   for (i = 0; i < array->n_slots; i++) {
03330     os_aio_slot_t*  slot = os_aio_array_get_nth_slot(array, i);
03331     CloseHandle(slot->handle);
03332   }
03333 #endif /* WIN_ASYNC_IO */
03334 
03335 #ifdef __WIN__
03336   ut_free(array->handles);
03337 #endif /* __WIN__ */
03338   os_mutex_free(array->mutex);
03339   os_event_free(array->not_full);
03340   os_event_free(array->is_empty);
03341 
03342 #if defined(LINUX_NATIVE_AIO)
03343   if (srv_use_native_aio) {
03344     ut_free(array->aio_events);
03345     ut_free(array->aio_ctx);
03346   }
03347 #endif /* LINUX_NATIVE_AIO */
03348 
03349   ut_free(array->slots);
03350   ut_free(array);
03351 }
03352 
03353 /***********************************************************************
03354 Initializes the asynchronous io system. Creates one array each for ibuf
03355 and log i/o. Also creates one array each for read and write where each
03356 array is divided logically into n_read_segs and n_write_segs
03357 respectively. The caller must create an i/o handler thread for each
03358 segment in these arrays. This function also creates the sync array.
03359 No i/o handler thread needs to be created for that */
03360 UNIV_INTERN
03361 ibool
03362 os_aio_init(
03363 /*========*/
03364   ulint n_per_seg,  /*<! in: maximum number of pending aio
03365         operations allowed per segment */
03366   ulint n_read_segs,  /*<! in: number of reader threads */
03367   ulint n_write_segs, /*<! in: number of writer threads */
03368   ulint n_slots_sync) /*<! in: number of slots in the sync aio
03369         array */
03370 {
03371   ulint i;
03372   ulint   n_segments = 2 + n_read_segs + n_write_segs;
03373 
03374   ut_ad(n_segments >= 4);
03375 
03376   os_io_init_simple();
03377 
03378   for (i = 0; i < n_segments; i++) {
03379     srv_set_io_thread_op_info(i, "not started yet");
03380   }
03381 
03382 
03383   /* fprintf(stderr, "Array n per seg %lu\n", n_per_seg); */
03384 
03385   os_aio_ibuf_array = os_aio_array_create(n_per_seg, 1);
03386   if (os_aio_ibuf_array == NULL) {
03387     goto err_exit;
03388   }
03389 
03390   srv_io_thread_function[0] = "insert buffer thread";
03391 
03392   os_aio_log_array = os_aio_array_create(n_per_seg, 1);
03393   if (os_aio_log_array == NULL) {
03394     goto err_exit;
03395   }
03396 
03397   srv_io_thread_function[1] = "log thread";
03398 
03399   os_aio_read_array = os_aio_array_create(n_read_segs * n_per_seg,
03400             n_read_segs);
03401   if (os_aio_read_array == NULL) {
03402     goto err_exit;
03403   }
03404 
03405   for (i = 2; i < 2 + n_read_segs; i++) {
03406     ut_a(i < SRV_MAX_N_IO_THREADS);
03407     srv_io_thread_function[i] = "read thread";
03408   }
03409 
03410   os_aio_write_array = os_aio_array_create(n_write_segs * n_per_seg,
03411              n_write_segs);
03412   if (os_aio_write_array == NULL) {
03413     goto err_exit;
03414   }
03415 
03416   for (i = 2 + n_read_segs; i < n_segments; i++) {
03417     ut_a(i < SRV_MAX_N_IO_THREADS);
03418     srv_io_thread_function[i] = "write thread";
03419   }
03420 
03421   os_aio_sync_array = os_aio_array_create(n_slots_sync, 1);
03422   if (os_aio_sync_array == NULL) {
03423     goto err_exit;
03424   }
03425 
03426 
03427   os_aio_n_segments = n_segments;
03428 
03429   os_aio_validate();
03430 
03431   os_aio_segment_wait_events = static_cast<os_event_t *>(ut_malloc(n_segments * sizeof(void*)));
03432 
03433   for (i = 0; i < n_segments; i++) {
03434     os_aio_segment_wait_events[i] = os_event_create(NULL);
03435   }
03436 
03437   os_last_printout = time(NULL);
03438 
03439   return(TRUE);
03440 
03441 err_exit:
03442   return(FALSE);
03443 
03444 }
03445 
03446 /***********************************************************************
03447 Frees the asynchronous io system. */
03448 UNIV_INTERN
03449 void
03450 os_aio_free(void)
03451 /*=============*/
03452 {
03453   ulint i;
03454 
03455   os_aio_array_free(os_aio_ibuf_array);
03456   os_aio_ibuf_array = NULL;
03457   os_aio_array_free(os_aio_log_array);
03458   os_aio_log_array = NULL;
03459   os_aio_array_free(os_aio_read_array);
03460   os_aio_read_array = NULL;
03461   os_aio_array_free(os_aio_write_array);
03462   os_aio_write_array = NULL;
03463   os_aio_array_free(os_aio_sync_array);
03464   os_aio_sync_array = NULL;
03465 
03466   for (i = 0; i < os_aio_n_segments; i++) {
03467     os_event_free(os_aio_segment_wait_events[i]);
03468   }
03469 
03470   ut_free(os_aio_segment_wait_events);
03471   os_aio_segment_wait_events = 0;
03472   os_aio_n_segments = 0;
03473 }
03474 
03475 #ifdef WIN_ASYNC_IO
03476 /************************************************************************/
03479 static
03480 void
03481 os_aio_array_wake_win_aio_at_shutdown(
03482 /*==================================*/
03483   os_aio_array_t* array)  
03484 {
03485   ulint i;
03486 
03487   for (i = 0; i < array->n_slots; i++) {
03488 
03489     SetEvent((array->slots + i)->handle);
03490   }
03491 }
03492 #endif
03493 
03494 /************************************************************************/
03497 UNIV_INTERN
03498 void
03499 os_aio_wake_all_threads_at_shutdown(void)
03500 /*=====================================*/
03501 {
03502   ulint i;
03503 
03504 #ifdef WIN_ASYNC_IO
03505   /* This code wakes up all ai/o threads in Windows native aio */
03506   os_aio_array_wake_win_aio_at_shutdown(os_aio_read_array);
03507   os_aio_array_wake_win_aio_at_shutdown(os_aio_write_array);
03508   os_aio_array_wake_win_aio_at_shutdown(os_aio_ibuf_array);
03509   os_aio_array_wake_win_aio_at_shutdown(os_aio_log_array);
03510 
03511 #elif defined(LINUX_NATIVE_AIO)
03512 
03513   /* When using native AIO interface the io helper threads
03514   wait on io_getevents with a timeout value of 500ms. At
03515   each wake up these threads check the server status.
03516   No need to do anything to wake them up. */
03517 
03518   if (srv_use_native_aio) {
03519     return;
03520   }
03521   /* Fall through to simulated AIO handler wakeup if we are
03522   not using native AIO. */
03523 #endif
03524   /* This loop wakes up all simulated ai/o threads */
03525 
03526   for (i = 0; i < os_aio_n_segments; i++) {
03527 
03528     os_event_set(os_aio_segment_wait_events[i]);
03529   }
03530 }
03531 
03532 /************************************************************************/
03535 UNIV_INTERN
03536 void
03537 os_aio_wait_until_no_pending_writes(void)
03538 /*=====================================*/
03539 {
03540   os_event_wait(os_aio_write_array->is_empty);
03541 }
03542 
03543 /**********************************************************************/
03547 static
03548 ulint
03549 os_aio_get_segment_no_from_slot(
03550 /*============================*/
03551   os_aio_array_t* array,  
03552   os_aio_slot_t*  slot) 
03553 {
03554   ulint segment;
03555   ulint seg_len;
03556 
03557   if (array == os_aio_ibuf_array) {
03558     segment = 0;
03559 
03560   } else if (array == os_aio_log_array) {
03561     segment = 1;
03562 
03563   } else if (array == os_aio_read_array) {
03564     seg_len = os_aio_read_array->n_slots
03565       / os_aio_read_array->n_segments;
03566 
03567     segment = 2 + slot->pos / seg_len;
03568   } else {
03569     ut_a(array == os_aio_write_array);
03570     seg_len = os_aio_write_array->n_slots
03571       / os_aio_write_array->n_segments;
03572 
03573     segment = os_aio_read_array->n_segments + 2
03574       + slot->pos / seg_len;
03575   }
03576 
03577   return(segment);
03578 }
03579 
03580 /**********************************************************************/
03583 static
03584 ulint
03585 os_aio_get_array_and_local_segment(
03586 /*===============================*/
03587   os_aio_array_t** array,   
03588   ulint    global_segment)
03589 {
03590   ulint segment;
03591 
03592   ut_a(global_segment < os_aio_n_segments);
03593 
03594   if (global_segment == 0) {
03595     *array = os_aio_ibuf_array;
03596     segment = 0;
03597 
03598   } else if (global_segment == 1) {
03599     *array = os_aio_log_array;
03600     segment = 0;
03601 
03602   } else if (global_segment < os_aio_read_array->n_segments + 2) {
03603     *array = os_aio_read_array;
03604 
03605     segment = global_segment - 2;
03606   } else {
03607     *array = os_aio_write_array;
03608 
03609     segment = global_segment - (os_aio_read_array->n_segments + 2);
03610   }
03611 
03612   return(segment);
03613 }
03614 
03615 /*******************************************************************/
03619 static
03620 os_aio_slot_t*
03621 os_aio_array_reserve_slot(
03622 /*======================*/
03623   ulint   type, 
03624   os_aio_array_t* array,  
03625   fil_node_t* message1,
03627   void*   message2,
03629   os_file_t file, 
03630   const char* name, 
03632   void*   buf,  
03634   ulint   offset, 
03636   ulint   offset_high, 
03638   ulint   len)  
03639 {
03640   os_aio_slot_t*  slot = NULL;
03641 #ifdef WIN_ASYNC_IO
03642   OVERLAPPED* control;
03643 
03644 #elif defined(LINUX_NATIVE_AIO)
03645 
03646   struct iocb*  iocb;
03647   off_t   aio_offset;
03648 
03649 #endif
03650   ulint   i;
03651   ulint   counter;
03652   ulint   slots_per_seg;
03653   ulint   local_seg;
03654 
03655 #ifdef WIN_ASYNC_IO
03656   ut_a((len & 0xFFFFFFFFUL) == len);
03657 #endif
03658 
03659   /* No need of a mutex. Only reading constant fields */
03660   slots_per_seg = array->n_slots / array->n_segments;
03661 
03662   /* We attempt to keep adjacent blocks in the same local
03663   segment. This can help in merging IO requests when we are
03664   doing simulated AIO */
03665   local_seg = (offset >> (UNIV_PAGE_SIZE_SHIFT + 6))
03666         % array->n_segments;
03667 
03668 loop:
03669   os_mutex_enter(array->mutex);
03670 
03671   if (array->n_reserved == array->n_slots) {
03672     os_mutex_exit(array->mutex);
03673 
03674     if (!srv_use_native_aio) {
03675       /* If the handler threads are suspended, wake them
03676       so that we get more slots */
03677 
03678       os_aio_simulated_wake_handler_threads();
03679     }
03680 
03681     os_event_wait(array->not_full);
03682 
03683     goto loop;
03684   }
03685 
03686   /* We start our search for an available slot from our preferred
03687   local segment and do a full scan of the array. We are
03688   guaranteed to find a slot in full scan. */
03689   for (i = local_seg * slots_per_seg, counter = 0;
03690        counter < array->n_slots; i++, counter++) {
03691 
03692     i %= array->n_slots;
03693     slot = os_aio_array_get_nth_slot(array, i);
03694 
03695     if (slot->reserved == FALSE) {
03696       goto found;
03697     }
03698   }
03699 
03700   /* We MUST always be able to get hold of a reserved slot. */
03701   ut_error;
03702 
03703 found:
03704   ut_a(slot->reserved == FALSE);
03705   array->n_reserved++;
03706 
03707   if (array->n_reserved == 1) {
03708     os_event_reset(array->is_empty);
03709   }
03710 
03711   if (array->n_reserved == array->n_slots) {
03712     os_event_reset(array->not_full);
03713   }
03714 
03715   slot->reserved = TRUE;
03716   slot->reservation_time = time(NULL);
03717   slot->message1 = message1;
03718   slot->message2 = message2;
03719   slot->file     = file;
03720   slot->name     = name;
03721   slot->len      = len;
03722   slot->type     = type;
03723   slot->buf      = static_cast<unsigned char *>(buf);
03724   slot->offset   = offset;
03725   slot->offset_high = offset_high;
03726   slot->io_already_done = FALSE;
03727 
03728 #ifdef WIN_ASYNC_IO
03729   control = &(slot->control);
03730   control->Offset = (DWORD)offset;
03731   control->OffsetHigh = (DWORD)offset_high;
03732   ResetEvent(slot->handle);
03733 
03734 #elif defined(LINUX_NATIVE_AIO)
03735 
03736   /* If we are not using native AIO skip this part. */
03737   if (!srv_use_native_aio) {
03738     goto skip_native_aio;
03739   }
03740 
03741   /* Check if we are dealing with 64 bit arch.
03742   If not then make sure that offset fits in 32 bits. */
03743   if (sizeof(aio_offset) == 8) {
03744     aio_offset = offset_high;
03745     aio_offset <<= 32;
03746     aio_offset += offset;
03747   } else {
03748     ut_a(offset_high == 0);
03749     aio_offset = offset;
03750   }
03751 
03752   iocb = &slot->control;
03753 
03754   if (type == OS_FILE_READ) {
03755     io_prep_pread(iocb, file, buf, len, aio_offset);
03756   } else {
03757     ut_a(type == OS_FILE_WRITE);
03758     io_prep_pwrite(iocb, file, buf, len, aio_offset);
03759   }
03760 
03761   iocb->data = (void*)slot;
03762   slot->n_bytes = 0;
03763   slot->ret = 0;
03764   /*fprintf(stderr, "Filled up Linux native iocb.\n");*/
03765   
03766 
03767 skip_native_aio:
03768 #endif /* LINUX_NATIVE_AIO */
03769   os_mutex_exit(array->mutex);
03770 
03771   return(slot);
03772 }
03773 
03774 /*******************************************************************/
03776 static
03777 void
03778 os_aio_array_free_slot(
03779 /*===================*/
03780   os_aio_array_t* array,  
03781   os_aio_slot_t*  slot) 
03782 {
03783   ut_ad(array);
03784   ut_ad(slot);
03785 
03786   os_mutex_enter(array->mutex);
03787 
03788   ut_ad(slot->reserved);
03789 
03790   slot->reserved = FALSE;
03791 
03792   array->n_reserved--;
03793 
03794   if (array->n_reserved == array->n_slots - 1) {
03795     os_event_set(array->not_full);
03796   }
03797 
03798   if (array->n_reserved == 0) {
03799     os_event_set(array->is_empty);
03800   }
03801 
03802 #ifdef WIN_ASYNC_IO
03803 
03804   ResetEvent(slot->handle);
03805 
03806 #elif defined(LINUX_NATIVE_AIO)
03807 
03808   if (srv_use_native_aio) {
03809     memset(&slot->control, 0x0, sizeof(slot->control));
03810     slot->n_bytes = 0;
03811     slot->ret = 0;
03812     /*fprintf(stderr, "Freed up Linux native slot.\n");*/
03813   } else {
03814     /* These fields should not be used if we are not
03815     using native AIO. */
03816     ut_ad(slot->n_bytes == 0);
03817     ut_ad(slot->ret == 0);
03818   }
03819 
03820 #endif
03821   os_mutex_exit(array->mutex);
03822 }
03823 
03824 /**********************************************************************/
03826 static
03827 void
03828 os_aio_simulated_wake_handler_thread(
03829 /*=================================*/
03830   ulint global_segment) 
03832 {
03833   os_aio_array_t* array;
03834   os_aio_slot_t*  slot;
03835   ulint   segment;
03836   ulint   n;
03837   ulint   i;
03838 
03839   ut_ad(!srv_use_native_aio);
03840 
03841   segment = os_aio_get_array_and_local_segment(&array, global_segment);
03842 
03843   n = array->n_slots / array->n_segments;
03844 
03845   /* Look through n slots after the segment * n'th slot */
03846 
03847   os_mutex_enter(array->mutex);
03848 
03849   for (i = 0; i < n; i++) {
03850     slot = os_aio_array_get_nth_slot(array, i + segment * n);
03851 
03852     if (slot->reserved) {
03853       /* Found an i/o request */
03854 
03855       break;
03856     }
03857   }
03858 
03859   os_mutex_exit(array->mutex);
03860 
03861   if (i < n) {
03862     os_event_set(os_aio_segment_wait_events[global_segment]);
03863   }
03864 }
03865 
03866 /**********************************************************************/
03868 UNIV_INTERN
03869 void
03870 os_aio_simulated_wake_handler_threads(void)
03871 /*=======================================*/
03872 {
03873   ulint i;
03874 
03875   if (srv_use_native_aio) {
03876     /* We do not use simulated aio: do nothing */
03877 
03878     return;
03879   }
03880 
03881   os_aio_recommend_sleep_for_read_threads = FALSE;
03882 
03883   for (i = 0; i < os_aio_n_segments; i++) {
03884     os_aio_simulated_wake_handler_thread(i);
03885   }
03886 }
03887 
03888 /**********************************************************************/
03893 UNIV_INTERN
03894 void
03895 os_aio_simulated_put_read_threads_to_sleep(void)
03896 /*============================================*/
03897 {
03898 
03899 /* The idea of putting background IO threads to sleep is only for
03900 Windows when using simulated AIO. Windows XP seems to schedule
03901 background threads too eagerly to allow for coalescing during
03902 readahead requests. */
03903 #ifdef __WIN__
03904   os_aio_array_t* array;
03905   ulint   g;
03906 
03907   if (srv_use_native_aio) {
03908     /* We do not use simulated aio: do nothing */
03909 
03910     return;
03911   }
03912 
03913   os_aio_recommend_sleep_for_read_threads = TRUE;
03914 
03915   for (g = 0; g < os_aio_n_segments; g++) {
03916     os_aio_get_array_and_local_segment(&array, g);
03917 
03918     if (array == os_aio_read_array) {
03919 
03920       os_event_reset(os_aio_segment_wait_events[g]);
03921     }
03922   }
03923 #endif /* __WIN__ */
03924 }
03925 
03926 #if defined(LINUX_NATIVE_AIO)
03927 /*******************************************************************/
03930 static
03931 ibool
03932 os_aio_linux_dispatch(
03933 /*==================*/
03934   os_aio_array_t* array,  
03935   os_aio_slot_t*  slot) 
03936 {
03937   int   ret;
03938   ulint   io_ctx_index;
03939   struct iocb*  iocb;
03940 
03941   ut_ad(slot != NULL);
03942   ut_ad(array);
03943 
03944   ut_a(slot->reserved);
03945 
03946   /* Find out what we are going to work with.
03947   The iocb struct is directly in the slot.
03948   The io_context is one per segment. */
03949 
03950   iocb = &slot->control;
03951   io_ctx_index = (slot->pos * array->n_segments) / array->n_slots;
03952 
03953   ret = io_submit(array->aio_ctx[io_ctx_index], 1, &iocb);
03954 
03955 #if defined(UNIV_AIO_DEBUG)
03956   fprintf(stderr,
03957     "io_submit[%c] ret[%d]: slot[%p] ctx[%p] seg[%lu]\n",
03958     (slot->type == OS_FILE_WRITE) ? 'w' : 'r', ret, slot,
03959     array->aio_ctx[io_ctx_index], (ulong)io_ctx_index);
03960 #endif
03961 
03962   /* io_submit returns number of successfully
03963   queued requests or -errno. */
03964   if (UNIV_UNLIKELY(ret != 1)) {
03965     errno = -ret;
03966     return(FALSE);
03967   }
03968 
03969   return(TRUE);
03970 }
03971 #endif /* LINUX_NATIVE_AIO */
03972 
03973 
03974 /*******************************************************************/
03978 UNIV_INTERN
03979 ibool
03980 os_aio_func(
03981 /*========*/
03982   ulint   type, 
03983   ulint   mode, 
03996   const char* name, 
03998   os_file_t file, 
03999   void*   buf,  
04001   ulint   offset, 
04003   ulint   offset_high, 
04005   ulint   n,  
04006   fil_node_t* message1,
04010   void*   message2)
04014 {
04015   os_aio_array_t* array;
04016   os_aio_slot_t*  slot;
04017 #ifdef WIN_ASYNC_IO
04018   ibool   retval;
04019   BOOL    ret   = TRUE;
04020   DWORD   len   = (DWORD) n;
04021   struct fil_node_struct * dummy_mess1;
04022   void*   dummy_mess2;
04023   ulint   dummy_type;
04024 #endif /* WIN_ASYNC_IO */
04025 #if defined LINUX_NATIVE_AIO || defined WIN_ASYNC_IO
04026   ibool   retry;
04027 #endif
04028   ulint   wake_later;
04029 
04030   ut_ad(file);
04031   ut_ad(buf);
04032   ut_ad(n > 0);
04033   ut_ad(n % OS_FILE_LOG_BLOCK_SIZE == 0);
04034   ut_ad(offset % OS_FILE_LOG_BLOCK_SIZE == 0);
04035   ut_ad(os_aio_validate());
04036 #ifdef WIN_ASYNC_IO
04037   ut_ad((n & 0xFFFFFFFFUL) == n);
04038 #endif
04039 
04040   wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
04041   mode = mode & (~OS_AIO_SIMULATED_WAKE_LATER);
04042 
04043   if (mode == OS_AIO_SYNC
04044 #ifdef WIN_ASYNC_IO
04045       && !srv_use_native_aio
04046 #endif /* WIN_ASYNC_IO */
04047       ) {
04048     /* This is actually an ordinary synchronous read or write:
04049     no need to use an i/o-handler thread. NOTE that if we use
04050     Windows async i/o, Windows does not allow us to use
04051     ordinary synchronous os_file_read etc. on the same file,
04052     therefore we have built a special mechanism for synchronous
04053     wait in the Windows case. */
04054 
04055     if (type == OS_FILE_READ) {
04056       return(os_file_read(file, buf, offset,
04057               offset_high, n));
04058     }
04059 
04060     ut_a(type == OS_FILE_WRITE);
04061 
04062     return(os_file_write(name, file, buf, offset, offset_high, n));
04063   }
04064 
04065 #if defined LINUX_NATIVE_AIO || defined WIN_ASYNC_IO
04066 try_again:
04067 #endif
04068   if (mode == OS_AIO_NORMAL) {
04069     if (type == OS_FILE_READ) {
04070       array = os_aio_read_array;
04071     } else {
04072       array = os_aio_write_array;
04073     }
04074   } else if (mode == OS_AIO_IBUF) {
04075     ut_ad(type == OS_FILE_READ);
04076     /* Reduce probability of deadlock bugs in connection with ibuf:
04077     do not let the ibuf i/o handler sleep */
04078 
04079     wake_later = FALSE;
04080 
04081     array = os_aio_ibuf_array;
04082   } else if (mode == OS_AIO_LOG) {
04083 
04084     array = os_aio_log_array;
04085   } else if (mode == OS_AIO_SYNC) {
04086     array = os_aio_sync_array;
04087 
04088 #if defined(LINUX_NATIVE_AIO)
04089     /* In Linux native AIO we don't use sync IO array. */
04090     ut_a(!srv_use_native_aio);
04091 #endif /* LINUX_NATIVE_AIO */
04092   } else {
04093     array = NULL; /* Eliminate compiler warning */
04094     ut_error;
04095   }
04096 
04097   slot = os_aio_array_reserve_slot(type, array, message1, message2, file,
04098            name, buf, offset, offset_high, n);
04099   if (type == OS_FILE_READ) {
04100     if (srv_use_native_aio) {
04101       os_n_file_reads++;
04102       os_bytes_read_since_printout += n;
04103 #ifdef WIN_ASYNC_IO
04104       ret = ReadFile(file, buf, (DWORD)n, &len,
04105                &(slot->control));
04106 
04107 #elif defined(LINUX_NATIVE_AIO)
04108       if (!os_aio_linux_dispatch(array, slot)) {
04109         goto err_exit;
04110       }
04111 #endif
04112     } else {
04113       if (!wake_later) {
04114         os_aio_simulated_wake_handler_thread(
04115           os_aio_get_segment_no_from_slot(
04116             array, slot));
04117       }
04118     }
04119   } else if (type == OS_FILE_WRITE) {
04120     if (srv_use_native_aio) {
04121       os_n_file_writes++;
04122 #ifdef WIN_ASYNC_IO
04123       ret = WriteFile(file, buf, (DWORD)n, &len,
04124           &(slot->control));
04125 
04126 #elif defined(LINUX_NATIVE_AIO)
04127       if (!os_aio_linux_dispatch(array, slot)) {
04128         goto err_exit;
04129       }
04130 #endif
04131     } else {
04132       if (!wake_later) {
04133         os_aio_simulated_wake_handler_thread(
04134           os_aio_get_segment_no_from_slot(
04135             array, slot));
04136       }
04137     }
04138   } else {
04139     ut_error;
04140   }
04141 
04142 #ifdef WIN_ASYNC_IO
04143   if (srv_use_native_aio) {
04144     if ((ret && len == n)
04145         || (!ret && GetLastError() == ERROR_IO_PENDING)) {
04146       /* aio was queued successfully! */
04147 
04148       if (mode == OS_AIO_SYNC) {
04149         /* We want a synchronous i/o operation on a
04150         file where we also use async i/o: in Windows
04151         we must use the same wait mechanism as for
04152         async i/o */
04153 
04154         retval = os_aio_windows_handle(ULINT_UNDEFINED,
04155                      slot->pos,
04156                      &dummy_mess1,
04157                      &dummy_mess2,
04158                      &dummy_type);
04159 
04160         return(retval);
04161       }
04162 
04163       return(TRUE);
04164     }
04165 
04166     goto err_exit;
04167   }
04168 #endif /* WIN_ASYNC_IO */
04169   /* aio was queued successfully! */
04170   return(TRUE);
04171 
04172 #if defined LINUX_NATIVE_AIO || defined WIN_ASYNC_IO
04173 err_exit:
04174   os_aio_array_free_slot(array, slot);
04175 
04176   retry = os_file_handle_error(name,
04177              type == OS_FILE_READ
04178              ? "aio read" : "aio write");
04179   if (retry) {
04180 
04181     goto try_again;
04182   }
04183 
04184   return(FALSE);
04185 #endif /* LINUX_NATIVE_AIO || WIN_ASYNC_IO */
04186 }
04187 
04188 #ifdef WIN_ASYNC_IO
04189 /**********************************************************************/
04197 UNIV_INTERN
04198 ibool
04199 os_aio_windows_handle(
04200 /*==================*/
04201   ulint segment,  
04209   ulint pos,    
04211   fil_node_t**message1, 
04216   void**  message2,
04217   ulint*  type)   
04218 {
04219   ulint   orig_seg  = segment;
04220   os_aio_array_t* array;
04221   os_aio_slot_t*  slot;
04222   ulint   n;
04223   ulint   i;
04224   ibool   ret_val;
04225   BOOL    ret;
04226   DWORD   len;
04227   BOOL    retry   = FALSE;
04228 
04229   if (segment == ULINT_UNDEFINED) {
04230     array = os_aio_sync_array;
04231     segment = 0;
04232   } else {
04233     segment = os_aio_get_array_and_local_segment(&array, segment);
04234   }
04235 
04236   /* NOTE! We only access constant fields in os_aio_array. Therefore
04237   we do not have to acquire the protecting mutex yet */
04238 
04239   ut_ad(os_aio_validate());
04240   ut_ad(segment < array->n_segments);
04241 
04242   n = array->n_slots / array->n_segments;
04243 
04244   if (array == os_aio_sync_array) {
04245     WaitForSingleObject(
04246       os_aio_array_get_nth_slot(array, pos)->handle,
04247       INFINITE);
04248     i = pos;
04249   } else {
04250     srv_set_io_thread_op_info(orig_seg, "wait Windows aio");
04251     i = WaitForMultipleObjects((DWORD) n,
04252              array->handles + segment * n,
04253              FALSE,
04254              INFINITE);
04255   }
04256 
04257   if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
04258     os_thread_exit(NULL);
04259   }
04260 
04261   os_mutex_enter(array->mutex);
04262 
04263   slot = os_aio_array_get_nth_slot(array, i + segment * n);
04264 
04265   ut_a(slot->reserved);
04266 
04267   if (orig_seg != ULINT_UNDEFINED) {
04268     srv_set_io_thread_op_info(orig_seg,
04269             "get windows aio return value");
04270   }
04271 
04272   ret = GetOverlappedResult(slot->file, &(slot->control), &len, TRUE);
04273 
04274   *message1 = slot->message1;
04275   *message2 = slot->message2;
04276 
04277   *type = slot->type;
04278 
04279   if (ret && len == slot->len) {
04280     ret_val = TRUE;
04281 
04282 #ifdef UNIV_DO_FLUSH
04283     if (slot->type == OS_FILE_WRITE
04284         && !os_do_not_call_flush_at_each_write) {
04285       if (!os_file_flush(slot->file)) {
04286         ut_error;
04287       }
04288     }
04289 #endif /* UNIV_DO_FLUSH */
04290   } else if (os_file_handle_error(slot->name, "Windows aio")) {
04291 
04292     retry = TRUE;
04293   } else {
04294 
04295     ret_val = FALSE;
04296   }
04297 
04298   os_mutex_exit(array->mutex);
04299 
04300   if (retry) {
04301     /* retry failed read/write operation synchronously.
04302     No need to hold array->mutex. */
04303 
04304 #ifdef UNIV_PFS_IO
04305     /* This read/write does not go through os_file_read
04306     and os_file_write APIs, need to register with
04307     performance schema explicitly here. */
04308     struct PSI_file_locker* locker = NULL;
04309     register_pfs_file_io_begin(locker, slot->file, slot->len,
04310              (slot->type == OS_FILE_WRITE)
04311             ? PSI_FILE_WRITE
04312             : PSI_FILE_READ,
04313               __FILE__, __LINE__);
04314 #endif
04315 
04316     ut_a((slot->len & 0xFFFFFFFFUL) == slot->len);
04317 
04318     switch (slot->type) {
04319     case OS_FILE_WRITE:
04320       ret = WriteFile(slot->file, slot->buf,
04321           (DWORD) slot->len, &len,
04322           &(slot->control));
04323 
04324       break;
04325     case OS_FILE_READ:
04326       ret = ReadFile(slot->file, slot->buf,
04327                (DWORD) slot->len, &len,
04328                &(slot->control));
04329 
04330       break;
04331     default:
04332       ut_error;
04333     }
04334 
04335 #ifdef UNIV_PFS_IO
04336     register_pfs_file_io_end(locker, len);
04337 #endif
04338 
04339     if (!ret && GetLastError() == ERROR_IO_PENDING) {
04340       /* aio was queued successfully!
04341       We want a synchronous i/o operation on a
04342       file where we also use async i/o: in Windows
04343       we must use the same wait mechanism as for
04344       async i/o */
04345 
04346       ret = GetOverlappedResult(slot->file,
04347               &(slot->control),
04348               &len, TRUE);
04349     }
04350 
04351     ret_val = ret && len == slot->len;
04352   }
04353 
04354   os_aio_array_free_slot(array, slot);
04355 
04356   return(ret_val);
04357 }
04358 #endif
04359 
04360 #if defined(LINUX_NATIVE_AIO)
04361 /******************************************************************/
04372 static
04373 void
04374 os_aio_linux_collect(
04375 /*=================*/
04376   os_aio_array_t* array,    
04377   ulint   segment,  
04378   ulint   seg_size) 
04379 {
04380   int     i;
04381   int     ret;
04382   ulint     start_pos;
04383   ulint     end_pos;
04384   struct timespec   timeout;
04385   struct io_event*  events;
04386   struct io_context*  io_ctx;
04387 
04388   /* sanity checks. */
04389   ut_ad(array != NULL);
04390   ut_ad(seg_size > 0);
04391   ut_ad(segment < array->n_segments);
04392 
04393   /* Which part of event array we are going to work on. */
04394   events = &array->aio_events[segment * seg_size];
04395 
04396   /* Which io_context we are going to use. */
04397   io_ctx = array->aio_ctx[segment];
04398 
04399   /* Starting point of the segment we will be working on. */
04400   start_pos = segment * seg_size;
04401 
04402   /* End point. */
04403   end_pos = start_pos + seg_size;
04404 
04405 retry:
04406 
04407   /* Go down if we are in shutdown mode.
04408   In case of srv_fast_shutdown == 2, there may be pending
04409   IO requests but that should be OK as we essentially treat
04410   that as a crash of InnoDB. */
04411   if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
04412     os_thread_exit(NULL);
04413   }
04414 
04415   /* Initialize the events. The timeout value is arbitrary.
04416   We probably need to experiment with it a little. */
04417   memset(events, 0, sizeof(*events) * seg_size);
04418   timeout.tv_sec = 0;
04419   timeout.tv_nsec = OS_AIO_REAP_TIMEOUT;
04420 
04421   ret = io_getevents(io_ctx, 1, seg_size, events, &timeout);
04422 
04423   /* This error handling is for any error in collecting the
04424   IO requests. The errors, if any, for any particular IO
04425   request are simply passed on to the calling routine. */
04426 
04427   /* Not enough resources! Try again. */
04428   if (ret == -EAGAIN) {
04429     goto retry;
04430   }
04431 
04432   /* Interrupted! I have tested the behaviour in case of an
04433   interrupt. If we have some completed IOs available then
04434   the return code will be the number of IOs. We get EINTR only
04435   if there are no completed IOs and we have been interrupted. */
04436   if (ret == -EINTR) {
04437     goto retry;
04438   }
04439 
04440   /* No pending request! Go back and check again. */
04441   if (ret == 0) {
04442     goto retry;
04443   }
04444 
04445   /* All other errors! should cause a trap for now. */
04446   if (UNIV_UNLIKELY(ret < 0)) {
04447     ut_print_timestamp(stderr);
04448     fprintf(stderr,
04449       "  InnoDB: unexpected ret_code[%d] from"
04450       " io_getevents()!\n", ret);
04451     ut_error;
04452   }
04453 
04454   ut_a(ret > 0);
04455 
04456   for (i = 0; i < ret; i++) {
04457     os_aio_slot_t*  slot;
04458     struct iocb*  control;
04459 
04460     control = (struct iocb *)events[i].obj;
04461     ut_a(control != NULL);
04462 
04463     slot = (os_aio_slot_t *) control->data;
04464 
04465     /* Some sanity checks. */
04466     ut_a(slot != NULL);
04467     ut_a(slot->reserved);
04468 
04469 #if defined(UNIV_AIO_DEBUG)
04470     fprintf(stderr,
04471       "io_getevents[%c]: slot[%p] ctx[%p]"
04472       " seg[%lu]\n",
04473       (slot->type == OS_FILE_WRITE) ? 'w' : 'r',
04474       slot, io_ctx, segment);
04475 #endif
04476 
04477     /* We are not scribbling previous segment. */
04478     ut_a(slot->pos >= start_pos);
04479 
04480     /* We have not overstepped to next segment. */
04481     ut_a(slot->pos < end_pos);
04482 
04483     /* Mark this request as completed. The error handling
04484     will be done in the calling function. */
04485     os_mutex_enter(array->mutex);
04486     slot->n_bytes = events[i].res;
04487     slot->ret = events[i].res2;
04488     slot->io_already_done = TRUE;
04489     os_mutex_exit(array->mutex);
04490   }
04491 
04492   return;
04493 }
04494 
04495 /**********************************************************************/
04503 UNIV_INTERN
04504 ibool
04505 os_aio_linux_handle(
04506 /*================*/
04507   ulint global_seg, 
04513   fil_node_t**message1, 
04514   void**  message2, 
04518   ulint*  type)   
04519 {
04520   ulint   segment;
04521   os_aio_array_t* array;
04522   os_aio_slot_t*  slot;
04523   ulint   n;
04524   ulint   i;
04525   ibool   ret = FALSE;
04526 
04527   /* Should never be doing Sync IO here. */
04528   ut_a(global_seg != ULINT_UNDEFINED);
04529 
04530   /* Find the array and the local segment. */
04531   segment = os_aio_get_array_and_local_segment(&array, global_seg);
04532   n = array->n_slots / array->n_segments;
04533 
04534   /* Loop until we have found a completed request. */
04535   for (;;) {
04536     os_mutex_enter(array->mutex);
04537     for (i = 0; i < n; ++i) {
04538       slot = os_aio_array_get_nth_slot(
04539           array, i + segment * n);
04540       if (slot->reserved && slot->io_already_done) {
04541         /* Something for us to work on. */
04542         goto found;
04543       }
04544     }
04545 
04546     os_mutex_exit(array->mutex);
04547 
04548     /* We don't have any completed request.
04549     Wait for some request. Note that we return
04550     from wait iff we have found a request. */
04551 
04552     srv_set_io_thread_op_info(global_seg,
04553       "waiting for completed aio requests");
04554     os_aio_linux_collect(array, segment, n);
04555   }
04556 
04557 found:
04558   /* Note that it may be that there are more then one completed
04559   IO requests. We process them one at a time. We may have a case
04560   here to improve the performance slightly by dealing with all
04561   requests in one sweep. */
04562   srv_set_io_thread_op_info(global_seg,
04563         "processing completed aio requests");
04564 
04565   /* Ensure that we are scribbling only our segment. */
04566   ut_a(i < n);
04567 
04568   ut_ad(slot != NULL);
04569   ut_ad(slot->reserved);
04570   ut_ad(slot->io_already_done);
04571 
04572   *message1 = slot->message1;
04573   *message2 = slot->message2;
04574 
04575   *type = slot->type;
04576 
04577   if ((slot->ret == 0) && (slot->n_bytes == (long)slot->len)) {
04578     ret = TRUE;
04579 
04580 #ifdef UNIV_DO_FLUSH
04581     if (slot->type == OS_FILE_WRITE
04582         && !os_do_not_call_flush_at_each_write)
04583         && !os_file_flush(slot->file) {
04584       ut_error;
04585     }
04586 #endif /* UNIV_DO_FLUSH */
04587   } else {
04588     errno = -slot->ret;
04589 
04590     /* os_file_handle_error does tell us if we should retry
04591     this IO. As it stands now, we don't do this retry when
04592     reaping requests from a different context than
04593     the dispatcher. This non-retry logic is the same for
04594     windows and linux native AIO.
04595     We should probably look into this to transparently
04596     re-submit the IO. */
04597     os_file_handle_error(slot->name, "Linux aio");
04598 
04599     ret = FALSE;
04600   }
04601 
04602   os_mutex_exit(array->mutex);
04603 
04604   os_aio_array_free_slot(array, slot);
04605 
04606   return(ret);
04607 }
04608 #endif /* LINUX_NATIVE_AIO */
04609 
04610 /**********************************************************************/
04614 UNIV_INTERN
04615 ibool
04616 os_aio_simulated_handle(
04617 /*====================*/
04618   ulint global_segment, 
04623   fil_node_t**message1, 
04628   void**  message2,
04629   ulint*  type)   
04630 {
04631   os_aio_array_t* array;
04632   ulint   segment;
04633   os_aio_slot_t*  slot;
04634   os_aio_slot_t*  slot2;
04635   os_aio_slot_t*  consecutive_ios[OS_AIO_MERGE_N_CONSECUTIVE];
04636   ulint   n_consecutive;
04637   ulint   total_len;
04638   ulint   offs;
04639   ulint   lowest_offset;
04640   ulint   biggest_age;
04641   ulint   age;
04642   byte*   combined_buf;
04643   byte*   combined_buf2;
04644   ibool   ret;
04645   ulint   n;
04646   ulint   i;
04647 
04648   /* Fix compiler warning */
04649   *consecutive_ios = NULL;
04650 
04651   memset(consecutive_ios, 0, sizeof(os_aio_slot_t*) * OS_AIO_MERGE_N_CONSECUTIVE);
04652   segment = os_aio_get_array_and_local_segment(&array, global_segment);
04653 
04654 restart:
04655   /* NOTE! We only access constant fields in os_aio_array. Therefore
04656   we do not have to acquire the protecting mutex yet */
04657 
04658   srv_set_io_thread_op_info(global_segment,
04659           "looking for i/o requests (a)");
04660   ut_ad(os_aio_validate());
04661   ut_ad(segment < array->n_segments);
04662 
04663   n = array->n_slots / array->n_segments;
04664 
04665   /* Look through n slots after the segment * n'th slot */
04666 
04667   if (array == os_aio_read_array
04668       && os_aio_recommend_sleep_for_read_threads) {
04669 
04670     /* Give other threads chance to add several i/os to the array
04671     at once. */
04672 
04673     goto recommended_sleep;
04674   }
04675 
04676   os_mutex_enter(array->mutex);
04677 
04678   srv_set_io_thread_op_info(global_segment,
04679           "looking for i/o requests (b)");
04680 
04681   /* Check if there is a slot for which the i/o has already been
04682   done */
04683 
04684   for (i = 0; i < n; i++) {
04685     slot = os_aio_array_get_nth_slot(array, i + segment * n);
04686 
04687     if (slot->reserved && slot->io_already_done) {
04688 
04689       if (os_aio_print_debug) {
04690         fprintf(stderr,
04691           "InnoDB: i/o for slot %lu"
04692           " already done, returning\n",
04693           (ulong) i);
04694       }
04695 
04696       ret = TRUE;
04697 
04698       goto slot_io_done;
04699     }
04700   }
04701 
04702   n_consecutive = 0;
04703 
04704   /* If there are at least 2 seconds old requests, then pick the oldest
04705   one to prevent starvation. If several requests have the same age,
04706   then pick the one at the lowest offset. */
04707 
04708   biggest_age = 0;
04709   lowest_offset = ULINT_MAX;
04710 
04711   for (i = 0; i < n; i++) {
04712     slot = os_aio_array_get_nth_slot(array, i + segment * n);
04713 
04714     if (slot->reserved) {
04715       age = (ulint)difftime(time(NULL),
04716                 slot->reservation_time);
04717 
04718       if ((age >= 2 && age > biggest_age)
04719           || (age >= 2 && age == biggest_age
04720         && slot->offset < lowest_offset)) {
04721 
04722         /* Found an i/o request */
04723         consecutive_ios[0] = slot;
04724 
04725         n_consecutive = 1;
04726 
04727         biggest_age = age;
04728         lowest_offset = slot->offset;
04729       }
04730     }
04731   }
04732 
04733   if (n_consecutive == 0) {
04734     /* There were no old requests. Look for an i/o request at the
04735     lowest offset in the array (we ignore the high 32 bits of the
04736     offset in these heuristics) */
04737 
04738     lowest_offset = ULINT_MAX;
04739 
04740     for (i = 0; i < n; i++) {
04741       slot = os_aio_array_get_nth_slot(array,
04742                i + segment * n);
04743 
04744       if (slot->reserved && slot->offset < lowest_offset) {
04745 
04746         /* Found an i/o request */
04747         consecutive_ios[0] = slot;
04748 
04749         n_consecutive = 1;
04750 
04751         lowest_offset = slot->offset;
04752       }
04753     }
04754   }
04755 
04756   if (n_consecutive == 0) {
04757 
04758     /* No i/o requested at the moment */
04759 
04760     goto wait_for_io;
04761   }
04762 
04763   /* if n_consecutive != 0, then we have assigned
04764   something valid to consecutive_ios[0] */
04765   ut_ad(n_consecutive != 0);
04766   ut_ad(consecutive_ios[0] != NULL);
04767 
04768   slot = consecutive_ios[0];
04769 
04770   /* Check if there are several consecutive blocks to read or write */
04771 
04772 consecutive_loop:
04773   for (i = 0; i < n; i++) {
04774     slot2 = os_aio_array_get_nth_slot(array, i + segment * n);
04775 
04776     if (slot2->reserved && slot2 != slot
04777         && slot2->offset == slot->offset + slot->len
04778         /* check that sum does not wrap over */
04779         && slot->offset + slot->len > slot->offset
04780         && slot2->offset_high == slot->offset_high
04781         && slot2->type == slot->type
04782         && slot2->file == slot->file) {
04783 
04784       /* Found a consecutive i/o request */
04785 
04786       consecutive_ios[n_consecutive] = slot2;
04787       n_consecutive++;
04788 
04789       slot = slot2;
04790 
04791       if (n_consecutive < OS_AIO_MERGE_N_CONSECUTIVE) {
04792 
04793         goto consecutive_loop;
04794       } else {
04795         break;
04796       }
04797     }
04798   }
04799 
04800   srv_set_io_thread_op_info(global_segment, "consecutive i/o requests");
04801 
04802   /* We have now collected n_consecutive i/o requests in the array;
04803   allocate a single buffer which can hold all data, and perform the
04804   i/o */
04805 
04806   total_len = 0;
04807   slot = consecutive_ios[0];
04808 
04809   for (i = 0; i < n_consecutive; i++) {
04810     total_len += consecutive_ios[i]->len;
04811   }
04812 
04813   if (n_consecutive == 1) {
04814     /* We can use the buffer of the i/o request */
04815     combined_buf = slot->buf;
04816     combined_buf2 = NULL;
04817   } else {
04818     combined_buf2 = static_cast<unsigned char *>(ut_malloc(total_len + UNIV_PAGE_SIZE));
04819 
04820     ut_a(combined_buf2);
04821 
04822     combined_buf = static_cast<unsigned char *>(ut_align(combined_buf2, UNIV_PAGE_SIZE));
04823   }
04824 
04825   /* We release the array mutex for the time of the i/o: NOTE that
04826   this assumes that there is just one i/o-handler thread serving
04827   a single segment of slots! */
04828 
04829   os_mutex_exit(array->mutex);
04830 
04831   if (slot->type == OS_FILE_WRITE && n_consecutive > 1) {
04832     /* Copy the buffers to the combined buffer */
04833     offs = 0;
04834 
04835     for (i = 0; i < n_consecutive; i++) {
04836 
04837       ut_memcpy(combined_buf + offs, consecutive_ios[i]->buf,
04838           consecutive_ios[i]->len);
04839       offs += consecutive_ios[i]->len;
04840     }
04841   }
04842 
04843   srv_set_io_thread_op_info(global_segment, "doing file i/o");
04844 
04845   if (os_aio_print_debug) {
04846     fprintf(stderr,
04847       "InnoDB: doing i/o of type %lu at offset %lu %lu,"
04848       " length %lu\n",
04849       (ulong) slot->type, (ulong) slot->offset_high,
04850       (ulong) slot->offset, (ulong) total_len);
04851   }
04852 
04853   /* Do the i/o with ordinary, synchronous i/o functions: */
04854   if (slot->type == OS_FILE_WRITE) {
04855     ret = os_file_write(slot->name, slot->file, combined_buf,
04856             slot->offset, slot->offset_high,
04857             total_len);
04858   } else {
04859     ret = os_file_read(slot->file, combined_buf,
04860            slot->offset, slot->offset_high, total_len);
04861   }
04862 
04863   ut_a(ret);
04864   srv_set_io_thread_op_info(global_segment, "file i/o done");
04865 
04866 #if 0
04867   fprintf(stderr,
04868     "aio: %lu consecutive %lu:th segment, first offs %lu blocks\n",
04869     n_consecutive, global_segment, slot->offset / UNIV_PAGE_SIZE);
04870 #endif
04871 
04872   if (slot->type == OS_FILE_READ && n_consecutive > 1) {
04873     /* Copy the combined buffer to individual buffers */
04874     offs = 0;
04875 
04876     for (i = 0; i < n_consecutive; i++) {
04877 
04878       ut_memcpy(consecutive_ios[i]->buf, combined_buf + offs,
04879           consecutive_ios[i]->len);
04880       offs += consecutive_ios[i]->len;
04881     }
04882   }
04883 
04884   if (combined_buf2) {
04885     ut_free(combined_buf2);
04886   }
04887 
04888   os_mutex_enter(array->mutex);
04889 
04890   /* Mark the i/os done in slots */
04891 
04892   for (i = 0; i < n_consecutive; i++) {
04893     consecutive_ios[i]->io_already_done = TRUE;
04894   }
04895 
04896   /* We return the messages for the first slot now, and if there were
04897   several slots, the messages will be returned with subsequent calls
04898   of this function */
04899 
04900 slot_io_done:
04901 
04902   ut_a(slot->reserved);
04903 
04904   *message1 = slot->message1;
04905   *message2 = slot->message2;
04906 
04907   *type = slot->type;
04908 
04909   os_mutex_exit(array->mutex);
04910 
04911   os_aio_array_free_slot(array, slot);
04912 
04913   return(ret);
04914 
04915 wait_for_io:
04916   srv_set_io_thread_op_info(global_segment, "resetting wait event");
04917 
04918   /* We wait here until there again can be i/os in the segment
04919   of this thread */
04920 
04921   os_event_reset(os_aio_segment_wait_events[global_segment]);
04922 
04923   os_mutex_exit(array->mutex);
04924 
04925 recommended_sleep:
04926   srv_set_io_thread_op_info(global_segment, "waiting for i/o request");
04927 
04928   os_event_wait(os_aio_segment_wait_events[global_segment]);
04929 
04930   if (os_aio_print_debug) {
04931     fprintf(stderr,
04932       "InnoDB: i/o handler thread for i/o"
04933       " segment %lu wakes up\n",
04934       (ulong) global_segment);
04935   }
04936 
04937   goto restart;
04938 }
04939 
04940 /**********************************************************************/
04943 static
04944 ibool
04945 os_aio_array_validate(
04946 /*==================*/
04947   os_aio_array_t* array)  
04948 {
04949   os_aio_slot_t*  slot;
04950   ulint   n_reserved  = 0;
04951   ulint   i;
04952 
04953   ut_a(array);
04954 
04955   os_mutex_enter(array->mutex);
04956 
04957   ut_a(array->n_slots > 0);
04958   ut_a(array->n_segments > 0);
04959 
04960   for (i = 0; i < array->n_slots; i++) {
04961     slot = os_aio_array_get_nth_slot(array, i);
04962 
04963     if (slot->reserved) {
04964       n_reserved++;
04965       ut_a(slot->len > 0);
04966     }
04967   }
04968 
04969   ut_a(array->n_reserved == n_reserved);
04970 
04971   os_mutex_exit(array->mutex);
04972 
04973   return(TRUE);
04974 }
04975 
04976 /**********************************************************************/
04979 UNIV_INTERN
04980 ibool
04981 os_aio_validate(void)
04982 /*=================*/
04983 {
04984   os_aio_array_validate(os_aio_read_array);
04985   os_aio_array_validate(os_aio_write_array);
04986   os_aio_array_validate(os_aio_ibuf_array);
04987   os_aio_array_validate(os_aio_log_array);
04988   os_aio_array_validate(os_aio_sync_array);
04989 
04990   return(TRUE);
04991 }
04992 
04993 /**********************************************************************/
04998 static
04999 void
05000 os_aio_print_segment_info(
05001 /*======================*/
05002   FILE*   file, 
05003   ulint*    n_seg,  
05004   os_aio_array_t* array)  
05005 {
05006   ulint i;
05007 
05008   ut_ad(array);
05009   ut_ad(n_seg);
05010   ut_ad(array->n_segments > 0);
05011 
05012   if (array->n_segments == 1) {
05013     return;
05014   }
05015 
05016   fprintf(file, " [");
05017   for (i = 0; i < array->n_segments; i++) {
05018     if (i != 0) {
05019       fprintf(file, ", ");
05020     }
05021 
05022     fprintf(file, "%lu", n_seg[i]);
05023   }
05024   fprintf(file, "] ");
05025 }
05026 
05027 /**********************************************************************/
05029 UNIV_INTERN
05030 void
05031 os_aio_print(
05032 /*=========*/
05033   FILE* file) 
05034 {
05035   os_aio_array_t* array;
05036   os_aio_slot_t*  slot;
05037   ulint   n_reserved;
05038   ulint   n_res_seg[SRV_MAX_N_IO_THREADS];
05039   time_t    current_time;
05040   double    time_elapsed;
05041   double    avg_bytes_read;
05042   ulint   i;
05043 
05044   for (i = 0; i < srv_n_file_io_threads; i++) {
05045     fprintf(file, "I/O thread %lu state: %s (%s)", (ulong) i,
05046       srv_io_thread_op_info[i],
05047       srv_io_thread_function[i]);
05048 
05049 #ifndef __WIN__
05050     if (os_aio_segment_wait_events[i]->is_set) {
05051       fprintf(file, " ev set");
05052     }
05053 #endif
05054 
05055     fprintf(file, "\n");
05056   }
05057 
05058   fputs("Pending normal aio reads:", file);
05059 
05060   array = os_aio_read_array;
05061 loop:
05062   ut_a(array);
05063 
05064   os_mutex_enter(array->mutex);
05065 
05066   ut_a(array->n_slots > 0);
05067   ut_a(array->n_segments > 0);
05068 
05069   n_reserved = 0;
05070 
05071   memset(n_res_seg, 0x0, sizeof(n_res_seg));
05072 
05073   for (i = 0; i < array->n_slots; i++) {
05074     ulint seg_no;
05075 
05076     slot = os_aio_array_get_nth_slot(array, i);
05077 
05078     seg_no = (i * array->n_segments) / array->n_slots;
05079     if (slot->reserved) {
05080       n_reserved++;
05081       n_res_seg[seg_no]++;
05082 #if 0
05083       fprintf(stderr, "Reserved slot, messages %p %p\n",
05084         (void*) slot->message1,
05085         (void*) slot->message2);
05086 #endif
05087       ut_a(slot->len > 0);
05088     }
05089   }
05090 
05091   ut_a(array->n_reserved == n_reserved);
05092 
05093   fprintf(file, " %lu", (ulong) n_reserved);
05094 
05095   os_aio_print_segment_info(file, n_res_seg, array);
05096 
05097   os_mutex_exit(array->mutex);
05098 
05099   if (array == os_aio_read_array) {
05100     fputs(", aio writes:", file);
05101 
05102     array = os_aio_write_array;
05103 
05104     goto loop;
05105   }
05106 
05107   if (array == os_aio_write_array) {
05108     fputs(",\n ibuf aio reads:", file);
05109     array = os_aio_ibuf_array;
05110 
05111     goto loop;
05112   }
05113 
05114   if (array == os_aio_ibuf_array) {
05115     fputs(", log i/o's:", file);
05116     array = os_aio_log_array;
05117 
05118     goto loop;
05119   }
05120 
05121   if (array == os_aio_log_array) {
05122     fputs(", sync i/o's:", file);
05123     array = os_aio_sync_array;
05124 
05125     goto loop;
05126   }
05127 
05128   putc('\n', file);
05129   current_time = time(NULL);
05130   time_elapsed = 0.001 + difftime(current_time, os_last_printout);
05131 
05132   fprintf(file,
05133     "Pending flushes (fsync) log: %lu; buffer pool: %lu\n"
05134     "%lu OS file reads, %lu OS file writes, %lu OS fsyncs\n",
05135     (ulong) fil_n_pending_log_flushes,
05136     (ulong) fil_n_pending_tablespace_flushes,
05137     (ulong) os_n_file_reads, (ulong) os_n_file_writes,
05138     (ulong) os_n_fsyncs);
05139 
05140   if (os_file_n_pending_preads != 0 || os_file_n_pending_pwrites != 0) {
05141     fprintf(file,
05142       "%lu pending preads, %lu pending pwrites\n",
05143       (ulong) os_file_n_pending_preads,
05144       (ulong) os_file_n_pending_pwrites);
05145   }
05146 
05147   if (os_n_file_reads == os_n_file_reads_old) {
05148     avg_bytes_read = 0.0;
05149   } else {
05150     avg_bytes_read = (double) os_bytes_read_since_printout
05151       / (os_n_file_reads - os_n_file_reads_old);
05152   }
05153 
05154   fprintf(file,
05155     "%.2f reads/s, %lu avg bytes/read,"
05156     " %.2f writes/s, %.2f fsyncs/s\n",
05157     (os_n_file_reads - os_n_file_reads_old)
05158     / time_elapsed,
05159     (ulong)avg_bytes_read,
05160     (os_n_file_writes - os_n_file_writes_old)
05161     / time_elapsed,
05162     (os_n_fsyncs - os_n_fsyncs_old)
05163     / time_elapsed);
05164 
05165   os_n_file_reads_old = os_n_file_reads;
05166   os_n_file_writes_old = os_n_file_writes;
05167   os_n_fsyncs_old = os_n_fsyncs;
05168   os_bytes_read_since_printout = 0;
05169 
05170   os_last_printout = current_time;
05171 }
05172 
05173 /**********************************************************************/
05175 UNIV_INTERN
05176 void
05177 os_aio_refresh_stats(void)
05178 /*======================*/
05179 {
05180   os_n_file_reads_old = os_n_file_reads;
05181   os_n_file_writes_old = os_n_file_writes;
05182   os_n_fsyncs_old = os_n_fsyncs;
05183   os_bytes_read_since_printout = 0;
05184 
05185   os_last_printout = time(NULL);
05186 }
05187 
05188 #ifdef UNIV_DEBUG
05189 /**********************************************************************/
05193 UNIV_INTERN
05194 ibool
05195 os_aio_all_slots_free(void)
05196 /*=======================*/
05197 {
05198   os_aio_array_t* array;
05199   ulint   n_res = 0;
05200 
05201   array = os_aio_read_array;
05202 
05203   os_mutex_enter(array->mutex);
05204 
05205   n_res += array->n_reserved;
05206 
05207   os_mutex_exit(array->mutex);
05208 
05209   array = os_aio_write_array;
05210 
05211   os_mutex_enter(array->mutex);
05212 
05213   n_res += array->n_reserved;
05214 
05215   os_mutex_exit(array->mutex);
05216 
05217   array = os_aio_ibuf_array;
05218 
05219   os_mutex_enter(array->mutex);
05220 
05221   n_res += array->n_reserved;
05222 
05223   os_mutex_exit(array->mutex);
05224 
05225   array = os_aio_log_array;
05226 
05227   os_mutex_enter(array->mutex);
05228 
05229   n_res += array->n_reserved;
05230 
05231   os_mutex_exit(array->mutex);
05232 
05233   array = os_aio_sync_array;
05234 
05235   os_mutex_enter(array->mutex);
05236 
05237   n_res += array->n_reserved;
05238 
05239   os_mutex_exit(array->mutex);
05240 
05241   if (n_res == 0) {
05242 
05243     return(TRUE);
05244   }
05245 
05246   return(FALSE);
05247 }
05248 #endif /* UNIV_DEBUG */
05249 
05250 #endif /* !UNIV_HOTBACKUP */