/* * __posix_directory_sync -- * Flush a directory to ensure file creation is durable. */ static int __posix_directory_sync( WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *path) { WT_DECL_RET; WT_SESSION_IMPL *session; int fd, tret; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; WT_SYSCALL_RETRY(( (fd = open(path, O_RDONLY, 0444)) == -1 ? 1 : 0), ret); if (ret != 0) WT_RET_MSG(session, ret, "%s: directory-sync: open", path); ret = __posix_sync(session, fd, path, "directory-sync"); WT_SYSCALL_RETRY(close(fd), tret); if (tret != 0) { __wt_err(session, tret, "%s: directory-sync: close", path); if (ret == 0) ret = tret; } return (ret); }
/* * __open_directory_sync -- * Fsync the directory in which we created the file. */ static int __open_directory_sync(WT_SESSION_IMPL *session) { #ifdef __linux__ WT_CONNECTION_IMPL *conn; WT_DECL_RET; int fd; conn = S2C(session); /* * According to the Linux fsync man page: * Calling fsync() does not necessarily ensure that the entry in * the directory containing the file has also reached disk. For * that an explicit fsync() on a file descriptor for the directory * is also needed. * * Open the WiredTiger home directory and sync it, I don't want the rest * of the system to have to wonder if opening a file creates it. */ WT_SYSCALL_RETRY(((fd = open(conn->home, O_RDONLY, 0444)) == -1 ? 1 : 0), ret); if (ret != 0) WT_RET_MSG(session, ret, "%s: open", conn->home); WT_SYSCALL_RETRY(fsync(fd), ret); if (ret != 0) WT_ERR_MSG(session, ret, "%s: fsync", conn->home); err: WT_SYSCALL_RETRY(close(fd), ret); if (ret != 0) WT_ERR_MSG(session, ret, "%s: close", conn->home); #else WT_UNUSED(session); #endif return (0); }
/* * __wt_filesize_name -- * Return the size of a file in bytes, given a file name. */ int __wt_filesize_name(WT_SESSION_IMPL *session, const char *filename, bool silent, wt_off_t *sizep) { struct stat sb; WT_DECL_RET; char *path; WT_RET(__wt_filename(session, filename, &path)); WT_SYSCALL_RETRY(stat(path, &sb), ret); __wt_free(session, path); if (ret == 0) { *sizep = sb.st_size; return (0); } /* * Some callers of this function expect failure if the file doesn't * exist, and don't want an error message logged. */ if (!silent) WT_RET_MSG(session, ret, "%s: fstat", filename); return (ret); }
/* * __posix_file_lock -- * Lock/unlock a file. */ static int __posix_file_lock( WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, bool lock) { struct flock fl; WT_DECL_RET; WT_FILE_HANDLE_POSIX *pfh; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; pfh = (WT_FILE_HANDLE_POSIX *)file_handle; /* * WiredTiger requires this function be able to acquire locks past * the end of file. * * Note we're using fcntl(2) locking: all fcntl locks associated with a * file for a given process are removed when any file descriptor for the * file is closed by the process, even if a lock was never requested for * that file descriptor. */ fl.l_start = 0; fl.l_len = 1; fl.l_type = lock ? F_WRLCK : F_UNLCK; fl.l_whence = SEEK_SET; WT_SYSCALL_RETRY(fcntl(pfh->fd, F_SETLK, &fl), ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "%s: handle-lock: fcntl", file_handle->name); }
/* * __posix_sys_fallocate -- * Linux fallocate call (system call version). */ static int __posix_sys_fallocate(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t offset, wt_off_t len) { #if defined(__linux__) && defined(SYS_fallocate) WT_DECL_RET; WT_FILE_HANDLE_POSIX *pfh; WT_UNUSED(wt_session); pfh = (WT_FILE_HANDLE_POSIX *)file_handle; /* * Try the system call for fallocate even if the C library wrapper was * not found. The system call actually exists in the kernel for some * Linux versions (RHEL 5.5), but not in the version of the C library. * This allows it to work everywhere the kernel supports it. */ WT_SYSCALL_RETRY(syscall(SYS_fallocate, pfh->fd, 0, offset, len), ret); return (ret); #else WT_UNUSED(file_handle); WT_UNUSED(wt_session); WT_UNUSED(offset); WT_UNUSED(len); return (ENOTSUP); #endif }
/* * __posix_file_advise -- * POSIX fadvise. */ static int __posix_file_advise(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t offset, wt_off_t len, int advice) { WT_DECL_RET; WT_FILE_HANDLE_POSIX *pfh; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; pfh = (WT_FILE_HANDLE_POSIX *)file_handle; WT_SYSCALL_RETRY(posix_fadvise(pfh->fd, offset, len, advice), ret); if (ret == 0) return (0); /* * Treat EINVAL as not-supported, some systems don't support some flags. * Quietly fail, callers expect not-supported failures, and reset the * handle method to prevent future calls. */ if (ret == EINVAL) { file_handle->fadvise = NULL; return (ENOTSUP); } WT_RET_MSG(session, ret, "%s: handle-advise: posix_fadvise", file_handle->name); }
/* * __wt_rename -- * Rename a file. */ int __wt_rename(WT_SESSION_IMPL *session, const char *from, const char *to) { WT_DECL_RET; char *from_path, *to_path; WT_RET(__wt_verbose( session, WT_VERB_FILEOPS, "rename %s to %s", from, to)); WT_ASSERT(session, !F_ISSET(S2C(session), WT_CONN_READONLY)); from_path = to_path = NULL; WT_RET(__wt_filename(session, from, &from_path)); WT_TRET(__wt_filename(session, to, &to_path)); if (ret == 0) WT_SYSCALL_RETRY(rename(from_path, to_path), ret); __wt_free(session, from_path); __wt_free(session, to_path); if (ret == 0) return (0); WT_RET_MSG(session, ret, "rename %s to %s", from, to); }
/* * __wt_fsync -- * Flush a file handle. */ int __wt_fsync(WT_SESSION_IMPL *session, WT_FH *fh) { WT_DECL_RET; WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "%s: fsync", fh->name)); #ifdef HAVE_FDATASYNC WT_SYSCALL_RETRY(fdatasync(fh->fd), ret); #else WT_SYSCALL_RETRY(fsync(fh->fd), ret); #endif if (ret != 0) WT_RET_MSG(session, ret, "%s fsync error", fh->name); return (0); }
/* * __wt_fallocate -- * Allocate space for a file handle. */ int __wt_fallocate( WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, wt_off_t len) { WT_DECL_RET; #if defined(HAVE_FALLOCATE) WT_RET(__wt_verbose( session, WT_VERB_FILEOPS, "%s: fallocate", fh->name)); WT_SYSCALL_RETRY( fallocate(fh->fd, FALLOC_FL_KEEP_SIZE, offset, len), ret); if (ret == 0) return (0); /* * Linux returns ENOTSUP for fallocate on some file systems; we return * ENOTSUP, and our caller should avoid calling us again. */ if (ret != ENOTSUP) WT_RET_MSG(session, ret, "%s: fallocate", fh->name); #elif defined(HAVE_POSIX_FALLOCATE) WT_RET(__wt_verbose( session, WT_VERB_FILEOPS, "%s: posix_fallocate", fh->name)); WT_SYSCALL_RETRY(posix_fallocate(fh->fd, offset, len), ret); if (ret == 0) return (0); /* * Solaris returns EINVAL for posix_fallocate on some file systems; we * return ENOTSUP, and our caller should avoid calling us again. */ if (ret != EINVAL) WT_RET_MSG(session, ret, "%s: posix_fallocate", fh->name); #else WT_UNUSED(session); WT_UNUSED(fh); WT_UNUSED(offset); WT_UNUSED(len); WT_UNUSED(ret); #endif fh->fallocate_available = 0; fh->fallocate_requires_locking = 0; return (ENOTSUP); }
/* * __wt_thread_join -- * Wait for a thread of control to exit. */ int __wt_thread_join(WT_SESSION_IMPL *session, wt_thread_t tid) { WT_DECL_RET; WT_SYSCALL_RETRY(pthread_join(tid, NULL), ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "pthread_join"); }
/* * __wt_ftruncate -- * Truncate a file. */ int __wt_ftruncate(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t len) { WT_DECL_RET; WT_SYSCALL_RETRY(ftruncate(fh->fd, len), ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "%s ftruncate error", fh->name); }
/* * __posix_sync -- * Underlying support function to flush a file descriptor. */ static int __posix_sync( WT_SESSION_IMPL *session, int fd, const char *name, const char *func) { WT_DECL_RET; #if defined(F_FULLFSYNC) /* * OS X fsync documentation: * "Note that while fsync() will flush all data from the host to the * drive (i.e. the "permanent storage device"), the drive itself may * not physically write the data to the platters for quite some time * and it may be written in an out-of-order sequence. 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." * * OS X F_FULLFSYNC fcntl documentation: * "This is currently implemented on HFS, MS-DOS (FAT), and Universal * Disk Format (UDF) file systems." */ WT_SYSCALL_RETRY(fcntl(fd, F_FULLFSYNC, 0) == -1 ? -1 : 0, ret); if (ret == 0) return (0); /* * Assume F_FULLFSYNC failed because the file system doesn't support it * and fallback to fsync. */ #endif #if defined(HAVE_FDATASYNC) WT_SYSCALL_RETRY(fdatasync(fd), ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "%s: %s: fdatasync", name, func); #else WT_SYSCALL_RETRY(fsync(fd), ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "%s: %s: fsync", name, func); #endif }
/* * __wt_thread_create -- * Create a new thread of control. */ int __wt_thread_create(WT_SESSION_IMPL *session, wt_thread_t *tidret, WT_THREAD_CALLBACK(*func)(void *), void *arg) { WT_DECL_RET; /* Spawn a new thread of control. */ WT_SYSCALL_RETRY(pthread_create(tidret, NULL, func, arg), ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "pthread_create"); }
/* * __wt_ftruncate -- * Truncate a file. */ int __wt_ftruncate(WT_SESSION_IMPL *session, WT_FH *fh, off_t len) { int ret; WT_SYSCALL_RETRY(ftruncate(fh->fd, len), ret); if (ret == 0) { fh->file_size = len; return (0); } WT_RET_MSG(session, ret, "%s ftruncate error", fh->name); }
/* * __wt_fsync -- * Flush a file handle. */ int __wt_fsync(WT_SESSION_IMPL *session, WT_FH *fh) { WT_DECL_RET; WT_VERBOSE_RET(session, fileops, "%s: fsync", fh->name); WT_SYSCALL_RETRY(fsync(fh->fd), ret); if (ret != 0) WT_RET_MSG(session, ret, "%s fsync error", fh->name); return (0); }
/* * __wt_posix_fallocate -- * POSIX fallocate call. */ static int __wt_posix_fallocate(WT_FH *fh, wt_off_t offset, wt_off_t len) { #if defined(HAVE_POSIX_FALLOCATE) WT_DECL_RET; WT_SYSCALL_RETRY(posix_fallocate(fh->fd, offset, len), ret); return (ret); #else WT_UNUSED(fh); WT_UNUSED(offset); WT_UNUSED(len); return (ENOTSUP); #endif }
/* * __posix_fs_rename -- * Rename a file. */ static int __posix_fs_rename(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *from, const char *to) { WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; WT_SYSCALL_RETRY(rename(from, to), ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "%s to %s: file-rename: rename", from, to); }
/* * __wt_filesize -- * Get the size of a file in bytes. */ int __wt_filesize(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t *sizep) { struct stat sb; WT_DECL_RET; WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "%s: fstat", fh->name)); WT_SYSCALL_RETRY(fstat(fh->fd, &sb), ret); if (ret == 0) { *sizep = sb.st_size; return (0); } WT_RET_MSG(session, ret, "%s: fstat", fh->name); }
/* * __posix_file_truncate -- * POSIX ftruncate. */ static int __posix_file_truncate( WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t len) { WT_DECL_RET; WT_FILE_HANDLE_POSIX *pfh; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; pfh = (WT_FILE_HANDLE_POSIX *)file_handle; WT_SYSCALL_RETRY(ftruncate(pfh->fd, len), ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "%s: handle-truncate: ftruncate", file_handle->name); }
/* * __posix_file_sync_nowait -- * POSIX fsync. */ static int __posix_file_sync_nowait(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session) { WT_DECL_RET; WT_FILE_HANDLE_POSIX *pfh; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; pfh = (WT_FILE_HANDLE_POSIX *)file_handle; WT_SYSCALL_RETRY(sync_file_range(pfh->fd, (off64_t)0, (off64_t)0, SYNC_FILE_RANGE_WRITE), ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "%s: handle-sync-nowait: sync_file_range", file_handle->name); }
/* * __posix_file_size -- * Get the size of a file in bytes, by file handle. */ static int __posix_file_size( WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t *sizep) { struct stat sb; WT_DECL_RET; WT_FILE_HANDLE_POSIX *pfh; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; pfh = (WT_FILE_HANDLE_POSIX *)file_handle; WT_SYSCALL_RETRY(fstat(pfh->fd, &sb), ret); if (ret == 0) { *sizep = sb.st_size; return (0); } WT_RET_MSG(session, ret, "%s: handle-size: fstat", file_handle->name); }
/* * __posix_fs_size -- * Get the size of a file in bytes, by file name. */ static int __posix_fs_size(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, wt_off_t *sizep) { struct stat sb; WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; WT_SYSCALL_RETRY(stat(name, &sb), ret); if (ret == 0) { *sizep = sb.st_size; return (0); } WT_RET_MSG(session, ret, "%s: file-size: stat", name); }
/* * __wt_rename -- * Rename a file. */ int __wt_rename(WT_SESSION_IMPL *session, const char *from, const char *to) { int ret; const char *from_path, *to_path; WT_VERBOSE(session, fileops, "rename %s to %s", from, to); WT_RET(__wt_filename(session, from, &from_path)); WT_RET(__wt_filename(session, to, &to_path)); WT_SYSCALL_RETRY(rename(from_path, to_path), ret); __wt_free(session, from_path); __wt_free(session, to_path); if (ret == 0) return (0); WT_RET_MSG(session, ret, "rename %s to %s", from, to); }
/* * __wt_filesize_name -- * Return the size of a file in bytes, given a file name. */ int __wt_filesize_name( WT_SESSION_IMPL *session, const char *filename, wt_off_t *sizep) { struct stat sb; WT_DECL_RET; char *path; WT_RET(__wt_filename(session, filename, &path)); WT_SYSCALL_RETRY(stat(path, &sb), ret); __wt_free(session, path); if (ret == 0) { *sizep = sb.st_size; return (0); } WT_RET_MSG(session, ret, "%s: fstat", filename); }
/* * __wt_remove -- * Remove a file. */ int __wt_remove(WT_SESSION_IMPL *session, const char *name) { WT_DECL_RET; char *path; WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "%s: remove", name)); __remove_file_check(session, name); WT_RET(__wt_filename(session, name, &path)); WT_SYSCALL_RETRY(remove(path), ret); __wt_free(session, path); if (ret == 0 || ret == ENOENT) return (0); WT_RET_MSG(session, ret, "%s: remove", name); }
/* * __wt_sys_fallocate -- * Linux fallocate call (system call version). */ static int __wt_sys_fallocate(WT_FH *fh, wt_off_t offset, wt_off_t len) { #if defined(__linux__) && defined(SYS_fallocate) WT_DECL_RET; /* * Try the system call for fallocate even if the C library wrapper was * not found. The system call actually exists in the kernel for some * Linux versions (RHEL 5.5), but not in the version of the C library. * This allows it to work everywhere the kernel supports it. */ WT_SYSCALL_RETRY(syscall(SYS_fallocate, fh->fd, 0, offset, len), ret); return (ret); #else WT_UNUSED(fh); WT_UNUSED(offset); WT_UNUSED(len); return (ENOTSUP); #endif }
/* * __posix_posix_fallocate -- * POSIX fallocate call. */ static int __posix_posix_fallocate(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t offset, wt_off_t len) { #if defined(HAVE_POSIX_FALLOCATE) WT_DECL_RET; WT_FILE_HANDLE_POSIX *pfh; WT_UNUSED(wt_session); pfh = (WT_FILE_HANDLE_POSIX *)file_handle; WT_SYSCALL_RETRY(posix_fallocate(pfh->fd, offset, len), ret); return (ret); #else WT_UNUSED(file_handle); WT_UNUSED(wt_session); WT_UNUSED(offset); WT_UNUSED(len); return (ENOTSUP); #endif }
/* * __posix_file_close -- * ANSI C close. */ static int __posix_file_close(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session) { WT_DECL_RET; WT_FILE_HANDLE_POSIX *pfh; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; pfh = (WT_FILE_HANDLE_POSIX *)file_handle; /* Close the file handle. */ if (pfh->fd != -1) { WT_SYSCALL_RETRY(close(pfh->fd), ret); if (ret != 0) __wt_err(session, ret, "%s: handle-close: close", file_handle->name); } __wt_free(session, file_handle->name); __wt_free(session, pfh); return (ret); }
/* * __posix_fs_exist -- * Return if the file exists. */ static int __posix_fs_exist(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, bool *existp) { struct stat sb; WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; WT_SYSCALL_RETRY(stat(name, &sb), ret); if (ret == 0) { *existp = true; return (0); } if (ret == ENOENT) { *existp = false; return (0); } WT_RET_MSG(session, ret, "%s: file-exist: stat", name); }
/* * __posix_directory_sync -- * Flush a directory to ensure file creation, remove or rename is durable. */ static int __posix_directory_sync(WT_SESSION_IMPL *session, const char *path) { WT_DECL_ITEM(tmp); WT_DECL_RET; int fd, tret; char *dir; WT_RET(__wt_scr_alloc(session, 0, &tmp)); WT_ERR(__wt_buf_setstr(session, tmp, path)); /* * This layer should never see a path that doesn't include a trailing * path separator, this code asserts that fact. */ dir = tmp->mem; strrchr(dir, '/')[1] = '\0'; fd = -1; /* -Wconditional-uninitialized */ WT_SYSCALL_RETRY(( (fd = open(dir, O_RDONLY, 0444)) == -1 ? -1 : 0), ret); if (ret != 0) WT_ERR_MSG(session, ret, "%s: directory-sync: open", dir); ret = __posix_sync(session, fd, dir, "directory-sync"); WT_SYSCALL(close(fd), tret); if (tret != 0) { __wt_err(session, tret, "%s: directory-sync: close", dir); if (ret == 0) ret = tret; } err: __wt_scr_free(session, &tmp); return (ret); }