~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/os/os0file.c

  • Committer: Lee
  • Date: 2008-10-30 22:02:01 UTC
  • mto: (572.1.2 devel)
  • mto: This revision was merged to the branch mainline in revision 573.
  • Revision ID: lbieber@lbieber-desktop-20081030220201-elb6qprbzpn7c5a4
add my name to the AUTHORS file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
The interface to the operating system file i/o primitives
 
3
 
 
4
(c) 1995 Innobase Oy
 
5
 
 
6
Created 10/21/1995 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "os0file.h"
 
10
#include "os0sync.h"
 
11
#include "os0thread.h"
 
12
#include "ut0mem.h"
 
13
#include "srv0srv.h"
 
14
#include "srv0start.h"
 
15
#include "fil0fil.h"
 
16
#include "buf0buf.h"
 
17
 
 
18
#if defined(UNIV_HOTBACKUP) && defined(__WIN__)
 
19
/* Add includes for the _stat() call to compile on Windows */
 
20
#include <sys/types.h>
 
21
#include <sys/stat.h>
 
22
#include <errno.h>
 
23
#endif /* UNIV_HOTBACKUP */
 
24
 
 
25
#ifdef POSIX_ASYNC_IO
 
26
/* We assume in this case that the OS has standard Posix aio (at least SunOS
 
27
2.6, HP-UX 11i and AIX 4.3 have) */
 
28
 
 
29
#endif
 
30
 
 
31
/* This specifies the file permissions InnoDB uses when it creates files in
 
32
Unix; the value of os_innodb_umask is initialized in ha_innodb.cc to
 
33
my_umask */
 
34
 
 
35
#ifndef __WIN__
 
36
UNIV_INTERN ulint       os_innodb_umask
 
37
                        = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
 
38
#else
 
39
UNIV_INTERN ulint       os_innodb_umask         = 0;
 
40
#endif
 
41
 
 
42
#ifdef UNIV_DO_FLUSH
 
43
/* If the following is set to TRUE, we do not call os_file_flush in every
 
44
os_file_write. We can set this TRUE when the doublewrite buffer is used. */
 
45
UNIV_INTERN ibool       os_do_not_call_flush_at_each_write      = FALSE;
 
46
#else
 
47
/* We do not call os_file_flush in every os_file_write. */
 
48
#endif /* UNIV_DO_FLUSH */
 
49
 
 
50
/* We use these mutexes to protect lseek + file i/o operation, if the
 
51
OS does not provide an atomic pread or pwrite, or similar */
 
52
#define OS_FILE_N_SEEK_MUTEXES  16
 
53
UNIV_INTERN os_mutex_t  os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES];
 
54
 
 
55
/* In simulated aio, merge at most this many consecutive i/os */
 
56
#define OS_AIO_MERGE_N_CONSECUTIVE      64
 
57
 
 
58
/* If this flag is TRUE, then we will use the native aio of the
 
59
OS (provided we compiled Innobase with it in), otherwise we will
 
60
use simulated aio we build below with threads */
 
61
 
 
62
UNIV_INTERN ibool       os_aio_use_native_aio   = FALSE;
 
63
 
 
64
UNIV_INTERN ibool       os_aio_print_debug      = FALSE;
 
65
 
 
66
/* The aio array slot structure */
 
67
typedef struct os_aio_slot_struct       os_aio_slot_t;
 
68
 
 
69
struct os_aio_slot_struct{
 
70
        ibool           is_read;        /* TRUE if a read operation */
 
71
        ulint           pos;            /* index of the slot in the aio
 
72
                                        array */
 
73
        ibool           reserved;       /* TRUE if this slot is reserved */
 
74
        time_t          reservation_time;/* time when reserved */
 
75
        ulint           len;            /* length of the block to read or
 
76
                                        write */
 
77
        byte*           buf;            /* buffer used in i/o */
 
78
        ulint           type;           /* OS_FILE_READ or OS_FILE_WRITE */
 
79
        ulint           offset;         /* 32 low bits of file offset in
 
80
                                        bytes */
 
81
        ulint           offset_high;    /* 32 high bits of file offset */
 
82
        os_file_t       file;           /* file where to read or write */
 
83
        const char*     name;           /* file name or path */
 
84
        ibool           io_already_done;/* used only in simulated aio:
 
85
                                        TRUE if the physical i/o already
 
86
                                        made and only the slot message
 
87
                                        needs to be passed to the caller
 
88
                                        of os_aio_simulated_handle */
 
89
        fil_node_t*     message1;       /* message which is given by the */
 
90
        void*           message2;       /* the requester of an aio operation
 
91
                                        and which can be used to identify
 
92
                                        which pending aio operation was
 
93
                                        completed */
 
94
#ifdef WIN_ASYNC_IO
 
95
        os_event_t      event;          /* event object we need in the
 
96
                                        OVERLAPPED struct */
 
97
        OVERLAPPED      control;        /* Windows control block for the
 
98
                                        aio request */
 
99
#elif defined(POSIX_ASYNC_IO)
 
100
        struct aiocb    control;        /* Posix control block for aio
 
101
                                        request */
 
102
#endif
 
103
};
 
104
 
 
105
/* The aio array structure */
 
106
typedef struct os_aio_array_struct      os_aio_array_t;
 
107
 
 
108
struct os_aio_array_struct{
 
109
        os_mutex_t      mutex;    /* the mutex protecting the aio array */
 
110
        os_event_t      not_full; /* The event which is set to the signaled
 
111
                                  state when there is space in the aio
 
112
                                  outside the ibuf segment */
 
113
        os_event_t      is_empty; /* The event which is set to the signaled
 
114
                                  state when there are no pending i/os
 
115
                                  in this array */
 
116
        ulint           n_slots;  /* Total number of slots in the aio array.
 
117
                                  This must be divisible by n_threads. */
 
118
        ulint           n_segments;/* Number of segments in the aio array of
 
119
                                  pending aio requests. A thread can wait
 
120
                                  separately for any one of the segments. */
 
121
        ulint           n_reserved;/* Number of reserved slots in the
 
122
                                  aio array outside the ibuf segment */
 
123
        os_aio_slot_t*  slots;    /* Pointer to the slots in the array */
 
124
#ifdef __WIN__
 
125
        os_native_event_t* native_events;
 
126
                                  /* Pointer to an array of OS native event
 
127
                                  handles where we copied the handles from
 
128
                                  slots, in the same order. This can be used
 
129
                                  in WaitForMultipleObjects; used only in
 
130
                                  Windows */
 
131
#endif
 
132
};
 
133
 
 
134
/* Array of events used in simulated aio */
 
135
static os_event_t*      os_aio_segment_wait_events      = NULL;
 
136
 
 
137
/* The aio arrays for non-ibuf i/o and ibuf i/o, as well as sync aio. These
 
138
are NULL when the module has not yet been initialized. */
 
139
static os_aio_array_t*  os_aio_read_array       = NULL;
 
140
static os_aio_array_t*  os_aio_write_array      = NULL;
 
141
static os_aio_array_t*  os_aio_ibuf_array       = NULL;
 
142
static os_aio_array_t*  os_aio_log_array        = NULL;
 
143
static os_aio_array_t*  os_aio_sync_array       = NULL;
 
144
 
 
145
static ulint    os_aio_n_segments       = ULINT_UNDEFINED;
 
146
 
 
147
/* If the following is TRUE, read i/o handler threads try to
 
148
wait until a batch of new read requests have been posted */
 
149
static ibool    os_aio_recommend_sleep_for_read_threads = FALSE;
 
150
 
 
151
UNIV_INTERN ulint       os_n_file_reads         = 0;
 
152
UNIV_INTERN ulint       os_bytes_read_since_printout = 0;
 
153
UNIV_INTERN ulint       os_n_file_writes        = 0;
 
154
UNIV_INTERN ulint       os_n_fsyncs             = 0;
 
155
UNIV_INTERN ulint       os_n_file_reads_old     = 0;
 
156
UNIV_INTERN ulint       os_n_file_writes_old    = 0;
 
157
UNIV_INTERN ulint       os_n_fsyncs_old         = 0;
 
158
UNIV_INTERN time_t      os_last_printout;
 
159
 
 
160
UNIV_INTERN ibool       os_has_said_disk_full   = FALSE;
 
161
 
 
162
/* The mutex protecting the following counts of pending I/O operations */
 
163
static os_mutex_t       os_file_count_mutex;
 
164
UNIV_INTERN ulint       os_file_n_pending_preads  = 0;
 
165
UNIV_INTERN ulint       os_file_n_pending_pwrites = 0;
 
166
UNIV_INTERN ulint       os_n_pending_writes = 0;
 
167
UNIV_INTERN ulint       os_n_pending_reads = 0;
 
168
 
 
169
/***************************************************************************
 
170
Gets the operating system version. Currently works only on Windows. */
 
171
UNIV_INTERN
 
172
ulint
 
173
os_get_os_version(void)
 
174
/*===================*/
 
175
                  /* out: OS_WIN95, OS_WIN31, OS_WINNT, OS_WIN2000 */
 
176
{
 
177
#ifdef __WIN__
 
178
        OSVERSIONINFO     os_info;
 
179
 
 
180
        os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 
181
 
 
182
        ut_a(GetVersionEx(&os_info));
 
183
 
 
184
        if (os_info.dwPlatformId == VER_PLATFORM_WIN32s) {
 
185
                return(OS_WIN31);
 
186
        } else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
 
187
                return(OS_WIN95);
 
188
        } else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
 
189
                if (os_info.dwMajorVersion <= 4) {
 
190
                        return(OS_WINNT);
 
191
                } else {
 
192
                        return(OS_WIN2000);
 
193
                }
 
194
        } else {
 
195
                ut_error;
 
196
                return(0);
 
197
        }
 
198
#else
 
199
        ut_error;
 
200
 
 
201
        return(0);
 
202
#endif
 
203
}
 
204
 
 
205
/***************************************************************************
 
206
Retrieves the last error number if an error occurs in a file io function.
 
207
The number should be retrieved before any other OS calls (because they may
 
208
overwrite the error number). If the number is not known to this program,
 
209
the OS error number + 100 is returned. */
 
210
UNIV_INTERN
 
211
ulint
 
212
os_file_get_last_error(
 
213
/*===================*/
 
214
                                        /* out: error number, or OS error
 
215
                                        number + 100 */
 
216
        ibool   report_all_errors)      /* in: TRUE if we want an error message
 
217
                                        printed of all errors */
 
218
{
 
219
        ulint   err;
 
220
 
 
221
#ifdef __WIN__
 
222
 
 
223
        err = (ulint) GetLastError();
 
224
 
 
225
        if (report_all_errors
 
226
            || (err != ERROR_DISK_FULL && err != ERROR_FILE_EXISTS)) {
 
227
 
 
228
                ut_print_timestamp(stderr);
 
229
                fprintf(stderr,
 
230
                        "  InnoDB: Operating system error number %lu"
 
231
                        " in a file operation.\n", (ulong) err);
 
232
 
 
233
                if (err == ERROR_PATH_NOT_FOUND) {
 
234
                        fprintf(stderr,
 
235
                                "InnoDB: The error means the system"
 
236
                                " cannot find the path specified.\n");
 
237
 
 
238
                        if (srv_is_being_started) {
 
239
                                fprintf(stderr,
 
240
                                        "InnoDB: If you are installing InnoDB,"
 
241
                                        " remember that you must create\n"
 
242
                                        "InnoDB: directories yourself, InnoDB"
 
243
                                        " does not create them.\n");
 
244
                        }
 
245
                } else if (err == ERROR_ACCESS_DENIED) {
 
246
                        fprintf(stderr,
 
247
                                "InnoDB: The error means mysqld does not have"
 
248
                                " the access rights to\n"
 
249
                                "InnoDB: the directory. It may also be"
 
250
                                " you have created a subdirectory\n"
 
251
                                "InnoDB: of the same name as a data file.\n");
 
252
                } else if (err == ERROR_SHARING_VIOLATION
 
253
                           || err == ERROR_LOCK_VIOLATION) {
 
254
                        fprintf(stderr,
 
255
                                "InnoDB: The error means that another program"
 
256
                                " is using InnoDB's files.\n"
 
257
                                "InnoDB: This might be a backup or antivirus"
 
258
                                " software or another instance\n"
 
259
                                "InnoDB: of MySQL."
 
260
                                " Please close it to get rid of this error.\n");
 
261
                } else {
 
262
                        fprintf(stderr,
 
263
                                "InnoDB: Some operating system error numbers"
 
264
                                " are described at\n"
 
265
                                "InnoDB: "
 
266
                                "http://dev.mysql.com/doc/refman/5.1/en/"
 
267
                                "operating-system-error-codes.html\n");
 
268
                }
 
269
        }
 
270
 
 
271
        fflush(stderr);
 
272
 
 
273
        if (err == ERROR_FILE_NOT_FOUND) {
 
274
                return(OS_FILE_NOT_FOUND);
 
275
        } else if (err == ERROR_DISK_FULL) {
 
276
                return(OS_FILE_DISK_FULL);
 
277
        } else if (err == ERROR_FILE_EXISTS) {
 
278
                return(OS_FILE_ALREADY_EXISTS);
 
279
        } else if (err == ERROR_SHARING_VIOLATION
 
280
                   || err == ERROR_LOCK_VIOLATION) {
 
281
                return(OS_FILE_SHARING_VIOLATION);
 
282
        } else {
 
283
                return(100 + err);
 
284
        }
 
285
#else
 
286
        err = (ulint) errno;
 
287
 
 
288
        if (report_all_errors
 
289
            || (err != ENOSPC && err != EEXIST)) {
 
290
 
 
291
                ut_print_timestamp(stderr);
 
292
                fprintf(stderr,
 
293
                        "  InnoDB: Operating system error number %lu"
 
294
                        " in a file operation.\n", (ulong) err);
 
295
 
 
296
                if (err == ENOENT) {
 
297
                        fprintf(stderr,
 
298
                                "InnoDB: The error means the system"
 
299
                                " cannot find the path specified.\n");
 
300
 
 
301
                        if (srv_is_being_started) {
 
302
                                fprintf(stderr,
 
303
                                        "InnoDB: If you are installing InnoDB,"
 
304
                                        " remember that you must create\n"
 
305
                                        "InnoDB: directories yourself, InnoDB"
 
306
                                        " does not create them.\n");
 
307
                        }
 
308
                } else if (err == EACCES) {
 
309
                        fprintf(stderr,
 
310
                                "InnoDB: The error means mysqld does not have"
 
311
                                " the access rights to\n"
 
312
                                "InnoDB: the directory.\n");
 
313
                } else {
 
314
                        if (strerror((int)err) != NULL) {
 
315
                                fprintf(stderr,
 
316
                                        "InnoDB: Error number %lu"
 
317
                                        " means '%s'.\n",
 
318
                                        err, strerror((int)err));
 
319
                        }
 
320
 
 
321
                        fprintf(stderr,
 
322
                                "InnoDB: Some operating system"
 
323
                                " error numbers are described at\n"
 
324
                                "InnoDB: "
 
325
                                "http://dev.mysql.com/doc/refman/5.1/en/"
 
326
                                "operating-system-error-codes.html\n");
 
327
                }
 
328
        }
 
329
 
 
330
        fflush(stderr);
 
331
 
 
332
        if (err == ENOSPC) {
 
333
                return(OS_FILE_DISK_FULL);
 
334
#ifdef POSIX_ASYNC_IO
 
335
        } else if (err == EAGAIN) {
 
336
                return(OS_FILE_AIO_RESOURCES_RESERVED);
 
337
#endif
 
338
        } else if (err == ENOENT) {
 
339
                return(OS_FILE_NOT_FOUND);
 
340
        } else if (err == EEXIST) {
 
341
                return(OS_FILE_ALREADY_EXISTS);
 
342
        } else if (err == EXDEV || err == ENOTDIR || err == EISDIR) {
 
343
                return(OS_FILE_PATH_ERROR);
 
344
        } else {
 
345
                return(100 + err);
 
346
        }
 
347
#endif
 
348
}
 
349
 
 
350
/********************************************************************
 
351
Does error handling when a file operation fails.
 
352
Conditionally exits (calling exit(3)) based on should_exit value and the
 
353
error type */
 
354
static
 
355
ibool
 
356
os_file_handle_error_cond_exit(
 
357
/*===========================*/
 
358
                                        /* out: TRUE if we should retry the
 
359
                                        operation */
 
360
        const char*     name,           /* in: name of a file or NULL */
 
361
        const char*     operation,      /* in: operation */
 
362
        ibool           should_exit)    /* in: call exit(3) if unknown error
 
363
                                        and this parameter is TRUE */
 
364
{
 
365
        ulint   err;
 
366
 
 
367
        err = os_file_get_last_error(FALSE);
 
368
 
 
369
        if (err == OS_FILE_DISK_FULL) {
 
370
                /* We only print a warning about disk full once */
 
371
 
 
372
                if (os_has_said_disk_full) {
 
373
 
 
374
                        return(FALSE);
 
375
                }
 
376
 
 
377
                if (name) {
 
378
                        ut_print_timestamp(stderr);
 
379
                        fprintf(stderr,
 
380
                                "  InnoDB: Encountered a problem with"
 
381
                                " file %s\n", name);
 
382
                }
 
383
 
 
384
                ut_print_timestamp(stderr);
 
385
                fprintf(stderr,
 
386
                        "  InnoDB: Disk is full. Try to clean the disk"
 
387
                        " to free space.\n");
 
388
 
 
389
                os_has_said_disk_full = TRUE;
 
390
 
 
391
                fflush(stderr);
 
392
 
 
393
                return(FALSE);
 
394
        } else if (err == OS_FILE_AIO_RESOURCES_RESERVED) {
 
395
 
 
396
                return(TRUE);
 
397
        } else if (err == OS_FILE_ALREADY_EXISTS
 
398
                   || err == OS_FILE_PATH_ERROR) {
 
399
 
 
400
                return(FALSE);
 
401
        } else if (err == OS_FILE_SHARING_VIOLATION) {
 
402
 
 
403
                os_thread_sleep(10000000);  /* 10 sec */
 
404
                return(TRUE);
 
405
        } else {
 
406
                if (name) {
 
407
                        fprintf(stderr, "InnoDB: File name %s\n", name);
 
408
                }
 
409
 
 
410
                fprintf(stderr, "InnoDB: File operation call: '%s'.\n",
 
411
                        operation);
 
412
 
 
413
                if (should_exit) {
 
414
                        fprintf(stderr, "InnoDB: Cannot continue operation.\n");
 
415
 
 
416
                        fflush(stderr);
 
417
 
 
418
                        exit(1);
 
419
                }
 
420
        }
 
421
 
 
422
        return(FALSE);
 
423
}
 
424
 
 
425
/********************************************************************
 
426
Does error handling when a file operation fails. */
 
427
static
 
428
ibool
 
429
os_file_handle_error(
 
430
/*=================*/
 
431
                                /* out: TRUE if we should retry the
 
432
                                operation */
 
433
        const char*     name,   /* in: name of a file or NULL */
 
434
        const char*     operation)/* in: operation */
 
435
{
 
436
        /* exit in case of unknown error */
 
437
        return(os_file_handle_error_cond_exit(name, operation, TRUE));
 
438
}
 
439
 
 
440
/********************************************************************
 
441
Does error handling when a file operation fails. */
 
442
static
 
443
ibool
 
444
os_file_handle_error_no_exit(
 
445
/*=========================*/
 
446
                                /* out: TRUE if we should retry the
 
447
                                operation */
 
448
        const char*     name,   /* in: name of a file or NULL */
 
449
        const char*     operation)/* in: operation */
 
450
{
 
451
        /* don't exit in case of unknown error */
 
452
        return(os_file_handle_error_cond_exit(name, operation, FALSE));
 
453
}
 
454
 
 
455
#undef USE_FILE_LOCK
 
456
#define USE_FILE_LOCK
 
457
#if defined(UNIV_HOTBACKUP) || defined(__WIN__) || defined(__NETWARE__)
 
458
/* InnoDB Hot Backup does not lock the data files.
 
459
 * On Windows, mandatory locking is used.
 
460
 */
 
461
# undef USE_FILE_LOCK
 
462
#endif
 
463
#ifdef USE_FILE_LOCK
 
464
/********************************************************************
 
465
Obtain an exclusive lock on a file. */
 
466
static
 
467
int
 
468
os_file_lock(
 
469
/*=========*/
 
470
                                /* out: 0 on success */
 
471
        int             fd,     /* in: file descriptor */
 
472
        const char*     name)   /* in: file name */
 
473
{
 
474
        struct flock lk;
 
475
        lk.l_type = F_WRLCK;
 
476
        lk.l_whence = SEEK_SET;
 
477
        lk.l_start = lk.l_len = 0;
 
478
        if (fcntl(fd, F_SETLK, &lk) == -1) {
 
479
                fprintf(stderr,
 
480
                        "InnoDB: Unable to lock %s, error: %d\n", name, errno);
 
481
 
 
482
                if (errno == EAGAIN || errno == EACCES) {
 
483
                        fprintf(stderr,
 
484
                                "InnoDB: Check that you do not already have"
 
485
                                " another mysqld process\n"
 
486
                                "InnoDB: using the same InnoDB data"
 
487
                                " or log files.\n");
 
488
                }
 
489
 
 
490
                return(-1);
 
491
        }
 
492
 
 
493
        return(0);
 
494
}
 
495
#endif /* USE_FILE_LOCK */
 
496
 
 
497
/********************************************************************
 
498
Creates the seek mutexes used in positioned reads and writes. */
 
499
UNIV_INTERN
 
500
void
 
501
os_io_init_simple(void)
 
502
/*===================*/
 
503
{
 
504
        ulint   i;
 
505
 
 
506
        os_file_count_mutex = os_mutex_create(NULL);
 
507
 
 
508
        for (i = 0; i < OS_FILE_N_SEEK_MUTEXES; i++) {
 
509
                os_file_seek_mutexes[i] = os_mutex_create(NULL);
 
510
        }
 
511
}
 
512
 
 
513
/***************************************************************************
 
514
Creates a temporary file.  This function is like tmpfile(3), but
 
515
the temporary file is created in the MySQL temporary directory.
 
516
On Netware, this function is like tmpfile(3), because the C run-time
 
517
library of Netware does not expose the delete-on-close flag. */
 
