diff options
Diffstat (limited to 'src/third_party/wiredtiger/src/os_posix')
28 files changed, 2174 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/src/os_posix/os_abort.c b/src/third_party/wiredtiger/src/os_posix/os_abort.c new file mode 100644 index 00000000000..3d99ffe20b2 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_abort.c @@ -0,0 +1,26 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_abort -- + * Abort the process, dropping core. + */ +void +__wt_abort(WT_SESSION_IMPL *session) + WT_GCC_FUNC_ATTRIBUTE((noreturn)) +{ + __wt_errx(session, "aborting WiredTiger library"); + +#ifdef HAVE_DIAGNOSTIC + __wt_attach(session); +#endif + + abort(); + /* NOTREACHED */ +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_alloc.c b/src/third_party/wiredtiger/src/os_posix/os_alloc.c new file mode 100644 index 00000000000..f7344032a15 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_alloc.c @@ -0,0 +1,238 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * There's no malloc interface, WiredTiger never calls malloc. + * + * The problem is an application might allocate memory, write secret stuff in + * it, free the memory, then WiredTiger allocates the memory and uses it for a + * file page or log record, then writes it to disk, without having overwritten + * it fully. That results in the secret stuff being protected by WiredTiger's + * permission mechanisms, potentially inappropriate for the secret stuff. + */ + +/* + * __wt_calloc -- + * ANSI calloc function. + */ +int +__wt_calloc(WT_SESSION_IMPL *session, size_t number, size_t size, void *retp) +{ + void *p; + + /* + * !!! + * This function MUST handle a NULL WT_SESSION_IMPL handle. + */ + WT_ASSERT(session, number != 0 && size != 0); + + if (session != NULL) + WT_STAT_FAST_CONN_INCR(session, memory_allocation); + + if ((p = calloc(number, size)) == NULL) + WT_RET_MSG(session, __wt_errno(), "memory allocation"); + + *(void **)retp = p; + return (0); +} + +/* + * __wt_realloc -- + * ANSI realloc function. + */ +int +__wt_realloc(WT_SESSION_IMPL *session, + size_t *bytes_allocated_ret, size_t bytes_to_allocate, void *retp) +{ + void *p; + size_t bytes_allocated; + + /* + * !!! + * This function MUST handle a NULL WT_SESSION_IMPL handle. + * + * Sometimes we're allocating memory and we don't care about the + * final length -- bytes_allocated_ret may be NULL. + */ + p = *(void **)retp; + bytes_allocated = + (bytes_allocated_ret == NULL) ? 0 : *bytes_allocated_ret; + WT_ASSERT(session, + (p == NULL && bytes_allocated == 0) || + (p != NULL && + (bytes_allocated_ret == NULL || bytes_allocated != 0))); + WT_ASSERT(session, bytes_to_allocate != 0); + WT_ASSERT(session, bytes_allocated < bytes_to_allocate); + + if (session != NULL) { + if (p == NULL) + WT_STAT_FAST_CONN_INCR(session, memory_allocation); + else + WT_STAT_FAST_CONN_INCR(session, memory_grow); + } + + if ((p = realloc(p, bytes_to_allocate)) == NULL) + WT_RET_MSG(session, __wt_errno(), "memory allocation"); + + /* + * Clear the allocated memory -- an application might: allocate memory, + * write secret stuff into it, free the memory, then we re-allocate the + * memory and use it for a file page or log record, and then write it to + * disk. That would result in the secret stuff being protected by the + * WiredTiger permission mechanisms, potentially inappropriate for the + * secret stuff. + */ + memset((uint8_t *) + p + bytes_allocated, 0, bytes_to_allocate - bytes_allocated); + + /* Update caller's bytes allocated value. */ + if (bytes_allocated_ret != NULL) + *bytes_allocated_ret = bytes_to_allocate; + + *(void **)retp = p; + return (0); +} + +/* + * __wt_realloc_aligned -- + * ANSI realloc function that aligns to buffer boundaries, configured with + * the "buffer_alignment" key to wiredtiger_open. + */ +int +__wt_realloc_aligned(WT_SESSION_IMPL *session, + size_t *bytes_allocated_ret, size_t bytes_to_allocate, void *retp) +{ +#if defined(HAVE_POSIX_MEMALIGN) + WT_DECL_RET; + + /* + * !!! + * This function MUST handle a NULL WT_SESSION_IMPL handle. + */ + if (session != NULL && S2C(session)->buffer_alignment > 0) { + void *p, *newp; + size_t bytes_allocated; + + /* + * Sometimes we're allocating memory and we don't care about the + * final length -- bytes_allocated_ret may be NULL. + */ + p = *(void **)retp; + bytes_allocated = + (bytes_allocated_ret == NULL) ? 0 : *bytes_allocated_ret; + WT_ASSERT(session, + (p == NULL && bytes_allocated == 0) || + (p != NULL && + (bytes_allocated_ret == NULL || bytes_allocated != 0))); + WT_ASSERT(session, bytes_to_allocate != 0); + WT_ASSERT(session, bytes_allocated < bytes_to_allocate); + + if (session != NULL) + WT_STAT_FAST_CONN_INCR(session, memory_allocation); + + if ((ret = posix_memalign(&newp, + S2C(session)->buffer_alignment, + bytes_to_allocate)) != 0) + WT_RET_MSG(session, ret, "memory allocation"); + + if (p != NULL) + memcpy(newp, p, bytes_allocated); + __wt_free(session, p); + p = newp; + + /* Clear the allocated memory (see above). */ + memset((uint8_t *)p + bytes_allocated, 0, + bytes_to_allocate - bytes_allocated); + + /* Update caller's bytes allocated value. */ + if (bytes_allocated_ret != NULL) + *bytes_allocated_ret = bytes_to_allocate; + + *(void **)retp = p; + return (0); + } +#endif + /* + * If there is no posix_memalign function, or no alignment configured, + * fall back to realloc. + * + * Windows note: Visual C CRT memalign does not match Posix behavior + * and would also double each allocation so it is bad for memory use + */ + return (__wt_realloc( + session, bytes_allocated_ret, bytes_to_allocate, retp)); +} + +/* + * __wt_strndup -- + * Duplicate a byte string of a given length (and NUL-terminate). + */ +int +__wt_strndup(WT_SESSION_IMPL *session, const void *str, size_t len, void *retp) +{ + void *p; + + if (str == NULL) { + *(void **)retp = NULL; + return (0); + } + + WT_RET(__wt_calloc(session, len + 1, 1, &p)); + + /* + * Don't change this to strncpy, we rely on this function to duplicate + * "strings" that contain nul bytes. + */ + memcpy(p, str, len); + + *(void **)retp = p; + return (0); +} + +/* + * __wt_strdup -- + * ANSI strdup function. + */ +int +__wt_strdup(WT_SESSION_IMPL *session, const char *str, void *retp) +{ + return (__wt_strndup( + session, str, (str == NULL) ? 0 : strlen(str), retp)); +} + +/* + * __wt_free_int -- + * ANSI free function. + */ +void +__wt_free_int(WT_SESSION_IMPL *session, const void *p_arg) +{ + void *p; + + p = *(void **)p_arg; + if (p == NULL) /* ANSI C free semantics */ + return; + + /* + * If there's a serialization bug we might race with another thread. + * We can't avoid the race (and we aren't willing to flush memory), + * but we minimize the window by clearing the free address, hoping a + * racing thread will see, and won't free, a NULL pointer. + */ + *(void **)p_arg = NULL; + + /* + * !!! + * This function MUST handle a NULL WT_SESSION_IMPL handle. + */ + if (session != NULL) + WT_STAT_FAST_CONN_INCR(session, memory_free); + + free(p); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_dir.c b/src/third_party/wiredtiger/src/os_posix/os_dir.c new file mode 100644 index 00000000000..98b2d4926cd --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_dir.c @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" +/* I'm sure we need to config this */ +#include <dirent.h> + +/* + * __wt_dirlist -- + * Get a list of files from a directory, optionally filtered by + * a given prefix. + */ +int +__wt_dirlist(WT_SESSION_IMPL *session, const char *dir, const char *prefix, + uint32_t flags, char ***dirlist, u_int *countp) +{ + struct dirent *dp; + DIR *dirp; + WT_DECL_RET; + size_t dirallocsz; + u_int count, dirsz; + int match; + char **entries, *path; + + *dirlist = NULL; + *countp = 0; + + WT_RET(__wt_filename(session, dir, &path)); + + dirp = NULL; + dirallocsz = 0; + dirsz = 0; + entries = NULL; + if (flags == 0) + LF_SET(WT_DIRLIST_INCLUDE); + + WT_ERR(__wt_verbose(session, WT_VERB_FILEOPS, + "wt_dirlist of %s %s prefix %s", + path, LF_ISSET(WT_DIRLIST_INCLUDE) ? "include" : "exclude", + prefix == NULL ? "all" : prefix)); + + WT_SYSCALL_RETRY(((dirp = opendir(path)) == NULL ? 1 : 0), ret); + if (ret != 0) + WT_ERR_MSG(session, ret, "%s: opendir", path); + for (dirsz = 0, count = 0; (dp = readdir(dirp)) != NULL;) { + /* + * Skip . and .. + */ + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + match = 0; + if (prefix != NULL && + ((LF_ISSET(WT_DIRLIST_INCLUDE) && + WT_PREFIX_MATCH(dp->d_name, prefix)) || + (LF_ISSET(WT_DIRLIST_EXCLUDE) && + !WT_PREFIX_MATCH(dp->d_name, prefix)))) + match = 1; + if (prefix == NULL || match) { + /* + * We have a file name we want to return. + */ + count++; + if (count > dirsz) { + dirsz += WT_DIR_ENTRY; + WT_ERR(__wt_realloc_def( + session, &dirallocsz, dirsz, &entries)); + } + WT_ERR(__wt_strdup( + session, dp->d_name, &entries[count-1])); + } + } + if (count > 0) + *dirlist = entries; + *countp = count; +err: + if (dirp != NULL) + (void)closedir(dirp); + __wt_free(session, path); + + if (ret == 0) + return (0); + + if (*dirlist != NULL) { + for (count = dirsz; count > 0; count--) + __wt_free(session, entries[count]); + __wt_free(session, entries); + } + WT_RET_MSG(session, ret, "dirlist %s prefix %s", dir, prefix); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_dlopen.c b/src/third_party/wiredtiger/src/os_posix/os_dlopen.c new file mode 100644 index 00000000000..91410c54c04 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_dlopen.c @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_dlopen -- + * Open a dynamic library. + */ +int +__wt_dlopen(WT_SESSION_IMPL *session, const char *path, WT_DLH **dlhp) +{ + WT_DECL_RET; + WT_DLH *dlh; + + WT_RET(__wt_calloc_def(session, 1, &dlh)); + WT_ERR(__wt_strdup(session, path, &dlh->name)); + + if ((dlh->handle = dlopen(path, RTLD_LAZY)) == NULL) + WT_ERR_MSG( + session, __wt_errno(), "dlopen(%s): %s", path, dlerror()); + + *dlhp = dlh; + if (0) { +err: __wt_free(session, dlh->name); + __wt_free(session, dlh); + } + return (ret); +} + +/* + * __wt_dlsym -- + * Lookup a symbol in a dynamic library. + */ +int +__wt_dlsym(WT_SESSION_IMPL *session, + WT_DLH *dlh, const char *name, int fail, void *sym_ret) +{ + void *sym; + + *(void **)sym_ret = NULL; + if ((sym = dlsym(dlh->handle, name)) == NULL) { + if (fail) + WT_RET_MSG(session, __wt_errno(), + "dlsym(%s in %s): %s", name, dlh->name, dlerror()); + return (0); + } + + *(void **)sym_ret = sym; + return (0); +} + +/* + * __wt_dlclose -- + * Close a dynamic library + */ +int +__wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh) +{ + WT_DECL_RET; + + /* + * FreeBSD dies inside __cxa_finalize when closing handles. + * + * For now, just skip the dlclose: this may leak some resources until + * the process exits, but that is preferable to hard-to-debug crashes + * during exit. + */ +#ifndef __FreeBSD__ + if (dlclose(dlh->handle) != 0) { + ret = __wt_errno(); + __wt_err(session, ret, "dlclose: %s", dlerror()); + } +#endif + + __wt_free(session, dlh->name); + __wt_free(session, dlh); + return (ret); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_errno.c b/src/third_party/wiredtiger/src/os_posix/os_errno.c new file mode 100644 index 00000000000..9290f7d651f --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_errno.c @@ -0,0 +1,22 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_errno -- + * Return errno, or WT_ERROR if errno not set. + */ +int +__wt_errno(void) +{ + /* + * Called when we know an error occurred, and we want the system + * error code, but there's some chance it's not set. + */ + return (errno == 0 ? WT_ERROR : errno); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_exist.c b/src/third_party/wiredtiger/src/os_posix/os_exist.c new file mode 100644 index 00000000000..723f07026e1 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_exist.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_exist -- + * Return if the file exists. + */ +int +__wt_exist(WT_SESSION_IMPL *session, const char *filename, int *existp) +{ + 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) { + *existp = 1; + return (0); + } + if (ret == ENOENT) { + *existp = 0; + return (0); + } + + WT_RET_MSG(session, ret, "%s: fstat", filename); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_fallocate.c b/src/third_party/wiredtiger/src/os_posix/os_fallocate.c new file mode 100644 index 00000000000..28cd1979c77 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_fallocate.c @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +#if defined(HAVE_FALLOCATE) +#include <linux/falloc.h> +#endif + +/* + * __wt_fallocate_config -- + * Configure fallocate behavior for a file handle. + */ +void +__wt_fallocate_config(WT_SESSION_IMPL *session, WT_FH *fh) +{ + WT_UNUSED(session); + + fh->fallocate_available = 0; + fh->fallocate_requires_locking = 0; + +#ifdef __linux__ + /* + * We've seen Linux systems where posix_fallocate corrupts existing data + * (even though that is explicitly disallowed by POSIX). We've not seen + * problems with fallocate, it's unlocked for now. + */ +#if defined(HAVE_FALLOCATE) + fh->fallocate_available = 1; + fh->fallocate_requires_locking = 0; +#elif defined(HAVE_POSIX_FALLOCATE) + fh->fallocate_available = 1; + fh->fallocate_requires_locking = 1; +#endif +#elif defined(HAVE_POSIX_FALLOCATE) + /* + * FreeBSD and Solaris support posix_fallocate, and so far we've seen + * no problems leaving it unlocked. + */ + fh->fallocate_available = 1; + fh->fallocate_requires_locking = 0; +#endif +} + +/* + * __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); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_filesize.c b/src/third_party/wiredtiger/src/os_posix/os_filesize.c new file mode 100644 index 00000000000..3692b135d73 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_filesize.c @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __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); +} + +/* + * __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); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_flock.c b/src/third_party/wiredtiger/src/os_posix/os_flock.c new file mode 100644 index 00000000000..e9e653d73e6 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_flock.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_bytelock -- + * Lock/unlock a byte in a file. + */ +int +__wt_bytelock(WT_FH *fhp, wt_off_t byte, int lock) +{ + struct flock fl; + WT_DECL_RET; + + /* + * 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 = byte; + fl.l_len = 1; + fl.l_type = lock ? F_WRLCK : F_UNLCK; + fl.l_whence = SEEK_SET; + + WT_SYSCALL_RETRY(fcntl(fhp->fd, F_SETLK, &fl), ret); + + return (ret); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_fsync.c b/src/third_party/wiredtiger/src/os_posix/os_fsync.c new file mode 100644 index 00000000000..c181809df95 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_fsync.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __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_fsync_async -- + * Flush a file handle and don't wait for the result. + */ +int +__wt_fsync_async(WT_SESSION_IMPL *session, WT_FH *fh) +{ +#ifdef HAVE_SYNC_FILE_RANGE + WT_DECL_RET; + + WT_RET(__wt_verbose( + session, WT_VERB_FILEOPS, "%s: sync_file_range", fh->name)); + + if ((ret = sync_file_range(fh->fd, + (off64_t)0, (off64_t)0, SYNC_FILE_RANGE_WRITE)) == 0) + return (0); + WT_RET_MSG(session, ret, "%s: sync_file_range", fh->name); +#else + WT_UNUSED(session); + WT_UNUSED(fh); + return (0); +#endif +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_ftruncate.c b/src/third_party/wiredtiger/src/os_posix/os_ftruncate.c new file mode 100644 index 00000000000..3f3034de551 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_ftruncate.c @@ -0,0 +1,26 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __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) { + fh->size = fh->extend_size = len; + return (0); + } + + WT_RET_MSG(session, ret, "%s ftruncate error", fh->name); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_getline.c b/src/third_party/wiredtiger/src/os_posix/os_getline.c new file mode 100644 index 00000000000..7ef4065ac3b --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_getline.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_getline -- + * Get a line from a stream. + * + * Implementation of the POSIX getline or BSD fgetln functions (finding the + * function in a portable way is hard, it's simple enough to write it instead). + * + * Note: Unlike the standard getline calls, this function doesn't include the + * trailing newline character in the returned buffer and discards empty lines + * (so the caller's EOF marker is a returned line length of 0). + */ +int +__wt_getline(WT_SESSION_IMPL *session, WT_ITEM *buf, FILE *fp) +{ + int c; + + /* + * We always NUL-terminate the returned string (even if it's empty), + * make sure there's buffer space for a trailing NUL in all cases. + */ + WT_RET(__wt_buf_init(session, buf, 100)); + + while ((c = fgetc(fp)) != EOF) { + /* Leave space for a trailing NUL. */ + WT_RET(__wt_buf_extend(session, buf, buf->size + 2)); + if (c == '\n') { + if (buf->size == 0) + continue; + break; + } + ((char *)buf->mem)[buf->size++] = (char)c; + } + if (c == EOF && ferror(fp)) + WT_RET_MSG(session, __wt_errno(), "file read"); + + ((char *)buf->mem)[buf->size] = '\0'; + + return (0); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_getopt.c b/src/third_party/wiredtiger/src/os_posix/os_getopt.c new file mode 100644 index 00000000000..1c25521dacd --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_getopt.c @@ -0,0 +1,150 @@ +/*- + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "wt_internal.h" + +extern int __wt_opterr, __wt_optind, __wt_optopt, __wt_optreset; +int __wt_opterr = 1, /* if error message should be printed */ + __wt_optind = 1, /* index into parent argv vector */ + __wt_optopt, /* character checked for validity */ + __wt_optreset; /* reset getopt */ + +extern char *__wt_optarg; +char *__wt_optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * __wt_getopt -- + * Parse argc/argv argument vector. + */ +int +__wt_getopt( + const char *progname, int nargc, char * const *nargv, const char *ostr) +{ + static const char *place = EMSG; /* option letter processing */ + const char *oli; /* option letter list index */ + + if (__wt_optreset || *place == 0) { /* update scanning pointer */ + __wt_optreset = 0; + place = nargv[__wt_optind]; + if (__wt_optind >= nargc || *place++ != '-') { + /* Argument is absent or is not an option */ + place = EMSG; + return (-1); + } + __wt_optopt = *place++; + if (__wt_optopt == '-' && *place == 0) { + /* "--" => end of options */ + ++__wt_optind; + place = EMSG; + return (-1); + } + if (__wt_optopt == 0) { + /* Solitary '-', treat as a '-' option + if the program (eg su) is looking for it. */ + place = EMSG; + if (strchr(ostr, '-') == NULL) + return (-1); + __wt_optopt = '-'; + } + } else + __wt_optopt = *place++; + + /* See if option letter is one the caller wanted... */ + if (__wt_optopt == ':' || (oli = strchr(ostr, __wt_optopt)) == NULL) { + if (*place == 0) + ++__wt_optind; + if (__wt_opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", progname, + __wt_optopt); + return (BADCH); + } + + /* Does this option need an argument? */ + if (oli[1] != ':') { + /* don't need argument */ + __wt_optarg = NULL; + if (*place == 0) + ++__wt_optind; + } else { + /* Option-argument is either the rest of this argument or the + entire next argument. */ + if (*place) + __wt_optarg = (char *)place; + else if (nargc > ++__wt_optind) + __wt_optarg = nargv[__wt_optind]; + else { + /* option-argument absent */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (__wt_opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + progname, __wt_optopt); + return (BADCH); + } + place = EMSG; + ++__wt_optind; + } + return (__wt_optopt); /* return option letter */ +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_map.c b/src/third_party/wiredtiger/src/os_posix/os_map.c new file mode 100644 index 00000000000..be4d27e96a3 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_map.c @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_mmap -- + * Map a file into memory. + */ +int +__wt_mmap(WT_SESSION_IMPL *session, + WT_FH *fh, void *mapp, size_t *lenp, void **mappingcookie) +{ + void *map; + size_t orig_size; + + WT_UNUSED(mappingcookie); + + /* + * Record the current size and only map and set that as the length, it + * could change between the map call and when we set the return length. + * For the same reason we could actually map past the end of the file; + * we don't read bytes past the end of the file though, so as long as + * the map call succeeds, it's all OK. + */ + orig_size = (size_t)fh->size; + if ((map = mmap(NULL, orig_size, + PROT_READ, +#ifdef MAP_NOCORE + MAP_NOCORE | +#endif + MAP_PRIVATE, + fh->fd, (wt_off_t)0)) == MAP_FAILED) { + WT_RET_MSG(session, __wt_errno(), + "%s map error: failed to map %" WT_SIZET_FMT " bytes", + fh->name, orig_size); + } + (void)__wt_verbose(session, WT_VERB_FILEOPS, + "%s: map %p: %" WT_SIZET_FMT " bytes", fh->name, map, orig_size); + + *(void **)mapp = map; + *lenp = orig_size; + return (0); +} + +#define WT_VM_PAGESIZE 4096 + +/* + * __wt_mmap_preload -- + * Cause a section of a memory map to be faulted in. + */ +int +__wt_mmap_preload(WT_SESSION_IMPL *session, const void *p, size_t size) +{ +#ifdef HAVE_POSIX_MADVISE + /* Linux requires the address be aligned to a 4KB boundary. */ + WT_BM *bm = S2BT(session)->bm; + WT_DECL_RET; + void *blk = (void *)((uintptr_t)p & ~(uintptr_t)(WT_VM_PAGESIZE - 1)); + size += WT_PTRDIFF(p, blk); + + /* XXX proxy for "am I doing a scan?" -- manual read-ahead */ + if (F_ISSET(session, WT_SESSION_NO_CACHE)) { + /* Read in 2MB blocks every 1MB of data. */ + if (((uintptr_t)((uint8_t *)blk + size) & + (uintptr_t)((1<<20) - 1)) < (uintptr_t)blk) + return (0); + size = WT_MIN(WT_MAX(20 * size, 2 << 20), + WT_PTRDIFF((uint8_t *)bm->map + bm->maplen, blk)); + } + + /* + * Manual pages aren't clear on whether alignment is required for the + * size, so we will be conservative. + */ + size &= ~(size_t)(WT_VM_PAGESIZE - 1); + + if (size > WT_VM_PAGESIZE && + (ret = posix_madvise(blk, size, POSIX_MADV_WILLNEED)) != 0) + WT_RET_MSG(session, ret, "posix_madvise will need"); +#else + WT_UNUSED(session); + WT_UNUSED(p); + WT_UNUSED(size); +#endif + + return (0); +} + +/* + * __wt_mmap_discard -- + * Discard a chunk of the memory map. + */ +int +__wt_mmap_discard(WT_SESSION_IMPL *session, void *p, size_t size) +{ +#ifdef HAVE_POSIX_MADVISE + /* Linux requires the address be aligned to a 4KB boundary. */ + WT_DECL_RET; + void *blk = (void *)((uintptr_t)p & ~(uintptr_t)(WT_VM_PAGESIZE - 1)); + size += WT_PTRDIFF(p, blk); + + if ((ret = posix_madvise(blk, size, POSIX_MADV_DONTNEED)) != 0) + WT_RET_MSG(session, ret, "posix_madvise don't need"); +#else + WT_UNUSED(session); + WT_UNUSED(p); + WT_UNUSED(size); +#endif + return (0); +} + +/* + * __wt_munmap -- + * Remove a memory mapping. + */ +int +__wt_munmap(WT_SESSION_IMPL *session, + WT_FH *fh, void *map, size_t len, void **mappingcookie) +{ + WT_UNUSED(mappingcookie); + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, + "%s: unmap %p: %" WT_SIZET_FMT " bytes", fh->name, map, len)); + + if (munmap(map, len) == 0) + return (0); + + WT_RET_MSG(session, __wt_errno(), + "%s unmap error: failed to unmap %" WT_SIZET_FMT " bytes", + fh->name, len); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_mtx_cond.c b/src/third_party/wiredtiger/src/os_posix/os_mtx_cond.c new file mode 100644 index 00000000000..3a76cceb3f0 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_mtx_cond.c @@ -0,0 +1,157 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_cond_alloc -- + * Allocate and initialize a condition variable. + */ +int +__wt_cond_alloc(WT_SESSION_IMPL *session, + const char *name, int is_signalled, WT_CONDVAR **condp) +{ + WT_CONDVAR *cond; + WT_DECL_RET; + + /* + * !!! + * This function MUST handle a NULL session handle. + */ + WT_RET(__wt_calloc(session, 1, sizeof(WT_CONDVAR), &cond)); + + WT_ERR(pthread_mutex_init(&cond->mtx, NULL)); + + /* Initialize the condition variable to permit self-blocking. */ + WT_ERR(pthread_cond_init(&cond->cond, NULL)); + + cond->name = name; + cond->waiters = is_signalled ? -1 : 0; + + *condp = cond; + return (0); + +err: __wt_free(session, cond); + return (ret); +} + +/* + * __wt_cond_wait -- + * Wait on a mutex, optionally timing out. + */ +int +__wt_cond_wait(WT_SESSION_IMPL *session, WT_CONDVAR *cond, long usecs) +{ + struct timespec ts; + WT_DECL_RET; + int locked; + + locked = 0; + WT_ASSERT(session, usecs >= 0); + + /* Fast path if already signalled. */ + if (WT_ATOMIC_ADD4(cond->waiters, 1) == 0) + return (0); + + /* + * !!! + * This function MUST handle a NULL session handle. + */ + if (session != NULL) { + WT_RET(__wt_verbose(session, WT_VERB_MUTEX, + "wait %s cond (%p)", cond->name, cond)); + WT_STAT_FAST_CONN_INCR(session, cond_wait); + } + + WT_ERR(pthread_mutex_lock(&cond->mtx)); + locked = 1; + + if (usecs > 0) { + WT_ERR(__wt_epoch(session, &ts)); + ts.tv_sec += (ts.tv_nsec + 1000 * usecs) / WT_BILLION; + ts.tv_nsec = (ts.tv_nsec + 1000 * usecs) % WT_BILLION; + ret = pthread_cond_timedwait(&cond->cond, &cond->mtx, &ts); + } else + ret = pthread_cond_wait(&cond->cond, &cond->mtx); + + /* + * Check pthread_cond_wait() return for EINTR, ETIME and + * ETIMEDOUT, some systems return these errors. + */ + if (ret == EINTR || +#ifdef ETIME + ret == ETIME || +#endif + ret == ETIMEDOUT) + ret = 0; + + (void)WT_ATOMIC_SUB4(cond->waiters, 1); + +err: if (locked) + WT_TRET(pthread_mutex_unlock(&cond->mtx)); + if (ret == 0) + return (0); + WT_RET_MSG(session, ret, "pthread_cond_wait"); +} + +/* + * __wt_cond_signal -- + * Signal a waiting thread. + */ +int +__wt_cond_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond) +{ + WT_DECL_RET; + int locked; + + locked = 0; + + /* + * !!! + * This function MUST handle a NULL session handle. + */ + if (session != NULL) + WT_RET(__wt_verbose(session, WT_VERB_MUTEX, + "signal %s cond (%p)", cond->name, cond)); + + /* Fast path if already signalled. */ + if (cond->waiters == -1) + return (0); + + if (cond->waiters > 0 || !WT_ATOMIC_CAS4(cond->waiters, 0, -1)) { + WT_ERR(pthread_mutex_lock(&cond->mtx)); + locked = 1; + WT_ERR(pthread_cond_broadcast(&cond->cond)); + } + +err: if (locked) + WT_TRET(pthread_mutex_unlock(&cond->mtx)); + if (ret == 0) + return (0); + WT_RET_MSG(session, ret, "pthread_cond_broadcast"); +} + +/* + * __wt_cond_destroy -- + * Destroy a condition variable. + */ +int +__wt_cond_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp) +{ + WT_CONDVAR *cond; + WT_DECL_RET; + + cond = *condp; + if (cond == NULL) + return (0); + + ret = pthread_cond_destroy(&cond->cond); + WT_TRET(pthread_mutex_destroy(&cond->mtx)); + __wt_free(session, *condp); + + return (ret); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_mtx_rw.c b/src/third_party/wiredtiger/src/os_posix/os_mtx_rw.c new file mode 100644 index 00000000000..1a692f71dce --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_mtx_rw.c @@ -0,0 +1,227 @@ +/*- + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Based on "Spinlocks and Read-Write Locks" by Dr. Steven Fuerst: + * http://locklessinc.com/articles/locks/ + * + * Dr. Fuerst further credits: + * There exists a form of the ticket lock that is designed for read-write + * locks. An example written in assembly was posted to the Linux kernel mailing + * list in 2002 by David Howells from RedHat. This was a highly optimized + * version of a read-write ticket lock developed at IBM in the early 90's by + * Joseph Seigh. Note that a similar (but not identical) algorithm was published + * by John Mellor-Crummey and Michael Scott in their landmark paper "Scalable + * Reader-Writer Synchronization for Shared-Memory Multiprocessors". + */ + +#include "wt_internal.h" + +/* + * __wt_rwlock_alloc -- + * Allocate and initialize a read/write lock. + */ +int +__wt_rwlock_alloc( + WT_SESSION_IMPL *session, WT_RWLOCK **rwlockp, const char *name) +{ + WT_RWLOCK *rwlock; + + WT_RET(__wt_verbose(session, WT_VERB_MUTEX, "rwlock: alloc %s", name)); + + WT_RET(__wt_calloc_def(session, 1, &rwlock)); + + rwlock->name = name; + + *rwlockp = rwlock; + return (0); +} + +/* + * __wt_try_readlock -- + * Try to get a shared lock, fail immediately if unavailable. + */ +int +__wt_try_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) +{ + wt_rwlock_t *l; + uint64_t old, new, pad, users, writers; + + WT_RET(__wt_verbose( + session, WT_VERB_MUTEX, "rwlock: try_readlock %s", rwlock->name)); + WT_STAT_FAST_CONN_INCR(session, rwlock_read); + + l = &rwlock->rwlock; + pad = l->s.pad; + users = l->s.users; + writers = l->s.writers; + old = (pad << 48) + (users << 32) + (users << 16) + writers; + new = (pad << 48) + ((users + 1) << 32) + ((users + 1) << 16) + writers; + return (WT_ATOMIC_CAS_VAL8(l->u, old, new) == old ? 0 : EBUSY); +} + +/* + * __wt_readlock -- + * Get a shared lock. + */ +int +__wt_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) +{ + wt_rwlock_t *l; + uint64_t me; + uint16_t val; + + WT_RET(__wt_verbose( + session, WT_VERB_MUTEX, "rwlock: readlock %s", rwlock->name)); + WT_STAT_FAST_CONN_INCR(session, rwlock_read); + + l = &rwlock->rwlock; + me = WT_ATOMIC_FETCH_ADD8(l->u, (uint64_t)1 << 32); + val = (uint16_t)(me >> 32); + while (val != l->s.readers) + WT_PAUSE(); + + ++l->s.readers; + + return (0); +} + +/* + * __wt_readunlock -- + * Release a shared lock. + */ +int +__wt_readunlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) +{ + wt_rwlock_t *l; + + WT_RET(__wt_verbose( + session, WT_VERB_MUTEX, "rwlock: read unlock %s", rwlock->name)); + + l = &rwlock->rwlock; + WT_ATOMIC_ADD2(l->s.writers, 1); + + return (0); +} + +/* + * __wt_try_writelock -- + * Try to get an exclusive lock, fail immediately if unavailable. + */ +int +__wt_try_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) +{ + wt_rwlock_t *l; + uint64_t old, new, pad, readers, users; + + WT_RET(__wt_verbose( + session, WT_VERB_MUTEX, "rwlock: try_writelock %s", rwlock->name)); + WT_STAT_FAST_CONN_INCR(session, rwlock_write); + + l = &rwlock->rwlock; + pad = l->s.pad; + readers = l->s.readers; + users = l->s.users; + old = (pad << 48) + (users << 32) + (readers << 16) + users; + new = (pad << 48) + ((users + 1) << 32) + (readers << 16) + users; + return (WT_ATOMIC_CAS_VAL8(l->u, old, new) == old ? 0 : EBUSY); +} + +/* + * __wt_writelock -- + * Wait to get an exclusive lock. + */ +int +__wt_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) +{ + wt_rwlock_t *l; + uint64_t me; + uint16_t val; + + WT_RET(__wt_verbose( + session, WT_VERB_MUTEX, "rwlock: writelock %s", rwlock->name)); + WT_STAT_FAST_CONN_INCR(session, rwlock_write); + + /* + * Possibly wrap: if we have more than 64K lockers waiting, the count + * of writers will wrap and two lockers will simultaneously be granted + * the write lock. + */ + l = &rwlock->rwlock; + me = WT_ATOMIC_FETCH_ADD8(l->u, (uint64_t)1 << 32); + val = (uint16_t)(me >> 32); + while (val != l->s.writers) + WT_PAUSE(); + + return (0); +} + +/* + * __wt_writeunlock -- + * Release an exclusive lock. + */ +int +__wt_writeunlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) +{ + wt_rwlock_t *l, copy; + + WT_RET(__wt_verbose( + session, WT_VERB_MUTEX, "rwlock: writeunlock %s", rwlock->name)); + + l = &rwlock->rwlock; + + copy = *l; + + WT_BARRIER(); + + ++copy.s.writers; + ++copy.s.readers; + + l->us = copy.us; + return (0); +} + +/* + * __wt_rwlock_destroy -- + * Destroy a read/write lock. + */ +int +__wt_rwlock_destroy(WT_SESSION_IMPL *session, WT_RWLOCK **rwlockp) +{ + WT_RWLOCK *rwlock; + + rwlock = *rwlockp; /* Clear our caller's reference. */ + if (rwlock == NULL) + return (0); + *rwlockp = NULL; + + WT_RET(__wt_verbose( + session, WT_VERB_MUTEX, "rwlock: destroy %s", rwlock->name)); + + __wt_free(session, rwlock); + return (0); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_once.c b/src/third_party/wiredtiger/src/os_posix/os_once.c new file mode 100644 index 00000000000..22eaf5f0ee5 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_once.c @@ -0,0 +1,20 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_once -- + * One-time initialization per process. + */ +int +__wt_once(void (*init_routine)(void)) +{ + static pthread_once_t once_control = PTHREAD_ONCE_INIT; + + return (pthread_once(&once_control, init_routine)); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_open.c b/src/third_party/wiredtiger/src/os_posix/os_open.c new file mode 100644 index 00000000000..a1bc3feb7d2 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_open.c @@ -0,0 +1,253 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __open_directory_sync -- + * Fsync the directory in which we created the file. + */ +static int +__open_directory_sync(WT_SESSION_IMPL *session, char *path) +{ +#ifdef __linux__ + WT_DECL_RET; + int fd; + char *dir; + + /* + * 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. + */ + if ((dir = strrchr(path, '/')) == NULL) + path = (char *)"."; + else + *dir = '\0'; + WT_SYSCALL_RETRY(((fd = + open(path, O_RDONLY, 0444)) == -1 ? 1 : 0), ret); + if (dir != NULL) + *dir = '/'; + if (ret != 0) + WT_RET_MSG(session, ret, "%s: open", path); + + WT_SYSCALL_RETRY(fsync(fd), ret); + if (ret != 0) + WT_ERR_MSG(session, ret, "%s: fsync", path); + +err: WT_SYSCALL_RETRY(close(fd), ret); + if (ret != 0) + __wt_err(session, ret, "%s: close", path); + return (ret); +#else + WT_UNUSED(session); + WT_UNUSED(path); + return (0); +#endif +} + +/* + * __wt_open -- + * Open a file handle. + */ +int +__wt_open(WT_SESSION_IMPL *session, + const char *name, int ok_create, int exclusive, int dio_type, WT_FH **fhp) +{ + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + WT_FH *fh, *tfh; + mode_t mode; + int direct_io, f, fd, matched; + char *path; + + conn = S2C(session); + fh = NULL; + fd = -1; + path = NULL; + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "%s: open", name)); + + /* Increment the reference count if we already have the file open. */ + matched = 0; + __wt_spin_lock(session, &conn->fh_lock); + TAILQ_FOREACH(tfh, &conn->fhqh, q) + if (strcmp(name, tfh->name) == 0) { + ++tfh->ref; + *fhp = tfh; + matched = 1; + break; + } + __wt_spin_unlock(session, &conn->fh_lock); + if (matched) + return (0); + + WT_RET(__wt_filename(session, name, &path)); + + f = O_RDWR; +#ifdef O_BINARY + /* Windows clones: we always want to treat the file as a binary. */ + f |= O_BINARY; +#endif +#ifdef O_CLOEXEC + /* + * Security: + * The application may spawn a new process, and we don't want another + * process to have access to our file handles. + */ + f |= O_CLOEXEC; +#endif +#ifdef O_NOATIME + /* Avoid updating metadata for read-only workloads. */ + if (dio_type == WT_FILE_TYPE_DATA || + dio_type == WT_FILE_TYPE_CHECKPOINT) + f |= O_NOATIME; +#endif + + if (ok_create) { + f |= O_CREAT; + if (exclusive) + f |= O_EXCL; + mode = 0666; + } else + mode = 0; + + direct_io = 0; +#ifdef O_DIRECT + if (dio_type && FLD_ISSET(conn->direct_io, dio_type)) { + f |= O_DIRECT; + direct_io = 1; + } +#endif + if (dio_type == WT_FILE_TYPE_LOG && + FLD_ISSET(conn->txn_logsync, WT_LOG_DSYNC)) +#ifdef O_DSYNC + f |= O_DSYNC; +#elif defined(O_SYNC) + f |= O_SYNC; +#else + WT_ERR_MSG(session, ENOTSUP, + "Unsupported log sync mode requested"); +#endif + WT_SYSCALL_RETRY(((fd = open(path, f, mode)) == -1 ? 1 : 0), ret); + if (ret != 0) + WT_ERR_MSG(session, ret, + direct_io ? + "%s: open failed with direct I/O configured, some " + "filesystem types do not support direct I/O" : "%s", path); + +#if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) && !defined(O_CLOEXEC) + /* + * Security: + * The application may spawn a new process, and we don't want another + * process to have access to our file handles. There's an obvious + * race here, so we prefer the flag to open if available. + */ + if ((f = fcntl(fd, F_GETFD)) == -1 || + fcntl(fd, F_SETFD, f | FD_CLOEXEC) == -1) + WT_ERR_MSG(session, __wt_errno(), "%s: fcntl", name); +#endif + +#if defined(HAVE_POSIX_FADVISE) + /* Disable read-ahead on trees: it slows down random read workloads. */ + if (dio_type == WT_FILE_TYPE_DATA || + dio_type == WT_FILE_TYPE_CHECKPOINT) + WT_ERR(posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM)); +#endif + + if (F_ISSET(conn, WT_CONN_CKPT_SYNC)) + WT_ERR(__open_directory_sync(session, path)); + + WT_ERR(__wt_calloc(session, 1, sizeof(WT_FH), &fh)); + WT_ERR(__wt_strdup(session, name, &fh->name)); + fh->fd = fd; + fh->ref = 1; + fh->direct_io = direct_io; + + /* Set the file's size. */ + WT_ERR(__wt_filesize(session, fh, &fh->size)); + + /* Configure file extension. */ + if (dio_type == WT_FILE_TYPE_DATA || + dio_type == WT_FILE_TYPE_CHECKPOINT) + fh->extend_len = conn->data_extend_len; + + /* Configure fallocate/posix_fallocate calls. */ + __wt_fallocate_config(session, fh); + + /* + * Repeat the check for a match, but then link onto the database's list + * of files. + */ + matched = 0; + __wt_spin_lock(session, &conn->fh_lock); + TAILQ_FOREACH(tfh, &conn->fhqh, q) + if (strcmp(name, tfh->name) == 0) { + ++tfh->ref; + *fhp = tfh; + matched = 1; + break; + } + if (!matched) { + TAILQ_INSERT_TAIL(&conn->fhqh, fh, q); + WT_STAT_FAST_CONN_INCR(session, file_open); + + *fhp = fh; + } + __wt_spin_unlock(session, &conn->fh_lock); + if (matched) { +err: if (fh != NULL) { + __wt_free(session, fh->name); + __wt_free(session, fh); + } + if (fd != -1) + (void)close(fd); + } + + __wt_free(session, path); + return (ret); +} + +/* + * __wt_close -- + * Close a file handle. + */ +int +__wt_close(WT_SESSION_IMPL *session, WT_FH *fh) +{ + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + + conn = S2C(session); + + __wt_spin_lock(session, &conn->fh_lock); + if (fh == NULL || fh->ref == 0 || --fh->ref > 0) { + __wt_spin_unlock(session, &conn->fh_lock); + return (0); + } + + /* Remove from the list. */ + TAILQ_REMOVE(&conn->fhqh, fh, q); + WT_STAT_FAST_CONN_DECR(session, file_open); + + __wt_spin_unlock(session, &conn->fh_lock); + + /* Discard the memory. */ + if (close(fh->fd) != 0) { + ret = __wt_errno(); + __wt_err(session, ret, "close: %s", fh->name); + } + + __wt_free(session, fh->name); + __wt_free(session, fh); + return (ret); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_path.c b/src/third_party/wiredtiger/src/os_posix/os_path.c new file mode 100644 index 00000000000..aed99d1d027 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_path.c @@ -0,0 +1,28 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_absolute_path -- + * Return if a filename is an absolute path. + */ +int +__wt_absolute_path(const char *path) +{ + return (path[0] == '/' ? 1 : 0); +} + +/* + * __wt_path_separator -- + * Return the path separator string. + */ +const char * +__wt_path_separator(void) +{ + return ("/"); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_priv.c b/src/third_party/wiredtiger/src/os_posix/os_priv.c new file mode 100644 index 00000000000..7d56359da4f --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_priv.c @@ -0,0 +1,19 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_has_priv -- + * Return if the process has special privileges, defined as having + * different effective and read UIDs or GIDs. + */ +int +__wt_has_priv(void) +{ + return (getuid() != geteuid() || getgid() != getegid()); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_remove.c b/src/third_party/wiredtiger/src/os_posix/os_remove.c new file mode 100644 index 00000000000..a52a4db6bc7 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_remove.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __remove_file_check -- + * Check if the file is currently open before removing it. + */ +static void +__remove_file_check(WT_SESSION_IMPL *session, const char *name) +{ +#ifdef HAVE_DIAGNOSTIC + WT_CONNECTION_IMPL *conn; + WT_FH *fh; + + conn = S2C(session); + fh = NULL; + + /* + * Check if the file is open: it's an error if it is, since a higher + * level should have closed it before removing. + */ + __wt_spin_lock(session, &conn->fh_lock); + TAILQ_FOREACH(fh, &conn->fhqh, q) { + if (strcmp(name, fh->name) == 0) + break; + } + __wt_spin_unlock(session, &conn->fh_lock); + + WT_ASSERT(session, fh == NULL); +#else + WT_UNUSED(session); + WT_UNUSED(name); +#endif +} + +/* + * __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); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_rename.c b/src/third_party/wiredtiger/src/os_posix/os_rename.c new file mode 100644 index 00000000000..ddbb59aaf37 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_rename.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __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)); + + 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); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_rw.c b/src/third_party/wiredtiger/src/os_posix/os_rw.c new file mode 100644 index 00000000000..4247fb30fd1 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_rw.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_read -- + * Read a chunk. + */ +int +__wt_read( + WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, size_t len, void *buf) +{ + size_t chunk; + ssize_t nr; + uint8_t *addr; + + WT_STAT_FAST_CONN_INCR(session, read_io); + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, + "%s: read %" WT_SIZET_FMT " bytes at offset %" PRIuMAX, + fh->name, len, (uintmax_t)offset)); + + /* Assert direct I/O is aligned and a multiple of the alignment. */ + WT_ASSERT(session, + !fh->direct_io || + S2C(session)->buffer_alignment == 0 || + (!((uintptr_t)buf & + (uintptr_t)(S2C(session)->buffer_alignment - 1)) && + len >= S2C(session)->buffer_alignment && + len % S2C(session)->buffer_alignment == 0)); + + /* Break reads larger than 1GB into 1GB chunks. */ + for (addr = buf; len > 0; addr += nr, len -= (size_t)nr, offset += nr) { + chunk = WT_MIN(len, WT_GIGABYTE); + if ((nr = pread(fh->fd, addr, chunk, offset)) <= 0) + WT_RET_MSG(session, nr == 0 ? WT_ERROR : __wt_errno(), + "%s read error: failed to read %" WT_SIZET_FMT + " bytes at offset %" PRIuMAX, + fh->name, chunk, (uintmax_t)offset); + } + return (0); +} + +/* + * __wt_write -- + * Write a chunk. + */ +int +__wt_write(WT_SESSION_IMPL *session, + WT_FH *fh, wt_off_t offset, size_t len, const void *buf) +{ + size_t chunk; + ssize_t nw; + const uint8_t *addr; + + WT_STAT_FAST_CONN_INCR(session, write_io); + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, + "%s: write %" WT_SIZET_FMT " bytes at offset %" PRIuMAX, + fh->name, len, (uintmax_t)offset)); + + /* Assert direct I/O is aligned and a multiple of the alignment. */ + WT_ASSERT(session, + !fh->direct_io || + S2C(session)->buffer_alignment == 0 || + (!((uintptr_t)buf & + (uintptr_t)(S2C(session)->buffer_alignment - 1)) && + len >= S2C(session)->buffer_alignment && + len % S2C(session)->buffer_alignment == 0)); + + /* Break writes larger than 1GB into 1GB chunks. */ + for (addr = buf; len > 0; addr += nw, len -= (size_t)nw, offset += nw) { + chunk = WT_MIN(len, WT_GIGABYTE); + if ((nw = pwrite(fh->fd, addr, chunk, offset)) < 0) + WT_RET_MSG(session, __wt_errno(), + "%s write error: failed to write %" WT_SIZET_FMT + " bytes at offset %" PRIuMAX, + fh->name, chunk, (uintmax_t)offset); + } + return (0); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_sleep.c b/src/third_party/wiredtiger/src/os_posix/os_sleep.c new file mode 100644 index 00000000000..665330a26e7 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_sleep.c @@ -0,0 +1,23 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_sleep -- + * Pause the thread of control. + */ +void +__wt_sleep(long seconds, long micro_seconds) +{ + struct timeval t; + + t.tv_sec = seconds + micro_seconds / 1000000; + t.tv_usec = (suseconds_t)(micro_seconds % 1000000); + + (void)select(0, NULL, NULL, NULL, &t); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_strtouq.c b/src/third_party/wiredtiger/src/os_posix/os_strtouq.c new file mode 100644 index 00000000000..97f9759f76f --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_strtouq.c @@ -0,0 +1,24 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_strtouq -- + * Convert a string to an unsigned quad integer. + */ +uint64_t +__wt_strtouq(const char *nptr, char **endptr, int base) +{ +#if defined(HAVE_STRTOUQ) + return (strtouq(nptr, endptr, base)); +#else + WT_STATIC_ASSERT(sizeof(uint64_t) == sizeof(unsigned long long)); + + return (strtoull(nptr, endptr, base)); +#endif +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_thread.c b/src/third_party/wiredtiger/src/os_posix/os_thread.c new file mode 100644 index 00000000000..7c447710b46 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_thread.c @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_thread_create -- + * Create a new thread of control. + */ +int +__wt_thread_create(WT_SESSION_IMPL *session, + wt_thread_t *tidret, void *(*func)(void *), void *arg) +{ + WT_DECL_RET; + + /* Spawn a new thread of control. */ + if ((ret = pthread_create(tidret, NULL, func, arg)) == 0) + return (0); + WT_RET_MSG(session, ret, "pthread_create"); +} + +/* + * __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; + + if ((ret = pthread_join(tid, NULL)) == 0) + return (0); + + WT_RET_MSG(session, ret, "pthread_join"); +} + +/* + * __wt_thread_id -- + * Fill in a printable version of the process and thread IDs. + */ +void +__wt_thread_id(char *buf, size_t buflen) +{ + pthread_t self; + + /* + * POSIX 1003.1 allows pthread_t to be an opaque type, but on systems + * where it's a pointer, we'd rather print out the pointer and match + * gdb output. Since we don't yet run on any systems where pthread_t + * is not a pointer, do it that way for now. + */ + self = pthread_self(); + (void)snprintf(buf, buflen, + "%" PRIu64 ":%p", (uint64_t)getpid(), (void *)self); +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_time.c b/src/third_party/wiredtiger/src/os_posix/os_time.c new file mode 100644 index 00000000000..56f688a1e14 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_time.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_seconds -- + * Return the seconds since the Epoch. + */ +int +__wt_seconds(WT_SESSION_IMPL *session, time_t *timep) +{ + struct timespec t; + + WT_RET(__wt_epoch(session, &t)); + + *timep = t.tv_sec; + + return (0); +} + +/* + * __wt_epoch -- + * Return the time since the Epoch. + */ +int +__wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp) +{ + WT_DECL_RET; + +#if defined(HAVE_CLOCK_GETTIME) + WT_SYSCALL_RETRY(clock_gettime(CLOCK_REALTIME, tsp), ret); + if (ret == 0) + return (0); + WT_RET_MSG(session, ret, "clock_gettime"); +#elif defined(HAVE_GETTIMEOFDAY) + struct timeval v; + + WT_SYSCALL_RETRY(gettimeofday(&v, NULL), ret); + if (ret == 0) { + tsp->tv_sec = v.tv_sec; + tsp->tv_nsec = v.tv_usec * 1000; + return (0); + } + WT_RET_MSG(session, ret, "gettimeofday"); +#else + NO TIME-OF-DAY IMPLEMENTATION: see src/os_posix/os_time.c +#endif +} diff --git a/src/third_party/wiredtiger/src/os_posix/os_yield.c b/src/third_party/wiredtiger/src/os_posix/os_yield.c new file mode 100644 index 00000000000..6af30803e81 --- /dev/null +++ b/src/third_party/wiredtiger/src/os_posix/os_yield.c @@ -0,0 +1,18 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_yield -- + * Yield the thread of control. + */ +void +__wt_yield(void) +{ + sched_yield(); +} |