diff options
author | Alex Gorrod <alexg@wiredtiger.com> | 2016-04-05 14:43:57 +1000 |
---|---|---|
committer | Alex Gorrod <alexg@wiredtiger.com> | 2016-04-05 14:44:50 +1000 |
commit | de6f136d83b20f8a58ba6fe4ba02be229b6c9159 (patch) | |
tree | 3221d66b54cbf6208fc3c995fdbb36d347ae85ff /src/third_party/wiredtiger/src/os_common | |
parent | 5d1262cc394d685b59ae3185d7315227085e897d (diff) | |
download | mongo-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.c | 193 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/os_common/os_abort.c | 27 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/os_common/os_alloc.c | 308 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/os_common/os_fhandle.c | 306 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/os_common/os_fs_inmemory.c | 482 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/os_common/os_fs_stdio.c | 239 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/os_common/os_getline.c | 51 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/os_common/os_getopt.c | 151 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/os_common/os_init.c | 41 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/os_common/os_strtouq.c | 25 |
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 +} |