518
UNIV_INTERN
 
519
FILE*
 
520
os_file_create_tmpfile(void)
 
521
/*========================*/
 
522
                        /* out: temporary file handle, or NULL on error */
 
523
{
 
524
#ifdef UNIV_HOTBACKUP
 
525
        ut_error;
 
526
 
 
527
        return(NULL);
 
528
#else
 
529
# ifdef __NETWARE__
 
530
        FILE*   file    = tmpfile();
 
531
# else /* __NETWARE__ */
 
532
        FILE*   file    = NULL;
 
533
        int     fd      = innobase_mysql_tmpfile();
 
534
 
 
535
        if (fd >= 0) {
 
536
                file = fdopen(fd, "w+b");
 
537
        }
 
538
# endif /* __NETWARE__ */
 
539
 
 
540
        if (!file) {
 
541
                ut_print_timestamp(stderr);
 
542
                fprintf(stderr,
 
543
                        "  InnoDB: Error: unable to create temporary file;"
 
544
                        " errno: %d\n", errno);
 
545
# ifndef __NETWARE__
 
546
                if (fd >= 0) {
 
547
                        close(fd);
 
548
                }
 
549
# endif /* !__NETWARE__ */
 
550
        }
 
551
 
 
552
        return(file);
 
553
#endif /* UNIV_HOTBACKUP */
 
554
}
 
555
 
 
556
/***************************************************************************
 
557
The os_file_opendir() function opens a directory stream corresponding to the
 
558
directory named by the dirname argument. The directory stream is positioned
 
559
at the first entry. In both Unix and Windows we automatically skip the '.'
 
560
and '..' items at the start of the directory listing. */
 
561
UNIV_INTERN
 
562
os_file_dir_t
 
563
os_file_opendir(
 
564
/*============*/
 
565
                                        /* out: directory stream, NULL if
 
566
                                        error */
 
567
        const char*     dirname,        /* in: directory name; it must not
 
568
                                        contain a trailing '\' or '/' */
 
569
        ibool           error_is_fatal) /* in: TRUE if we should treat an
 
570
                                        error as a fatal error; if we try to
 
571
                                        open symlinks then we do not wish a
 
572
                                        fatal error if it happens not to be
 
573
                                        a directory */
 
574
{
 
575
        os_file_dir_t           dir;
 
576
#ifdef __WIN__
 
577
        LPWIN32_FIND_DATA       lpFindFileData;
 
578
        char                    path[OS_FILE_MAX_PATH + 3];
 
579
 
 
580
        ut_a(strlen(dirname) < OS_FILE_MAX_PATH);
 
581
 
 
582
        strcpy(path, dirname);
 
583
        strcpy(path + strlen(path), "\\*");
 
584
 
 
585
        /* Note that in Windows opening the 'directory stream' also retrieves
 
586
        the first entry in the directory. Since it is '.', that is no problem,
 
587
        as we will skip over the '.' and '..' entries anyway. */
 
588
 
 
589
        lpFindFileData = ut_malloc(sizeof(WIN32_FIND_DATA));
 
590
 
 
591
        dir = FindFirstFile((LPCTSTR) path, lpFindFileData);
 
592
 
 
593
        ut_free(lpFindFileData);
 
594
 
 
595
        if (dir == INVALID_HANDLE_VALUE) {
 
596
 
 
597
                if (error_is_fatal) {
 
598
                        os_file_handle_error(dirname, "opendir");
 
599
                }
 
600
 
 
601
                return(NULL);
 
602
        }
 
603
 
 
604
        return(dir);
 
605
#else
 
606
        dir = opendir(dirname);
 
607
 
 
608
        if (dir == NULL && error_is_fatal) {
 
609
                os_file_handle_error(dirname, "opendir");
 
610
        }
 
611
 
 
612
        return(dir);
 
613
#endif
 
614
}
 
615
 
 
616
/***************************************************************************
 
617
Closes a directory stream. */
 
618
UNIV_INTERN
 
619
int
 
620
os_file_closedir(
 
621
/*=============*/
 
622
                                /* out: 0 if success, -1 if failure */
 
623
        os_file_dir_t   dir)    /* in: directory stream */
 
624
{
 
625
#ifdef __WIN__
 
626
        BOOL            ret;
 
627
 
 
628
        ret = FindClose(dir);
 
629
 
 
630
        if (!ret) {
 
631
                os_file_handle_error_no_exit(NULL, "closedir");
 
632
 
 
633
                return(-1);
 
634
        }
 
635
 
 
636
        return(0);
 
637
#else
 
638
        int     ret;
 
639
 
 
640
        ret = closedir(dir);
 
641
 
 
642
        if (ret) {
 
643
                os_file_handle_error_no_exit(NULL, "closedir");
 
644
        }
 
645
 
 
646
        return(ret);
 
647
#endif
 
648
}
 
649
 
 
650
/***************************************************************************
 
651
This function returns information of the next file in the directory. We jump
 
652
over the '.' and '..' entries in the directory. */
 
653
UNIV_INTERN
 
654
int
 
655
os_file_readdir_next_file(
 
656
/*======================*/
 
657
                                /* out: 0 if ok, -1 if error, 1 if at the end
 
658
                                of the directory */
 
659
        const char*     dirname,/* in: directory name or path */
 
660
        os_file_dir_t   dir,    /* in: directory stream */
 
661
        os_file_stat_t* info)   /* in/out: buffer where the info is returned */
 
662
{
 
663
#ifdef __WIN__
 
664
        LPWIN32_FIND_DATA       lpFindFileData;
 
665
        BOOL                    ret;
 
666
 
 
667
        lpFindFileData = ut_malloc(sizeof(WIN32_FIND_DATA));
 
668
next_file:
 
669
        ret = FindNextFile(dir, lpFindFileData);
 
670
 
 
671
        if (ret) {
 
672
                ut_a(strlen((char *) lpFindFileData->cFileName)
 
673
                     < OS_FILE_MAX_PATH);
 
674
 
 
675
                if (strcmp((char *) lpFindFileData->cFileName, ".") == 0
 
676
                    || strcmp((char *) lpFindFileData->cFileName, "..") == 0) {
 
677
 
 
678
                        goto next_file;
 
679
                }
 
680
 
 
681
                strcpy(info->name, (char *) lpFindFileData->cFileName);
 
682
 
 
683
                info->size = (ib_int64_t)(lpFindFileData->nFileSizeLow)
 
684
                        + (((ib_int64_t)(lpFindFileData->nFileSizeHigh))
 
685
                           << 32);
 
686
 
 
687
                if (lpFindFileData->dwFileAttributes
 
688
                    & FILE_ATTRIBUTE_REPARSE_POINT) {
 
689
                        /* TODO: test Windows symlinks */
 
690
                        /* TODO: MySQL has apparently its own symlink
 
691
                        implementation in Windows, dbname.sym can
 
692
                        redirect a database directory:
 
693
                        http://dev.mysql.com/doc/refman/5.1/en/
 
694
                        windows-symbolic-links.html */
 
695
                        info->type = OS_FILE_TYPE_LINK;
 
696
                } else if (lpFindFileData->dwFileAttributes
 
697
                           & FILE_ATTRIBUTE_DIRECTORY) {
 
698
                        info->type = OS_FILE_TYPE_DIR;
 
699
                } else {
 
700
                        /* It is probably safest to assume that all other
 
701
                        file types are normal. Better to check them rather
 
702
                        than blindly skip them. */
 
703
 
 
704
                        info->type = OS_FILE_TYPE_FILE;
 
705
                }
 
706
        }
 
707
 
 
708
        ut_free(lpFindFileData);
 
709
 
 
710
        if (ret) {
 
711
                return(0);
 
712
        } else if (GetLastError() == ERROR_NO_MORE_FILES) {
 
713
 
 
714
                return(1);
 
715
        } else {
 
716
                os_file_handle_error_no_exit(dirname,
 
717
                                             "readdir_next_file");
 
718
                return(-1);
 
719
        }
 
720
#else
 
721
        struct dirent*  ent;
 
722
        char*           full_path;
 
723
        int             ret;
 
724
        struct stat     statinfo;
 
725
#ifdef HAVE_READDIR_R
 
726
        char            dirent_buf[sizeof(struct dirent)
 
727
                                   + _POSIX_PATH_MAX + 100];
 
728
        /* In /mysys/my_lib.c, _POSIX_PATH_MAX + 1 is used as
 
729
        the max file name len; but in most standards, the
 
730
        length is NAME_MAX; we add 100 to be even safer */
 
731
#endif
 
732
 
 
733
next_file:
 
734
 
 
735
#ifdef HAVE_READDIR_R
 
736
        ret = readdir_r(dir, (struct dirent*)dirent_buf, &ent);
 
737
 
 
738
        if (ret != 0) {
 
739
                fprintf(stderr,
 
740
                        "InnoDB: cannot read directory %s, error %lu\n",
 
741
                        dirname, (ulong)ret);
 
742
 
 
743
                return(-1);
 
744
        }
 
745
 
 
746
        if (ent == NULL) {
 
747
                /* End of directory */
 
748
 
 
749
                return(1);
 
750
        }
 
751
 
 
752
        ut_a(strlen(ent->d_name) < _POSIX_PATH_MAX + 100 - 1);
 
753
#else
 
754
        ent = readdir(dir);
 
755
 
 
756
        if (ent == NULL) {
 
757
 
 
758
                return(1);
 
759
        }
 
760
#endif
 
761
        ut_a(strlen(ent->d_name) < OS_FILE_MAX_PATH);
 
762
 
 
763
        if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
 
764
 
 
765
                goto next_file;
 
766
        }
 
767
 
 
768
        strcpy(info->name, ent->d_name);
 
769
 
 
770
        full_path = ut_malloc(strlen(dirname) + strlen(ent->d_name) + 10);
 
771
 
 
772
        sprintf(full_path, "%s/%s", dirname, ent->d_name);
 
773
 
 
774
        ret = stat(full_path, &statinfo);
 
775
 
 
776
        if (ret) {
 
777
                os_file_handle_error_no_exit(full_path, "stat");
 
778
 
 
779
                ut_free(full_path);
 
780
 
 
781
                return(-1);
 
782
        }
 
783
 
 
784
        info->size = (ib_int64_t)statinfo.st_size;
 
785
 
 
786
        if (S_ISDIR(statinfo.st_mode)) {
 
787
                info->type = OS_FILE_TYPE_DIR;
 
788
        } else if (S_ISLNK(statinfo.st_mode)) {
 
789
                info->type = OS_FILE_TYPE_LINK;
 
790
        } else if (S_ISREG(statinfo.st_mode)) {
 
791
                info->type = OS_FILE_TYPE_FILE;
 
792
        } else {
 
793
                info->type = OS_FILE_TYPE_UNKNOWN;
 
794
        }
 
795
 
 
796
        ut_free(full_path);
 
797
 
 
798
        return(0);
 
799
#endif
 
800
}
 
801
 
 
802
/*********************************************************************
 
803
This function attempts to create a directory named pathname. The new directory
 
804
gets default permissions. On Unix the permissions are (0770 & ~umask). If the
 
805
directory exists already, nothing is done and the call succeeds, unless the
 
806
fail_if_exists arguments is true. */
 
807
UNIV_INTERN
 
808
ibool
 
809
os_file_create_directory(
 
810
/*=====================*/
 
811
                                        /* out: TRUE if call succeeds,
 
812
                                        FALSE on error */
 
813
        const char*     pathname,       /* in: directory name as
 
814
                                        null-terminated string */
 
815
        ibool           fail_if_exists) /* in: if TRUE, pre-existing directory
 
816
                                        is treated as an error. */
 
817
{
 
818
#ifdef __WIN__
 
819
        BOOL    rcode;
 
820
 
 
821
        rcode = CreateDirectory((LPCTSTR) pathname, NULL);
 
822
        if (!(rcode != 0
 
823
              || (GetLastError() == ERROR_ALREADY_EXISTS
 
824
                  && !fail_if_exists))) {
 
825
                /* failure */
 
826
                os_file_handle_error(pathname, "CreateDirectory");
 
827
 
 
828
                return(FALSE);
 
829
        }
 
830
 
 
831
        return (TRUE);
 
832
#else
 
833
        int     rcode;
 
834
 
 
835
        rcode = mkdir(pathname, 0770);
 
836
 
 
837
        if (!(rcode == 0 || (errno == EEXIST && !fail_if_exists))) {
 
838
                /* failure */
 
839
                os_file_handle_error(pathname, "mkdir");
 
840
 
 
841
                return(FALSE);
 
842
        }
 
843
 
 
844
        return (TRUE);
 
845
#endif
 
846
}
 
847
 
 
848
/********************************************************************
 
849
A simple function to open or create a file. */
 
850
UNIV_INTERN
 
851
os_file_t
 
852
os_file_create_simple(
 
853
/*==================*/
 
854
                                /* out, own: handle to the file, not defined
 
855
                                if error, error number can be retrieved with
 
856
                                os_file_get_last_error */
 
857
        const char*     name,   /* in: name of the file or path as a
 
858
                                null-terminated string */
 
859
        ulint           create_mode,/* in: OS_FILE_OPEN if an existing file is
 
860
                                opened (if does not exist, error), or
 
861
                                OS_FILE_CREATE if a new file is created
 
862
                                (if exists, error), or
 
863
                                OS_FILE_CREATE_PATH if new file
 
864
                                (if exists, error) and subdirectories along
 
865
                                its path are created (if needed)*/
 
866
        ulint           access_type,/* in: OS_FILE_READ_ONLY or
 
867
                                OS_FILE_READ_WRITE */
 
868
        ibool*          success)/* out: TRUE if succeed, FALSE if error */
 
869
{
 
870
#ifdef __WIN__
 
871
        os_file_t       file;
 
872
        DWORD           create_flag;
 
873
        DWORD           access;
 
874
        DWORD           attributes      = 0;
 
875
        ibool           retry;
 
876
 
 
877
try_again:
 
878
        ut_a(name);
 
879
 
 
880
        if (create_mode == OS_FILE_OPEN) {
 
881
                create_flag = OPEN_EXISTING;
 
882
        } else if (create_mode == OS_FILE_CREATE) {
 
883
                create_flag = CREATE_NEW;
 
884
        } else if (create_mode == OS_FILE_CREATE_PATH) {
 
885
                /* create subdirs along the path if needed  */
 
886
                *success = os_file_create_subdirs_if_needed(name);
 
887
                if (!*success) {
 
888
                        ut_error;
 
889
                }
 
890
                create_flag = CREATE_NEW;
 
891
                create_mode = OS_FILE_CREATE;
 
892
        } else {
 
893
                create_flag = 0;
 
894
                ut_error;
 
895
        }
 
896
 
 
897
        if (access_type == OS_FILE_READ_ONLY) {
 
898
                access = GENERIC_READ;
 
899
        } else if (access_type == OS_FILE_READ_WRITE) {
 
900
                access = GENERIC_READ | GENERIC_WRITE;
 
901
        } else {
 
902
                access = 0;
 
903
                ut_error;
 
904
        }
 
905
 
 
906
        file = CreateFile((LPCTSTR) name,
 
907
                          access,
 
908
                          FILE_SHARE_READ | FILE_SHARE_WRITE,
 
909
                          /* file can be read and written also
 
910
                          by other processes */
 
911
                          NULL, /* default security attributes */
 
912
                          create_flag,
 
913
                          attributes,
 
914
                          NULL);        /* no template file */
 
915
 
 
916
        if (file == INVALID_HANDLE_VALUE) {
 
917
                *success = FALSE;
 
918
 
 
919
                retry = os_file_handle_error(name,
 
920
                                             create_mode == OS_FILE_OPEN ?
 
921
                                             "open" : "create");
 
922
                if (retry) {
 
923
                        goto try_again;
 
924
                }
 
925
        } else {
 
926
                *success = TRUE;
 
927
        }
 
928
 
 
929
        return(file);
 
930
#else /* __WIN__ */
 
931
        os_file_t       file;
 
932
        int             create_flag;
 
933
        ibool           retry;
 
934
 
 
935
try_again:
 
936
        ut_a(name);
 
937
 
 
938
        if (create_mode == OS_FILE_OPEN) {
 
939
                if (access_type == OS_FILE_READ_ONLY) {
 
940
                        create_flag = O_RDONLY;
 
941
                } else {
 
942
                        create_flag = O_RDWR;
 
943
                }
 
944
        } else if (create_mode == OS_FILE_CREATE) {
 
945
                create_flag = O_RDWR | O_CREAT | O_EXCL;
 
946
        } else if (create_mode == OS_FILE_CREATE_PATH) {
 
947
                /* create subdirs along the path if needed  */
 
948
                *success = os_file_create_subdirs_if_needed(name);
 
949
                if (!*success) {
 
950
                        return (-1);
 
951
                }
 
952
                create_flag = O_RDWR | O_CREAT | O_EXCL;
 
953
                create_mode = OS_FILE_CREATE;
 
954
        } else {
 
955
                create_flag = 0;
 
956
                ut_error;
 
957
        }
 
958
 
 
959
        if (create_mode == OS_FILE_CREATE) {
 
960
                file = open(name, create_flag, S_IRUSR | S_IWUSR
 
961
                            | S_IRGRP | S_IWGRP);
 
962
        } else {
 
963
                file = open(name, create_flag);
 
964
        }
 
965
 
 
966
        if (file == -1) {
 
967
                *success = FALSE;
 
968
 
 
969
                retry = os_file_handle_error(name,
 
970
                                             create_mode == OS_FILE_OPEN ?
 
971
                                             "open" : "create");
 
972
                if (retry) {
 
973
                        goto try_again;
 
974
                }
 
975
#ifdef USE_FILE_LOCK
 
976
        } else if (access_type == OS_FILE_READ_WRITE
 
977
                   && os_file_lock(file, name)) {
 
978
                *success = FALSE;
 
979
                close(file);
 
980
                file = -1;
 
981
#endif
 
982
        } else {
 
983
                *success = TRUE;
 
984
        }
 
985
 
 
986
        return(file);
 
987
#endif /* __WIN__ */
 
988
}
 
989
 
 
990
/********************************************************************
 
991
A simple function to open or create a file. */
 
992
UNIV_INTERN
 
993
os_file_t
 
994
os_file_create_simple_no_error_handling(
 
995
/*====================================*/
 
996
                                /* out, own: handle to the file, not defined
 
997
                                if error, error number can be retrieved with
 
998
                                os_file_get_last_error */
 
999
        const char*     name,   /* in: name of the file or path as a
 
1000
                                null-terminated string */
 
1001
        ulint           create_mode,/* in: OS_FILE_OPEN if an existing file
 
1002
                                is opened (if does not exist, error), or
 
1003
                                OS_FILE_CREATE if a new file is created
 
1004
                                (if exists, error) */
 
1005
        ulint           access_type,/* in: OS_FILE_READ_ONLY,
 
1006
                                OS_FILE_READ_WRITE, or
 
1007
                                OS_FILE_READ_ALLOW_DELETE; the last option is
 
1008
                                used by a backup program reading the file */
 
1009
        ibool*          success)/* out: TRUE if succeed, FALSE if error */
 
1010
{
 
1011
#ifdef __WIN__
 
1012
        os_file_t       file;
 
1013
        DWORD           create_flag;
 
1014
        DWORD           access;
 
1015
        DWORD           attributes      = 0;
 
1016
        DWORD           share_mode      = FILE_SHARE_READ | FILE_SHARE_WRITE;
 
1017
 
 
1018
        ut_a(name);
 
1019
 
 
1020
        if (create_mode == OS_FILE_OPEN) {
 
1021
                create_flag = OPEN_EXISTING;
 
1022
        } else if (create_mode == OS_FILE_CREATE) {
 
1023
                create_flag = CREATE_NEW;
 
1024
        } else {
 
1025
                create_flag = 0;
 
1026
                ut_error;
 
1027
        }
 
1028
 
 
1029
        if (access_type == OS_FILE_READ_ONLY) {
 
1030
                access = GENERIC_READ;
 
1031
        } else if (access_type == OS_FILE_READ_WRITE) {
 
1032
                access = GENERIC_READ | GENERIC_WRITE;
 
1033
        } else if (access_type == OS_FILE_READ_ALLOW_DELETE) {
 
1034
                access = GENERIC_READ;
 
1035
                share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ
 
1036
                        | FILE_SHARE_WRITE;     /* A backup program has to give
 
1037
                                                mysqld the maximum freedom to
 
1038
                                                do what it likes with the
 
1039
                                                file */
 
1040
        } else {
 
1041
                access = 0;
 
1042
                ut_error;
 
1043
        }
 
1044
 
 
1045
        file = CreateFile((LPCTSTR) name,
 
1046
                          access,
 
1047
                          share_mode,
 
1048
                          NULL, /* default security attributes */
 
1049
                          create_flag,
 
1050
                          attributes,
 
1051
                          NULL);        /* no template file */
 
1052
 
 
1053
        if (file == INVALID_HANDLE_VALUE) {
 
1054
                *success = FALSE;
 
1055
        } else {
 
1056
                *success = TRUE;
 
1057
        }
 
1058
 
 
1059
        return(file);
 
1060
#else /* __WIN__ */
 
1061
        os_file_t       file;
 
1062
        int             create_flag;
 
1063
 
 
1064
        ut_a(name);
 
1065
 
 
1066
        if (create_mode == OS_FILE_OPEN) {
 
1067
                if (access_type == OS_FILE_READ_ONLY) {
 
1068
                        create_flag = O_RDONLY;
 
1069
                } else {
 
1070
                        create_flag = O_RDWR;
 
1071
                }
 
1072
        } else if (create_mode == OS_FILE_CREATE) {
 
1073
                create_flag = O_RDWR | O_CREAT | O_EXCL;
 
1074
        } else {
 
1075
                create_flag = 0;
 
1076
                ut_error;
 
1077
        }
 
1078
 
 
1079
        if (create_mode == OS_FILE_CREATE) {
 
1080
                file = open(name, create_flag, S_IRUSR | S_IWUSR
 
1081
                            | S_IRGRP | S_IWGRP);
 
1082
        } else {
 
1083
                file = open(name, create_flag);
 
1084
        }
 
1085
 
 
1086
        if (file == -1) {
 
1087
                *success = FALSE;
 
1088
#ifdef USE_FILE_LOCK
 
1089
        } else if (access_type == OS_FILE_READ_WRITE
 
1090
                   && os_file_lock(file, name)) {
 
1091
                *success = FALSE;
 
1092
                close(file);
 
1093
                file = -1;
 
1094
#endif
 
1095
        } else {
 
1096
                *success = TRUE;
 
1097
        }
 
1098
 
 
1099
        return(file);
 
1100
#endif /* __WIN__ */
 
1101
}
 
