/src/server/mysys/my_sync.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright (c) 2003, 2011, Oracle and/or its affiliates |
3 | | |
4 | | This program is free software; you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation; version 2 of the License. |
7 | | |
8 | | This program is distributed in the hope that it will be useful, |
9 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | | GNU General Public License for more details. |
12 | | |
13 | | You should have received a copy of the GNU General Public License |
14 | | along with this program; if not, write to the Free Software |
15 | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ |
16 | | |
17 | | #include "mysys_priv.h" |
18 | | #include "mysys_err.h" |
19 | | #include <errno.h> |
20 | | |
21 | | |
22 | | ulong my_sync_count; /* Count number of sync calls */ |
23 | | |
24 | | static void (*before_sync_wait)(void)= 0; |
25 | | static void (*after_sync_wait)(void)= 0; |
26 | | |
27 | | void thr_set_sync_wait_callback(void (*before_wait)(void), |
28 | | void (*after_wait)(void)) |
29 | 0 | { |
30 | 0 | before_sync_wait= before_wait; |
31 | 0 | after_sync_wait= after_wait; |
32 | 0 | } |
33 | | |
34 | | /* |
35 | | Sync data in file to disk |
36 | | |
37 | | SYNOPSIS |
38 | | my_sync() |
39 | | fd File descritor to sync |
40 | | my_flags Flags (now only MY_WME is supported) |
41 | | |
42 | | NOTE |
43 | | If file system supports its, only file data is synced, not inode data. |
44 | | |
45 | | MY_IGNORE_BADFD is useful when fd is "volatile" - not protected by a |
46 | | mutex. In this case by the time of fsync(), fd may be already closed by |
47 | | another thread, or even reassigned to a different file. With this flag - |
48 | | MY_IGNORE_BADFD - such a situation will not be considered an error. |
49 | | (which is correct behaviour, if we know that the other thread synced the |
50 | | file before closing) |
51 | | |
52 | | RETURN |
53 | | 0 ok |
54 | | -1 error |
55 | | */ |
56 | | |
57 | | int my_sync(File fd, myf my_flags) |
58 | 0 | { |
59 | 0 | int res; |
60 | 0 | DBUG_ENTER("my_sync"); |
61 | 0 | DBUG_PRINT("my",("fd: %d my_flags: %lu", fd, my_flags)); |
62 | |
|
63 | 0 | if (my_disable_sync) |
64 | 0 | DBUG_RETURN(0); |
65 | | |
66 | 0 | statistic_increment(my_sync_count,&THR_LOCK_open); |
67 | |
|
68 | 0 | if (before_sync_wait) |
69 | 0 | (*before_sync_wait)(); |
70 | |
|
71 | 0 | do |
72 | 0 | { |
73 | | #if defined(F_FULLFSYNC) |
74 | | /* |
75 | | In Mac OS X >= 10.3 this call is safer than fsync() (it forces the |
76 | | disk's cache and guarantees ordered writes). |
77 | | */ |
78 | | if (!(res= fcntl(fd, F_FULLFSYNC, 0))) |
79 | | break; /* ok */ |
80 | | /* Some file systems don't support F_FULLFSYNC and fail above: */ |
81 | | DBUG_PRINT("info",("fcntl(F_FULLFSYNC) failed, falling back")); |
82 | | #endif |
83 | 0 | #if defined(HAVE_FDATASYNC) && HAVE_DECL_FDATASYNC |
84 | 0 | res= fdatasync(fd); |
85 | | #elif defined(HAVE_FSYNC) |
86 | | res= fsync(fd); |
87 | | if (res == -1 && errno == ENOLCK) |
88 | | res= 0; /* Result Bug in Old FreeBSD */ |
89 | | #elif defined(_WIN32) |
90 | | res= my_win_fsync(fd); |
91 | | #else |
92 | | #error Cannot find a way to sync a file, durability in danger |
93 | | res= 0; /* No sync (strange OS) */ |
94 | | #endif |
95 | 0 | } while (res == -1 && errno == EINTR); |
96 | |
|
97 | 0 | if (res) |
98 | 0 | { |
99 | 0 | int er= errno; |
100 | 0 | if (!(my_errno= er)) |
101 | 0 | my_errno= -1; /* Unknown error */ |
102 | 0 | if (after_sync_wait) |
103 | 0 | (*after_sync_wait)(); |
104 | 0 | if ((my_flags & MY_IGNORE_BADFD) && |
105 | 0 | (er == EBADF || er == EINVAL || er == EROFS)) |
106 | 0 | { |
107 | 0 | DBUG_PRINT("info", ("ignoring errno %d", er)); |
108 | 0 | res= 0; |
109 | 0 | } |
110 | 0 | else if (my_flags & MY_WME) |
111 | 0 | my_error(EE_SYNC, MYF(ME_BELL), my_filename(fd), my_errno); |
112 | 0 | } |
113 | 0 | else |
114 | 0 | { |
115 | 0 | if (after_sync_wait) |
116 | 0 | (*after_sync_wait)(); |
117 | 0 | } |
118 | 0 | DBUG_RETURN(res); |
119 | 0 | } /* my_sync */ |
120 | | |
121 | | |
122 | | /* |
123 | | Force directory information to disk. |
124 | | |
125 | | SYNOPSIS |
126 | | my_sync_dir() |
127 | | dir_name the name of the directory |
128 | | my_flags flags (MY_WME etc) |
129 | | |
130 | | RETURN |
131 | | 0 if ok, !=0 if error |
132 | | */ |
133 | | |
134 | | int my_sync_dir(const char *dir_name __attribute__((unused)), |
135 | | myf my_flags __attribute__((unused))) |
136 | 0 | { |
137 | 0 | #ifdef NEED_EXPLICIT_SYNC_DIR |
138 | 0 | static const char cur_dir_name[]= {FN_CURLIB, 0}; |
139 | 0 | File dir_fd; |
140 | 0 | int res= 0; |
141 | 0 | const char *correct_dir_name; |
142 | 0 | DBUG_ENTER("my_sync_dir"); |
143 | 0 | DBUG_PRINT("my",("Dir: '%s' my_flags: %lu", dir_name, my_flags)); |
144 | | /* Sometimes the path does not contain an explicit directory */ |
145 | 0 | correct_dir_name= (dir_name[0] == 0) ? cur_dir_name : dir_name; |
146 | | /* |
147 | | Syncing a dir may give EINVAL on tmpfs on Linux, which is ok. |
148 | | EIO on the other hand is very important. Hence MY_IGNORE_BADFD. |
149 | | */ |
150 | 0 | if ((dir_fd= my_open(correct_dir_name, O_RDONLY, MYF(my_flags))) >= 0) |
151 | 0 | { |
152 | 0 | if (my_sync(dir_fd, MYF(my_flags | MY_IGNORE_BADFD))) |
153 | 0 | res= 2; |
154 | 0 | if (my_close(dir_fd, MYF(my_flags))) |
155 | 0 | res= 3; |
156 | 0 | } |
157 | 0 | else |
158 | 0 | res= 1; |
159 | 0 | DBUG_RETURN(res); |
160 | | #else |
161 | | return 0; |
162 | | #endif |
163 | 0 | } |
164 | | |
165 | | /* |
166 | | Force directory information to disk. |
167 | | |
168 | | SYNOPSIS |
169 | | my_sync_dir_by_file() |
170 | | file_name the name of a file in the directory |
171 | | my_flags flags (MY_WME etc) |
172 | | |
173 | | RETURN |
174 | | 0 if ok, !=0 if error |
175 | | */ |
176 | | |
177 | | int my_sync_dir_by_file(const char *file_name __attribute__((unused)), |
178 | | myf my_flags __attribute__((unused))) |
179 | 0 | { |
180 | 0 | #ifdef NEED_EXPLICIT_SYNC_DIR |
181 | 0 | char dir_name[FN_REFLEN]; |
182 | 0 | size_t dir_name_length; |
183 | 0 | dirname_part(dir_name, file_name, &dir_name_length); |
184 | 0 | return my_sync_dir(dir_name, my_flags & ~MY_NOSYMLINKS); |
185 | | #else |
186 | | return 0; |
187 | | #endif |
188 | 0 | } |