darwin: emulate fdatasync() with fcntl(F_FULLFSYNC)

OS X has no public API for fdatasync. And as pointed out in `man fsync(2)`:

  For applications that require tighter guarantees about the integrity of
  their data, Mac OS X provides the F_FULLFSYNC fcntl. The F_FULLFSYNC
  fcntl asks the drive to flush all buffered data to permanent storage.
  Applications, such as databases, that require a strict ordering of writes
  should use F_FULLFSYNC to ensure that their data is written in the order
  they expect.  Please see fcntl(2) for more detail.
This commit is contained in:
Fedor Indutny 2012-07-21 12:49:35 +04:00 committed by Ben Noordhuis
parent 837edf4c0f
commit 23dc564f3b
2 changed files with 42 additions and 1 deletions

View File

@ -267,7 +267,8 @@ struct uv__io_s {
#define UV_FS_PRIVATE_FIELDS \
struct stat statbuf; \
eio_req* eio;
uv_file file; \
eio_req* eio; \
#define UV_WORK_PRIVATE_FIELDS \
eio_req* eio;

View File

@ -72,6 +72,7 @@ static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type,
req->result = 0;
req->ptr = NULL;
req->path = path ? strdup(path) : NULL;
req->file = -1;
req->errorno = 0;
req->eio = NULL;
@ -445,6 +446,20 @@ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
}
#if defined(__APPLE__) && defined(F_FULLFSYNC)
ssize_t uv__fs_fdatasync(uv_file file) {
return fcntl(file, F_FULLFSYNC);
}
void uv__fs_fdatasync_work(eio_req* eio) {
uv_fs_t* req = eio->data;
eio->result = uv__fs_fdatasync(req->file);
}
#endif
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
char* path = NULL;
#if defined(__FreeBSD__) \
@ -453,6 +468,31 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
* do a full fsync instead.
*/
WRAP_EIO(UV_FS_FDATASYNC, eio_fdatasync, fsync, ARGS1(file))
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
/* OSX >= 10.6 does have fdatasync, but better use fcntl anyway */
uv_fs_req_init(loop, req, UV_FS_FDATASYNC, path, cb);
req->file = file;
if (cb) {
/* async */
req->eio = eio_custom(uv__fs_fdatasync_work,
EIO_PRI_DEFAULT,
uv__fs_after,
req,
&loop->uv_eio_channel);
if (req->eio == NULL) {
uv__set_sys_error(loop, ENOMEM);
return -1;
}
} else {
/* sync */
req->result = uv__fs_fdatasync(file);
if (req->result) {
uv__set_sys_error(loop, errno);
}
return req->result;
}
return 0;
#else
WRAP_EIO(UV_FS_FDATASYNC, eio_fdatasync, fdatasync, ARGS1(file))
#endif