1102
 
 
1103
/********************************************************************
 
1104
Tries to disable OS caching on an opened file descriptor. */
 
1105
UNIV_INTERN
 
1106
void
 
1107
os_file_set_nocache(
 
1108
/*================*/
 
1109
        int             fd,             /* in: file descriptor to alter */
 
1110
        const char*     file_name,      /* in: file name, used in the
 
1111
                                        diagnostic message */
 
1112
        const char*     operation_name) /* in: "open" or "create"; used in the
 
1113
                                        diagnostic message */
 
1114
{
 
1115
        /* some versions of Solaris may not have DIRECTIO_ON */
 
1116
#if defined(UNIV_SOLARIS) && defined(DIRECTIO_ON)
 
1117
        if (directio(fd, DIRECTIO_ON) == -1) {
 
1118
                int     errno_save;
 
1119
                errno_save = (int)errno;
 
1120
                ut_print_timestamp(stderr);
 
1121
                fprintf(stderr,
 
1122
                        "  InnoDB: Failed to set DIRECTIO_ON "
 
1123
                        "on file %s: %s: %s, continuing anyway\n",
 
1124
                        file_name, operation_name, strerror(errno_save));
 
1125
        }
 
1126
#elif defined(O_DIRECT)
 
1127
        if (fcntl(fd, F_SETFL, O_DIRECT) == -1) {
 
1128
                int     errno_save;
 
1129
                errno_save = (int)errno;
 
1130
                ut_print_timestamp(stderr);
 
1131
                fprintf(stderr,
 
1132
                        "  InnoDB: Failed to set O_DIRECT "
 
1133
                        "on file %s: %s: %s, continuing anyway\n",
 
1134
                        file_name, operation_name, strerror(errno_save));
 
1135
                if (errno_save == EINVAL) {
 
1136
                        ut_print_timestamp(stderr);
 
1137
                        fprintf(stderr,
 
1138
                                "  InnoDB: O_DIRECT is known to result in "
 
1139
                                "'Invalid argument' on Linux on tmpfs, "
 
1140
                                "see MySQL Bug#26662\n");
 
1141
                }
 
1142
        }
 
1143
#else /* Required for OSX */
 
1144
        (void)fd;
 
1145
        (void)file_name;
 
1146
        (void)operation_name;
 
1147
#endif
 
1148
}
 
1149
 
 
1150
/********************************************************************
 
1151
Opens an existing file or creates a new. */
 
1152
UNIV_INTERN
 
1153
os_file_t
 
1154
os_file_create(
 
1155
/*===========*/
 
1156
                                /* out, own: handle to the file, not defined
 
1157
                                if error, error number can be retrieved with
 
1158
                                os_file_get_last_error */
 
1159
        const char*     name,   /* in: name of the file or path as a
 
1160
                                null-terminated string */
 
1161
        ulint           create_mode,/* in: OS_FILE_OPEN if an existing file
 
1162
                                is opened (if does not exist, error), or
 
1163
                                OS_FILE_CREATE if a new file is created
 
1164
                                (if exists, error),
 
1165
                                OS_FILE_OVERWRITE if a new file is created
 
1166
                                or an old overwritten;
 
1167
                                OS_FILE_OPEN_RAW, if a raw device or disk
 
1168
                                partition should be opened */
 
1169
        ulint           purpose,/* in: OS_FILE_AIO, if asynchronous,
 
1170
                                non-buffered i/o is desired,
 
1171
                                OS_FILE_NORMAL, if any normal file;
 
1172
                                NOTE that it also depends on type, os_aio_..
 
1173
                                and srv_.. variables whether we really use
 
1174
                                async i/o or unbuffered i/o: look in the
 
1175
                                function source code for the exact rules */
 
1176
        ulint           type,   /* in: OS_DATA_FILE or OS_LOG_FILE */
 
1177
        ibool*          success)/* out: TRUE if succeed, FALSE if error */
 
1178
{
 
1179
#ifdef __WIN__
 
1180
        os_file_t       file;
 
1181
        DWORD           share_mode      = FILE_SHARE_READ;
 
1182
        DWORD           create_flag;
 
1183
        DWORD           attributes;
 
1184
        ibool           retry;
 
1185
try_again:
 
1186
        ut_a(name);
 
1187
 
 
1188
        if (create_mode == OS_FILE_OPEN_RAW) {
 
1189
                create_flag = OPEN_EXISTING;
 
1190
                share_mode = FILE_SHARE_WRITE;
 
1191
        } else if (create_mode == OS_FILE_OPEN
 
1192
                   || create_mode == OS_FILE_OPEN_RETRY) {
 
1193
                create_flag = OPEN_EXISTING;
 
1194
        } else if (create_mode == OS_FILE_CREATE) {
 
1195
                create_flag = CREATE_NEW;
 
1196
        } else if (create_mode == OS_FILE_OVERWRITE) {
 
1197
                create_flag = CREATE_ALWAYS;
 
1198
        } else {
 
1199
                create_flag = 0;
 
1200
                ut_error;
 
1201
        }
 
1202
 
 
1203
        if (purpose == OS_FILE_AIO) {
 
1204
                /* If specified, use asynchronous (overlapped) io and no
 
1205
                buffering of writes in the OS */
 
1206
                attributes = 0;
 
1207
#ifdef WIN_ASYNC_IO
 
1208
                if (os_aio_use_native_aio) {
 
1209
                        attributes = attributes | FILE_FLAG_OVERLAPPED;
 
1210
                }
 
1211
#endif
 
1212
#ifdef UNIV_NON_BUFFERED_IO
 
1213
                if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) {
 
1214
                        /* Do not use unbuffered i/o to log files because
 
1215
                        value 2 denotes that we do not flush the log at every
 
1216
                        commit, but only once per second */
 
1217
                } else if (srv_win_file_flush_method
 
1218
                           == SRV_WIN_IO_UNBUFFERED) {
 
1219
                        attributes = attributes | FILE_FLAG_NO_BUFFERING;
 
1220
                }
 
1221
#endif
 
1222
        } else if (purpose == OS_FILE_NORMAL) {
 
1223
                attributes = 0;
 
1224
#ifdef UNIV_NON_BUFFERED_IO
 
1225
                if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) {
 
1226
                        /* Do not use unbuffered i/o to log files because
 
1227
                        value 2 denotes that we do not flush the log at every
 
1228
                        commit, but only once per second */
 
1229
                } else if (srv_win_file_flush_method
 
1230
                           == SRV_WIN_IO_UNBUFFERED) {
 
1231
                        attributes = attributes | FILE_FLAG_NO_BUFFERING;
 
1232
                }
 
1233
#endif
 
1234
        } else {
 
1235
                attributes = 0;
 
1236
                ut_error;
 
1237
        }
 
1238
 
 
1239
        file = CreateFile((LPCTSTR) name,
 
1240
                          GENERIC_READ | GENERIC_WRITE, /* read and write
 
1241
                                                        access */
 
1242
                          share_mode,   /* File can be read also by other
 
1243
                                        processes; we must give the read
 
1244
                                        permission because of ibbackup. We do
 
1245
                                        not give the write permission to
 
1246
                                        others because if one would succeed to
 
1247
                                        start 2 instances of mysqld on the
 
1248
                                        SAME files, that could cause severe
 
1249
                                        database corruption! When opening
 
1250
                                        raw disk partitions, Microsoft manuals
 
1251
                                        say that we must give also the write
 
1252
                                        permission. */
 
1253
                          NULL, /* default security attributes */
 
1254
                          create_flag,
 
1255
                          attributes,
 
1256
                          NULL);        /* no template file */
 
1257
 
 
1258
        if (file == INVALID_HANDLE_VALUE) {
 
1259
                *success = FALSE;
 
1260
 
 
1261
                retry = os_file_handle_error(name,
 
1262
                                             create_mode == OS_FILE_CREATE ?
 
1263
                                             "create" : "open");
 
1264
                if (retry) {
 
1265
                        goto try_again;
 
1266
                }
 
1267
        } else {
 
1268
                *success = TRUE;
 
1269
        }
 
1270
 
 
1271
        return(file);
 
1272
#else /* __WIN__ */
 
1273
        os_file_t       file;
 
1274
        int             create_flag;
 
1275
        ibool           retry;
 
1276
        const char*     mode_str        = NULL;
 
1277
        const char*     type_str        = NULL;
 
1278
        const char*     purpose_str     = NULL;
 
1279
 
 
1280
try_again:
 
1281
        ut_a(name);
 
1282
 
 
1283
        if (create_mode == OS_FILE_OPEN || create_mode == OS_FILE_OPEN_RAW
 
1284
            || create_mode == OS_FILE_OPEN_RETRY) {
 
1285
                mode_str = "OPEN";
 
1286
                create_flag = O_RDWR;
 
1287
        } else if (create_mode == OS_FILE_CREATE) {
 
1288
                mode_str = "CREATE";
 
1289
                create_flag = O_RDWR | O_CREAT | O_EXCL;
 
1290
        } else if (create_mode == OS_FILE_OVERWRITE) {
 
1291
                mode_str = "OVERWRITE";
 
1292
                create_flag = O_RDWR | O_CREAT | O_TRUNC;
 
1293
        } else {
 
1294
                create_flag = 0;
 
1295
                ut_error;
 
1296
        }
 
1297
 
 
1298
        if (type == OS_LOG_FILE) {
 
1299
                type_str = "LOG";
 
1300
        } else if (type == OS_DATA_FILE) {
 
1301
                type_str = "DATA";
 
1302
        } else {
 
1303
                ut_error;
 
1304
        }
 
1305
 
 
1306
        if (purpose == OS_FILE_AIO) {
 
1307
                purpose_str = "AIO";
 
1308
        } else if (purpose == OS_FILE_NORMAL) {
 
1309
                purpose_str = "NORMAL";
 
1310
        } else {
 
1311
                ut_error;
 
1312
        }
 
1313
 
 
1314
#if 0
 
1315
        fprintf(stderr, "Opening file %s, mode %s, type %s, purpose %s\n",
 
1316
                name, mode_str, type_str, purpose_str);
 
1317
#endif
 
1318
#ifdef O_SYNC
 
1319
        /* We let O_SYNC only affect log files; note that we map O_DSYNC to
 
1320
        O_SYNC because the datasync options seemed to corrupt files in 2001
 
1321
        in both Linux and Solaris */
 
1322
        if (type == OS_LOG_FILE
 
1323
            && srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) {
 
1324
 
 
1325
# if 0
 
1326
                fprintf(stderr, "Using O_SYNC for file %s\n", name);
 
1327
# endif
 
1328
 
 
1329
                create_flag = create_flag | O_SYNC;
 
1330
        }
 
1331
#endif /* O_SYNC */
 
1332
 
 
1333
        file = open(name, create_flag, os_innodb_umask);
 
1334
 
 
1335
        if (file == -1) {
 
1336
                *success = FALSE;
 
1337
 
 
1338
                retry = os_file_handle_error(name,
 
1339
                                             create_mode == OS_FILE_CREATE ?
 
1340
                                             "create" : "open");
 
1341
                if (retry) {
 
1342
                        goto try_again;
 
1343
                } else {
 
1344
                        return(file /* -1 */);
 
1345
                }
 
1346
        }
 
1347
        /* else */
 
1348
 
 
1349
        *success = TRUE;
 
1350
 
 
1351
        /* We disable OS caching (O_DIRECT) only on data files */
 
1352
        if (type != OS_LOG_FILE
 
1353
            && srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
 
1354
                
 
1355
                os_file_set_nocache(file, name, mode_str);
 
1356
        }
 
1357
 
 
1358
#ifdef USE_FILE_LOCK
 
1359
        if (create_mode != OS_FILE_OPEN_RAW && os_file_lock(file, name)) {
 
1360
 
 
1361
                if (create_mode == OS_FILE_OPEN_RETRY) {
 
1362
                        int i;
 
1363
                        ut_print_timestamp(stderr);
 
1364
                        fputs("  InnoDB: Retrying to lock"
 
1365
                              " the first data file\n",
 
1366
                              stderr);
 
1367
                        for (i = 0; i < 100; i++) {
 
1368
                                os_thread_sleep(1000000);
 
1369
                                if (!os_file_lock(file, name)) {
 
1370
                                        *success = TRUE;
 
1371
                                        return(file);
 
1372
                                }
 
1373
                        }
 
1374
                        ut_print_timestamp(stderr);
 
1375
                        fputs("  InnoDB: Unable to open the first data file\n",
 
1376
                              stderr);
 
1377
                }
 
1378
 
 
1379
                *success = FALSE;
 
1380
                close(file);
 
1381
                file = -1;
 
1382
        }
 
1383
#endif /* USE_FILE_LOCK */
 
1384
 
 
1385
        return(file);
 
1386
#endif /* __WIN__ */
 
1387
}
 
1388
 
 
1389
/***************************************************************************
 
1390
Deletes a file if it exists. The file has to be closed before calling this. */
 
1391
UNIV_INTERN
 
1392
ibool
 
1393
os_file_delete_if_exists(
 
1394
/*=====================*/
 
1395
                                /* out: TRUE if success */
 
1396
        const char*     name)   /* in: file path as a null-terminated string */
 
1397
{
 
1398
#ifdef __WIN__
 
1399
        BOOL    ret;
 
1400
        ulint   count   = 0;
 
1401
loop:
 
1402
        /* In Windows, deleting an .ibd file may fail if ibbackup is copying
 
1403
        it */
 
1404
 
 
1405
        ret = DeleteFile((LPCTSTR)name);
 
1406
 
 
1407
        if (ret) {
 
1408
                return(TRUE);
 
1409
        }
 
1410
 
 
1411
        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
 
1412
                /* the file does not exist, this not an error */
 
1413
 
 
1414
                return(TRUE);
 
1415
        }
 
1416
 
 
1417
        count++;
 
1418
 
 
1419
        if (count > 100 && 0 == (count % 10)) {
 
1420
                fprintf(stderr,
 
1421
                        "InnoDB: Warning: cannot delete file %s\n"
 
1422
                        "InnoDB: Are you running ibbackup"
 
1423
                        " to back up the file?\n", name);
 
1424
 
 
1425
                os_file_get_last_error(TRUE); /* print error information */
 
1426
        }
 
1427
 
 
1428
        os_thread_sleep(1000000);       /* sleep for a second */
 
1429
 
 
1430
        if (count > 2000) {
 
1431
 
 
1432
                return(FALSE);
 
1433
        }
 
1434
 
 
1435
        goto loop;
 
1436
#else
 
1437
        int     ret;
 
1438
 
 
1439
        ret = unlink(name);
 
1440
 
 
1441
        if (ret != 0 && errno != ENOENT) {
 
1442
                os_file_handle_error_no_exit(name, "delete");
 
1443
 
 
1444
                return(FALSE);
 
1445
        }
 
1446
 
 
1447
        return(TRUE);
 
1448
#endif
 
1449
}
 
1450
 
 
1451
/***************************************************************************
 
1452
Deletes a file. The file has to be closed before calling this. */
 
1453
UNIV_INTERN
 
1454
ibool
 
1455
os_file_delete(
 
1456
/*===========*/
 
1457
                                /* out: TRUE if success */
 
1458
        const char*     name)   /* in: file path as a null-terminated string */
 
1459
{
 
1460
#ifdef __WIN__
 
1461
        BOOL    ret;
 
1462
        ulint   count   = 0;
 
1463
loop:
 
1464
        /* In Windows, deleting an .ibd file may fail if ibbackup is copying
 
1465
        it */
 
1466
 
 
1467
        ret = DeleteFile((LPCTSTR)name);
 
1468
 
 
1469
        if (ret) {
 
1470
                return(TRUE);
 
1471
        }
 
1472
 
 
1473
        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
 
1474
                /* If the file does not exist, we classify this as a 'mild'
 
1475
                error and return */
 
1476
 
 
1477
                return(FALSE);
 
1478
        }
 
1479
 
 
1480
        count++;
 
1481
 
 
1482
        if (count > 100 && 0 == (count % 10)) {
 
1483
                fprintf(stderr,
 
1484
                        "InnoDB: Warning: cannot delete file %s\n"
 
1485
                        "InnoDB: Are you running ibbackup"
 
1486
                        " to back up the file?\n", name);
 
1487
 
 
1488
                os_file_get_last_error(TRUE); /* print error information */
 
1489
        }
 
1490
 
 
1491
        os_thread_sleep(1000000);       /* sleep for a second */
 
1492
 
 
1493
        if (count > 2000) {
 
1494
 
 
1495
                return(FALSE);
 
1496
        }
 
1497
 
 
1498
        goto loop;
 
1499
#else
 
1500
        int     ret;
 
1501
 
 
1502
        ret = unlink(name);
 
1503
 
 
1504
        if (ret != 0) {
 
1505
                os_file_handle_error_no_exit(name, "delete");
 
1506
 
 
1507
                return(FALSE);
 
1508
        }
 
1509
 
 
1510
        return(TRUE);
 
1511
#endif
 
1512
}
 
1513
 
 
1514
/***************************************************************************
 
1515
Renames a file (can also move it to another directory). It is safest that the
 
1516
file is closed before calling this function. */
 
1517
UNIV_INTERN
 
1518
ibool
 
1519
os_file_rename(
 
1520
/*===========*/
 
1521
                                /* out: TRUE if success */
 
1522
        const char*     oldpath,/* in: old file path as a null-terminated
 
1523
                                string */
 
1524
        const char*     newpath)/* in: new file path */
 
1525
{
 
1526
#ifdef __WIN__
 
1527
        BOOL    ret;
 
1528
 
 
1529
        ret = MoveFile((LPCTSTR)oldpath, (LPCTSTR)newpath);
 
1530
 
 
1531
        if (ret) {
 
1532
                return(TRUE);
 
1533
        }
 
1534
 
 
1535
        os_file_handle_error_no_exit(oldpath, "rename");
 
1536
 
 
1537
        return(FALSE);
 
1538
#else
 
1539
        int     ret;
 
1540
 
 
1541
        ret = rename(oldpath, newpath);
 
1542
 
 
1543
        if (ret != 0) {
 
1544
                os_file_handle_error_no_exit(oldpath, "rename");
 
1545
 
 
1546
                return(FALSE);
 
1547
        }
 
1548
 
 
1549
        return(TRUE);
 
1550
#endif
 
1551
}
 
1552
 
 
1553
/***************************************************************************
 
1554
Closes a file handle. In case of error, error number can be retrieved with
 
1555
os_file_get_last_error. */
 
1556
UNIV_INTERN
 
1557
ibool
 
1558
os_file_close(
 
1559
/*==========*/
 
1560
                                /* out: TRUE if success */
 
1561
        os_file_t       file)   /* in, own: handle to a file */
 
1562
{
 
1563
#ifdef __WIN__
 
1564
        BOOL    ret;
 
1565
 
 
1566
        ut_a(file);
 
1567
 
 
1568
        ret = CloseHandle(file);
 
1569
 
 
1570
        if (ret) {
 
1571
                return(TRUE);
 
1572
        }
 
1573
 
 
1574
        os_file_handle_error(NULL, "close");
 
1575
 
 
1576
        return(FALSE);
 
1577
#else
 
1578
        int     ret;
 
1579
 
 
1580
        ret = close(file);
 
1581
 
 
1582
        if (ret == -1) {
 
1583
                os_file_handle_error(NULL, "close");
 
1584
 
 
1585
                return(FALSE);
 
1586
        }
 
1587
 
 
1588
        return(TRUE);
 
1589
#endif
 
1590
}
 
1591
 
 
1592
/***************************************************************************
 
1593
Closes a file handle. */
 
1594
UNIV_INTERN
 
1595
ibool
 
1596
os_file_close_no_error_handling(
 
1597
/*============================*/
 
1598
                                /* out: TRUE if success */
 
1599
        os_file_t       file)   /* in, own: handle to a file */
 
1600
{
 
1601
#ifdef __WIN__
 
1602
        BOOL    ret;
 
1603
 
 
1604
        ut_a(file);
 
1605
 
 
1606
        ret = CloseHandle(file);
 
1607
 
 
1608
        if (ret) {
 
1609
                return(TRUE);
 
1610
        }
 
1611
 
 
1612
        return(FALSE);
 
1613
#else
 
1614
        int     ret;
 
1615
 
 
1616
        ret = close(file);
 
1617
 
 
1618
        if (ret == -1) {
 
1619
 
 
1620
                return(FALSE);
 
1621
        }
 
1622
 
 
1623
        return(TRUE);
 
1624
#endif
 
1625
}
 
1626
 
 
1627
/***************************************************************************
 
1628
Gets a file size. */
 
1629
UNIV_INTERN
 
1630
ibool
 
1631
os_file_get_size(
 
1632
/*=============*/
 
1633
                                /* out: TRUE if success */
 
1634
        os_file_t       file,   /* in: handle to a file */
 
1635
        ulint*          size,   /* out: least significant 32 bits of file
 
1636
                                size */
 
1637
        ulint*          size_high)/* out: most significant 32 bits of size */
 
