summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/src/os_common
diff options
context:
space:
mode:
authorAlex Gorrod <alexg@wiredtiger.com>2016-04-05 14:43:57 +1000
committerAlex Gorrod <alexg@wiredtiger.com>2016-04-05 14:44:50 +1000
commitde6f136d83b20f8a58ba6fe4ba02be229b6c9159 (patch)
tree3221d66b54cbf6208fc3c995fdbb36d347ae85ff /src/third_party/wiredtiger/src/os_common
parent5d1262cc394d685b59ae3185d7315227085e897d (diff)
downloadmongo-de6f136d83b20f8a58ba6fe4ba02be229b6c9159.tar.gz
Import wiredtiger-wiredtiger-2.8.0-134-g5047aab.tar.gz from wiredtiger branch mongodb-3.4
ref: 9cf8eb2..5047aab SERVER-23504 Coverity analysis defect 98177: Resource leak WT-2330 in-memory configurations should not create on-disk collection files WT-2513 conversion from 'int64_t' to 'uint32_t' WT-2522 Incorrect format code in message WT-2525 in-memory configurations: miscellaneous cleanups WT-2527 OS X compile error, missing POSIX_FADV_WILLNEED #define WT-2528 style error in WiredTiger build WT-2529 The readonly test case is crashing with a stack overflow WT-2531 in-memory tables are allocating unnecessary memory WT-2532 WT_STREAM_APPEND and WT_STREAM_LINE_BUFFER flag overlap WT-2533 Ensure that in-memory tables don't report a zero size SERVER-23517 WiredTiger changes for MongoDB 3.3.5
Diffstat (limited to 'src/third_party/wiredtiger/src/os_common')
-rw-r--r--src/third_party/wiredtiger/src/os_common/filename.c193
-rw-r--r--src/third_party/wiredtiger/src/os_common/os_abort.c27
-rw-r--r--src/third_party/wiredtiger/src/os_common/os_alloc.c308
-rw-r--r--src/third_party/wiredtiger/src/os_common/os_fhandle.c306
-rw-r--r--src/third_party/wiredtiger/src/os_common/os_fs_inmemory.c482
-rw-r--r--src/third_party/wiredtiger/src/os_common/os_fs_stdio.c239
-rw-r--r--src/third_party/wiredtiger/src/os_common/os_getline.c51
-rw-r--r--src/third_party/wiredtiger/src/os_common/os_getopt.c151
-rw-r--r--src/third_party/wiredtiger/src/os_common/os_init.c41
-rw-r--r--src/third_party/wiredtiger/src/os_common/os_strtouq.c25
10 files changed, 1823 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/src/os_common/filename.c b/src/third_party/wiredtiger/src/os_common/filename.c
new file mode 100644
index 00000000000..dfd67284948
--- /dev/null
+++ b/src/third_party/wiredtiger/src/os_common/filename.c
@@ -0,0 +1,193 @@
+/*-
+ * Copyright (c) 2014-2016 MongoDB, Inc.
+ * Copyright (c) 2008-2014 WiredTiger, Inc.
+ * All rights reserved.
+ *
+ * See the file LICENSE for redistribution information.
+ */
+
+#include "wt_internal.h"
+
+/*
+ * __wt_filename --
+ * Build a file name in a scratch buffer, automatically calculate the
+ * length of the file name.
+ */
+int
+__wt_filename(WT_SESSION_IMPL *session, const char *name, char **path)
+{
+ return (__wt_nfilename(session, name, strlen(name), path));
+}
+
+/*
+ * __wt_nfilename --
+ * Build a file name in a scratch buffer. If the name is already an
+ * absolute path duplicate it, otherwise generate a path relative to the
+ * connection home directory.
+ */
+int
+__wt_nfilename(
+ WT_SESSION_IMPL *session, const char *name, size_t namelen, char **path)
+{
+ size_t len;
+ char *buf;
+
+ *path = NULL;
+
+ /*
+ * Needs to work with a NULL session handle - since this is called via
+ * the exists API which is used by the test utilities.
+ */
+ if (session == NULL || __wt_absolute_path(name))
+ WT_RET(__wt_strndup(session, name, namelen, path));
+ else {
+ len = strlen(S2C(session)->home) + 1 + namelen + 1;
+ WT_RET(__wt_calloc(session, 1, len, &buf));
+ snprintf(buf, len, "%s%s%.*s", S2C(session)->home,
+ __wt_path_separator(), (int)namelen, name);
+ *path = buf;
+ }
+
+ return (0);
+}
+
+/*
+ * __wt_remove_if_exists --
+ * Remove a file if it exists.
+ */
+int
+__wt_remove_if_exists(WT_SESSION_IMPL *session, const char *name)
+{
+ bool exist;
+
+ WT_RET(__wt_exist(session, name, &exist));
+ if (exist)
+ WT_RET(__wt_remove(session, name));
+ return (0);
+}
+
+/*
+ * __wt_rename_and_sync_directory --
+ * Rename a file and sync the enclosing directory.
+ */
+int
+__wt_rename_and_sync_directory(
+ WT_SESSION_IMPL *session, const char *from, const char *to)
+{
+ const char *fp, *tp;
+ bool same_directory;
+
+ /* Rename the source file to the target. */
+ WT_RET(__wt_rename(session, from, to));
+
+ /*
+ * Flush the backing directory to guarantee the rename. My reading of
+ * POSIX 1003.1 is there's no guarantee flushing only one of the from
+ * or to directories, or flushing a common parent, is sufficient, and
+ * even if POSIX were to make that guarantee, existing filesystems are
+ * known to not provide the guarantee or only provide the guarantee
+ * with specific mount options. Flush both of the from/to directories
+ * until it's a performance problem.
+ */
+ WT_RET(__wt_directory_sync(session, from));
+
+ /*
+ * In almost all cases, we're going to be renaming files in the same
+ * directory, we can at least fast-path that.
+ */
+ fp = strrchr(from, '/');
+ tp = strrchr(to, '/');
+ same_directory = (fp == NULL && tp == NULL) ||
+ (fp != NULL && tp != NULL &&
+ fp - from == tp - to && memcmp(from, to, (size_t)(fp - from)) == 0);
+
+ return (same_directory ? 0 : __wt_directory_sync(session, to));
+}
+
+/*
+ * __wt_sync_handle_and_rename --
+ * Sync and close a handle, and swap it into place.
+ */
+int
+__wt_sync_handle_and_rename(
+ WT_SESSION_IMPL *session, WT_FH **fhp, const char *from, const char *to)
+{
+ WT_DECL_RET;
+ WT_FH *fh;
+
+ fh = *fhp;
+ *fhp = NULL;
+
+ /* Flush to disk and close the handle. */
+ ret = __wt_fsync(session, fh, true);
+ WT_TRET(__wt_close(session, &fh));
+ WT_RET(ret);
+
+ return (__wt_rename_and_sync_directory(session, from, to));
+}
+
+/*
+ * __wt_copy_and_sync --
+ * Copy a file safely; here to support the wt utility.
+ */
+int
+__wt_copy_and_sync(WT_SESSION *wt_session, const char *from, const char *to)
+{
+ WT_DECL_ITEM(tmp);
+ WT_DECL_RET;
+ WT_FH *ffh, *tfh;
+ WT_SESSION_IMPL *session;
+ wt_off_t n, offset, size;
+ char *buf;
+
+ session = (WT_SESSION_IMPL *)wt_session;
+ ffh = tfh = NULL;
+ buf = NULL;
+
+ /*
+ * Remove the target file if it exists, then create a temporary file,
+ * copy the original into it and rename it into place. I don't think
+ * its necessary to remove the file, or create a copy and do a rename,
+ * it's likely safe to overwrite the backup file directly. I'm doing
+ * the remove and rename to insulate us from errors in other programs
+ * that might not detect a corrupted backup file; it's cheap insurance
+ * in a path where undetected failure is very bad.
+ */
+ WT_ERR(__wt_scr_alloc(session, 0, &tmp));
+ WT_ERR(__wt_buf_fmt(session, tmp, "%s.copy", to));
+
+ WT_ERR(__wt_remove_if_exists(session, to));
+ WT_ERR(__wt_remove_if_exists(session, tmp->data));
+
+ /* Open the from and temporary file handles. */
+ WT_ERR(__wt_open(session, from,
+ WT_FILE_TYPE_REGULAR, WT_OPEN_READONLY, &ffh));
+ WT_ERR(__wt_open(session, tmp->data,
+ WT_FILE_TYPE_REGULAR, WT_OPEN_CREATE | WT_OPEN_EXCLUSIVE, &tfh));
+
+ /*
+ * Allocate a copy buffer. Don't use a scratch buffer, this thing is
+ * big, and we don't want it hanging around.
+ */
+#define WT_BACKUP_COPY_SIZE (128 * 1024)
+ WT_ERR(__wt_malloc(session, WT_BACKUP_COPY_SIZE, &buf));
+
+ /* Get the file's size, then copy the bytes. */
+ WT_ERR(__wt_filesize(session, ffh, &size));
+ for (offset = 0; size > 0; size -= n, offset += n) {
+ n = WT_MIN(size, WT_BACKUP_COPY_SIZE);
+ WT_ERR(__wt_read(session, ffh, offset, (size_t)n, buf));
+ WT_ERR(__wt_write(session, tfh, offset, (size_t)n, buf));
+ }
+
+ /* Close the from handle, then swap the temporary file into place. */
+ WT_ERR(__wt_close(session, &ffh));
+ ret = __wt_sync_handle_and_rename(session, &tfh, tmp->data, to);
+
+err: WT_TRET(__wt_close(session, &ffh));
+ WT_TRET(__wt_close(session, &tfh));
+
+ __wt_free(session, buf);
+ __wt_scr_free(session, &tmp);
+ return (ret);
+}
diff --git a/src/third_party/wiredtiger/src/os_common/os_abort.c b/src/third_party/wiredtiger/src/os_common/os_abort.c
new file mode 100644
index 00000000000..034eedcfbf8
--- /dev/null
+++ b/src/third_party/wiredtiger/src/os_common/os_abort.c
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2014-2016 MongoDB, Inc.
+ * 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_common/os_alloc.c b/src/third_party/wiredtiger/src/os_common/os_alloc.c
new file mode 100644
index 00000000000..cfc7b80450e
--- /dev/null
+++ b/src/third_party/wiredtiger/src/os_common/os_alloc.c
@@ -0,0 +1,308 @@
+/*-
+ * Copyright (c) 2014-2016 MongoDB, Inc.
+ * Copyright (c) 2008-2014 WiredTiger, Inc.
+ * All rights reserved.
+ *
+ * See the file LICENSE for redistribution information.
+ */
+
+#include "wt_internal.h"
+
+/*
+ * On systems with poor default allocators for allocations greater than 16 KB,
+ * we provide an option to use TCMalloc explicitly.
+ * This is important on Windows which does not have a builtin mechanism
+ * to replace C run-time memory management functions with alternatives.
+ */
+#ifdef HAVE_LIBTCMALLOC
+#include <gperftools/tcmalloc.h>
+
+#define calloc tc_calloc
+#define malloc tc_malloc
+#define realloc tc_realloc
+#define posix_memalign tc_posix_memalign
+#define free tc_free
+#endif
+
+/*
+ * __wt_calloc --
+ * ANSI calloc function.
+ */
+int
+__wt_calloc(WT_SESSION_IMPL *session, size_t number, size_t size, void *retp)
+{
+ void *p;
+
+ /*
+ * Defensive: if our caller doesn't handle errors correctly, ensure a
+ * free won't fail.
+ */
+ *(void **)retp = NULL;
+
+ /*
+ * !!!
+ * 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 of %" WT_SIZET_FMT " bytes failed",
+ size * number);
+
+ *(void **)retp = p;
+ return (0);
+}
+
+/*
+ * __wt_malloc --
+ * ANSI malloc function.
+ */
+int
+__wt_malloc(WT_SESSION_IMPL *session, size_t bytes_to_allocate, void *retp)
+{
+ void *p;
+
+ /*
+ * Defensive: if our caller doesn't handle errors correctly, ensure a
+ * free won't fail.
+ */
+ *(void **)retp = NULL;
+
+ /*
+ * !!!
+ * This function MUST handle a NULL WT_SESSION_IMPL handle.
+ */
+ WT_ASSERT(session, bytes_to_allocate != 0);
+
+ if (session != NULL)
+ WT_STAT_FAST_CONN_INCR(session, memory_allocation);
+
+ if ((p = malloc(bytes_to_allocate)) == NULL)
+ WT_RET_MSG(session, __wt_errno(),
+ "memory allocation of %" WT_SIZET_FMT " bytes failed",
+ bytes_to_allocate);
+
+ *(void **)retp = p;
+ return (0);
+}
+
+/*
+ * __realloc_func --
+ * ANSI realloc function.
+ */
+static int
+__realloc_func(WT_SESSION_IMPL *session,
+ size_t *bytes_allocated_ret, size_t bytes_to_allocate, bool clear_memory,
+ 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 of %" WT_SIZET_FMT " bytes failed",
+ bytes_to_allocate);
+
+ /*
+ * Clear the allocated memory, parts of WiredTiger depend on allocated
+ * memory being cleared.
+ */
+ if (clear_memory)
+ 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 --
+ * WiredTiger's realloc API.
+ */
+int
+__wt_realloc(WT_SESSION_IMPL *session,
+ size_t *bytes_allocated_ret, size_t bytes_to_allocate, void *retp)
+{
+ return (__realloc_func(
+ session, bytes_allocated_ret, bytes_to_allocate, true, retp));
+}
+
+/*
+ * __wt_realloc_noclear --
+ * WiredTiger's realloc API, not clearing allocated memory.
+ */
+int
+__wt_realloc_noclear(WT_SESSION_IMPL *session,
+ size_t *bytes_allocated_ret, size_t bytes_to_allocate, void *retp)
+{
+ return (__realloc_func(
+ session, bytes_allocated_ret, bytes_to_allocate, false, retp));
+}
+
+/*
+ * __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);
+
+ /*
+ * We are going to allocate an aligned buffer. When we do this
+ * repeatedly, the allocator is expected to start on a boundary
+ * each time, account for that additional space by never asking
+ * for less than a full alignment size. The primary use case
+ * for aligned buffers is Linux direct I/O, which requires that
+ * the size be a multiple of the alignment anyway.
+ */
+ bytes_to_allocate =
+ WT_ALIGN(bytes_to_allocate, S2C(session)->buffer_alignment);
+
+ 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 of %" WT_SIZET_FMT
+ " bytes failed", bytes_to_allocate);
+
+ if (p != NULL)
+ memcpy(newp, p, bytes_allocated);
+ __wt_free(session, p);
+ p = newp;
+
+ /* 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 (__realloc_func(
+ session, bytes_allocated_ret, bytes_to_allocate, false, 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_malloc(session, len + 1, &p));
+
+ /*
+ * Don't change this to strncpy, we rely on this function to duplicate
+ * "strings" that contain nul bytes.
+ */
+ memcpy(p, str, len);
+ ((uint8_t *)p)[len] = '\0';
+
+ *(void **)retp = p;
+ return (0);
+}
+
+/*
+ * __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_common/os_fhandle.c b/src/third_party/wiredtiger/src/os_common/os_fhandle.c
new file mode 100644
index 00000000000..b16b2e24bfa
--- /dev/null
+++ b/src/third_party/wiredtiger/src/os_common/os_fhandle.c
@@ -0,0 +1,306 @@
+/*-
+ * Copyright (c) 2014-2016 MongoDB, Inc.
+ * Copyright (c) 2008-2014 WiredTiger, Inc.
+ * All rights reserved.
+ *
+ * See the file LICENSE for redistribution information.
+ */
+
+#include "wt_internal.h"
+
+/*
+ * __wt_handle_search --
+ * Search for a matching handle.
+ */
+bool
+__wt_handle_search(WT_SESSION_IMPL *session,
+ const char *name, bool increment_ref, WT_FH *newfh, WT_FH **fhp)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_FH *fh;
+ uint64_t bucket, hash;
+ bool found;
+
+ if (fhp != NULL)
+ *fhp = NULL;
+
+ conn = S2C(session);
+ found = false;
+
+ hash = __wt_hash_city64(name, strlen(name));
+ bucket = hash % WT_HASH_ARRAY_SIZE;
+
+ __wt_spin_lock(session, &conn->fh_lock);
+
+ /*
+ * If we already have the file open, optionally increment the reference
+ * count and return a pointer.
+ */
+ TAILQ_FOREACH(fh, &conn->fhhash[bucket], hashq)
+ if (strcmp(name, fh->name) == 0) {
+ if (increment_ref)
+ ++fh->ref;
+ if (fhp != NULL)
+ *fhp = fh;
+ found = true;
+ break;
+ }
+
+ /* If we don't find a match, optionally add a new entry. */
+ if (!found && newfh != NULL) {
+ newfh->name_hash = hash;
+ WT_CONN_FILE_INSERT(conn, newfh, bucket);
+ (void)__wt_atomic_add32(&conn->open_file_count, 1);
+
+ if (increment_ref)
+ ++newfh->ref;
+ if (fhp != NULL)
+ *fhp = newfh;
+ }
+
+ __wt_spin_unlock(session, &conn->fh_lock);
+
+ return (found);
+}
+
+/*
+ * __open_verbose --
+ * Optionally output a verbose message on handle open.
+ */
+static inline int
+__open_verbose(WT_SESSION_IMPL *session,
+ const char *name, uint32_t file_type, uint32_t flags)
+{
+#ifdef HAVE_VERBOSE
+ WT_DECL_RET;
+ WT_DECL_ITEM(tmp);
+ const char *file_type_tag, *sep;
+
+ if (!WT_VERBOSE_ISSET(session, WT_VERB_FILEOPS))
+ return (0);
+
+ /*
+ * It's useful to track file opens when debugging platforms, take some
+ * effort to output good tracking information.
+ */
+
+ switch (file_type) {
+ case WT_FILE_TYPE_CHECKPOINT:
+ file_type_tag = "checkpoint";
+ break;
+ case WT_FILE_TYPE_DATA:
+ file_type_tag = "data";
+ break;
+ case WT_FILE_TYPE_DIRECTORY:
+ file_type_tag = "directory";
+ break;
+ case WT_FILE_TYPE_LOG:
+ file_type_tag = "log";
+ break;
+ case WT_FILE_TYPE_REGULAR:
+ file_type_tag = "regular";
+ break;
+ default:
+ file_type_tag = "unknown open type";
+ break;
+ }
+
+ WT_RET(__wt_scr_alloc(session, 0, &tmp));
+ sep = " (";
+#define WT_OPEN_VERBOSE_FLAG(f, name) \
+ if (LF_ISSET(f)) { \
+ WT_ERR(__wt_buf_catfmt( \
+ session, tmp, "%s%s", sep, name)); \
+ sep = ", "; \
+ }
+
+ WT_OPEN_VERBOSE_FLAG(WT_OPEN_CREATE, "create");
+ WT_OPEN_VERBOSE_FLAG(WT_OPEN_EXCLUSIVE, "exclusive");
+ WT_OPEN_VERBOSE_FLAG(WT_OPEN_FIXED, "fixed");
+ WT_OPEN_VERBOSE_FLAG(WT_OPEN_READONLY, "readonly");
+ WT_OPEN_VERBOSE_FLAG(WT_STREAM_APPEND, "stream-append");
+ WT_OPEN_VERBOSE_FLAG(WT_STREAM_READ, "stream-read");
+ WT_OPEN_VERBOSE_FLAG(WT_STREAM_WRITE, "stream-write");
+
+ if (tmp->size != 0)
+ WT_ERR(__wt_buf_catfmt(session, tmp, ")"));
+
+ ret = __wt_verbose(session, WT_VERB_FILEOPS,
+ "%s: handle-open: type %s%s",
+ name, file_type_tag, tmp->size == 0 ? "" : (char *)tmp->data);
+
+err: __wt_scr_free(session, &tmp);
+ return (ret);
+#else
+ WT_UNUSED(session);
+ WT_UNUSED(name);
+ WT_UNUSED(file_type);
+ WT_UNUSED(flags);
+ return (0);
+#endif
+}
+
+/*
+ * __wt_open --
+ * Open a file handle.
+ */
+int
+__wt_open(WT_SESSION_IMPL *session,
+ const char *name, uint32_t file_type, uint32_t flags, WT_FH **fhp)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ WT_FH *fh;
+ bool lock_file, open_called;
+ char *path;
+
+ WT_ASSERT(session, file_type != 0); /* A file type is required. */
+
+ conn = S2C(session);
+ fh = NULL;
+ open_called = false;
+ path = NULL;
+
+ WT_RET(__open_verbose(session, name, file_type, flags));
+
+ /* Check if the handle is already open. */
+ if (__wt_handle_search(session, name, true, NULL, &fh)) {
+ /*
+ * XXX
+ * The in-memory implementation has to reset the file offset
+ * when a file is re-opened (which obviously also depends on
+ * in-memory configurations never opening a file in more than
+ * one thread at a time). This needs to be fixed.
+ */
+ if (F_ISSET(fh, WT_FH_IN_MEMORY) && fh->ref == 1)
+ fh->off = 0;
+ *fhp = fh;
+ return (0);
+ }
+
+ /* Allocate a structure and set the name. */
+ WT_ERR(__wt_calloc_one(session, &fh));
+ WT_ERR(__wt_strdup(session, name, &fh->name));
+
+ /*
+ * If this is a read-only connection, open all files read-only except
+ * the lock file.
+ *
+ * The only file created in read-only mode is the lock file.
+ */
+ if (F_ISSET(conn, WT_CONN_READONLY)) {
+ lock_file = strcmp(name, WT_SINGLETHREAD) == 0;
+ if (!lock_file)
+ LF_SET(WT_OPEN_READONLY);
+ WT_ASSERT(session, lock_file || !LF_ISSET(WT_OPEN_CREATE));
+ }
+
+ /* Create the path to the file. */
+ if (!LF_ISSET(WT_OPEN_FIXED))
+ WT_ERR(__wt_filename(session, name, &path));
+
+ /* Call the underlying open function. */
+ WT_ERR(conn->handle_open(
+ session, fh, path == NULL ? name : path, file_type, flags));
+ open_called = true;
+
+ /*
+ * Repeat the check for a match: if there's no match, link our newly
+ * created handle onto the database's list of files.
+ */
+ if (__wt_handle_search(session, name, true, fh, fhp)) {
+err: if (open_called)
+ WT_TRET(fh->fh_close(session, fh));
+ if (fh != NULL) {
+ __wt_free(session, fh->name);
+ __wt_free(session, fh);
+ }
+ }
+
+ __wt_free(session, path);
+ return (ret);
+}
+
+/*
+ * __wt_close --
+ * Close a file handle.
+ */
+int
+__wt_close(WT_SESSION_IMPL *session, WT_FH **fhp)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ WT_FH *fh;
+ uint64_t bucket;
+
+ conn = S2C(session);
+
+ if (*fhp == NULL)
+ return (0);
+ fh = *fhp;
+ *fhp = NULL;
+
+ /* Track handle-close as a file operation, so open and close match. */
+ WT_RET(__wt_verbose(
+ session, WT_VERB_FILEOPS, "%s: handle-close", fh->name));
+
+ /*
+ * If the reference count hasn't gone to 0, or if it's an in-memory
+ * object, we're done.
+ *
+ * Assert the reference count is correct, but don't let it wrap.
+ */
+ __wt_spin_lock(session, &conn->fh_lock);
+ WT_ASSERT(session, fh->ref > 0);
+ if ((fh->ref > 0 && --fh->ref > 0) || F_ISSET(fh, WT_FH_IN_MEMORY)) {
+ __wt_spin_unlock(session, &conn->fh_lock);
+ return (0);
+ }
+
+ /* Remove from the list. */
+ bucket = fh->name_hash % WT_HASH_ARRAY_SIZE;
+ WT_CONN_FILE_REMOVE(conn, fh, bucket);
+ (void)__wt_atomic_sub32(&conn->open_file_count, 1);
+
+ __wt_spin_unlock(session, &conn->fh_lock);
+
+ /* Discard underlying resources. */
+ ret = fh->fh_close(session, fh);
+
+ __wt_free(session, fh->name);
+ __wt_free(session, fh);
+
+ return (ret);
+}
+
+/*
+ * __wt_close_connection_close --
+ * Close any open file handles at connection close.
+ */
+int
+__wt_close_connection_close(WT_SESSION_IMPL *session)
+{
+ WT_DECL_RET;
+ WT_FH *fh;
+ WT_CONNECTION_IMPL *conn;
+
+ conn = S2C(session);
+
+ while ((fh = TAILQ_FIRST(&conn->fhqh)) != NULL) {
+ /*
+ * In-memory configurations will have open files, but the ref
+ * counts should be zero.
+ */
+ if (!F_ISSET(conn, WT_CONN_IN_MEMORY) || fh->ref != 0) {
+ ret = EBUSY;
+ __wt_errx(session,
+ "Connection has open file handles: %s", fh->name);
+ }
+
+ fh->ref = 1;
+ F_CLR(fh, WT_FH_IN_MEMORY);
+
+ WT_TRET(__wt_close(session, &fh));
+ }
+ return (ret);
+}
diff --git a/src/third_party/wiredtiger/src/os_common/os_fs_inmemory.c b/src/third_party/wiredtiger/src/os_common/os_fs_inmemory.c
new file mode 100644
index 00000000000..260514eac66
--- /dev/null
+++ b/src/third_party/wiredtiger/src/os_common/os_fs_inmemory.c
@@ -0,0 +1,482 @@
+/*-
+ * Copyright (c) 2014-2016 MongoDB, Inc.
+ * Copyright (c) 2008-2014 WiredTiger, Inc.
+ * All rights reserved.
+ *
+ * See the file LICENSE for redistribution information.
+ */
+
+#include "wt_internal.h"
+
+static int __im_handle_size(WT_SESSION_IMPL *, WT_FH *, wt_off_t *);
+
+/*
+ * In-memory information.
+ */
+typedef struct {
+ WT_SPINLOCK lock;
+} WT_IM;
+
+/*
+ * __im_directory_list --
+ * Get a list of files from a directory, in-memory version.
+ */
+static int
+__im_directory_list(WT_SESSION_IMPL *session, const char *dir,
+ const char *prefix, uint32_t flags, char ***dirlist, u_int *countp)
+{
+ WT_UNUSED(session);
+ WT_UNUSED(dir);
+ WT_UNUSED(prefix);
+ WT_UNUSED(flags);
+ WT_UNUSED(dirlist);
+ WT_UNUSED(countp);
+
+ WT_RET_MSG(session, ENOTSUP, "directory-list");
+}
+
+/*
+ * __im_directory_sync --
+ * Flush a directory to ensure file creation is durable.
+ */
+static int
+__im_directory_sync(WT_SESSION_IMPL *session, const char *path)
+{
+ WT_UNUSED(session);
+ WT_UNUSED(path);
+ return (0);
+}
+
+/*
+ * __im_file_exist --
+ * Return if the file exists.
+ */
+static int
+__im_file_exist(WT_SESSION_IMPL *session, const char *name, bool *existp)
+{
+ *existp = __wt_handle_search(session, name, false, NULL, NULL);
+ return (0);
+}
+
+/*
+ * __im_file_remove --
+ * POSIX remove.
+ */
+static int
+__im_file_remove(WT_SESSION_IMPL *session, const char *name)
+{
+ WT_DECL_RET;
+ WT_FH *fh;
+
+ if (__wt_handle_search(session, name, true, NULL, &fh)) {
+ WT_ASSERT(session, fh->ref == 1);
+
+ /* Force a discard of the handle. */
+ F_CLR(fh, WT_FH_IN_MEMORY);
+ ret = __wt_close(session, &fh);
+ }
+ return (ret);
+}
+
+/*
+ * __im_file_rename --
+ * POSIX rename.
+ */
+static int
+__im_file_rename(WT_SESSION_IMPL *session, const char *from, const char *to)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ WT_FH *fh;
+ uint64_t bucket, hash;
+ char *to_name;
+
+ conn = S2C(session);
+
+ /* We'll need a copy of the target name. */
+ WT_RET(__wt_strdup(session, to, &to_name));
+
+ __wt_spin_lock(session, &conn->fh_lock);
+
+ /* Make sure the target name isn't active. */
+ hash = __wt_hash_city64(to, strlen(to));
+ bucket = hash % WT_HASH_ARRAY_SIZE;
+ TAILQ_FOREACH(fh, &conn->fhhash[bucket], hashq)
+ if (strcmp(to, fh->name) == 0)
+ WT_ERR(EPERM);
+
+ /* Find the source name. */
+ hash = __wt_hash_city64(from, strlen(from));
+ bucket = hash % WT_HASH_ARRAY_SIZE;
+ TAILQ_FOREACH(fh, &conn->fhhash[bucket], hashq)
+ if (strcmp(from, fh->name) == 0)
+ break;
+ if (fh == NULL)
+ WT_ERR(ENOENT);
+
+ /* Remove source from the list. */
+ WT_CONN_FILE_REMOVE(conn, fh, bucket);
+
+ /* Swap the names. */
+ __wt_free(session, fh->name);
+ fh->name = to_name;
+ to_name = NULL;
+
+ /* Put source back on the list. */
+ hash = __wt_hash_city64(to, strlen(to));
+ bucket = hash % WT_HASH_ARRAY_SIZE;
+ WT_CONN_FILE_INSERT(conn, fh, bucket);
+
+ if (0) {
+err: __wt_free(session, to_name);
+ }
+ __wt_spin_unlock(session, &conn->fh_lock);
+
+ return (ret);
+}
+
+/*
+ * __im_file_size --
+ * Get the size of a file in bytes, by file name.
+ */
+static int
+__im_file_size(
+ WT_SESSION_IMPL *session, const char *name, bool silent, wt_off_t *sizep)
+{
+ WT_DECL_RET;
+ WT_FH *fh;
+ WT_IM *im;
+
+ WT_UNUSED(silent);
+
+ im = S2C(session)->inmemory;
+ __wt_spin_lock(session, &im->lock);
+
+ if (__wt_handle_search(session, name, true, NULL, &fh)) {
+ WT_ERR(__im_handle_size(session, fh, sizep));
+ WT_ERR(__wt_close(session, &fh));
+ } else
+ ret = ENOENT;
+
+err: __wt_spin_unlock(session, &im->lock);
+ return (ret);
+}
+
+/*
+ * __im_handle_advise --
+ * POSIX fadvise.
+ */
+static int
+__im_handle_advise(WT_SESSION_IMPL *session,
+ WT_FH *fh, wt_off_t offset, wt_off_t len, int advice)
+{
+ WT_UNUSED(session);
+ WT_UNUSED(fh);
+ WT_UNUSED(offset);
+ WT_UNUSED(len);
+ WT_UNUSED(advice);
+ return (ENOTSUP);
+}
+
+/*
+ * __im_handle_close --
+ * ANSI C close/fclose.
+ */
+static int
+__im_handle_close(WT_SESSION_IMPL *session, WT_FH *fh)
+{
+ __wt_buf_free(session, &fh->buf);
+
+ return (0);
+}
+
+/*
+ * __im_handle_getc --
+ * ANSI C fgetc.
+ */
+static int
+__im_handle_getc(WT_SESSION_IMPL *session, WT_FH *fh, int *chp)
+{
+ WT_IM *im;
+
+ im = S2C(session)->inmemory;
+ __wt_spin_lock(session, &im->lock);
+
+ if (fh->off >= fh->buf.size)
+ *chp = EOF;
+ else
+ *chp = ((char *)fh->buf.data)[fh->off++];
+
+ __wt_spin_unlock(session, &im->lock);
+ return (0);
+}
+
+/*
+ * __im_handle_lock --
+ * Lock/unlock a file.
+ */
+static int
+__im_handle_lock(WT_SESSION_IMPL *session, WT_FH *fh, bool lock)
+{
+ WT_UNUSED(session);
+ WT_UNUSED(fh);
+ WT_UNUSED(lock);
+ return (0);
+}
+
+/*
+ * __im_handle_printf --
+ * ANSI C vfprintf.
+ */
+static int
+__im_handle_printf(
+ WT_SESSION_IMPL *session, WT_FH *fh, const char *fmt, va_list ap)
+{
+ va_list ap_copy;
+ WT_DECL_ITEM(tmp);
+ WT_DECL_RET;
+ WT_IM *im;
+ size_t len;
+
+ im = S2C(session)->inmemory;
+
+ /* Build the string we're writing. */
+ WT_RET(__wt_scr_alloc(session, strlen(fmt) * 2 + 128, &tmp));
+ for (;;) {
+ va_copy(ap_copy, ap);
+ len = (size_t)vsnprintf(tmp->mem, tmp->memsize, fmt, ap_copy);
+ va_end(ap_copy);
+ if (len < tmp->memsize) {
+ tmp->data = tmp->mem;
+ tmp->size = len;
+ break;
+ }
+ WT_ERR(__wt_buf_extend(session, tmp, len + 1));
+ }
+
+ __wt_spin_lock(session, &im->lock);
+
+ /* Grow the handle's buffer as necessary. */
+ WT_ERR(__wt_buf_grow(session, &fh->buf, fh->off + len));
+
+ /* Copy the data into place and update the offset. */
+ memcpy((uint8_t *)fh->buf.mem + fh->off, tmp->data, len);
+ fh->off += len;
+
+err: __wt_spin_unlock(session, &im->lock);
+
+ __wt_scr_free(session, &tmp);
+ return (ret);
+}
+
+/*
+ * __im_handle_read --
+ * POSIX pread.
+ */
+static int
+__im_handle_read(
+ WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, size_t len, void *buf)
+{
+ WT_DECL_RET;
+ WT_IM *im;
+ size_t off;
+
+ im = S2C(session)->inmemory;
+ __wt_spin_lock(session, &im->lock);
+
+ off = (size_t)offset;
+ if (off < fh->buf.size) {
+ len = WT_MIN(len, fh->buf.size - off);
+ memcpy(buf, (uint8_t *)fh->buf.mem + off, len);
+ fh->off = off + len;
+ } else
+ ret = WT_ERROR;
+
+ __wt_spin_unlock(session, &im->lock);
+ if (ret == 0)
+ return (0);
+ WT_RET_MSG(session, WT_ERROR,
+ "%s: handle-read: failed to read %" WT_SIZET_FMT " bytes at "
+ "offset %" WT_SIZET_FMT,
+ fh->name, len, off);
+}
+
+/*
+ * __im_handle_size --
+ * Get the size of a file in bytes, by file handle.
+ */
+static int
+__im_handle_size(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t *sizep)
+{
+ WT_UNUSED(session);
+
+ /*
+ * XXX hack - MongoDB assumes that any file with content will have a
+ * non-zero size. In memory tables generally are zero-sized, make
+ * MongoDB happy.
+ */
+ *sizep = fh->buf.size == 0 ? 1024 : (wt_off_t)fh->buf.size;
+ return (0);
+}
+
+/*
+ * __im_handle_sync --
+ * POSIX fflush/fsync.
+ */
+static int
+__im_handle_sync(WT_SESSION_IMPL *session, WT_FH *fh, bool block)
+{
+ WT_UNUSED(session);
+ WT_UNUSED(fh);
+
+ /*
+ * Callers attempting asynchronous flush handle ENOTSUP returns, and
+ * won't make further attempts.
+ */
+ return (block ? 0 : ENOTSUP);
+}
+
+/*
+ * __im_handle_truncate --
+ * POSIX ftruncate.
+ */
+static int
+__im_handle_truncate(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset)
+{
+ WT_DECL_RET;
+ WT_IM *im;
+ size_t off;
+
+ im = S2C(session)->inmemory;
+ __wt_spin_lock(session, &im->lock);
+
+ /*
+ * Grow the buffer as necessary, clear any new space in the file,
+ * and reset the file's data length.
+ */
+ off = (size_t)offset;
+ WT_ERR(__wt_buf_grow(session, &fh->buf, off));
+ if (fh->buf.size < off)
+ memset((uint8_t *)
+ fh->buf.data + fh->buf.size, 0, off - fh->buf.size);
+ fh->buf.size = off;
+
+err: __wt_spin_unlock(session, &im->lock);
+ return (ret);
+}
+
+/*
+ * __im_handle_write --
+ * POSIX pwrite.
+ */
+static int
+__im_handle_write(WT_SESSION_IMPL *session,
+ WT_FH *fh, wt_off_t offset, size_t len, const void *buf)
+{
+ WT_DECL_RET;
+ WT_IM *im;
+ size_t off;
+
+ im = S2C(session)->inmemory;
+ __wt_spin_lock(session, &im->lock);
+
+ off = (size_t)offset;
+ WT_ERR(__wt_buf_grow(session, &fh->buf, off + len + 1024));
+
+ memcpy((uint8_t *)fh->buf.data + off, buf, len);
+ if (off + len > fh->buf.size)
+ fh->buf.size = off + len;
+ fh->off = off + len;
+
+err: __wt_spin_unlock(session, &im->lock);
+ if (ret == 0)
+ return (0);
+ WT_RET_MSG(session, ret,
+ "%s: handle-write: failed to write %" WT_SIZET_FMT " bytes at "
+ "offset %" WT_SIZET_FMT,
+ fh->name, len, off);
+}
+
+/*
+ * __im_handle_open --
+ * POSIX fopen/open.
+ */
+static int
+__im_handle_open(WT_SESSION_IMPL *session,
+ WT_FH *fh, const char *path, uint32_t file_type, uint32_t flags)
+{
+ WT_UNUSED(session);
+ WT_UNUSED(path);
+ WT_UNUSED(file_type);
+ WT_UNUSED(flags);
+
+ fh->off = 0;
+ F_SET(fh, WT_FH_IN_MEMORY);
+
+ fh->fh_advise = __im_handle_advise;
+ fh->fh_close = __im_handle_close;
+ fh->fh_getc = __im_handle_getc;
+ fh->fh_lock = __im_handle_lock;
+ fh->fh_printf = __im_handle_printf;
+ fh->fh_read = __im_handle_read;
+ fh->fh_size = __im_handle_size;
+ fh->fh_sync = __im_handle_sync;
+ fh->fh_truncate = __im_handle_truncate;
+ fh->fh_write = __im_handle_write;
+
+ return (0);
+}
+
+/*
+ * __wt_os_inmemory --
+ * Initialize an in-memory configuration.
+ */
+int
+__wt_os_inmemory(WT_SESSION_IMPL *session)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ WT_IM *im;
+
+ conn = S2C(session);
+ im = NULL;
+
+ /* Initialize the in-memory jump table. */
+ conn->file_directory_list = __im_directory_list;
+ conn->file_directory_sync = __im_directory_sync;
+ conn->file_exist = __im_file_exist;
+ conn->file_remove = __im_file_remove;
+ conn->file_rename = __im_file_rename;
+ conn->file_size = __im_file_size;
+ conn->handle_open = __im_handle_open;
+
+ /* Allocate an in-memory structure. */
+ WT_RET(__wt_calloc_one(session, &im));
+ WT_ERR(__wt_spin_init(session, &im->lock, "in-memory I/O"));
+ conn->inmemory = im;
+
+ return (0);
+
+err: __wt_free(session, im);
+ return (ret);
+}
+
+/*
+ * __wt_os_inmemory_cleanup --
+ * Discard an in-memory configuration.
+ */
+int
+__wt_os_inmemory_cleanup(WT_SESSION_IMPL *session)
+{
+ WT_DECL_RET;
+ WT_IM *im;
+
+ if ((im = S2C(session)->inmemory) == NULL)
+ return (0);
+ S2C(session)->inmemory = NULL;
+
+ __wt_spin_destroy(session, &im->lock);
+ __wt_free(session, im);
+
+ return (ret);
+}
diff --git a/src/third_party/wiredtiger/src/os_common/os_fs_stdio.c b/src/third_party/wiredtiger/src/os_common/os_fs_stdio.c
new file mode 100644
index 00000000000..9baba9b6945
--- /dev/null
+++ b/src/third_party/wiredtiger/src/os_common/os_fs_stdio.c
@@ -0,0 +1,239 @@
+/*-
+ * Copyright (c) 2014-2016 MongoDB, Inc.
+ * Copyright (c) 2008-2014 WiredTiger, Inc.
+ * All rights reserved.
+ *
+ * See the file LICENSE for redistribution information.
+ */
+
+#include "wt_internal.h"
+
+/*
+ * __stdio_handle_advise --
+ * POSIX fadvise.
+ */
+static int
+__stdio_handle_advise(WT_SESSION_IMPL *session,
+ WT_FH *fh, wt_off_t offset, wt_off_t len, int advice)
+{
+ WT_UNUSED(offset);
+ WT_UNUSED(len);
+ WT_UNUSED(advice);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-advise", fh->name);
+}
+
+/*
+ * __stdio_handle_allocate --
+ * POSIX fallocate.
+ */
+static int
+__stdio_handle_allocate(
+ WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, wt_off_t len)
+{
+ WT_UNUSED(offset);
+ WT_UNUSED(len);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-allocate", fh->name);
+}
+
+/*
+ * __stdio_handle_close --
+ * ANSI C close/fclose.
+ */
+static int
+__stdio_handle_close(WT_SESSION_IMPL *session, WT_FH *fh)
+{
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-close", fh->name);
+}
+
+/*
+ * __stdio_handle_getc --
+ * ANSI C fgetc.
+ */
+static int
+__stdio_handle_getc(WT_SESSION_IMPL *session, WT_FH *fh, int *chp)
+{
+ WT_UNUSED(chp);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-getc", fh->name);
+}
+
+/*
+ * __stdio_handle_lock --
+ * Lock/unlock a file.
+ */
+static int
+__stdio_handle_lock(WT_SESSION_IMPL *session, WT_FH *fh, bool lock)
+{
+ WT_UNUSED(lock);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-lock", fh->name);
+}
+
+/*
+ * __stdio_handle_map --
+ * Map a file.
+ */
+static int
+__stdio_handle_map(WT_SESSION_IMPL *session,
+ WT_FH *fh, void *p, size_t *lenp, void **mappingcookie)
+{
+ WT_UNUSED(p);
+ WT_UNUSED(lenp);
+ WT_UNUSED(mappingcookie);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-map", fh->name);
+}
+
+/*
+ * __stdio_handle_map_discard --
+ * Discard a section of a mapped region.
+ */
+static int
+__stdio_handle_map_discard(
+ WT_SESSION_IMPL *session, WT_FH *fh, void *p, size_t len)
+{
+ WT_UNUSED(p);
+ WT_UNUSED(len);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-map-discard", fh->name);
+}
+
+/*
+ * __stdio_handle_map_preload --
+ * Preload a section of a mapped region.
+ */
+static int
+__stdio_handle_map_preload(
+ WT_SESSION_IMPL *session, WT_FH *fh, const void *p, size_t len)
+{
+ WT_UNUSED(p);
+ WT_UNUSED(len);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-map-preload", fh->name);
+}
+
+/*
+ * __stdio_handle_map_unmap --
+ * Unmap a file.
+ */
+static int
+__stdio_handle_map_unmap(WT_SESSION_IMPL *session,
+ WT_FH *fh, void *p, size_t len, void **mappingcookie)
+{
+ WT_UNUSED(p);
+ WT_UNUSED(len);
+ WT_UNUSED(mappingcookie);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-map-unmap", fh->name);
+}
+
+/*
+ * __stdio_handle_printf --
+ * ANSI C vfprintf.
+ */
+static int
+__stdio_handle_printf(
+ WT_SESSION_IMPL *session, WT_FH *fh, const char *fmt, va_list ap)
+{
+ if (vfprintf(fh->fp, fmt, ap) >= 0)
+ return (0);
+ WT_RET_MSG(session, EIO, "%s: handle-printf: vfprintf", fh->name);
+}
+
+/*
+ * __stdio_handle_read --
+ * POSIX pread.
+ */
+static int
+__stdio_handle_read(
+ WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, size_t len, void *buf)
+{
+ WT_UNUSED(offset);
+ WT_UNUSED(len);
+ WT_UNUSED(buf);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-read", fh->name);
+}
+
+/*
+ * __stdio_handle_size --
+ * Get the size of a file in bytes, by file handle.
+ */
+static int
+__stdio_handle_size(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t *sizep)
+{
+ WT_UNUSED(sizep);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-size", fh->name);
+}
+
+/*
+ * __stdio_handle_sync --
+ * POSIX fflush/fsync.
+ */
+static int
+__stdio_handle_sync(WT_SESSION_IMPL *session, WT_FH *fh, bool block)
+{
+ WT_UNUSED(block);
+
+ if (fflush(fh->fp) == 0)
+ return (0);
+ WT_RET_MSG(session, __wt_errno(), "%s: handle-sync: fflush", fh->name);
+}
+
+/*
+ * __stdio_handle_truncate --
+ * POSIX ftruncate.
+ */
+static int
+__stdio_handle_truncate(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t len)
+{
+ WT_UNUSED(len);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-truncate", fh->name);
+}
+
+/*
+ * __stdio_handle_write --
+ * POSIX pwrite.
+ */
+static int
+__stdio_handle_write(WT_SESSION_IMPL *session,
+ WT_FH *fh, wt_off_t offset, size_t len, const void *buf)
+{
+ WT_UNUSED(offset);
+ WT_UNUSED(len);
+ WT_UNUSED(buf);
+ WT_RET_MSG(session, ENOTSUP, "%s: handle-write", fh->name);
+}
+
+/*
+ * __stdio_func_init --
+ * Initialize stdio functions.
+ */
+static void
+__stdio_func_init(WT_FH *fh, const char *name, FILE *fp)
+{
+ fh->name = name;
+ fh->fp = fp;
+
+ fh->fh_advise = __stdio_handle_advise;
+ fh->fh_allocate = __stdio_handle_allocate;
+ fh->fh_close = __stdio_handle_close;
+ fh->fh_getc = __stdio_handle_getc;
+ fh->fh_lock = __stdio_handle_lock;
+ fh->fh_map = __stdio_handle_map;
+ fh->fh_map_discard = __stdio_handle_map_discard;
+ fh->fh_map_preload = __stdio_handle_map_preload;
+ fh->fh_map_unmap = __stdio_handle_map_unmap;
+ fh->fh_printf = __stdio_handle_printf;
+ fh->fh_read = __stdio_handle_read;
+ fh->fh_size = __stdio_handle_size;
+ fh->fh_sync = __stdio_handle_sync;
+ fh->fh_truncate = __stdio_handle_truncate;
+ fh->fh_write = __stdio_handle_write;
+}
+
+/*
+ * __wt_os_stdio --
+ * Initialize the stdio configuration.
+ */
+int
+__wt_os_stdio(WT_SESSION_IMPL *session)
+{
+ __stdio_func_init(WT_STDERR(session), "stderr", stderr);
+ __stdio_func_init(WT_STDOUT(session), "stdout", stdout);
+
+ return (0);
+}
diff --git a/src/third_party/wiredtiger/src/os_common/os_getline.c b/src/third_party/wiredtiger/src/os_common/os_getline.c
new file mode 100644
index 00000000000..01e11581edf
--- /dev/null
+++ b/src/third_party/wiredtiger/src/os_common/os_getline.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2014-2016 MongoDB, Inc.
+ * 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, WT_FH *fh)
+{
+ 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));
+
+ for (;;) {
+ WT_RET(fh->fh_getc(session, fh, &c));
+ if (c == EOF)
+ break;
+
+ /* 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;
+ }
+
+ ((char *)buf->mem)[buf->size] = '\0';
+
+ return (0);
+}
diff --git a/src/third_party/wiredtiger/src/os_common/os_getopt.c b/src/third_party/wiredtiger/src/os_common/os_getopt.c
new file mode 100644
index 00000000000..0306ad1d79d
--- /dev/null
+++ b/src/third_party/wiredtiger/src/os_common/os_getopt.c
@@ -0,0 +1,151 @@
+/*-
+ * Public Domain 2014-2016 MongoDB, Inc.
+ * 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_common/os_init.c b/src/third_party/wiredtiger/src/os_common/os_init.c
new file mode 100644
index 00000000000..512216c52a5
--- /dev/null
+++ b/src/third_party/wiredtiger/src/os_common/os_init.c
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2014-2016 MongoDB, Inc.
+ * Copyright (c) 2008-2014 WiredTiger, Inc.
+ * All rights reserved.
+ *
+ * See the file LICENSE for redistribution information.
+ */
+
+#include "wt_internal.h"
+
+/*
+ * __wt_os_init --
+ * Initialize the OS layer.
+ */
+int
+__wt_os_init(WT_SESSION_IMPL *session)
+{
+ return (F_ISSET(S2C(session), WT_CONN_IN_MEMORY) ?
+ __wt_os_inmemory(session) :
+#if defined(_MSC_VER)
+ __wt_os_win(session));
+#else
+ __wt_os_posix(session));
+#endif
+}
+
+/*
+ * __wt_os_cleanup --
+ * Clean up the OS layer.
+ */
+int
+__wt_os_cleanup(WT_SESSION_IMPL *session)
+{
+ return (F_ISSET(S2C(session), WT_CONN_IN_MEMORY) ?
+ __wt_os_inmemory_cleanup(session) :
+#if defined(_MSC_VER)
+ __wt_os_win_cleanup(session));
+#else
+ __wt_os_posix_cleanup(session));
+#endif
+}
diff --git a/src/third_party/wiredtiger/src/os_common/os_strtouq.c b/src/third_party/wiredtiger/src/os_common/os_strtouq.c
new file mode 100644
index 00000000000..0ae604fc761
--- /dev/null
+++ b/src/third_party/wiredtiger/src/os_common/os_strtouq.c
@@ -0,0 +1,25 @@
+/*-
+ * Copyright (c) 2014-2016 MongoDB, Inc.
+ * 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
+}