1638
{
 
1639
#ifdef __WIN__
 
1640
        DWORD   high;
 
1641
        DWORD   low;
 
1642
 
 
1643
        low = GetFileSize(file, &high);
 
1644
 
 
1645
        if ((low == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) {
 
1646
                return(FALSE);
 
1647
        }
 
1648
 
 
1649
        *size = low;
 
1650
        *size_high = high;
 
1651
 
 
1652
        return(TRUE);
 
1653
#else
 
1654
        off_t   offs;
 
1655
 
 
1656
        offs = lseek(file, 0, SEEK_END);
 
1657
 
 
1658
        if (offs == ((off_t)-1)) {
 
1659
 
 
1660
                return(FALSE);
 
1661
        }
 
1662
 
 
1663
        if (sizeof(off_t) > 4) {
 
1664
                *size = (ulint)(offs & 0xFFFFFFFFUL);
 
1665
                *size_high = (ulint)(offs >> 32);
 
1666
        } else {
 
1667
                *size = (ulint) offs;
 
1668
                *size_high = 0;
 
1669
        }
 
1670
 
 
1671
        return(TRUE);
 
1672
#endif
 
1673
}
 
1674
 
 
1675
/***************************************************************************
 
1676
Gets file size as a 64-bit integer ib_int64_t. */
 
1677
UNIV_INTERN
 
1678
ib_int64_t
 
1679
os_file_get_size_as_iblonglong(
 
1680
/*===========================*/
 
1681
                                /* out: size in bytes, -1 if error */
 
1682
        os_file_t       file)   /* in: handle to a file */
 
1683
{
 
1684
        ulint   size;
 
1685
        ulint   size_high;
 
1686
        ibool   success;
 
1687
 
 
1688
        success = os_file_get_size(file, &size, &size_high);
 
1689
 
 
1690
        if (!success) {
 
1691
 
 
1692
                return(-1);
 
1693
        }
 
1694
 
 
1695
        return((((ib_int64_t)size_high) << 32) + (ib_int64_t)size);
 
1696
}
 
1697
 
 
1698
/***************************************************************************
 
1699
Write the specified number of zeros to a newly created file. */
 
1700
UNIV_INTERN
 
1701
ibool
 
1702
os_file_set_size(
 
1703
/*=============*/
 
1704
                                /* out: TRUE if success */
 
1705
        const char*     name,   /* in: name of the file or path as a
 
1706
                                null-terminated string */
 
1707
        os_file_t       file,   /* in: handle to a file */
 
1708
        ulint           size,   /* in: least significant 32 bits of file
 
1709
                                size */
 
1710
        ulint           size_high)/* in: most significant 32 bits of size */
 
1711
{
 
1712
        ib_int64_t      current_size;
 
1713
        ib_int64_t      desired_size;
 
1714
        ibool           ret;
 
1715
        byte*           buf;
 
1716
        byte*           buf2;
 
1717
        ulint           buf_size;
 
1718
 
 
1719
        ut_a(size == (size & 0xFFFFFFFF));
 
1720
 
 
1721
        current_size = 0;
 
1722
        desired_size = (ib_int64_t)size + (((ib_int64_t)size_high) << 32);
 
1723
 
 
1724
        /* Write up to 1 megabyte at a time. */
 
1725
        buf_size = ut_min(64, (ulint) (desired_size / UNIV_PAGE_SIZE))
 
1726
                * UNIV_PAGE_SIZE;
 
1727
        buf2 = ut_malloc(buf_size + UNIV_PAGE_SIZE);
 
1728
 
 
1729
        /* Align the buffer for possible raw i/o */
 
1730
        buf = ut_align(buf2, UNIV_PAGE_SIZE);
 
1731
 
 
1732
        /* Write buffer full of zeros */
 
1733
        memset(buf, 0, buf_size);
 
1734
 
 
1735
        if (desired_size >= (ib_int64_t)(100 * 1024 * 1024)) {
 
1736
 
 
1737
                fprintf(stderr, "InnoDB: Progress in MB:");
 
1738
        }
 
1739
 
 
1740
        while (current_size < desired_size) {
 
1741
                ulint   n_bytes;
 
1742
 
 
1743
                if (desired_size - current_size < (ib_int64_t) buf_size) {
 
1744
                        n_bytes = (ulint) (desired_size - current_size);
 
1745
                } else {
 
1746
                        n_bytes = buf_size;
 
1747
                }
 
1748
 
 
1749
                ret = os_file_write(name, file, buf,
 
1750
                                    (ulint)(current_size & 0xFFFFFFFF),
 
1751
                                    (ulint)(current_size >> 32),
 
1752
                                    n_bytes);
 
1753
                if (!ret) {
 
1754
                        ut_free(buf2);
 
1755
                        goto error_handling;
 
1756
                }
 
1757
 
 
1758
                /* Print about progress for each 100 MB written */
 
1759
                if ((ib_int64_t) (current_size + n_bytes) / (ib_int64_t)(100 * 1024 * 1024)
 
1760
                    != current_size / (ib_int64_t)(100 * 1024 * 1024)) {
 
1761
 
 
1762
                        fprintf(stderr, " %lu00",
 
1763
                                (ulong) ((current_size + n_bytes)
 
1764
                                         / (ib_int64_t)(100 * 1024 * 1024)));
 
1765
                }
 
1766
 
 
1767
                current_size += n_bytes;
 
1768
        }
 
1769
 
 
1770
        if (desired_size >= (ib_int64_t)(100 * 1024 * 1024)) {
 
1771
 
 
1772
                fprintf(stderr, "\n");
 
1773
        }
 
1774
 
 
1775
        ut_free(buf2);
 
1776
 
 
1777
        ret = os_file_flush(file);
 
1778
 
 
1779
        if (ret) {
 
1780
                return(TRUE);
 
1781
        }
 
1782
 
 
1783
error_handling:
 
1784
        return(FALSE);
 
1785
}
 
1786
 
 
1787
/***************************************************************************
 
1788
Truncates a file at its current position. */
 
1789
UNIV_INTERN
 
1790
ibool
 
1791
os_file_set_eof(
 
1792
/*============*/
 
1793
                                /* out: TRUE if success */
 
1794
        FILE*           file)   /* in: file to be truncated */
 
1795
{
 
1796
#ifdef __WIN__
 
1797
        HANDLE h = (HANDLE) _get_osfhandle(fileno(file));
 
1798
        return(SetEndOfFile(h));
 
1799
#else /* __WIN__ */
 
1800
        return(!ftruncate(fileno(file), ftell(file)));
 
1801
#endif /* __WIN__ */
 
1802
}
 
1803
 
 
1804
#ifndef __WIN__
 
1805
/***************************************************************************
 
1806
Wrapper to fsync(2) that retries the call on some errors.
 
1807
Returns the value 0 if successful; otherwise the value -1 is returned and
 
1808
the global variable errno is set to indicate the error. */
 
1809
 
 
1810
static
 
1811
int
 
1812
os_file_fsync(
 
1813
/*==========*/
 
1814
                                /* out: 0 if success, -1 otherwise */
 
1815
        os_file_t       file)   /* in: handle to a file */
 
1816
{
 
1817
        int     ret;
 
1818
        int     failures;
 
1819
        ibool   retry;
 
1820
 
 
1821
        failures = 0;
 
1822
 
 
1823
        do {
 
1824
                ret = fsync(file);
 
1825
 
 
1826
                os_n_fsyncs++;
 
1827
 
 
1828
                if (ret == -1 && errno == ENOLCK) {
 
1829
 
 
1830
                        if (failures % 100 == 0) {
 
1831
 
 
1832
                                ut_print_timestamp(stderr);
 
1833
                                fprintf(stderr,
 
1834
                                        "  InnoDB: fsync(): "
 
1835
                                        "No locks available; retrying\n");
 
1836
                        }
 
1837
 
 
1838
                        os_thread_sleep(200000 /* 0.2 sec */);
 
1839
 
 
1840
                        failures++;
 
1841
 
 
1842
                        retry = TRUE;
 
1843
                } else {
 
1844
 
 
1845
                        retry = FALSE;
 
1846
                }
 
1847
        } while (retry);
 
1848
 
 
1849
        return(ret);
 
1850
}
 
1851
#endif /* !__WIN__ */
 
1852
 
 
1853
/***************************************************************************
 
1854
Flushes the write buffers of a given file to the disk. */
 
1855
UNIV_INTERN
 
1856
ibool
 
1857
os_file_flush(
 
1858
/*==========*/
 
1859
                                /* out: TRUE if success */
 
1860
        os_file_t       file)   /* in, own: handle to a file */
 
1861
{
 
1862
#ifdef __WIN__
 
1863
        BOOL    ret;
 
1864
 
 
1865
        ut_a(file);
 
1866
 
 
1867
        os_n_fsyncs++;
 
1868
 
 
1869
        ret = FlushFileBuffers(file);
 
1870
 
 
1871
        if (ret) {
 
1872
                return(TRUE);
 
1873
        }
 
1874
 
 
1875
        /* Since Windows returns ERROR_INVALID_FUNCTION if the 'file' is
 
1876
        actually a raw device, we choose to ignore that error if we are using
 
1877
        raw disks */
 
1878
 
 
1879
        if (srv_start_raw_disk_in_use && GetLastError()
 
1880
            == ERROR_INVALID_FUNCTION) {
 
1881
                return(TRUE);
 
1882
        }
 
1883
 
 
1884
        os_file_handle_error(NULL, "flush");
 
1885
 
 
1886
        /* It is a fatal error if a file flush does not succeed, because then
 
1887
        the database can get corrupt on disk */
 
1888
        ut_error;
 
1889
 
 
1890
        return(FALSE);
 
1891
#else
 
1892
        int     ret;
 
1893
 
 
1894
#if defined(HAVE_DARWIN_THREADS)
 
1895
# ifndef F_FULLFSYNC
 
1896
        /* The following definition is from the Mac OS X 10.3 <sys/fcntl.h> */
 
1897
#  define F_FULLFSYNC 51 /* fsync + ask the drive to flush to the media */
 
1898
# elif F_FULLFSYNC != 51
 
1899
#  error "F_FULLFSYNC != 51: ABI incompatibility with Mac OS X 10.3"
 
1900
# endif
 
1901
        /* Apple has disabled fsync() for internal disk drives in OS X. That
 
1902
        caused corruption for a user when he tested a power outage. Let us in
 
1903
        OS X use a nonstandard flush method recommended by an Apple
 
1904
        engineer. */
 
1905
 
 
1906
        if (!srv_have_fullfsync) {
 
1907
                /* If we are not on an operating system that supports this,
 
1908
                then fall back to a plain fsync. */
 
1909
 
 
1910
                ret = os_file_fsync(file);
 
1911
        } else {
 
1912
                ret = fcntl(file, F_FULLFSYNC, NULL);
 
1913
 
 
1914
                if (ret) {
 
1915
                        /* If we are not on a file system that supports this,
 
1916
                        then fall back to a plain fsync. */
 
1917
                        ret = os_file_fsync(file);
 
1918
                }
 
1919
        }
 
1920
#else
 
1921
        ret = os_file_fsync(file);
 
1922
#endif
 
1923
 
 
1924
        if (ret == 0) {
 
1925
                return(TRUE);
 
1926
        }
 
1927
 
 
1928
        /* Since Linux returns EINVAL if the 'file' is actually a raw device,
 
1929
        we choose to ignore that error if we are using raw disks */
 
1930
 
 
1931
        if (srv_start_raw_disk_in_use && errno == EINVAL) {
 
1932
 
 
1933
                return(TRUE);
 
1934
        }
 
1935
 
 
1936
        ut_print_timestamp(stderr);
 
1937
 
 
1938
        fprintf(stderr,
 
1939
                "  InnoDB: Error: the OS said file flush did not succeed\n");
 
1940
 
 
1941
        os_file_handle_error(NULL, "flush");
 
1942
 
 
1943
        /* It is a fatal error if a file flush does not succeed, because then
 
1944
        the database can get corrupt on disk */
 
1945
        ut_error;
 
1946
 
 
1947
        return(FALSE);
 
1948
#endif
 
1949
}
 
1950
 
 
1951
#ifndef __WIN__
 
1952
/***********************************************************************
 
1953
Does a synchronous read operation in Posix. */
 
1954
static
 
1955
ssize_t
 
1956
os_file_pread(
 
1957
/*==========*/
 
1958
                                /* out: number of bytes read, -1 if error */
 
1959
        os_file_t       file,   /* in: handle to a file */
 
1960
        void*           buf,    /* in: buffer where to read */
 
1961
        ulint           n,      /* in: number of bytes to read */
 
1962
        ulint           offset, /* in: least significant 32 bits of file
 
1963
                                offset from where to read */
 
1964
        ulint           offset_high) /* in: most significant 32 bits of
 
1965
                                offset */
 
1966
{
 
1967
        off_t   offs;
 
1968
        ssize_t n_bytes;
 
1969
 
 
1970
        ut_a((offset & 0xFFFFFFFFUL) == offset);
 
1971
 
 
1972
        /* If off_t is > 4 bytes in size, then we assume we can pass a
 
1973
        64-bit address */
 
1974
 
 
1975
        if (sizeof(off_t) > 4) {
 
1976
                offs = (off_t)offset + (((off_t)offset_high) << 32);
 
1977
 
 
1978
        } else {
 
1979
                offs = (off_t)offset;
 
1980
 
 
1981
                if (offset_high > 0) {
 
1982
                        fprintf(stderr,
 
1983
                                "InnoDB: Error: file read at offset > 4 GB\n");
 
1984
                }
 
1985
        }
 
1986
 
 
1987
        os_n_file_reads++;
 
1988
 
 
1989
#if defined(HAVE_PREAD) && !defined(HAVE_BROKEN_PREAD)
 
1990
        os_mutex_enter(os_file_count_mutex);
 
1991
        os_file_n_pending_preads++;
 
1992
        os_n_pending_reads++;
 
1993
        os_mutex_exit(os_file_count_mutex);
 
1994
 
 
1995
        n_bytes = pread(file, buf, (ssize_t)n, offs);
 
1996
 
 
1997
        os_mutex_enter(os_file_count_mutex);
 
1998
        os_file_n_pending_preads--;
 
1999
        os_n_pending_reads--;
 
2000
        os_mutex_exit(os_file_count_mutex);
 
2001
 
 
2002
        return(n_bytes);
 
2003
#else
 
2004
        {
 
2005
                off_t   ret_offset;
 
2006
                ssize_t ret;
 
2007
                ulint   i;
 
2008
 
 
2009
                os_mutex_enter(os_file_count_mutex);
 
2010
                os_n_pending_reads++;
 
2011
                os_mutex_exit(os_file_count_mutex);
 
2012
 
 
2013
                /* Protect the seek / read operation with a mutex */
 
2014
                i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
 
2015
 
 
2016
                os_mutex_enter(os_file_seek_mutexes[i]);
 
2017
 
 
2018
                ret_offset = lseek(file, offs, SEEK_SET);
 
2019
 
 
2020
                if (ret_offset < 0) {
 
2021
                        ret = -1;
 
2022
                } else {
 
2023
                        ret = read(file, buf, (ssize_t)n);
 
2024
                }
 
2025
 
 
2026
                os_mutex_exit(os_file_seek_mutexes[i]);
 
2027
 
 
2028
                os_mutex_enter(os_file_count_mutex);
 
2029
                os_n_pending_reads--;
 
2030
                os_mutex_exit(os_file_count_mutex);
 
2031
 
 
2032
                return(ret);
 
2033
        }
 
2034
#endif
 
2035
}
 
2036
 
 
2037
/***********************************************************************
 
2038
Does a synchronous write operation in Posix. */
 
2039
static
 
2040
ssize_t
 
2041
os_file_pwrite(
 
2042
/*===========*/
 
2043
                                /* out: number of bytes written, -1 if error */
 
2044
        os_file_t       file,   /* in: handle to a file */
 
2045
        const void*     buf,    /* in: buffer from where to write */
 
2046
        ulint           n,      /* in: number of bytes to write */
 
2047
        ulint           offset, /* in: least significant 32 bits of file
 
2048
                                offset where to write */
 
2049
        ulint           offset_high) /* in: most significant 32 bits of
 
2050
                                offset */
 
2051
{
 
2052
        ssize_t ret;
 
2053
        off_t   offs;
 
2054
 
 
2055
        ut_a((offset & 0xFFFFFFFFUL) == offset);
 
2056
 
 
2057
        /* If off_t is > 4 bytes in size, then we assume we can pass a
 
2058
        64-bit address */
 
2059
 
 
2060
        if (sizeof(off_t) > 4) {
 
2061
                offs = (off_t)offset + (((off_t)offset_high) << 32);
 
2062
        } else {
 
2063
                offs = (off_t)offset;
 
2064
 
 
2065
                if (offset_high > 0) {
 
2066
                        fprintf(stderr,
 
2067
                                "InnoDB: Error: file write"
 
2068
                                " at offset > 4 GB\n");
 
2069
                }
 
2070
        }
 
2071
 
 
2072
        os_n_file_writes++;
 
2073
 
 
2074
#if defined(HAVE_PWRITE) && !defined(HAVE_BROKEN_PREAD)
 
2075
        os_mutex_enter(os_file_count_mutex);
 
2076
        os_file_n_pending_pwrites++;
 
2077
        os_n_pending_writes++;
 
2078
        os_mutex_exit(os_file_count_mutex);
 
2079
 
 
2080
        ret = pwrite(file, buf, (ssize_t)n, offs);
 
2081
 
 
2082
        os_mutex_enter(os_file_count_mutex);
 
2083
        os_file_n_pending_pwrites--;
 
2084
        os_n_pending_writes--;
 
2085
        os_mutex_exit(os_file_count_mutex);
 
2086
 
 
2087
# ifdef UNIV_DO_FLUSH
 
2088
        if (srv_unix_file_flush_method != SRV_UNIX_LITTLESYNC
 
2089
            && srv_unix_file_flush_method != SRV_UNIX_NOSYNC
 
2090
            && !os_do_not_call_flush_at_each_write) {
 
2091
 
 
2092
                /* Always do fsync to reduce the probability that when
 
2093
                the OS crashes, a database page is only partially
 
2094
                physically written to disk. */
 
2095
 
 
2096
                ut_a(TRUE == os_file_flush(file));
 
2097
        }
 
2098
# endif /* UNIV_DO_FLUSH */
 
2099
 
 
2100
        return(ret);
 
2101
#else
 
2102
        {
 
2103
                off_t   ret_offset;
 
2104
                ulint   i;
 
2105
 
 
2106
                os_mutex_enter(os_file_count_mutex);
 
2107
                os_n_pending_writes++;
 
2108
                os_mutex_exit(os_file_count_mutex);
 
2109
 
 
2110
                /* Protect the seek / write operation with a mutex */
 
2111
                i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
 
2112
 
 
2113
                os_mutex_enter(os_file_seek_mutexes[i]);
 
2114
 
 
2115
                ret_offset = lseek(file, offs, SEEK_SET);
 
2116
 
 
2117
                if (ret_offset < 0) {
 
2118
                        ret = -1;
 
2119
 
 
2120
                        goto func_exit;
 
2121
                }
 
2122
 
 
2123
                ret = write(file, buf, (ssize_t)n);
 
2124
 
 
2125
# ifdef UNIV_DO_FLUSH
 
2126
                if (srv_unix_file_flush_method != SRV_UNIX_LITTLESYNC
 
2127
                    && srv_unix_file_flush_method != SRV_UNIX_NOSYNC
 
2128
                    && !os_do_not_call_flush_at_each_write) {
 
2129
 
 
2130
                        /* Always do fsync to reduce the probability that when
 
2131
                        the OS crashes, a database page is only partially
 
2132
                        physically written to disk. */
 
2133
 
 
2134
                        ut_a(TRUE == os_file_flush(file));
 
2135
                }
 
2136
# endif /* UNIV_DO_FLUSH */
 
2137
 
 
2138
func_exit:
 
2139
                os_mutex_exit(os_file_seek_mutexes[i]);
 
2140
 
 
2141
                os_mutex_enter(os_file_count_mutex);
 
2142
                os_n_pending_writes--;
 
2143
                os_mutex_exit(os_file_count_mutex);
 
2144
 
 
2145
                return(ret);
 
2146
        }
 
2147
#endif
 
2148
}
 
2149
#endif
 
2150
 
 
2151
/***********************************************************************
 
2152
Requests a synchronous positioned read operation. */
 
2153
UNIV_INTERN
 
2154
ibool
 
2155
os_file_read(
 
2156
/*=========*/
 
2157
                                /* out: TRUE if request was
 
2158
                                successful, FALSE if fail */
 
2159
        os_file_t       file,   /* in: handle to a file */
 
2160
        void*           buf,    /* in: buffer where to read */
 
2161
        ulint           offset, /* in: least significant 32 bits of file
 
2162
                                offset where to read */
 
2163
        ulint           offset_high, /* in: most significant 32 bits of
 
2164
                                offset */
 
2165
        ulint           n)      /* in: number of bytes to read */
 
2166
{
 
2167
#ifdef __WIN__
 
2168
        BOOL            ret;
 
2169
        DWORD           len;
 
2170
        DWORD           ret2;
 
2171
        DWORD           low;
 
2172
        DWORD           high;
 
2173
        ibool           retry;
 
2174
        ulint           i;
 
2175
 
 
2176
        ut_a((offset & 0xFFFFFFFFUL) == offset);
 
2177
 
 
2178
        os_n_file_reads++;
 
2179
        os_bytes_read_since_printout += n;
 
2180
 
 
2181
try_again:
 
2182
        ut_ad(file);
 
2183
        ut_ad(buf);
 
2184
        ut_ad(n > 0);
 
2185
 
 
2186
        low = (DWORD) offset;
 
2187
        high = (DWORD) offset_high;
 
2188
 
 
2189
        os_mutex_enter(os_file_count_mutex);
 
2190
        os_n_pending_reads++;
 
2191
        os_mutex_exit(os_file_count_mutex);
 
2192
 
 
2193
        /* Protect the seek / read operation with a mutex */
 
2194
        i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
 
2195
 
 
2196
        os_mutex_enter(os_file_seek_mutexes[i]);
 
2197
 
 
2198
        ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
 
2199
 
 
2200
        if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
 
2201
 
 
2202
                os_mutex_exit(os_file_seek_mutexes[i]);
 
2203
 
 
2204
                os_mutex_enter(os_file_count_mutex);
 
2205
                os_n_pending_reads--;
 
2206
                os_mutex_exit(os_file_count_mutex);
 
2207
 
 
2208
                goto error_handling;
 
2209
        }
 
2210
 
 
2211
        ret = ReadFile(file, buf, (DWORD) n, &len, NULL);
 
2212
 
 
2213
        os_mutex_exit(os_file_seek_mutexes[i]);
 
2214
 
 
2215
        os_mutex_enter(os_file_count_mutex);
 
2216
        os_n_pending_reads--;
 
2217
        os_mutex_exit(os_file_count_mutex);
 
2218
 
 
2219
        if (ret && len == n) {
 
2220
                return(TRUE);
 
2221
        }
 
2222
#else
 
2223
        ibool   retry;
 
2224
        ssize_t ret;
 
2225
 
 
2226
        os_bytes_read_since_printout += n;
 
2227
 
 
2228
try_again:
 
2229
        ret = os_file_pread(file, buf, n, offset, offset_high);
 
2230
 
 
2231
        if ((ulint)ret == n) {
 
2232
 
 
2233
                return(TRUE);
 
2234
        }
 
2235
 
 
2236
        fprintf(stderr,
 
2237
                "InnoDB: Error: tried to read %lu bytes at offset %lu %lu.\n"
 
2238
                "InnoDB: Was only able to read %ld.\n",
 
2239
                (ulong)n, (ulong)offset_high,
 
2240
                (ulong)offset, (long)ret);
 
2241
#endif
 
2242
#ifdef __WIN__
 
2243
error_handling:
 
2244
#endif
 
2245
        retry = os_file_handle_error(NULL, "read");
 
2246
 
 
2247
        if (retry) {
 
2248
                goto try_again;
 
2249
        }
 
2250
 
 
2251
        fprintf(stderr,
 
2252
                "InnoDB: Fatal error: cannot read from file."
 
2253
                " OS error number %lu.\n",
 
2254
#ifdef __WIN__
 
2255
                (ulong) GetLastError()
 
2256
#else
 
2257
                (ulong) errno
 
2258
#endif
 
2259
                );
 
2260
        fflush(stderr);
 
2261
 
 
2262
        ut_error;
 
2263
 
 
2264
        return(FALSE);
 
2265
}
 
2266
 
 
2267
/***********************************************************************
 
2268
Requests a synchronous positioned read operation. This function does not do
 
2269
any error handling. In case of error it returns FALSE. */
 
2270
UNIV_INTERN
 
2271
ibool
 
2272
os_file_read_no_error_handling(
 
2273
/*===========================*/
 
2274
                                /* out: TRUE if request was
 
2275
                                successful, FALSE if fail */
 
2276
        os_file_t       file,   /* in: handle to a file */
 
2277
        void*           buf,    /* in: buffer where to read */
 
2278
        ulint           offset, /* in: least significant 32 bits of file
 
2279
                                offset where to read */
 
2280
        ulint           offset_high, /* in: most significant 32 bits of
 
2281
                                offset */
 
2282
        ulint           n)      /* in: number of bytes to read */
 
2283
{
 
2284
#ifdef __WIN__
 
2285
        BOOL            ret;
 
2286
        DWORD           len;
 
2287
        DWORD           ret2;
 
2288
        DWORD           low;
 
2289
        DWORD           high;
 
2290
        ibool           retry;
 
2291
        ulint           i;
 
2292
 
 
2293
        ut_a((offset & 0xFFFFFFFFUL) == offset);
 
2294
 
 
2295
        os_n_file_reads++;
 
2296
        os_bytes_read_since_printout += n;
 
2297
 
 
2298
try_again:
 
2299
        ut_ad(file);
 
2300
        ut_ad(buf);
 
2301
        ut_ad(n > 0);
 
2302
 
 
2303
        low = (DWORD) offset;
 
2304
        high = (DWORD) offset_high;
 
2305
 
 
2306
        os_mutex_enter(os_file_count_mutex);
 
2307
        os_n_pending_reads++;
 
2308
        os_mutex_exit(os_file_count_mutex);
 
2309
 
 
2310
        /* Protect the seek / read operation with a mutex */
 
2311
        i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
 
2312
 
 
2313
        os_mutex_enter(os_file_seek_mutexes[i]);
 
2314
 
 
2315
        ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
 
2316
 
 
2317
        if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
 
2318
 
 
2319
                os_mutex_exit(os_file_seek_mutexes[i]);
 
2320
 
 
2321
                os_mutex_enter(os_file_count_mutex);
 
2322
                os_n_pending_reads--;
 
2323
                os_mutex_exit(os_file_count_mutex);
 
2324
 
 
2325
                goto error_handling;
 
2326
        }
 
2327
 
 
2328
        ret = ReadFile(file, buf, (DWORD) n, &len, NULL);
 
2329
 
 
2330
        os_mutex_exit(os_file_seek_mutexes[i]);
 
2331
 
 
2332
        os_mutex_enter(os_file_count_mutex);
 
2333
        os_n_pending_reads--;
 
2334
        os_mutex_exit(os_file_count_mutex);
 
2335
 
 
2336
        if (ret && len == n) {
 
2337
                return(TRUE);
 
2338
        }
 
2339
#else
 
2340
        ibool   retry;
 
2341
        ssize_t ret;
 
2342
 
 
2343
        os_bytes_read_since_printout += n;
 
2344
 
 
2345
try_again:
 
2346
        ret = os_file_pread(file, buf, n, offset, offset_high);
 
2347
 
 
2348
        if ((ulint)ret == n) {
 
2349
 
 
2350
                return(TRUE);
 
2351
        }
 
2352
#endif
 
2353
#ifdef __WIN__
 
2354
error_handling:
 
2355
#endif
 
2356
        retry = os_file_handle_error_no_exit(NULL, "read");
 
2357
 
 
2358
        if (retry) {
 
2359
                goto try_again;
 
2360
        }
 
2361
 
 
2362
        return(FALSE);
 
2363
}
 
2364
 
 
2365
/***********************************************************************
 
2366
Rewind file to its start, read at most size - 1 bytes from it to str, and
 
2367
NUL-terminate str. All errors are silently ignored. This function is
 
2368
mostly meant to be used with temporary files. */
 
2369
UNIV_INTERN
 
2370
void
 
2371
os_file_read_string(
 
2372
/*================*/
 
2373
        FILE*   file,   /* in: file to read from */
 
2374
        char*   str,    /* in: buffer where to read */
 
2375
        ulint   size)   /* in: size of buffer */
 
2376
{
 
2377
        size_t  flen;
 
2378
 
 
2379
        if (size == 0) {
 
2380
                return;
 
2381
        }
 
2382
 
 
2383
        rewind(file);
 
2384
        flen = fread(str, 1, size - 1, file);
 
2385
        str[flen] = '\0';
 
2386
}
 
2387
 
 
2388
/***********************************************************************
 
2389
Requests a synchronous write operation. */
 
2390
UNIV_INTERN
 
2391
ibool
 
2392
os_file_write(
 
2393
/*==========*/
 
2394
                                /* out: TRUE if request was
 
2395
                                successful, FALSE if fail */
 
2396
        const char*     name,   /* in: name of the file or path as a
 
2397
                                null-terminated string */
 
2398
        os_file_t       file,   /* in: handle to a file */
 
2399
        const void*     buf,    /* in: buffer from which to write */
 
2400
        ulint           offset, /* in: least significant 32 bits of file
 
2401
                                offset where to write */
 
2402
        ulint           offset_high, /* in: most significant 32 bits of
 
2403
                                offset */
 
2404
        ulint           n)      /* in: number of bytes to write */
 
2405
{
 
2406
#ifdef __WIN__
 
2407
        BOOL            ret;
 
2408
        DWORD           len;
 
2409
        DWORD           ret2;
 
2410
        DWORD           low;
 
2411
        DWORD           high;
 
2412
        ulint           i;
 
2413
        ulint           n_retries       = 0;
 
2414
        ulint           err;
 
2415
 
 
2416
        ut_a((offset & 0xFFFFFFFF) == offset);
 
2417
 
 
2418
        os_n_file_writes++;
 
2419
 
 
2420
        ut_ad(file);
 
2421
        ut_ad(buf);
 
2422
        ut_ad(n > 0);
 
2423
retry:
 
2424
        low = (DWORD) offset;
 
2425
        high = (DWORD) offset_high;
 
2426
 
 
2427
        os_mutex_enter(os_file_count_mutex);
 
2428
        os_n_pending_writes++;
 
2429
        os_mutex_exit(os_file_count_mutex);
 
2430
 
 
2431
        /* Protect the seek / write operation with a mutex */
 
2432
        i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
 
2433
 
 
2434
        os_mutex_enter(os_file_seek_mutexes[i]);
 
2435
 
 
2436
        ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
 
2437
 
 
2438
        if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
 
2439
 
 
2440
                os_mutex_exit(os_file_seek_mutexes[i]);
 
2441
 
 
2442
                os_mutex_enter(os_file_count_mutex);
 
2443
                os_n_pending_writes--;
 
2444
                os_mutex_exit(os_file_count_mutex);
 
2445
 
 
2446
                ut_print_timestamp(stderr);
 
2447
 
 
2448
                fprintf(stderr,
 
2449
                        "  InnoDB: Error: File pointer positioning to"
 
2450
                        " file %s failed at\n"
 
2451
                        "InnoDB: offset %lu %lu. Operating system"
 
2452
                        " error number %lu.\n"
 
2453
                        "InnoDB: Some operating system error numbers"
 
2454
                        " are described at\n"
 
2455
                        "InnoDB: "
 
2456
                        "http://dev.mysql.com/doc/refman/5.1/en/"
 
2457
                        "operating-system-error-codes.html\n",
 
2458
                        name, (ulong) offset_high, (ulong) offset,
 
2459
                        (ulong) GetLastError());
 
2460
 
 
2461
                return(FALSE);
 
2462
        }
 
2463
 
 
2464
        ret = WriteFile(file, buf, (DWORD) n, &len, NULL);
 
2465
 
 
2466
        /* Always do fsync to reduce the probability that when the OS crashes,
 
2467
        a database page is only partially physically written to disk. */
 
2468
 
 
2469
# ifdef UNIV_DO_FLUSH
 
2470
        if (!os_do_not_call_flush_at_each_write) {
 
2471
                ut_a(TRUE == os_file_flush(file));
 
2472
        }
 
2473
# endif /* UNIV_DO_FLUSH */
 
2474
 
 
2475
        os_mutex_exit(os_file_seek_mutexes[i]);
 
2476
 
 
2477
        os_mutex_enter(os_file_count_mutex);
 
2478
        os_n_pending_writes--;
 
2479
        os_mutex_exit(os_file_count_mutex);
 
2480
 
 
2481
        if (ret && len == n) {
 
2482
 
 
2483
                return(TRUE);
 
2484
        }
 
2485
 
 
2486
        /* If some background file system backup tool is running, then, at
 
2487
        least in Windows 2000, we may get here a specific error. Let us
 
2488
        retry the operation 100 times, with 1 second waits. */
 
2489
 
 
2490
        if (GetLastError() == ERROR_LOCK_VIOLATION && n_retries < 100) {
 
2491
 
 
2492
                os_thread_sleep(1000000);
 
2493
 
 
2494
                n_retries++;
 
2495
 
 
2496
                goto retry;
 
2497
        }
 
2498
 
 
2499
        if (!os_has_said_disk_full) {
 
2500
 
 
2501
                err = (ulint)GetLastError();
 
2502
 
 
2503
                ut_print_timestamp(stderr);
 
2504
 
 
2505
                fprintf(stderr,
 
2506
                        "  InnoDB: Error: Write to file %s failed"
 
2507
                        " at offset %lu %lu.\n"
 
2508
                        "InnoDB: %lu bytes should have been written,"
 
2509
                        " only %lu were written.\n"
 
2510
                        "InnoDB: Operating system error number %lu.\n"
 
2511
                        "InnoDB: Check that your OS and file system"
 
2512
                        " support files of this size.\n"
 
2513
                        "InnoDB: Check also that the disk is not full"
 
2514
                        " or a disk quota exceeded.\n",
 
2515
                        name, (ulong) offset_high, (ulong) offset,
 
2516
                        (ulong) n, (ulong) len, (ulong) err);
 
2517
 
 
2518
                if (strerror((int)err) != NULL) {
 
2519
                        fprintf(stderr,
 
2520
                                "InnoDB: Error number %lu means '%s'.\n",
 
2521
                                (ulong) err, strerror((int)err));
 
2522
                }
 
2523
 
 
2524
                fprintf(stderr,
 
2525
                        "InnoDB: Some operating system error numbers"
 
2526
                        " are described at\n"
 
2527
                        "InnoDB: "
 
2528
                        "http://dev.mysql.com/doc/refman/5.1/en/"
 
2529
                        "operating-system-error-codes.html\n");
 
2530
 
 
2531
                os_has_said_disk_full = TRUE;
 
2532
        }
 
2533
 
 
2534
        return(FALSE);
 
2535
#else
 
2536
        ssize_t ret;
 
2537
 
 
2538
        ret = os_file_pwrite(file, buf, n, offset, offset_high);
 
2539
 
 
2540
        if ((ulint)ret == n) {
 
2541
 
 
2542
                return(TRUE);
 
2543
        }
 
2544
 
 
2545
        if (!os_has_said_disk_full) {
 
2546
 
 
2547
                ut_print_timestamp(stderr);
 
2548
 
 
2549
                fprintf(stderr,
 
2550
                        "  InnoDB: Error: Write to file %s failed"
 
2551
                        " at offset %lu %lu.\n"
 
2552
                        "InnoDB: %lu bytes should have been written,"
 
2553
                        " only %ld were written.\n"
 
2554
                        "InnoDB: Operating system error number %lu.\n"
 
2555
                        "InnoDB: Check that your OS and file system"
 
2556
                        " support files of this size.\n"
 
2557
                        "InnoDB: Check also that the disk is not full"
 
2558
                        " or a disk quota exceeded.\n",
 
2559
                        name, offset_high, offset, n, (long int)ret,
 
2560
                        (ulint)errno);
 
2561
                if (strerror(errno) != NULL) {
 
2562
                        fprintf(stderr,
 
2563
                                "InnoDB: Error number %lu means '%s'.\n",
 
2564
                                (ulint)errno, strerror(errno));
 
2565
                }
 
2566
 
 
2567
                fprintf(stderr,
 
2568
                        "InnoDB: Some operating system error numbers"
 
2569
                        " are described at\n"
 
2570
                        "InnoDB: "
 
2571
                        "http://dev.mysql.com/doc/refman/5.1/en/"
 
2572
                        "operating-system-error-codes.html\n");
 
2573
 
 
2574
                os_has_said_disk_full = TRUE;
 
2575
        }
 
2576
 
 
2577
        return(FALSE);
 
2578
#endif
 
2579
}
 
2580
 
 
2581
/***********************************************************************
 
2582
Check the existence and type of the given file. */
 
2583
UNIV_INTERN
 
2584
ibool
 
2585
os_file_status(
 
2586
/*===========*/
 
2587
                                /* out: TRUE if call succeeded */
 
2588
        const char*     path,   /* in:  pathname of the file */
 
2589
        ibool*          exists, /* out: TRUE if file exists */
 
2590
        os_file_type_t* type)   /* out: type of the file (if it exists) */
 
2591
{
 
2592
#ifdef __WIN__
 
2593
        int             ret;
 
2594
        struct _stat    statinfo;
 
2595
 
 
2596
        ret = _stat(path, &statinfo);
 
2597
        if (ret && (errno == ENOENT || errno == ENOTDIR)) {
 
2598
                /* file does not exist */
 
2599
                *exists = FALSE;
 
2600
                return(TRUE);
 
2601
        } else if (ret) {
 
2602
                /* file exists, but stat call failed */
 
2603
 
 
2604
                os_file_handle_error_no_exit(path, "stat");
 
2605
 
 
2606
                return(FALSE);
 
2607
        }
 
2608
 
 
2609
        if (_S_IFDIR & statinfo.st_mode) {
 
2610
                *type = OS_FILE_TYPE_DIR;
 
2611
        } else if (_S_IFREG & statinfo.st_mode) {
 
2612
                *type = OS_FILE_TYPE_FILE;
 
2613
        } else {
 
2614
                *type = OS_FILE_TYPE_UNKNOWN;
 
2615
        }
 
2616
 
 
2617
        *exists = TRUE;
 
2618
 
 
2619
        return(TRUE);
 
2620
#else
 
2621
        int             ret;
 
2622
        struct stat     statinfo;
 
2623
 
 
2624
        ret = stat(path, &statinfo);
 
2625
        if (ret && (errno == ENOENT || errno == ENOTDIR)) {
 
2626
                /* file does not exist */
 
2627
                *exists = FALSE;
 
2628
                return(TRUE);
 
2629
        } else if (ret) {
 
2630
                /* file exists, but stat call failed */
 
2631
 
 
2632
                os_file_handle_error_no_exit(path, "stat");
 
2633
 
 
2634
                return(FALSE);
 
2635
        }
 
2636
 
 
2637
        if (S_ISDIR(statinfo.st_mode)) {
 
2638
                *type = OS_FILE_TYPE_DIR;
 
2639
        } else if (S_ISLNK(statinfo.st_mode)) {
 
2640
                *type = OS_FILE_TYPE_LINK;
 
2641
        } else if (S_ISREG(statinfo.st_mode)) {
 
2642
                *type = OS_FILE_TYPE_FILE;
 
2643
        } else {
 
2644
                *type = OS_FILE_TYPE_UNKNOWN;
 
2645
        }
 
2646
 
 
2647
        *exists = TRUE;
 
2648
 
 
2649
        return(TRUE);
 
2650
#endif
 
2651
}
 
2652
 
 
2653
/***********************************************************************
 
2654
This function returns information about the specified file */
 
2655
UNIV_INTERN
 
2656
ibool
 
2657
os_file_get_status(
 
2658
/*===============*/
 
2659
                                        /* out: TRUE if stat
 
2660
                                        information found */
 
2661
        const char*     path,           /* in:  pathname of the file */
 
2662
        os_file_stat_t* stat_info)      /* information of a file in a
 
2663
                                        directory */
 
2664
{
 
2665
#ifdef __WIN__
 
2666
        int             ret;
 
2667
        struct _stat    statinfo;
 
2668
 
 
2669
        ret = _stat(path, &statinfo);
 
2670
        if (ret && (errno == ENOENT || errno == ENOTDIR)) {
 
2671
                /* file does not exist */
 
2672
 
 
2673
                return(FALSE);
 
2674
        } else if (ret) {
 
2675
                /* file exists, but stat call failed */
 
2676
 
 
2677
                os_file_handle_error_no_exit(path, "stat");
 
2678
 
 
2679
                return(FALSE);
 
2680
        }
 
2681
        if (_S_IFDIR & statinfo.st_mode) {
 
2682
                stat_info->type = OS_FILE_TYPE_DIR;
 
2683
        } else if (_S_IFREG & statinfo.st_mode) {
 
2684
                stat_info->type = OS_FILE_TYPE_FILE;
 
2685
        } else {
 
2686
                stat_info->type = OS_FILE_TYPE_UNKNOWN;
 
2687
        }
 
2688
 
 
2689
        stat_info->ctime = statinfo.st_ctime;
 
2690
        stat_info->atime = statinfo.st_atime;
 
2691
        stat_info->mtime = statinfo.st_mtime;
 
2692
        stat_info->size  = statinfo.st_size;
 
2693
 
 
2694
        return(TRUE);
 
2695
#else
 
2696
        int             ret;
 
2697
        struct stat     statinfo;
 
2698
 
 
2699
        ret = stat(path, &statinfo);
 
2700
 
 
2701
        if (ret && (errno == ENOENT || errno == ENOTDIR)) {
 
2702
                /* file does not exist */
 
2703
 
 
2704
                return(FALSE);
 
2705
        } else if (ret) {
 
2706
                /* file exists, but stat call failed */
 
2707
 
 
2708
                os_file_handle_error_no_exit(path, "stat");
 
2709
 
 
2710
                return(FALSE);
 
2711
        }
 
2712
 
 
2713
        if (S_ISDIR(statinfo.st_mode)) {
 
2714
                stat_info->type = OS_FILE_TYPE_DIR;
 
2715
        } else if (S_ISLNK(statinfo.st_mode)) {
 
2716
                stat_info->type = OS_FILE_TYPE_LINK;
 
2717
        } else if (S_ISREG(statinfo.st_mode)) {
 
2718
                stat_info->type = OS_FILE_TYPE_FILE;
 
2719
        } else {
 
2720
                stat_info->type = OS_FILE_TYPE_UNKNOWN;
 
2721
        }
 
2722
 
 
2723
        stat_info->ctime = statinfo.st_ctime;
 
2724
        stat_info->atime = statinfo.st_atime;
 
2725
        stat_info->mtime = statinfo.st_mtime;
 
2726
        stat_info->size  = statinfo.st_size;
 
2727
 
 
2728
        return(TRUE);
 
2729
#endif
 
2730
}
 
2731
 
 
2732
/* path name separator character */
 
2733
#ifdef __WIN__
 
2734
#  define OS_FILE_PATH_SEPARATOR        '\\'
 
2735
#else
 
2736
#  define OS_FILE_PATH_SEPARATOR        '/'
 
2737
#endif
 
2738
 
 
2739
/********************************************************************
 
2740
The function os_file_dirname returns a directory component of a
 
2741
null-terminated pathname string.  In the usual case, dirname returns
 
2742
the string up to, but not including, the final '/', and basename
 
2743
is the component following the final '/'.  Trailing '/' charac�
 
2744
ters are not counted as part of the pathname.
 
2745
 
 
2746
If path does not contain a slash, dirname returns the string ".".
 
2747
 
 
2748
Concatenating the string returned by dirname, a "/", and the basename
 
2749
yields a complete pathname.
 
2750
 
 
2751
The return value is  a copy of the directory component of the pathname.
 
2752
The copy is allocated from heap. It is the caller responsibility
 
2753
to free it after it is no longer needed.
 
2754
 
 
2755
The following list of examples (taken from SUSv2) shows the strings
 
2756
returned by dirname and basename for different paths:
 
2757
 
 
2758
       path           dirname        basename
 
2759
       "/usr/lib"     "/usr"         "lib"
 
2760
       "/usr/"        "/"            "usr"
 
2761
       "usr"          "."            "usr"
 
2762
       "/"            "/"            "/"
 
2763
       "."            "."            "."
 
2764
       ".."           "."            ".."
 
2765
*/
 
2766
UNIV_INTERN
 
2767
char*
 
2768
os_file_dirname(
 
2769
/*============*/
 
2770
                                /* out, own: directory component of the
 
2771
                                pathname */
 
2772
        const char*     path)   /* in: pathname */
 
2773
{
 
2774
        /* Find the offset of the last slash */
 
2775
        const char* last_slash = strrchr(path, OS_FILE_PATH_SEPARATOR);
 
2776
        if (!last_slash) {
 
2777
                /* No slash in the path, return "." */
 
2778
 
 
2779
                return(mem_strdup("."));
 
2780
        }
 
2781
 
 
2782
        /* Ok, there is a slash */
 
2783
 
 
2784
        if (last_slash == path) {
 
2785
                /* last slash is the first char of the path */
 
2786
 
 
2787
                return(mem_strdup("/"));
 
2788
        }
 
2789
 
 
2790
        /* Non-trivial directory component */
 
2791
 
 
2792
        return(mem_strdupl(path, last_slash - path));
 
2793
}
 
2794
 
 
2795
/********************************************************************
 
2796
Creates all missing subdirectories along the given path. */
 
2797
UNIV_INTERN
 
2798
ibool
 
2799
os_file_create_subdirs_if_needed(
 
2800
/*=============================*/
 
2801
                                /* out: TRUE if call succeeded
 
2802
                                   FALSE otherwise */
 
2803
        const char*     path)   /* in: path name */
 
2804
{
 
2805
        char*           subdir;
 
2806
        ibool           success, subdir_exists;
 
2807
        os_file_type_t  type;
 
2808
 
 
2809
        subdir = os_file_dirname(path);
 
2810
        if (strlen(subdir) == 1
 
2811
            && (*subdir == OS_FILE_PATH_SEPARATOR || *subdir == '.')) {
 
2812
                /* subdir is root or cwd, nothing to do */
 
2813
                mem_free(subdir);
 
2814
 
 
2815
                return(TRUE);
 
2816
        }
 
2817
 
 
2818
        /* Test if subdir exists */
 
2819
        success = os_file_status(subdir, &subdir_exists, &type);
 
2820
        if (success && !subdir_exists) {
 
2821
                /* subdir does not exist, create it */
 
2822
                success = os_file_create_subdirs_if_needed(subdir);
 
2823
                if (!success) {
 
2824
                        mem_free(subdir);
 
2825
 
 
2826
                        return(FALSE);
 
2827
                }
 
2828
                success = os_file_create_directory(subdir, FALSE);
 
2829
        }
 
2830
 
 
2831
        mem_free(subdir);
 
2832
 
 
2833
        return(success);
 
2834
}
 
2835
 
 
2836
/********************************************************************
 
2837
Returns a pointer to the nth slot in the aio array. */
 
2838
static
 
2839
os_aio_slot_t*
 
2840
os_aio_array_get_nth_slot(
 
2841
/*======================*/
 
2842
                                        /* out: pointer to slot */
 
2843
        os_aio_array_t*         array,  /* in: aio array */
 
2844
        ulint                   index)  /* in: index of the slot */
 
2845
{
 
2846
        ut_a(index < array->n_slots);
 
2847
 
 
2848
        return((array->slots) + index);
 
2849
}
 
2850
 
 
2851
/****************************************************************************
 
2852
Creates an aio wait array. */
 
2853
static
 
2854
os_aio_array_t*
 
2855
os_aio_array_create(
 
2856
/*================*/
 
2857
                                /* out, own: aio array */
 
2858
        ulint   n,              /* in: maximum number of pending aio operations
 
2859
                                allowed; n must be divisible by n_segments */
 
2860
        ulint   n_segments)     /* in: number of segments in the aio array */
 
2861
{
 
2862
        os_aio_array_t* array;
 
2863
        ulint           i;
 
2864
        os_aio_slot_t*  slot;
 
2865
#ifdef WIN_ASYNC_IO
 
2866
        OVERLAPPED*     over;
 
2867
#endif
 
2868
        ut_a(n > 0);
 
2869
        ut_a(n_segments > 0);
 
2870
 
 
2871
        array = ut_malloc(sizeof(os_aio_array_t));
 
2872
 
 
2873
        array->mutex            = os_mutex_create(NULL);
 
2874
        array->not_full         = os_event_create(NULL);
 
2875
        array->is_empty         = os_event_create(NULL);
 
2876
 
 
2877
        os_event_set(array->is_empty);
 
2878
 
 
2879
        array->n_slots          = n;
 
2880
        array->n_segments       = n_segments;
 
2881
        array->n_reserved       = 0;
 
2882
        array->slots            = ut_malloc(n * sizeof(os_aio_slot_t));
 
2883
#ifdef __WIN__
 
2884
        array->native_events    = ut_malloc(n * sizeof(os_native_event_t));
 
2885
#endif
 
2886
        for (i = 0; i < n; i++) {
 
2887
                slot = os_aio_array_get_nth_slot(array, i);
 
2888
 
 
2889
                slot->pos = i;
 
2890
                slot->reserved = FALSE;
 
2891
#ifdef WIN_ASYNC_IO
 
2892
                slot->event = os_event_create(NULL);
 
2893
 
 
2894
                over = &(slot->control);
 
2895
 
 
2896
                over->hEvent = slot->event->handle;
 
2897
 
 
2898
                *((array->native_events) + i) = over->hEvent;
 
2899
#endif
 
2900
        }
 
2901
 
 
2902
        return(array);
 
2903
}
 
2904
 
 
2905
/****************************************************************************
 
2906
Initializes the asynchronous io system. Calls also os_io_init_simple.
 
2907
Creates a separate aio array for
 
2908
non-ibuf read and write, a third aio array for the ibuf i/o, with just one
 
2909
segment, two aio arrays for log reads and writes with one segment, and a
 
2910
synchronous aio array of the specified size. The combined number of segments
 
2911
in the three first aio arrays is the parameter n_segments given to the
 
2912
function. The caller must create an i/o handler thread for each segment in
 
2913
the four first arrays, but not for the sync aio array. */
 
2914
UNIV_INTERN
 
2915
void
 
2916
os_aio_init(
 
2917
/*========*/
 
2918
        ulint   n,              /* in: maximum number of pending aio operations
 
2919
                                allowed; n must be divisible by n_segments */
 
2920
        ulint   n_segments,     /* in: combined number of segments in the four
 
2921
                                first aio arrays; must be >= 4 */
 
2922
        ulint   n_slots_sync)   /* in: number of slots in the sync aio array */
 
2923
{
 
2924
        ulint   n_read_segs;
 
2925
        ulint   n_write_segs;
 
2926
        ulint   n_per_seg;
 
2927
        ulint   i;
 
2928
#ifdef POSIX_ASYNC_IO
 
2929
        sigset_t   sigset;
 
2930
#endif
 
2931
        ut_ad(n % n_segments == 0);
 
2932
        ut_ad(n_segments >= 4);
 
2933
 
 
2934
        os_io_init_simple();
 
2935
 
 
2936
        for (i = 0; i < n_segments; i++) {
 
2937
                srv_set_io_thread_op_info(i, "not started yet");
 
2938
        }
 
2939
 
 
2940
        n_per_seg = n / n_segments;
 
2941
        n_write_segs = (n_segments - 2) / 2;
 
2942
        n_read_segs = n_segments - 2 - n_write_segs;
 
2943
 
 
2944
        /* fprintf(stderr, "Array n per seg %lu\n", n_per_seg); */
 
2945
 
 
2946
        os_aio_ibuf_array = os_aio_array_create(n_per_seg, 1);
 
2947
 
 
2948
        srv_io_thread_function[0] = "insert buffer thread";
 
2949
 
 
2950
        os_aio_log_array = os_aio_array_create(n_per_seg, 1);
 
2951
 
 
2952
        srv_io_thread_function[1] = "log thread";
 
2953
 
 
2954
        os_aio_read_array = os_aio_array_create(n_read_segs * n_per_seg,
 
2955
                                                n_read_segs);
 
2956
        for (i = 2; i < 2 + n_read_segs; i++) {
 
2957
                ut_a(i < SRV_MAX_N_IO_THREADS);
 
2958
                srv_io_thread_function[i] = "read thread";
 
2959
        }
 
2960
 
 
2961
        os_aio_write_array = os_aio_array_create(n_write_segs * n_per_seg,
 
2962
                                                 n_write_segs);
 
2963
        for (i = 2 + n_read_segs; i < n_segments; i++) {
 
2964
                ut_a(i < SRV_MAX_N_IO_THREADS);
 
2965
                srv_io_thread_function[i] = "write thread";
 
2966
        }
 
2967
 
 
2968
        os_aio_sync_array = os_aio_array_create(n_slots_sync, 1);
 
2969
 
 
2970
        os_aio_n_segments = n_segments;
 
2971
 
 
2972
        os_aio_validate();
 
2973
 
 
2974
        os_aio_segment_wait_events = ut_malloc(n_segments * sizeof(void*));
 
2975
 
 
2976
        for (i = 0; i < n_segments; i++) {
 
2977
                os_aio_segment_wait_events[i] = os_event_create(NULL);
 
2978
        }
 
2979
 
 
2980
        os_last_printout = time(NULL);
 
2981
 
 
2982
#ifdef POSIX_ASYNC_IO
 
2983
        /* Block aio signals from the current thread and its children:
 
2984
        for this to work, the current thread must be the first created
 
2985
        in the database, so that all its children will inherit its
 
2986
        signal mask */
 
2987
 
 
2988
        /* TODO: to work MySQL needs the SIGALARM signal; the following
 
2989
        will not work yet! */
 
2990
        sigemptyset(&sigset);
 
2991
        sigaddset(&sigset, SIGRTMIN + 1 + 0);
 
2992
        sigaddset(&sigset, SIGRTMIN + 1 + 1);
 
2993
        sigaddset(&sigset, SIGRTMIN + 1 + 2);
 
2994
        sigaddset(&sigset, SIGRTMIN + 1 + 3);
 
2995
 
 
2996
        pthread_sigmask(SIG_BLOCK, &sigset, NULL); */
 
2997
#endif
 
2998
                }
 
2999
 
 
3000
#ifdef WIN_ASYNC_IO
 
3001
/****************************************************************************
 
3002
Wakes up all async i/o threads in the array in Windows async i/o at
 
3003
shutdown. */
 
3004
static
 
3005
void
 
3006
os_aio_array_wake_win_aio_at_shutdown(
 
3007
/*==================================*/
 
3008
        os_aio_array_t* array)  /* in: aio array */
 
3009
{
 
3010
        ulint   i;
 
3011
 
 
3012
        for (i = 0; i < array->n_slots; i++) {
 
3013
 
 
3014
                os_event_set((array->slots + i)->event);
 
3015
        }
 
3016
}
 
3017
#endif
 
3018
 
 
3019
/****************************************************************************
 
3020
Wakes up all async i/o threads so that they know to exit themselves in
 
3021
shutdown. */
 
3022
UNIV_INTERN
 
3023
void
 
3024
os_aio_wake_all_threads_at_shutdown(void)
 
3025
/*=====================================*/
 
3026
{
 
3027
        ulint   i;
 
3028
 
 
3029
#ifdef WIN_ASYNC_IO
 
3030
        /* This code wakes up all ai/o threads in Windows native aio */
 
3031
        os_aio_array_wake_win_aio_at_shutdown(os_aio_read_array);
 
3032
        os_aio_array_wake_win_aio_at_shutdown(os_aio_write_array);
 
3033
        os_aio_array_wake_win_aio_at_shutdown(os_aio_ibuf_array);
 
3034
        os_aio_array_wake_win_aio_at_shutdown(os_aio_log_array);
 
3035
#endif
 
3036
        /* This loop wakes up all simulated ai/o threads */
 
3037
 
 
3038
        for (i = 0; i < os_aio_n_segments; i++) {
 
3039
 
 
3040
                os_event_set(os_aio_segment_wait_events[i]);
 
3041
        }
 
3042
}
 
3043
 
 
3044
/****************************************************************************
 
3045
Waits until there are no pending writes in os_aio_write_array. There can
 
3046
be other, synchronous, pending writes. */
 
3047
UNIV_INTERN
 
3048
void
 
3049
os_aio_wait_until_no_pending_writes(void)
 
3050
/*=====================================*/
 
3051
{
 
3052
        os_event_wait(os_aio_write_array->is_empty);
 
3053
}
 
3054
 
 
3055
/**************************************************************************
 
3056
Calculates segment number for a slot. */
 
3057
static
 
3058
ulint
 
3059
os_aio_get_segment_no_from_slot(
 
3060
/*============================*/
 
3061
                                /* out: segment number (which is the number
 
3062
                                used by, for example, i/o-handler threads) */
 
3063
        os_aio_array_t* array,  /* in: aio wait array */
 
3064
        os_aio_slot_t*  slot)   /* in: slot in this array */
 
3065
{
 
3066
        ulint   segment;
 
3067
        ulint   seg_len;
 
3068
 
 
3069
        if (array == os_aio_ibuf_array) {
 
3070
                segment = 0;
 
3071
 
 
3072
        } else if (array == os_aio_log_array) {
 
3073
                segment = 1;
 
3074
 
 
3075
        } else if (array == os_aio_read_array) {
 
3076
                seg_len = os_aio_read_array->n_slots
 
3077
                        / os_aio_read_array->n_segments;
 
3078
 
 
3079
                segment = 2 + slot->pos / seg_len;
 
3080
        } else {
 
3081
                ut_a(array == os_aio_write_array);
 
3082
                seg_len = os_aio_write_array->n_slots
 
3083
                        / os_aio_write_array->n_segments;
 
3084
 
 
3085
                segment = os_aio_read_array->n_segments + 2
 
3086
                        + slot->pos / seg_len;
 
3087
        }
 
3088
 
 
3089
        return(segment);
 
3090
}
 
3091
 
 
3092
/**************************************************************************
 
3093
Calculates local segment number and aio array from global segment number. */
 
3094
static
 
3095
ulint
 
3096
os_aio_get_array_and_local_segment(
 
3097
/*===============================*/
 
3098
                                        /* out: local segment number within
 
3099
                                        the aio array */
 
3100
        os_aio_array_t** array,         /* out: aio wait array */
 
3101
        ulint            global_segment)/* in: global segment number */
 
3102
{
 
3103
        ulint   segment;
 
3104
 
 
3105
        ut_a(global_segment < os_aio_n_segments);
 
3106
 
 
3107
        if (global_segment == 0) {
 
3108
                *array = os_aio_ibuf_array;
 
3109
                segment = 0;
 
3110
 
 
3111
        } else if (global_segment == 1) {
 
3112
                *array = os_aio_log_array;
 
3113
                segment = 0;
 
3114
 
 
3115
        } else if (global_segment < os_aio_read_array->n_segments + 2) {
 
3116
                *array = os_aio_read_array;
 
3117
 
 
3118
                segment = global_segment - 2;
 
3119
        } else {
 
3120
                *array = os_aio_write_array;
 
3121
 
 
3122
                segment = global_segment - (os_aio_read_array->n_segments + 2);
 
3123
        }
 
3124
 
 
3125
        return(segment);
 
3126
}
 
3127
 
 
3128
/***********************************************************************
 
3129
Gets an integer value designating a specified aio array. This is used
 
3130
to give numbers to signals in Posix aio. */
 
3131
 
 
3132
#if !defined(WIN_ASYNC_IO) && defined(POSIX_ASYNC_IO)
 
3133
static
 
3134
ulint
 
3135
os_aio_get_array_no(
 
3136
/*================*/
 
3137
        os_aio_array_t* array)  /* in: aio array */
 
3138
{
 
3139
        if (array == os_aio_ibuf_array) {
 
3140
 
 
3141
                return(0);
 
3142
 
 
3143
        } else if (array == os_aio_log_array) {
 
3144
 
 
3145
                return(1);
 
3146
 
 
3147
        } else if (array == os_aio_read_array) {
 
3148
 
 
3149
                return(2);
 
3150
        } else if (array == os_aio_write_array) {
 
3151
 
 
3152
                return(3);
 
3153
        } else {
 
3154
                ut_error;
 
3155
 
 
3156
                return(0);
 
3157
        }
 
3158
}
 
3159
 
 
3160
/***********************************************************************
 
3161
Gets the aio array for its number. */
 
3162
static
 
3163
os_aio_array_t*
 
3164
os_aio_get_array_from_no(
 
3165
/*=====================*/
 
3166
                        /* out: aio array */
 
3167
        ulint   n)      /* in: array number */
 
3168
{
 
3169
        if (n == 0) {
 
3170
                return(os_aio_ibuf_array);
 
3171
        } else if (n == 1) {
 
3172
 
 
3173
                return(os_aio_log_array);
 
3174
        } else if (n == 2) {
 
3175
 
 
3176
                return(os_aio_read_array);
 
3177
        } else if (n == 3) {
 
3178
 
 
3179
                return(os_aio_write_array);
 
3180
        } else {
 
3181
                ut_error;
 
3182
 
 
3183
                return(NULL);
 
3184
        }
 
3185
}
 
3186
#endif /* if !defined(WIN_ASYNC_IO) && defined(POSIX_ASYNC_IO) */
 
3187
 
 
3188
/***********************************************************************
 
3189
Requests for a slot in the aio array. If no slot is available, waits until
 
3190
not_full-event becomes signaled. */
 
3191
static
 
3192
os_aio_slot_t*
 
3193
os_aio_array_reserve_slot(
 
3194
/*======================*/
 
3195
                                /* out: pointer to slot */
 
3196
        ulint           type,   /* in: OS_FILE_READ or OS_FILE_WRITE */
 
3197
        os_aio_array_t* array,  /* in: aio array */
 
3198
        fil_node_t*     message1,/* in: message to be passed along with
 
3199
                                the aio operation */
 
3200
        void*           message2,/* in: message to be passed along with
 
3201
                                the aio operation */
 
3202
        os_file_t       file,   /* in: file handle */
 
3203
        const char*     name,   /* in: name of the file or path as a
 
3204
                                null-terminated string */
 
3205
        void*           buf,    /* in: buffer where to read or from which
 
3206
                                to write */
 
3207
        ulint           offset, /* in: least significant 32 bits of file
 
3208
                                offset */
 
3209
        ulint           offset_high, /* in: most significant 32 bits of
 
3210
                                offset */
 
3211
        ulint           len)    /* in: length of the block to read or write */
 
3212
{
 
3213
        os_aio_slot_t*  slot;
 
3214
#ifdef WIN_ASYNC_IO
 
3215
        OVERLAPPED*     control;
 
3216
 
 
3217
#elif defined(POSIX_ASYNC_IO)
 
3218
 
 
3219
        struct aiocb*   control;
 
3220
#endif
 
3221
        ulint           i;
 
3222
loop:
 
3223
        os_mutex_enter(array->mutex);
 
3224
 
 
3225
        if (array->n_reserved == array->n_slots) {
 
3226
                os_mutex_exit(array->mutex);
 
3227
 
 
3228
                if (!os_aio_use_native_aio) {
 
3229
                        /* If the handler threads are suspended, wake them
 
3230
                        so that we get more slots */
 
3231
 
 
3232
                        os_aio_simulated_wake_handler_threads();
 
3233
                }
 
3234
 
 
3235
                os_event_wait(array->not_full);
 
3236
 
 
3237
                goto loop;
 
3238
        }
 
3239
 
 
3240
        for (i = 0;; i++) {
 
3241
                slot = os_aio_array_get_nth_slot(array, i);
 
3242
 
 
3243
                if (slot->reserved == FALSE) {
 
3244
                        break;
 
3245
                }
 
3246
        }
 
3247
 
 
3248
        array->n_reserved++;
 
3249
 
 
3250
        if (array->n_reserved == 1) {
 
3251
                os_event_reset(array->is_empty);
 
3252
        }
 
3253
 
 
3254
        if (array->n_reserved == array->n_slots) {
 
3255
                os_event_reset(array->not_full);
 
3256
        }
 
3257
 
 
3258
        slot->reserved = TRUE;
 
3259
        slot->reservation_time = time(NULL);
 
3260
        slot->message1 = message1;
 
3261
        slot->message2 = message2;
 
3262
        slot->file     = file;
 
3263
        slot->name     = name;
 
3264
        slot->len      = len;
 
3265
        slot->type     = type;
 
3266
        slot->buf      = buf;
 
3267
        slot->offset   = offset;
 
3268
        slot->offset_high = offset_high;
 
3269
        slot->io_already_done = FALSE;
 
3270
 
 
3271
#ifdef WIN_ASYNC_IO
 
3272
        control = &(slot->control);
 
3273
        control->Offset = (DWORD)offset;
 
3274
        control->OffsetHigh = (DWORD)offset_high;
 
3275
        os_event_reset(slot->event);
 
3276
 
 
3277
#elif defined(POSIX_ASYNC_IO)
 
3278
 
 
3279
#if (UNIV_WORD_SIZE == 8)
 
3280
        offset = offset + (offset_high << 32);
 
3281
#else
 
3282
        ut_a(offset_high == 0);
 
3283
#endif
 
3284
        control = &(slot->control);
 
3285
        control->aio_fildes = file;
 
3286
        control->aio_buf = buf;
 
3287
        control->aio_nbytes = len;
 
3288
        control->aio_offset = offset;
 
3289
        control->aio_reqprio = 0;
 
3290
        control->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
 
3291
        control->aio_sigevent.sigev_signo
 
3292
                = SIGRTMIN + 1 + os_aio_get_array_no(array);
 
3293
        /* TODO: How to choose the signal numbers? */
 
3294
        /*
 
3295
        fprintf(stderr, "AIO signal number %lu\n",
 
3296
        (ulint) control->aio_sigevent.sigev_signo);
 
3297
        */
 
3298
        control->aio_sigevent.sigev_value.sival_ptr = slot;
 
3299
#endif
 
3300
        os_mutex_exit(array->mutex);
 
3301
 
 
3302
        return(slot);
 
3303
}
 
3304
 
 
3305
/***********************************************************************
 
3306
Frees a slot in the aio array. */
 
3307
static
 
3308
void
 
3309
os_aio_array_free_slot(
 
3310
/*===================*/
 
3311
        os_aio_array_t* array,  /* in: aio array */
 
3312
        os_aio_slot_t*  slot)   /* in: pointer to slot */
 
3313
{
 
3314
        ut_ad(array);
 
3315
        ut_ad(slot);
 
3316
 
 
3317
        os_mutex_enter(array->mutex);
 
3318
 
 
3319
        ut_ad(slot->reserved);
 
3320
 
 
3321
        slot->reserved = FALSE;
 
3322
 
 
3323
        array->n_reserved--;
 
3324
 
 
3325
        if (array->n_reserved == array->n_slots - 1) {
 
3326
                os_event_set(array->not_full);
 
3327
        }
 
3328
 
 
3329
        if (array->n_reserved == 0) {
 
3330
                os_event_set(array->is_empty);
 
3331
        }
 
3332
 
 
3333
#ifdef WIN_ASYNC_IO
 
3334
        os_event_reset(slot->event);
 
3335
#endif
 
3336
        os_mutex_exit(array->mutex);
 
3337
}
 
3338
 
 
3339
/**************************************************************************
 
3340
Wakes up a simulated aio i/o-handler thread if it has something to do. */
 
3341
static
 
3342
void
 
3343
os_aio_simulated_wake_handler_thread(
 
3344
/*=================================*/
 
3345
        ulint   global_segment) /* in: the number of the segment in the aio
 
3346
                                arrays */
 
3347
{
 
3348
        os_aio_array_t* array;
 
3349
        os_aio_slot_t*  slot;
 
3350
        ulint           segment;
 
3351
        ulint           n;
 
3352
        ulint           i;
 
3353
 
 
3354
        ut_ad(!os_aio_use_native_aio);
 
3355
 
 
3356
        segment = os_aio_get_array_and_local_segment(&array, global_segment);
 
3357
 
 
3358
        n = array->n_slots / array->n_segments;
 
3359
 
 
3360
        /* Look through n slots after the segment * n'th slot */
 
3361
 
 
3362
        os_mutex_enter(array->mutex);
 
3363
 
 
3364
        for (i = 0; i < n; i++) {
 
3365
                slot = os_aio_array_get_nth_slot(array, i + segment * n);
 
3366
 
 
3367
                if (slot->reserved) {
 
3368
                        /* Found an i/o request */
 
3369
 
 
3370
                        break;
 
3371
                }
 
3372
        }
 
3373
 
 
3374
        os_mutex_exit(array->mutex);
 
3375
 
 
3376
        if (i < n) {
 
3377
                os_event_set(os_aio_segment_wait_events[global_segment]);
 
3378
        }
 
3379
}
 
3380
 
 
3381
/**************************************************************************
 
3382
Wakes up simulated aio i/o-handler threads if they have something to do. */
 
3383
UNIV_INTERN
 
3384
void
 
3385
os_aio_simulated_wake_handler_threads(void)
 
3386
/*=======================================*/
 
3387
{
 
3388
        ulint   i;
 
3389
 
 
3390
        if (os_aio_use_native_aio) {
 
3391
                /* We do not use simulated aio: do nothing */
 
3392
 
 
3393
                return;
 
3394
        }
 
3395
 
 
3396
        os_aio_recommend_sleep_for_read_threads = FALSE;
 
3397
 
 
3398
        for (i = 0; i < os_aio_n_segments; i++) {
 
3399
                os_aio_simulated_wake_handler_thread(i);
 
3400
        }
 
3401
}
 
3402
 
 
3403
/**************************************************************************
 
3404
This function can be called if one wants to post a batch of reads and
 
3405
prefers an i/o-handler thread to handle them all at once later. You must
 
3406
call os_aio_simulated_wake_handler_threads later to ensure the threads
 
3407
are not left sleeping! */
 
3408
UNIV_INTERN
 
3409
void
 
3410
os_aio_simulated_put_read_threads_to_sleep(void)
 
3411
/*============================================*/
 
3412
{
 
3413
        os_aio_array_t* array;
 
3414
        ulint           g;
 
3415
 
 
3416
        os_aio_recommend_sleep_for_read_threads = TRUE;
 
3417
 
 
3418
        for (g = 0; g < os_aio_n_segments; g++) {
 
3419
                os_aio_get_array_and_local_segment(&array, g);
 
3420
 
 
3421
                if (array == os_aio_read_array) {
 
3422
 
 
3423
                        os_event_reset(os_aio_segment_wait_events[g]);
 
3424
                }
 
3425
        }
 
3426
}
 
3427
 
 
3428
/***********************************************************************
 
3429
Requests an asynchronous i/o operation. */
 
3430
UNIV_INTERN
 
3431
ibool
 
3432
os_aio(
 
3433
/*===*/
 
3434
                                /* out: TRUE if request was queued
 
3435
                                successfully, FALSE if fail */
 
3436
        ulint           type,   /* in: OS_FILE_READ or OS_FILE_WRITE */
 
3437
        ulint           mode,   /* in: OS_AIO_NORMAL, ..., possibly ORed
 
3438
                                to OS_AIO_SIMULATED_WAKE_LATER: the
 
3439
                                last flag advises this function not to wake
 
3440
                                i/o-handler threads, but the caller will
 
3441
                                do the waking explicitly later, in this
 
3442
                                way the caller can post several requests in
 
3443
                                a batch; NOTE that the batch must not be
 
3444
                                so big that it exhausts the slots in aio
 
3445
                                arrays! NOTE that a simulated batch
 
3446
                                may introduce hidden chances of deadlocks,
 
3447
                                because i/os are not actually handled until
 
3448
                                all have been posted: use with great
 
3449
                                caution! */
 
3450
        const char*     name,   /* in: name of the file or path as a
 
3451
                                null-terminated string */
 
3452
        os_file_t       file,   /* in: handle to a file */
 
3453
        void*           buf,    /* in: buffer where to read or from which
 
3454
                                to write */
 
3455
        ulint           offset, /* in: least significant 32 bits of file
 
3456
                                offset where to read or write */
 
3457
        ulint           offset_high, /* in: most significant 32 bits of
 
3458
                                offset */
 
3459
        ulint           n,      /* in: number of bytes to read or write */
 
3460
        fil_node_t*     message1,/* in: messages for the aio handler (these
 
3461
                                can be used to identify a completed aio
 
3462
                                operation); if mode is OS_AIO_SYNC, these
 
3463
                                are ignored */
 
3464
        void*           message2)
 
3465
{
 
3466
        os_aio_array_t* array;
 
3467
        os_aio_slot_t*  slot;
 
3468
#ifdef WIN_ASYNC_IO
 
3469
        ibool           retval;
 
3470
        BOOL            ret             = TRUE;
 
3471
        DWORD           len             = (DWORD) n;
 
3472
        struct fil_node_struct * dummy_mess1;
 
3473
        void*           dummy_mess2;
 
3474
        ulint           dummy_type;
 
3475
#endif
 
3476
        ulint           err             = 0;
 
3477
        ibool           retry;
 
3478
        ulint           wake_later;
 
3479
 
 
3480
        ut_ad(file);
 
3481
        ut_ad(buf);
 
3482
        ut_ad(n > 0);
 
3483
        ut_ad(n % OS_FILE_LOG_BLOCK_SIZE == 0);
 
3484
        ut_ad(offset % OS_FILE_LOG_BLOCK_SIZE == 0);
 
3485
        ut_ad(os_aio_validate());
 
3486
 
 
3487
        wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
 
3488
        mode = mode & (~OS_AIO_SIMULATED_WAKE_LATER);
 
3489
 
 
3490
        if (mode == OS_AIO_SYNC
 
3491
#ifdef WIN_ASYNC_IO
 
3492
            && !os_aio_use_native_aio
 
3493
#endif
 
3494
            ) {
 
3495
                /* This is actually an ordinary synchronous read or write:
 
3496
                no need to use an i/o-handler thread. NOTE that if we use
 
3497
                Windows async i/o, Windows does not allow us to use
 
3498
                ordinary synchronous os_file_read etc. on the same file,
 
3499
                therefore we have built a special mechanism for synchronous
 
3500
                wait in the Windows case. */
 
3501
 
 
3502
                if (type == OS_FILE_READ) {
 
3503
                        return(os_file_read(file, buf, offset,
 
3504
                                            offset_high, n));
 
3505
                }
 
3506
 
 
3507
                ut_a(type == OS_FILE_WRITE);
 
3508
 
 
3509
                return(os_file_write(name, file, buf, offset, offset_high, n));
 
3510
        }
 
3511
 
 
3512
try_again:
 
3513
        if (mode == OS_AIO_NORMAL) {
 
3514
                if (type == OS_FILE_READ) {
 
3515
                        array = os_aio_read_array;
 
3516
                } else {
 
3517
                        array = os_aio_write_array;
 
3518
                }
 
3519
        } else if (mode == OS_AIO_IBUF) {
 
3520
                ut_ad(type == OS_FILE_READ);
 
3521
                /* Reduce probability of deadlock bugs in connection with ibuf:
 
3522
                do not let the ibuf i/o handler sleep */
 
3523
 
 
3524
                wake_later = FALSE;
 
3525
 
 
3526
                array = os_aio_ibuf_array;
 
3527
        } else if (mode == OS_AIO_LOG) {
 
3528
 
 
3529
                array = os_aio_log_array;
 
3530
        } else if (mode == OS_AIO_SYNC) {
 
3531
                array = os_aio_sync_array;
 
3532
        } else {
 
3533
                array = NULL; /* Eliminate compiler warning */
 
3534
                ut_error;
 
3535
        }
 
3536
 
 
3537
        slot = os_aio_array_reserve_slot(type, array, message1, message2, file,
 
3538
                                         name, buf, offset, offset_high, n);
 
3539
        if (type == OS_FILE_READ) {
 
3540
                if (os_aio_use_native_aio) {
 
3541
#ifdef WIN_ASYNC_IO
 
3542
                        os_n_file_reads++;
 
3543
                        os_bytes_read_since_printout += len;
 
3544
 
 
3545
                        ret = ReadFile(file, buf, (DWORD)n, &len,
 
3546
                                       &(slot->control));
 
3547
#elif defined(POSIX_ASYNC_IO)
 
3548
                        slot->control.aio_lio_opcode = LIO_READ;
 
3549
                        err = (ulint) aio_read(&(slot->control));
 
3550
                        fprintf(stderr, "Starting POSIX aio read %lu\n", err);
 
3551
#endif
 
3552
                } else {
 
3553
                        if (!wake_later) {
 
3554
                                os_aio_simulated_wake_handler_thread(
 
3555
                                        os_aio_get_segment_no_from_slot(
 
3556
                                                array, slot));
 
3557
                        }
 
3558
                }
 
3559
        } else if (type == OS_FILE_WRITE) {
 
3560
                if (os_aio_use_native_aio) {
 
3561
#ifdef WIN_ASYNC_IO
 
3562
                        os_n_file_writes++;
 
3563
                        ret = WriteFile(file, buf, (DWORD)n, &len,
 
3564
                                        &(slot->control));
 
3565
#elif defined(POSIX_ASYNC_IO)
 
3566
                        slot->control.aio_lio_opcode = LIO_WRITE;
 
3567
                        err = (ulint) aio_write(&(slot->control));
 
3568
                        fprintf(stderr, "Starting POSIX aio write %lu\n", err);
 
3569
#endif
 
3570
                } else {
 
3571
                        if (!wake_later) {
 
3572
                                os_aio_simulated_wake_handler_thread(
 
3573
                                        os_aio_get_segment_no_from_slot(
 
3574
                                                array, slot));
 
3575
                        }
 
3576
                }
 
3577
        } else {
 
3578
                ut_error;
 
3579
        }
 
3580
 
 
3581
#ifdef WIN_ASYNC_IO
 
3582
        if (os_aio_use_native_aio) {
 
3583
                if ((ret && len == n)
 
3584
                    || (!ret && GetLastError() == ERROR_IO_PENDING)) {
 
3585
                        /* aio was queued successfully! */
 
3586
 
 
3587
                        if (mode == OS_AIO_SYNC) {
 
3588
                                /* We want a synchronous i/o operation on a
 
3589
                                file where we also use async i/o: in Windows
 
3590
                                we must use the same wait mechanism as for
 
3591
                                async i/o */
 
3592
 
 
3593
                                retval = os_aio_windows_handle(ULINT_UNDEFINED,
 
3594
                                                               slot->pos,
 
3595
                                                               &dummy_mess1,
 
3596
                                                               &dummy_mess2,
 
3597
                                                               &dummy_type);
 
3598
 
 
3599
                                return(retval);
 
3600
                        }
 
3601
 
 
3602
                        return(TRUE);
 
3603
                }
 
3604
 
 
3605
                err = 1; /* Fall through the next if */
 
3606
        }
 
3607
#endif
 
3608
        if (err == 0) {
 
3609
                /* aio was queued successfully! */
 
3610
 
 
3611
                return(TRUE);
 
3612
        }
 
3613
 
 
3614
        os_aio_array_free_slot(array, slot);
 
3615
 
 
3616
        retry = os_file_handle_error(name,
 
3617
                                     type == OS_FILE_READ
 
3618
                                     ? "aio read" : "aio write");
 
3619
        if (retry) {
 
3620
 
 
3621
                goto try_again;
 
3622
        }
 
3623
 
 
3624
        return(FALSE);
 
3625
}
 
3626
 
 
3627
#ifdef WIN_ASYNC_IO
 
3628
/**************************************************************************
 
3629
This function is only used in Windows asynchronous i/o.
 
3630
Waits for an aio operation to complete. This function is used to wait the
 
3631
for completed requests. The aio array of pending requests is divided
 
3632
into segments. The thread specifies which segment or slot it wants to wait
 
3633
for. NOTE: this function will also take care of freeing the aio slot,
 
3634
therefore no other thread is allowed to do the freeing! */
 
3635
UNIV_INTERN
 
3636
ibool
 
3637
os_aio_windows_handle(
 
3638
/*==================*/
 
3639
                                /* out: TRUE if the aio operation succeeded */
 
3640
        ulint   segment,        /* in: the number of the segment in the aio
 
3641
                                arrays to wait for; segment 0 is the ibuf
 
3642
                                i/o thread, segment 1 the log i/o thread,
 
3643
                                then follow the non-ibuf read threads, and as
 
3644
                                the last are the non-ibuf write threads; if
 
3645
                                this is ULINT_UNDEFINED, then it means that
 
3646
                                sync aio is used, and this parameter is
 
3647
                                ignored */
 
3648
        ulint   pos,            /* this parameter is used only in sync aio:
 
3649
                                wait for the aio slot at this position */
 
3650
        fil_node_t**message1,   /* out: the messages passed with the aio
 
3651
                                request; note that also in the case where
 
3652
                                the aio operation failed, these output
 
3653
                                parameters are valid and can be used to
 
3654
                                restart the operation, for example */
 
3655
        void**  message2,
 
3656
        ulint*  type)           /* out: OS_FILE_WRITE or ..._READ */
 
3657
{
 
3658
        ulint           orig_seg        = segment;
 
3659
        os_aio_array_t* array;
 
3660
        os_aio_slot_t*  slot;
 
3661
        ulint           n;
 
3662
        ulint           i;
 
3663
        ibool           ret_val;
 
3664
        BOOL            ret;
 
3665
        DWORD           len;
 
3666
 
 
3667
        if (segment == ULINT_UNDEFINED) {
 
3668
                array = os_aio_sync_array;
 
3669
                segment = 0;
 
3670
        } else {
 
3671
                segment = os_aio_get_array_and_local_segment(&array, segment);
 
3672
        }
 
3673
 
 
3674
        /* NOTE! We only access constant fields in os_aio_array. Therefore
 
3675
        we do not have to acquire the protecting mutex yet */
 
3676
 
 
3677
        ut_ad(os_aio_validate());
 
3678
        ut_ad(segment < array->n_segments);
 
3679
 
 
3680
        n = array->n_slots / array->n_segments;
 
3681
 
 
3682
        if (array == os_aio_sync_array) {
 
3683
                os_event_wait(os_aio_array_get_nth_slot(array, pos)->event);
 
3684
                i = pos;
 
3685
        } else {
 
3686
                srv_set_io_thread_op_info(orig_seg, "wait Windows aio");
 
3687
                i = os_event_wait_multiple(n,
 
3688
                                           (array->native_events)
 
3689
                                           + segment * n);
 
3690
        }
 
3691
 
 
3692
        os_mutex_enter(array->mutex);
 
3693
 
 
3694
        slot = os_aio_array_get_nth_slot(array, i + segment * n);
 
3695
 
 
3696
        ut_a(slot->reserved);
 
3697
 
 
3698
        if (orig_seg != ULINT_UNDEFINED) {
 
3699
                srv_set_io_thread_op_info(orig_seg,
 
3700
                                          "get windows aio return value");
 
3701
        }
 
3702
 
 
3703
        ret = GetOverlappedResult(slot->file, &(slot->control), &len, TRUE);
 
3704
 
 
3705
        *message1 = slot->message1;
 
3706
        *message2 = slot->message2;
 
3707
 
 
3708
        *type = slot->type;
 
3709
 
 
3710
        if (ret && len == slot->len) {
 
3711
                ret_val = TRUE;
 
3712
 
 
3713
# ifdef UNIV_DO_FLUSH
 
3714
                if (slot->type == OS_FILE_WRITE
 
3715
                    && !os_do_not_call_flush_at_each_write) {
 
3716
                        ut_a(TRUE == os_file_flush(slot->file));
 
3717
                }
 
3718
# endif /* UNIV_DO_FLUSH */
 
3719
        } else {
 
3720
                os_file_handle_error(slot->name, "Windows aio");
 
3721
 
 
3722
                ret_val = FALSE;
 
3723
        }
 
3724
 
 
3725
        os_mutex_exit(array->mutex);
 
3726
 
 
3727
        os_aio_array_free_slot(array, slot);
 
3728
 
 
3729
        return(ret_val);
 
3730
}
 
3731
#endif
 
3732
 
 
3733
#ifdef POSIX_ASYNC_IO
 
3734
 
 
3735
/**************************************************************************
 
3736
This function is only used in Posix asynchronous i/o. Waits for an aio
 
3737
operation to complete. */
 
3738
UNIV_INTERN
 
3739
ibool
 
3740
os_aio_posix_handle(
 
3741
/*================*/
 
3742
                                /* out: TRUE if the aio operation succeeded */
 
3743
        ulint   array_no,       /* in: array number 0 - 3 */
 
3744
        fil_node_t**message1,   /* out: the messages passed with the aio
 
3745
                                request; note that also in the case where
 
3746
                                the aio operation failed, these output
 
3747
                                parameters are valid and can be used to
 
3748
                                restart the operation, for example */
 
3749
        void**  message2)
 
3750
{
 
3751
        os_aio_array_t* array;
 
3752
        os_aio_slot_t*  slot;
 
3753
        siginfo_t       info;
 
3754
        sigset_t        sigset;
 
3755
        sigset_t        proc_sigset;
 
3756
        sigset_t        thr_sigset;
 
3757
        int             ret;
 
3758
        int             i;
 
3759
        int             sig;
 
3760
 
 
3761
        sigemptyset(&sigset);
 
3762
        sigaddset(&sigset, SIGRTMIN + 1 + array_no);
 
3763
 
 
3764
        pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
 
3765
 
 
3766
#if 0
 
3767
        sigprocmask(0, NULL, &proc_sigset);
 
3768
        pthread_sigmask(0, NULL, &thr_sigset);
 
3769
 
 
3770
        for (i = 32 ; i < 40; i++) {
 
3771
                fprintf(stderr, "%lu : %lu %lu\n", (ulint)i,
 
3772
                        (ulint) sigismember(&proc_sigset, i),
 
3773
                        (ulint) sigismember(&thr_sigset, i));
 
3774
        }
 
3775
#endif
 
3776
 
 
3777
        ret = sigwaitinfo(&sigset, &info);
 
3778
 
 
3779
        if (sig != SIGRTMIN + 1 + array_no) {
 
3780
 
 
3781
                ut_error;
 
3782
 
 
3783
                return(FALSE);
 
3784
        }
 
3785
 
 
3786
        fputs("Handling POSIX aio\n", stderr);
 
3787
 
 
3788
        array = os_aio_get_array_from_no(array_no);
 
3789
 
 
3790
        os_mutex_enter(array->mutex);
 
3791
 
 
3792
        slot = info.si_value.sival_ptr;
 
3793
 
 
3794
        ut_a(slot->reserved);
 
3795
 
 
3796
        *message1 = slot->message1;
 
3797
        *message2 = slot->message2;
 
3798
 
 
3799
# ifdef UNIV_DO_FLUSH
 
3800
        if (slot->type == OS_FILE_WRITE
 
3801
            && !os_do_not_call_flush_at_each_write) {
 
3802
                ut_a(TRUE == os_file_flush(slot->file));
 
3803
        }
 
3804
# endif /* UNIV_DO_FLUSH */
 
3805
 
 
3806
        os_mutex_exit(array->mutex);
 
3807
 
 
3808
        os_aio_array_free_slot(array, slot);
 
3809
 
 
3810
        return(TRUE);
 
3811
}
 
3812
#endif
 
3813
 
 
3814
/**************************************************************************
 
3815
Does simulated aio. This function should be called by an i/o-handler
 
3816
thread. */
 
3817
UNIV_INTERN
 
3818
ibool
 
3819
os_aio_simulated_handle(
 
3820
/*====================*/
 
3821
                                /* out: TRUE if the aio operation succeeded */
 
3822
        ulint   global_segment, /* in: the number of the segment in the aio
 
3823
                                arrays to wait for; segment 0 is the ibuf
 
3824
                                i/o thread, segment 1 the log i/o thread,
 
3825
                                then follow the non-ibuf read threads, and as
 
3826
                                the last are the non-ibuf write threads */
 
3827
        fil_node_t**message1,   /* out: the messages passed with the aio
 
3828
                                request; note that also in the case where
 
3829
                                the aio operation failed, these output
 
3830
                                parameters are valid and can be used to
 
3831
                                restart the operation, for example */
 
3832
        void**  message2,
 
3833
        ulint*  type)           /* out: OS_FILE_WRITE or ..._READ */
 
3834
{
 
3835
        os_aio_array_t* array;
 
3836
        ulint           segment;
 
3837
        os_aio_slot_t*  slot;
 
3838
        os_aio_slot_t*  slot2;
 
3839
        os_aio_slot_t*  consecutive_ios[OS_AIO_MERGE_N_CONSECUTIVE];
 
3840
        ulint           n_consecutive;
 
3841
        ulint           total_len;
 
3842
        ulint           offs;
 
3843
        ulint           lowest_offset;
 
3844
        ulint           biggest_age;
 
3845
        ulint           age;
 
3846
        byte*           combined_buf;
 
3847
        byte*           combined_buf2;
 
3848
        ibool           ret;
 
3849
        ulint           n;
 
3850
        ulint           i;
 
3851
 
 
3852
        segment = os_aio_get_array_and_local_segment(&array, global_segment);
 
3853
 
 
3854
restart:
 
3855
        /* NOTE! We only access constant fields in os_aio_array. Therefore
 
3856
        we do not have to acquire the protecting mutex yet */
 
3857
 
 
3858
        srv_set_io_thread_op_info(global_segment,
 
3859
                                  "looking for i/o requests (a)");
 
3860
        ut_ad(os_aio_validate());
 
3861
        ut_ad(segment < array->n_segments);
 
3862
 
 
3863
        n = array->n_slots / array->n_segments;
 
3864
 
 
3865
        /* Look through n slots after the segment * n'th slot */
 
3866
 
 
3867
        if (array == os_aio_read_array
 
3868
            && os_aio_recommend_sleep_for_read_threads) {
 
3869
 
 
3870
                /* Give other threads chance to add several i/os to the array
 
3871
                at once. */
 
3872
 
 
3873
                goto recommended_sleep;
 
3874
        }
 
3875
 
 
3876
        os_mutex_enter(array->mutex);
 
3877
 
 
3878
        srv_set_io_thread_op_info(global_segment,
 
3879
                                  "looking for i/o requests (b)");
 
3880
 
 
3881
        /* Check if there is a slot for which the i/o has already been
 
3882
        done */
 
3883
 
 
3884
        for (i = 0; i < n; i++) {
 
3885
                slot = os_aio_array_get_nth_slot(array, i + segment * n);
 
3886
 
 
3887
                if (slot->reserved && slot->io_already_done) {
 
3888
 
 
3889
                        if (os_aio_print_debug) {
 
3890
                                fprintf(stderr,
 
3891
                                        "InnoDB: i/o for slot %lu"
 
3892
                                        " already done, returning\n",
 
3893
                                        (ulong) i);
 
3894
                        }
 
3895
 
 
3896
                        ret = TRUE;
 
3897
 
 
3898
                        goto slot_io_done;
 
3899
                }
 
3900
        }
 
3901
 
 
3902
        n_consecutive = 0;
 
3903
 
 
3904
        /* If there are at least 2 seconds old requests, then pick the oldest
 
3905
        one to prevent starvation. If several requests have the same age,
 
3906
        then pick the one at the lowest offset. */
 
3907
 
 
3908
        biggest_age = 0;
 
3909
        lowest_offset = ULINT_MAX;
 
3910
 
 
3911
        for (i = 0; i < n; i++) {
 
3912
                slot = os_aio_array_get_nth_slot(array, i + segment * n);
 
3913
 
 
3914
                if (slot->reserved) {
 
3915
                        age = (ulint)difftime(time(NULL),
 
3916
                                              slot->reservation_time);
 
3917
 
 
3918
                        if ((age >= 2 && age > biggest_age)
 
3919
                            || (age >= 2 && age == biggest_age
 
3920
                                && slot->offset < lowest_offset)) {
 
3921
 
 
3922
                                /* Found an i/o request */
 
3923
                                consecutive_ios[0] = slot;
 
3924
 
 
3925
                                n_consecutive = 1;
 
3926
 
 
3927
                                biggest_age = age;
 
3928
                                lowest_offset = slot->offset;
 
3929
                        }
 
3930
                }
 
3931
        }
 
3932
 
 
3933
        if (n_consecutive == 0) {
 
3934
                /* There were no old requests. Look for an i/o request at the
 
3935
                lowest offset in the array (we ignore the high 32 bits of the
 
3936
                offset in these heuristics) */
 
3937
 
 
3938
                lowest_offset = ULINT_MAX;
 
3939
 
 
3940
                for (i = 0; i < n; i++) {
 
3941
                        slot = os_aio_array_get_nth_slot(array,
 
3942
                                                         i + segment * n);
 
3943
 
 
3944
                        if (slot->reserved && slot->offset < lowest_offset) {
 
3945
 
 
3946
                                /* Found an i/o request */
 
3947
                                consecutive_ios[0] = slot;
 
3948
 
 
3949
                                n_consecutive = 1;
 
3950
 
 
3951
                                lowest_offset = slot->offset;
 
3952
                        }
 
3953
                }
 
3954
        }
 
3955
 
 
3956
        if (n_consecutive == 0) {
 
3957
 
 
3958
                /* No i/o requested at the moment */
 
3959
 
 
3960
                goto wait_for_io;
 
3961
        }
 
3962
 
 
3963
        slot = consecutive_ios[0];
 
3964
 
 
3965
        /* Check if there are several consecutive blocks to read or write */
 
3966
 
 
3967
consecutive_loop:
 
3968
        for (i = 0; i < n; i++) {
 
3969
                slot2 = os_aio_array_get_nth_slot(array, i + segment * n);
 
3970
 
 
3971
                if (slot2->reserved && slot2 != slot
 
3972
                    && slot2->offset == slot->offset + slot->len
 
3973
                    /* check that sum does not wrap over */
 
3974
                    && slot->offset + slot->len > slot->offset
 
3975
                    && slot2->offset_high == slot->offset_high
 
3976
                    && slot2->type == slot->type
 
3977
                    && slot2->file == slot->file) {
 
3978
 
 
3979
                        /* Found a consecutive i/o request */
 
3980
 
 
3981
                        consecutive_ios[n_consecutive] = slot2;
 
3982
                        n_consecutive++;
 
3983
 
 
3984
                        slot = slot2;
 
3985
 
 
3986
                        if (n_consecutive < OS_AIO_MERGE_N_CONSECUTIVE) {
 
3987
 
 
3988
                                goto consecutive_loop;
 
3989
                        } else {
 
3990
                                break;
 
3991
                        }
 
3992
                }
 
3993
        }
 
3994
 
 
3995
        srv_set_io_thread_op_info(global_segment, "consecutive i/o requests");
 
3996
 
 
3997
        /* We have now collected n_consecutive i/o requests in the array;
 
3998
        allocate a single buffer which can hold all data, and perform the
 
3999
        i/o */
 
4000
 
 
4001
        total_len = 0;
 
4002
        slot = consecutive_ios[0];
 
4003
 
 
4004
        for (i = 0; i < n_consecutive; i++) {
 
4005
                total_len += consecutive_ios[i]->len;
 
4006
        }
 
4007
 
 
4008
        if (n_consecutive == 1) {
 
4009
                /* We can use the buffer of the i/o request */
 
4010
                combined_buf = slot->buf;
 
4011
                combined_buf2 = NULL;
 
4012
        } else {
 
4013
                combined_buf2 = ut_malloc(total_len + UNIV_PAGE_SIZE);
 
4014
 
 
4015
                ut_a(combined_buf2);
 
4016
 
 
4017
                combined_buf = ut_align(combined_buf2, UNIV_PAGE_SIZE);
 
4018
        }
 
4019
 
 
4020
        /* We release the array mutex for the time of the i/o: NOTE that
 
4021
        this assumes that there is just one i/o-handler thread serving
 
4022
        a single segment of slots! */
 
4023
 
 
4024
        os_mutex_exit(array->mutex);
 
4025
 
 
4026
        if (slot->type == OS_FILE_WRITE && n_consecutive > 1) {
 
4027
                /* Copy the buffers to the combined buffer */
 
4028
                offs = 0;
 
4029
 
 
4030
                for (i = 0; i < n_consecutive; i++) {
 
4031
 
 
4032
                        ut_memcpy(combined_buf + offs, consecutive_ios[i]->buf,
 
4033
                                  consecutive_ios[i]->len);
 
4034
                        offs += consecutive_ios[i]->len;
 
4035
                }
 
4036
        }
 
4037
 
 
4038
        srv_set_io_thread_op_info(global_segment, "doing file i/o");
 
4039
 
 
4040
        if (os_aio_print_debug) {
 
4041
                fprintf(stderr,
 
4042
                        "InnoDB: doing i/o of type %lu at offset %lu %lu,"
 
4043
                        " length %lu\n",
 
4044
                        (ulong) slot->type, (ulong) slot->offset_high,
 
4045
                        (ulong) slot->offset, (ulong) total_len);
 
4046
        }
 
4047
 
 
4048
        /* Do the i/o with ordinary, synchronous i/o functions: */
 
4049
        if (slot->type == OS_FILE_WRITE) {
 
4050
                ret = os_file_write(slot->name, slot->file, combined_buf,
 
4051
                                    slot->offset, slot->offset_high,
 
4052
                                    total_len);
 
4053
        } else {
 
4054
                ret = os_file_read(slot->file, combined_buf,
 
4055
                                   slot->offset, slot->offset_high, total_len);
 
4056
        }
 
4057
 
 
4058
        ut_a(ret);
 
4059
        srv_set_io_thread_op_info(global_segment, "file i/o done");
 
4060
 
 
4061
#if 0
 
4062
        fprintf(stderr,
 
4063
                "aio: %lu consecutive %lu:th segment, first offs %lu blocks\n",
 
4064
                n_consecutive, global_segment, slot->offset / UNIV_PAGE_SIZE);
 
4065
#endif
 
4066
 
 
4067
        if (slot->type == OS_FILE_READ && n_consecutive > 1) {
 
4068
                /* Copy the combined buffer to individual buffers */
 
4069
                offs = 0;
 
4070
 
 
4071
                for (i = 0; i < n_consecutive; i++) {
 
4072
 
 
4073
                        ut_memcpy(consecutive_ios[i]->buf, combined_buf + offs,
 
4074
                                  consecutive_ios[i]->len);
 
4075
                        offs += consecutive_ios[i]->len;
 
4076
                }
 
4077
        }
 
4078
 
 
4079
        if (combined_buf2) {
 
4080
                ut_free(combined_buf2);
 
4081
        }
 
4082
 
 
4083
        os_mutex_enter(array->mutex);
 
4084
 
 
4085
        /* Mark the i/os done in slots */
 
4086
 
 
4087
        for (i = 0; i < n_consecutive; i++) {
 
4088
                consecutive_ios[i]->io_already_done = TRUE;
 
4089
        }
 
4090
 
 
4091
        /* We return the messages for the first slot now, and if there were
 
4092
        several slots, the messages will be returned with subsequent calls
 
4093
        of this function */
 
4094
 
 
4095
slot_io_done:
 
4096
 
 
4097
        ut_a(slot->reserved);
 
4098
 
 
4099
        *message1 = slot->message1;
 
4100
        *message2 = slot->message2;
 
4101
 
 
4102
        *type = slot->type;
 
4103
 
 
4104
        os_mutex_exit(array->mutex);
 
4105
 
 
4106
        os_aio_array_free_slot(array, slot);
 
4107
 
 
4108
        return(ret);
 
4109
 
 
4110
wait_for_io:
 
4111
        srv_set_io_thread_op_info(global_segment, "resetting wait event");
 
4112
 
 
4113
        /* We wait here until there again can be i/os in the segment
 
4114
        of this thread */
 
4115
 
 
4116
        os_event_reset(os_aio_segment_wait_events[global_segment]);
 
4117
 
 
4118
        os_mutex_exit(array->mutex);
 
4119
 
 
4120
recommended_sleep:
 
4121
        srv_set_io_thread_op_info(global_segment, "waiting for i/o request");
 
4122
 
 
4123
        os_event_wait(os_aio_segment_wait_events[global_segment]);
 
4124
 
 
4125
        if (os_aio_print_debug) {
 
4126
                fprintf(stderr,
 
4127
                        "InnoDB: i/o handler thread for i/o"
 
4128
                        " segment %lu wakes up\n",
 
4129
                        (ulong) global_segment);
 
4130
        }
 
4131
 
 
4132
        goto restart;
 
4133
}
 
4134
 
 
4135
/**************************************************************************
 
4136
Validates the consistency of an aio array. */
 
4137
static
 
4138
ibool
 
4139
os_aio_array_validate(
 
4140
/*==================*/
 
4141
                                /* out: TRUE if ok */
 
4142
        os_aio_array_t* array)  /* in: aio wait array */
 
4143
{
 
4144
        os_aio_slot_t*  slot;
 
4145
        ulint           n_reserved      = 0;
 
4146
        ulint           i;
 
4147
 
 
4148
        ut_a(array);
 
4149
 
 
4150
        os_mutex_enter(array->mutex);
 
4151
 
 
4152
        ut_a(array->n_slots > 0);
 
4153
        ut_a(array->n_segments > 0);
 
4154
 
 
4155
        for (i = 0; i < array->n_slots; i++) {
 
4156
                slot = os_aio_array_get_nth_slot(array, i);
 
4157
 
 
4158
                if (slot->reserved) {
 
4159
                        n_reserved++;
 
4160
                        ut_a(slot->len > 0);
 
4161
                }
 
4162
        }
 
4163
 
 
4164
        ut_a(array->n_reserved == n_reserved);
 
4165
 
 
4166
        os_mutex_exit(array->mutex);
 
4167
 
 
4168
        return(TRUE);
 
4169
}
 
4170
 
 
4171
/**************************************************************************
 
4172
Validates the consistency the aio system. */
 
4173
UNIV_INTERN
 
4174
ibool
 
4175
os_aio_validate(void)
 
4176
/*=================*/
 
4177
                                /* out: TRUE if ok */
 
4178
{
 
4179
        os_aio_array_validate(os_aio_read_array);
 
4180
        os_aio_array_validate(os_aio_write_array);
 
4181
        os_aio_array_validate(os_aio_ibuf_array);
 
4182
        os_aio_array_validate(os_aio_log_array);
 
4183
        os_aio_array_validate(os_aio_sync_array);
 
4184
 
 
4185
        return(TRUE);
 
4186
}
 
4187
 
 
4188
/**************************************************************************
 
4189
Prints info of the aio arrays. */
 
4190
UNIV_INTERN
 
4191
void
 
4192
os_aio_print(
 
4193
/*=========*/
 
4194
        FILE*   file)   /* in: file where to print */
 
4195
{
 
4196
        os_aio_array_t* array;
 
4197
        os_aio_slot_t*  slot;
 
4198
        ulint           n_reserved;
 
4199
        time_t          current_time;
 
4200
        double          time_elapsed;
 
4201
        double          avg_bytes_read;
 
4202
        ulint           i;
 
4203
 
 
4204
        for (i = 0; i < srv_n_file_io_threads; i++) {
 
4205
                fprintf(file, "I/O thread %lu state: %s (%s)", (ulong) i,
 
4206
                        srv_io_thread_op_info[i],
 
4207
                        srv_io_thread_function[i]);
 
4208
 
 
4209
#ifndef __WIN__
 
4210
                if (os_aio_segment_wait_events[i]->is_set) {
 
4211
                        fprintf(file, " ev set");
 
4212
                }
 
4213
#endif
 
4214
 
 
4215
                fprintf(file, "\n");
 
4216
        }
 
4217
 
 
4218
        fputs("Pending normal aio reads:", file);
 
4219
 
 
4220
        array = os_aio_read_array;
 
4221
loop:
 
4222
        ut_a(array);
 
4223
 
 
4224
        os_mutex_enter(array->mutex);
 
4225
 
 
4226
        ut_a(array->n_slots > 0);
 
4227
        ut_a(array->n_segments > 0);
 
4228
 
 
4229
        n_reserved = 0;
 
4230
 
 
4231
        for (i = 0; i < array->n_slots; i++) {
 
4232
                slot = os_aio_array_get_nth_slot(array, i);
 
4233
 
 
4234
                if (slot->reserved) {
 
4235
                        n_reserved++;
 
4236
#if 0
 
4237
                        fprintf(stderr, "Reserved slot, messages %p %p\n",
 
4238
                                (void*) slot->message1,
 
4239
                                (void*) slot->message2);
 
4240
#endif
 
4241
                        ut_a(slot->len > 0);
 
4242
                }
 
4243
        }
 
4244
 
 
4245
        ut_a(array->n_reserved == n_reserved);
 
4246
 
 
4247
        fprintf(file, " %lu", (ulong) n_reserved);
 
4248
 
 
4249
        os_mutex_exit(array->mutex);
 
4250
 
 
4251
        if (array == os_aio_read_array) {
 
4252
                fputs(", aio writes:", file);
 
4253
 
 
4254
                array = os_aio_write_array;
 
4255
 
 
4256
                goto loop;
 
4257
        }
 
4258
 
 
4259
        if (array == os_aio_write_array) {
 
4260
                fputs(",\n ibuf aio reads:", file);
 
4261
                array = os_aio_ibuf_array;
 
4262
 
 
4263
                goto loop;
 
4264
        }
 
4265
 
 
4266
        if (array == os_aio_ibuf_array) {
 
4267
                fputs(", log i/o's:", file);
 
4268
                array = os_aio_log_array;
 
4269
 
 
4270
                goto loop;
 
4271
        }
 
4272
 
 
4273
        if (array == os_aio_log_array) {
 
4274
                fputs(", sync i/o's:", file);
 
4275
                array = os_aio_sync_array;
 
4276
 
 
4277
                goto loop;
 
4278
        }
 
4279
 
 
4280
        putc('\n', file);
 
4281
        current_time = time(NULL);
 
4282
        time_elapsed = 0.001 + difftime(current_time, os_last_printout);
 
4283
 
 
4284
        fprintf(file,
 
4285
                "Pending flushes (fsync) log: %lu; buffer pool: %lu\n"
 
4286
                "%lu OS file reads, %lu OS file writes, %lu OS fsyncs\n",
 
4287
                (ulong) fil_n_pending_log_flushes,
 
4288
                (ulong) fil_n_pending_tablespace_flushes,
 
4289
                (ulong) os_n_file_reads, (ulong) os_n_file_writes,
 
4290
                (ulong) os_n_fsyncs);
 
4291
 
 
4292
        if (os_file_n_pending_preads != 0 || os_file_n_pending_pwrites != 0) {
 
4293
                fprintf(file,
 
4294
                        "%lu pending preads, %lu pending pwrites\n",
 
4295
                        (ulong) os_file_n_pending_preads,
 
4296
                        (ulong) os_file_n_pending_pwrites);
 
4297
        }
 
4298
 
 
4299
        if (os_n_file_reads == os_n_file_reads_old) {
 
4300
                avg_bytes_read = 0.0;
 
4301
        } else {
 
4302
                avg_bytes_read = (double) os_bytes_read_since_printout
 
4303
                        / (os_n_file_reads - os_n_file_reads_old);
 
4304
        }
 
4305
 
 
4306
        fprintf(file,
 
4307
                "%.2f reads/s, %lu avg bytes/read,"
 
4308
                " %.2f writes/s, %.2f fsyncs/s\n",
 
4309
                (os_n_file_reads - os_n_file_reads_old)
 
4310
                / time_elapsed,
 
4311
                (ulong)avg_bytes_read,
 
4312
                (os_n_file_writes - os_n_file_writes_old)
 
4313
                / time_elapsed,
 
4314
                (os_n_fsyncs - os_n_fsyncs_old)
 
4315
                / time_elapsed);
 
4316
 
 
4317
        os_n_file_reads_old = os_n_file_reads;
 
4318
        os_n_file_writes_old = os_n_file_writes;
 
4319
        os_n_fsyncs_old = os_n_fsyncs;
 
4320
        os_bytes_read_since_printout = 0;
 
4321
 
 
4322
        os_last_printout = current_time;
 
4323
}
 
4324
 
 
4325
/**************************************************************************
 
4326
Refreshes the statistics used to print per-second averages. */
 
4327
UNIV_INTERN
 
4328
void
 
4329
os_aio_refresh_stats(void)
 
4330
/*======================*/
 
4331
{
 
4332
        os_n_file_reads_old = os_n_file_reads;
 
4333
        os_n_file_writes_old = os_n_file_writes;
 
4334
        os_n_fsyncs_old = os_n_fsyncs;
 
4335
        os_bytes_read_since_printout = 0;
 
4336
 
 
4337
        os_last_printout = time(NULL);
 
4338
}
 
4339
 
 
4340
#ifdef UNIV_DEBUG
 
4341
/**************************************************************************
 
4342
Checks that all slots in the system have been freed, that is, there are
 
4343
no pending io operations. */
 
4344
UNIV_INTERN
 
4345
ibool
 
4346
os_aio_all_slots_free(void)
 
4347
/*=======================*/
 
4348
                                /* out: TRUE if all free */
 
4349
{
 
4350
        os_aio_array_t* array;
 
4351
        ulint           n_res   = 0;
 
4352
 
 
4353
        array = os_aio_read_array;
 
4354
 
 
4355
        os_mutex_enter(array->mutex);
 
4356
 
 
4357
        n_res += array->n_reserved;
 
4358
 
 
4359
        os_mutex_exit(array->mutex);
 
4360
 
 
4361
        array = os_aio_write_array;
 
4362
 
 
4363
        os_mutex_enter(array->mutex);
 
4364
 
 
4365
        n_res += array->n_reserved;
 
4366
 
 
4367
        os_mutex_exit(array->mutex);
 
4368
 
 
4369
        array = os_aio_ibuf_array;
 
4370
 
 
4371
        os_mutex_enter(array->mutex);
 
4372
 
 
4373
        n_res += array->n_reserved;
 
4374
 
 
4375
        os_mutex_exit(array->mutex);
 
4376
 
 
4377
        array = os_aio_log_array;
 
4378
 
 
4379
        os_mutex_enter(array->mutex);
 
4380
 
 
4381
        n_res += array->n_reserved;
 
4382
 
 
4383
        os_mutex_exit(array->mutex);
 
4384
 
 
4385
        array = os_aio_sync_array;
 
4386
 
 
4387
        os_mutex_enter(array->mutex);
 
4388
 
 
4389
        n_res += array->n_reserved;
 
4390
 
 
4391
        os_mutex_exit(array->mutex);
 
4392
 
 
4393
        if (n_res == 0) {
 
4394
 
 
4395
                return(TRUE);
 
4396
        }
 
4397
 
 
4398
        return(FALSE);
 
4399
}
 
4400
#endif /* UNIV_DEBUG */