diff options
38 files changed, 2386 insertions, 4 deletions
diff --git a/SConstruct b/SConstruct new file mode 100644 index 00000000000..28fc1babdeb --- /dev/null +++ b/SConstruct @@ -0,0 +1,135 @@ +# -*- mode: python; -*- +import re +import os + +EnsureSConsVersion( 2, 0, 0 ) + +if not os.sys.platform == "win32": + print ("SConstruct is only supported for Windows, use build_posix for other platforms") + Exit(1) + +AddOption("--enable-zlib", dest="zlib", type="string", nargs=1, action="store", + help="Use zlib compression") + +AddOption("--enable-snappy", dest="snappy", type="string", nargs=1, action="store", + help="Use snappy compression") + +env = Environment( + CPPPATH = ["#/src/include/", "#/."], + CFLAGS = ["/Z7"], + LINKFLAGS = ["/DEBUG"], +) + +useZlib = GetOption("zlib") +useSnappy = GetOption("snappy") +wtlibs = [] + +conf = Configure(env) +if not conf.CheckCHeader('stdlib.h'): + print 'stdlib.h must be installed!' + Exit(1) + +if useZlib: + conf.emv.Append(CPPPATH=[useZlib + "/include"]) + conf.env.Append(LIBPATH=[useZlib + "/lib"]) + if conf.CheckCHeader('zlib.h'): + conf.env.Append(CPPDEFINES=["HAVE_BUILTIN_EXTENSION_ZLIB"]) + wtlibs.append("zlib") + else: + print 'zlib.h must be installed!' + Exit(1) + +if useSnappy: + conf.env.Append(CPPPATH=[useSnappy + "/include"]) + conf.env.Append(LIBPATH=[useSnappy + "/lib"]) + if conf.CheckCHeader('snappy-c.h'): + conf.env.Append(CPPDEFINES=['HAVE_BUILTIN_EXTENSION_SNAPPY']) + wtlibs.append("snappy") + else: + print 'snappy-c.h must be installed!' + Exit(1) + +env = conf.Finish() + +def GenerateWiredTigerH(target, source, env): + # Read the version information from the RELEASE_INFO file + for l in open('build_posix/aclocal/version-set.m4'): + if re.match(r'^VERSION_', l): + exec(l) + + print VERSION_STRING + + replacements = { + '@VERSION_MAJOR@' : VERSION_MAJOR, + '@VERSION_MINOR@' : VERSION_MINOR, + '@VERSION_PATCH@' : VERSION_PATCH, + '@VERSION_STRING@' : VERSION_STRING, + '@uintmax_t_decl@': "", + '@uintptr_t_decl@': "", + '@off_t_decl@' : 'typedef int64_t wt_off_t;', + '@wiredtiger_includes_decl@': + """ +#include <sys/types.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h>" + """ + } + + wt = open("src/include/wiredtiger.in") + out = open("wiredtiger.h", "w") + for l in wt: + lr = l + for r in replacements.items(): + lr = lr.replace(r[0], str(r[1])) + out.write(lr) + + wt.close() + out.close() + + +# +# WiredTiger library +# +filelist = open("dist/filelist") +distFiles = filelist.readlines() +wtsources = [b.strip().replace("os_posix", "os_win") + for b in distFiles + if not b.startswith("#") and len(b) > 1] +filelist.close() + +if useZlib: + wtsources.append("ext/compressors/zlib/zlib_compress.c") + +if useSnappy: + wtsources.append("ext/compressors/snappy/snappy_compress.c") + +#wtsources.append("wiredtiger.h") + +env.Command('wiredtiger.h', 'src/include/wiredtiger.in', GenerateWiredTigerH) + +wtlib = env.Library("wiredtiger", wtsources) + +env.Program("wt", [ + "src/utilities/util_backup.c", + "src/utilities/util_cpyright.c", + "src/utilities/util_compact.c", + "src/utilities/util_create.c", + "src/utilities/util_drop.c", + "src/utilities/util_dump.c", + "src/utilities/util_getopt.c", + "src/utilities/util_list.c", + "src/utilities/util_load.c", + "src/utilities/util_loadtext.c", + "src/utilities/util_main.c", + "src/utilities/util_misc.c", + "src/utilities/util_printlog.c", + "src/utilities/util_read.c", + "src/utilities/util_rename.c", + "src/utilities/util_salvage.c", + "src/utilities/util_stat.c", + "src/utilities/util_upgrade.c", + "src/utilities/util_verbose.c", + "src/utilities/util_verify.c", + "src/utilities/util_write.c"], + LIBS=[wtlib] + wtlibs) diff --git a/ext/compressors/snappy/snappy_compress.c b/ext/compressors/snappy/snappy_compress.c index bece436d6e4..018c7b5da6e 100644 --- a/ext/compressors/snappy/snappy_compress.c +++ b/ext/compressors/snappy/snappy_compress.c @@ -37,7 +37,14 @@ * We need to include the configuration file to detect whether this extension * is being built into the WiredTiger library. */ +#ifndef _WIN32 #include "wiredtiger_config.h" +#else +#include "os_win_wiredtiger_config.h" +#ifdef _MSC_VER +#define inline __inline +#endif +#endif /* Local compressor structure. */ typedef struct { diff --git a/ext/compressors/zlib/zlib_compress.c b/ext/compressors/zlib/zlib_compress.c index 3532ecf16cd..0f33023b166 100644 --- a/ext/compressors/zlib/zlib_compress.c +++ b/ext/compressors/zlib/zlib_compress.c @@ -38,7 +38,14 @@ * We need to include the configuration file to detect whether this extension * is being built into the WiredTiger library. */ +#ifndef _WIN32 #include "wiredtiger_config.h" +#else +#include "os_win_wiredtiger_config.h" +#ifdef _MSC_VER +#define inline __inline +#endif +#endif /* Local compressor structure. */ typedef struct { @@ -80,7 +87,7 @@ zlib_error( * Allocate a scratch buffer. */ static void * -zalloc(void *cookie, u_int number, u_int size) +zalloc(void *cookie, uint32_t number, uint32_t size) { ZLIB_OPAQUE *opaque; WT_EXTENSION_API *wt_api; diff --git a/src/include/intpack.i b/src/include/intpack.i index 9861e671857..881030f855a 100644 --- a/src/include/intpack.i +++ b/src/include/intpack.i @@ -53,10 +53,13 @@ #ifdef __GNUC__ #define WT_LEADING_ZEROS(x, i) \ (i = (x == 0) ? (int)sizeof (x) : __builtin_clzll(x) >> 3) +#elif _MSC_VER +#define WT_LEADING_ZEROS(x, i) \ + (i = (x == 0) ? (int)sizeof (x) : __lzcnt64(x) >> 3) #else #define WT_LEADING_ZEROS(x, i) do { \ uint64_t __x = (x); \ - uint64_t __m = 0xff << 56; \ + uint64_t __m = (uint64_t)0xff << 56; \ for (i = 0; !(__x & __m) && i != 8; i++) \ __m >>= 8; \ } while (0) diff --git a/src/include/msvc.h b/src/include/msvc.h new file mode 100644 index 00000000000..a96b8369e4b --- /dev/null +++ b/src/include/msvc.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ +#include <intrin.h> + +#define inline __inline + +#define WT_GCC_ATTRIBUTE(x) +#define WT_GCC_FUNC_ATTRIBUTE(x) + +#define WT_ATOMIC_ADD(v, val, n, s) \ + (WT_STATIC_ASSERT(sizeof(v) == (n)), \ + _InterlockedExchangeAdd ## s(&(v), val) + val) +#define WT_ATOMIC_CAS(v, old, new, n, s) \ + (WT_STATIC_ASSERT(sizeof(v) == (n)), \ + _InterlockedCompareExchange ## s(&(v), new, old) == old) +#define WT_ATOMIC_CAS_VAL(v, old, new, n, s) \ + (WT_STATIC_ASSERT(sizeof(v) == (n)), \ + _InterlockedCompareExchange ## s(&(v), new, old)) +#define WT_ATOMIC_STORE(v, val, n, s) \ + (WT_STATIC_ASSERT(sizeof(v) == (n)), \ + _InterlockedExchange ## s(&(v), val)) +#define WT_ATOMIC_SUB(v, val, n, s, t) \ + (WT_STATIC_ASSERT(sizeof(v) == (n)), \ + _InterlockedExchangeAdd ## s(&(v), -(t) val) - val) + +#define WT_ATOMIC_ADD1(v, val) WT_ATOMIC_ADD(v, val, 1, 8) +#define WT_ATOMIC_CAS1(v, old, new) WT_ATOMIC_CAS(v, old, new, 1, 8) +#define WT_ATOMIC_CAS_VAL1(v, old, new) WT_ATOMIC_CAS_VAL(v, old, new, 1, 8) +#define WT_ATOMIC_STORE1(v, val) WT_ATOMIC_STORE(v, val, 1, 8) +#define WT_ATOMIC_SUB1(v, val) WT_ATOMIC_SUB(v, val, 1, 8, int8_t) + +#define WT_ATOMIC_ADD2(v, val) WT_ATOMIC_ADD(v, val, 2, 16) +#define WT_ATOMIC_CAS2(v, old, new) WT_ATOMIC_CAS(v, old, new, 2, 16) +#define WT_ATOMIC_CAS_VAL2(v, old, new) WT_ATOMIC_CAS_VAL(v, old, new, 2, 16) +#define WT_ATOMIC_STORE2(v, val) WT_ATOMIC_STORE(v, val, 2, 16) +#define WT_ATOMIC_SUB2(v, val) WT_ATOMIC_SUB(v, val, 2, 16, int16_t) + +#define WT_ATOMIC_ADD4(v, val) WT_ATOMIC_ADD(v, val, 4, ) +#define WT_ATOMIC_CAS4(v, old, new) WT_ATOMIC_CAS(v, old, new, 4, ) +#define WT_ATOMIC_CAS_VAL4(v, old, new) WT_ATOMIC_CAS_VAL(v, old, new, 4, ) +#define WT_ATOMIC_STORE4(v, val) WT_ATOMIC_STORE(v, val, 4, ) +#define WT_ATOMIC_SUB4(v, val) WT_ATOMIC_SUB(v, val, 4, , int32_t) + +#define WT_ATOMIC_ADD8(v, val) WT_ATOMIC_ADD(v, val, 8, 64) +#define WT_ATOMIC_CAS8(v, old, new) WT_ATOMIC_CAS(v, old, new, 8, 64) +#define WT_ATOMIC_CAS_VAL8(v, old, new) WT_ATOMIC_CAS_VAL(v, old, new, 8, 64) +#define WT_ATOMIC_STORE8(v, val) WT_ATOMIC_STORE(v, val, 8, 64) +#define WT_ATOMIC_SUB8(v, val) WT_ATOMIC_SUB(v, val, 8, 64, int64_t) + +static inline void WT_BARRIER(void) { _ReadWriteBarrier(); } +static inline void WT_FULL_BARRIER(void) { _mm_mfence(); } +static inline void WT_PAUSE(void) { _mm_pause(); } +static inline void WT_READ_BARRIER(void) { _mm_lfence(); } +static inline void WT_WRITE_BARRIER(void) { _mm_sfence(); } + diff --git a/src/include/mutex.h b/src/include/mutex.h index 0e8900e8116..97c9c2803f3 100644 --- a/src/include/mutex.h +++ b/src/include/mutex.h @@ -31,6 +31,10 @@ struct __wt_rwlock { const char *name; /* Lock name for debugging */ pthread_rwlock_t rwlock; /* Read/write lock */ + +#ifdef _WIN32 + uint32_t exclusive_locked; +#endif }; /* @@ -44,6 +48,7 @@ struct __wt_rwlock { #define SPINLOCK_PTHREAD_MUTEX 1 #define SPINLOCK_PTHREAD_MUTEX_ADAPTIVE 2 #define SPINLOCK_PTHREAD_MUTEX_LOGGING 3 +#define SPINLOCK_MSVC 4 #if SPINLOCK_TYPE == SPINLOCK_GCC @@ -52,6 +57,7 @@ typedef volatile int #elif SPINLOCK_TYPE == SPINLOCK_PTHREAD_MUTEX ||\ SPINLOCK_TYPE == SPINLOCK_PTHREAD_MUTEX_ADAPTIVE ||\ + SPINLOCK_TYPE == SPINLOCK_MSVC ||\ SPINLOCK_TYPE == SPINLOCK_PTHREAD_MUTEX_LOGGING typedef struct { diff --git a/src/include/mutex.i b/src/include/mutex.i index 052a61562e3..251c22388c1 100644 --- a/src/include/mutex.i +++ b/src/include/mutex.i @@ -288,6 +288,80 @@ __wt_spin_unlock(WT_SESSION_IMPL *session, WT_SPINLOCK *t) pthread_mutex_unlock(&t->lock); } +#elif SPINLOCK_TYPE == SPINLOCK_MSVC + +#define WT_DECL_SPINLOCK_ID(i) \ + static int i = WT_SPINLOCK_REGISTER +#define WT_SPINLOCK_REGISTER -1 +#define WT_SPINLOCK_REGISTER_FAILED -2 + +#define __wt_spin_trylock(session, lock, idp) \ + __wt_spin_trylock_func(session, lock) + +/* + * __wt_spin_init -- + * Initialize a spinlock. + */ +static inline int +__wt_spin_init(WT_SESSION_IMPL *session, WT_SPINLOCK *t, const char *name) +{ + WT_UNUSED(session); + WT_UNUSED(name); + + InitializeCriticalSectionAndSpinCount(&t->lock, 4000); + + return (0); +} + +/* + * __wt_spin_destroy -- + * Destroy a spinlock. + */ +static inline void +__wt_spin_destroy(WT_SESSION_IMPL *session, WT_SPINLOCK *t) +{ + WT_UNUSED(session); + + DeleteCriticalSection(&t->lock); +} + +/* + * __wt_spin_trylock_func -- + * Try to lock a spinlock or fail immediately if it is busy. + */ +static inline int +__wt_spin_trylock_func(WT_SESSION_IMPL *session, WT_SPINLOCK *t) +{ + WT_UNUSED(session); + + BOOL b = TryEnterCriticalSection(&t->lock); + return b == 0 ? EBUSY : 0; +} + +/* + * __wt_spin_lock -- + * Spin until the lock is acquired. + */ +static inline void +__wt_spin_lock(WT_SESSION_IMPL *session, WT_SPINLOCK *t) +{ + WT_UNUSED(session); + + EnterCriticalSection(&t->lock); +} + +/* + * __wt_spin_unlock -- + * Release the spinlock. + */ +static inline void +__wt_spin_unlock(WT_SESSION_IMPL *session, WT_SPINLOCK *t) +{ + WT_UNUSED(session); + + LeaveCriticalSection(&t->lock); +} + #else #error Unknown spinlock type diff --git a/src/include/os.h b/src/include/os.h index 9a5da28d2c3..1b37301a841 100644 --- a/src/include/os.h +++ b/src/include/os.h @@ -1,3 +1,4 @@ + /*- * Copyright (c) 2008-2014 WiredTiger, Inc. * All rights reserved. @@ -51,7 +52,11 @@ struct __wt_fh { WT_SPINLOCK lock; /* Handle lock */ +#ifndef _WIN32 int fd; /* POSIX file handle */ +#else + HANDLE filehandle; /* Windows file handle */ +#endif wt_off_t size; /* File size */ wt_off_t extend_size; /* File extended size */ wt_off_t extend_len; /* File extend chunk size */ diff --git a/src/include/os_win_wiredtiger_config.h b/src/include/os_win_wiredtiger_config.h new file mode 100644 index 00000000000..9c20b8d33ac --- /dev/null +++ b/src/include/os_win_wiredtiger_config.h @@ -0,0 +1,189 @@ +/* wiredtiger_config.h. Generated from config.hin by configure. */ +/* build_posix/config.hin. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* Define to 1 to pause for debugger attach on failure. */ +/* #undef HAVE_ATTACH */ + +/* Build the LevelDB API with Basho LevelDB support. */ +/* #undef HAVE_BASHOLEVELDB */ + +/* Snappy support automatically loaded. */ +/* #undef HAVE_BUILTIN_EXTENSION_SNAPPY */ + +/* Zlib support automatically loaded. */ +/* #undef HAVE_BUILTIN_EXTENSION_ZLIB */ + +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Define to 1 for diagnostic tests. */ +/* #undef HAVE_DIAGNOSTIC */ + +/* Define to 1 if you have the <dlfcn.h> header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have the `fallocate' function. */ +/* #undef HAVE_FALLOCATE */ + +/* Define to 1 if you have the `fcntl' function. */ +/* #undef HAVE_FCNTL 1 */ + +/* Define to 1 if you have the `fdatasync' function. */ +/* #undef HAVE_FDATASYNC */ + +/* Define to 1 if you have the `fread_unlocked' function. */ +/* #undef HAVE_FREAD_UNLOCKED */ + +/* Define to 1 if you have the `ftruncate' function. */ +/* #undef HAVE_FTRUNCATE */ + +/* Define to 1 if you have the `gettimeofday' function. */ +/* #undef HAVE_GETTIMEOFDAY */ + +/* Build the LevelDB API with HyperLevelDB support. */ +/* #undef HAVE_HYPERLEVELDB */ + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `bz2' library (-lbz2). */ +/* #undef HAVE_LIBBZ2 */ + +/* Define to 1 if you have the `dl' library (-ldl). */ +/* #undef HAVE_LIBDL */ + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +/* #undef HAVE_LIBPTHREAD */ + +/* Define to 1 if you have the `rt' library (-lrt). */ +/* #undef HAVE_LIBRT */ + +/* Define to 1 if you have the `snappy' library (-lsnappy). */ +/* #undef HAVE_LIBSNAPPY */ + +/* Define to 1 if you have the `z' library (-lz). */ +/* #undef HAVE_LIBZ */ + +/* Define to 1 if you have the <memory.h> header file. */ +/* #undef HAVE_MEMORY_H */ + +/* Define if adaptive mutexes are supported. */ +/* #undef HAVE_MUTEX_ADAPTIVE */ + +/* Define to 1 if you have the `posix_fadvise' function. */ +/* #undef HAVE_POSIX_FADVISE */ + +/* Define to 1 if you have the `posix_fallocate' function. */ +/* #undef HAVE_POSIX_FALLOCATE */ + +/* Define to 1 if you have the `posix_madvise' function. */ +/* #undef HAVE_POSIX_MADVISE */ + +/* Define to 1 if you have the `posix_memalign' function. */ +/* #undef HAVE_POSIX_MEMALIGN */ + +/* Define to 1 if you have the <pthread_np.h> header file. */ +/* #undef HAVE_PTHREAD_NP_H */ + +/* Build the LevelDB API with RocksDB support. */ +/* #undef HAVE_ROCKSDB */ + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +/* #undef HAVE_STRINGS_H */ + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strtouq' function. */ +/* #undef HAVE_STRTOUQ */ + +/* Define to 1 if you have the `sync_file_range' function. */ +/* #undef HAVE_SYNC_FILE_RANGE */ + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +/* #undef HAVE_UNISTD_H */ + +/* Enable verbose message configuration. */ +/* #undef HAVE_VERBOSE */ + +/* The size of `char', as computed by sizeof. */ +#define SIZEOF_CHAR 1 + +/* The size of `char *', as computed by sizeof. */ +#define SIZEOF_CHAR_P 8 + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* The size of `long long', as computed by sizeof. */ +#define SIZEOF_LONG_LONG 8 + +/* The size of `short', as computed by sizeof. */ +#define SIZEOF_SHORT 2 + +/* The size of `unsigned char', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_CHAR 1 + +/* The size of `unsigned int', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_INT 4 + +/* The size of `unsigned long', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_LONG 8 + +/* The size of `unsigned long long', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_LONG_LONG 8 + +/* The size of `unsigned short', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_SHORT 2 + + +/* Spinlock type from mutex.h. */ +#define SPINLOCK_TYPE SPINLOCK_MSVC + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Default alignment of buffers used for I/O */ +#define WT_BUFFER_ALIGNMENT_DEFAULT 0 + +/* Enable large inode numbers on Mac OS X 10.5. */ +/* #ifndef _DARWIN_USE_64_BIT_INODE */ +/* # define _DARWIN_USE_64_BIT_INODE 1 */ +/* #endif */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ diff --git a/src/include/os_windows.h b/src/include/os_windows.h new file mode 100644 index 00000000000..da243074b96 --- /dev/null +++ b/src/include/os_windows.h @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +/* + * Windows does use support Posix Threads + * WT needs it so we mock it up with the Windows concurrency primitives + * Assumes Windows 7+/2008 R2+ + */ +typedef CRITICAL_SECTION pthread_mutex_t; + +typedef CONDITION_VARIABLE pthread_cond_t; + +typedef SRWLOCK pthread_rwlock_t; + +typedef HANDLE pthread_t; + +/* Timespec is a POSIX structure not defined in Windows*/ +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; + +#define strncasecmp _strnicmp + +/* + * Windows Portability stuff + * These are POSIX types which Windows lacks + * Eventually WiredTiger will migrate away from these types + */ +typedef uint32_t u_int; +typedef unsigned char u_char; +typedef unsigned long u_long; + +/* < VS 2013 is not C99 compat */ +#if _MSC_VER < 1900 +#define snprintf _snprintf +#endif + +/* + * Windows does have ssize_t + * Python headers declare also though so we need to guard it + */ +#ifndef HAVE_SSIZE_T +typedef int ssize_t; +#endif + +/* + * Provide a custom version of vsnprintf that returns the + * needed buffer length instead of -1 on truncation + */ +#define vsnprintf _wt_vsnprintf + +_Check_return_opt_ int __cdecl _wt_vsnprintf( + _Out_writes_(_MaxCount) char * _DstBuf, + _In_ size_t _MaxCount, + _In_z_ _Printf_format_string_ const char * _Format, + va_list _ArgList); + +/* Provide a custom version of localtime_r */ +struct tm *localtime_r(const time_t* timer, struct tm* result); diff --git a/src/include/wt_internal.h b/src/include/wt_internal.h index 08e8db83d68..f980b681b8f 100644 --- a/src/include/wt_internal.h +++ b/src/include/wt_internal.h @@ -12,31 +12,49 @@ extern "C" { /******************************************* * WiredTiger public include file, and configuration control. *******************************************/ +#ifndef _WIN32 #include "wiredtiger_config.h" +#else +#include "os_win_wiredtiger_config.h" +#endif #include "wiredtiger_ext.h" /******************************************* * WiredTiger system include files. *******************************************/ +#ifndef _WIN32 #include <sys/mman.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/uio.h> - +#endif #include <ctype.h> +#ifndef _WIN32 #include <dlfcn.h> +#endif #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <limits.h> +#ifndef _WIN32 #include <pthread.h> +#endif #ifdef HAVE_PTHREAD_NP_H #include <pthread_np.h> #endif #include <stddef.h> +#include <stdio.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> +#ifndef _WIN32 #include <unistd.h> +#endif +#include <time.h> +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif /******************************************* * WiredTiger externally maintained include files. @@ -255,10 +273,13 @@ struct __wt_update; #include "lint.h" #elif defined(__GNUC__) #include "gcc.h" +#elif defined(_MSC_VER) +#include "msvc.h" #endif #include "hardware.h" #include "misc.h" +#include "os_windows.h" #include "mutex.h" #include "posix.h" diff --git a/src/os_win/os_abort.c b/src/os_win/os_abort.c new file mode 100644 index 00000000000..3d99ffe20b2 --- /dev/null +++ b/src/os_win/os_abort.c @@ -0,0 +1,26 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_abort -- + * Abort the process, dropping core. + */ +void +__wt_abort(WT_SESSION_IMPL *session) + WT_GCC_FUNC_ATTRIBUTE((noreturn)) +{ + __wt_errx(session, "aborting WiredTiger library"); + +#ifdef HAVE_DIAGNOSTIC + __wt_attach(session); +#endif + + abort(); + /* NOTREACHED */ +} diff --git a/src/os_win/os_alloc.c b/src/os_win/os_alloc.c new file mode 100644 index 00000000000..875a4c001b8 --- /dev/null +++ b/src/os_win/os_alloc.c @@ -0,0 +1,234 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * There's no malloc interface, WiredTiger never calls malloc. + * + * The problem is an application might allocate memory, write secret stuff in + * it, free the memory, then WiredTiger allocates the memory and uses it for a + * file page or log record, then writes it to disk, without having overwritten + * it fully. That results in the secret stuff being protected by WiredTiger's + * permission mechanisms, potentially inappropriate for the secret stuff. + */ + +/* + * __wt_calloc -- + * ANSI calloc function. + */ +int +__wt_calloc(WT_SESSION_IMPL *session, size_t number, size_t size, void *retp) +{ + void *p; + + /* + * !!! + * This function MUST handle a NULL WT_SESSION_IMPL handle. + */ + WT_ASSERT(session, number != 0 && size != 0); + + if (session != NULL) + WT_STAT_FAST_CONN_INCR(session, memory_allocation); + + if ((p = calloc(number, size)) == NULL) + WT_RET_MSG(session, __wt_errno(), "memory allocation"); + + *(void **)retp = p; + return (0); +} + +/* + * __wt_realloc -- + * ANSI realloc function. + */ +int +__wt_realloc(WT_SESSION_IMPL *session, + size_t *bytes_allocated_ret, size_t bytes_to_allocate, void *retp) +{ + void *p; + size_t bytes_allocated; + + /* + * !!! + * This function MUST handle a NULL WT_SESSION_IMPL handle. + * + * Sometimes we're allocating memory and we don't care about the + * final length -- bytes_allocated_ret may be NULL. + */ + p = *(void **)retp; + bytes_allocated = + (bytes_allocated_ret == NULL) ? 0 : *bytes_allocated_ret; + WT_ASSERT(session, + (p == NULL && bytes_allocated == 0) || + (p != NULL && + (bytes_allocated_ret == NULL || bytes_allocated != 0))); + WT_ASSERT(session, bytes_to_allocate != 0); + WT_ASSERT(session, bytes_allocated < bytes_to_allocate); + + if (session != NULL) { + if (p == NULL) + WT_STAT_FAST_CONN_INCR(session, memory_allocation); + else + WT_STAT_FAST_CONN_INCR(session, memory_grow); + } + + if ((p = realloc(p, bytes_to_allocate)) == NULL) + WT_RET_MSG(session, __wt_errno(), "memory allocation"); + + /* + * Clear the allocated memory -- an application might: allocate memory, + * write secret stuff into it, free the memory, then we re-allocate the + * memory and use it for a file page or log record, and then write it to + * disk. That would result in the secret stuff being protected by the + * WiredTiger permission mechanisms, potentially inappropriate for the + * secret stuff. + */ + memset((uint8_t *) + p + bytes_allocated, 0, bytes_to_allocate - bytes_allocated); + + /* Update caller's bytes allocated value. */ + if (bytes_allocated_ret != NULL) + *bytes_allocated_ret = bytes_to_allocate; + + *(void **)retp = p; + return (0); +} + +/* + * __wt_realloc_aligned -- + * ANSI realloc function that aligns to buffer boundaries, configured with + * the "buffer_alignment" key to wiredtiger_open. + */ +int +__wt_realloc_aligned(WT_SESSION_IMPL *session, + size_t *bytes_allocated_ret, size_t bytes_to_allocate, void *retp) +{ + WT_DECL_RET; + + /* + * !!! + * This function MUST handle a NULL WT_SESSION_IMPL handle. + */ + if (session != NULL && S2C(session)->buffer_alignment > 0) { + void *p, *newp; + size_t bytes_allocated; + + /* + * Sometimes we're allocating memory and we don't care about the + * final length -- bytes_allocated_ret may be NULL. + */ + p = *(void **)retp; + bytes_allocated = + (bytes_allocated_ret == NULL) ? 0 : *bytes_allocated_ret; + WT_ASSERT(session, + (p == NULL && bytes_allocated == 0) || + (p != NULL && + (bytes_allocated_ret == NULL || bytes_allocated != 0))); + WT_ASSERT(session, bytes_to_allocate != 0); + WT_ASSERT(session, bytes_allocated < bytes_to_allocate); + + if (session != NULL) + WT_STAT_FAST_CONN_INCR(session, memory_allocation); + + if ((newp = _aligned_malloc( + S2C(session)->buffer_alignment, + bytes_to_allocate)) != 0) + WT_RET_MSG(session, errno, "memory allocation"); + + if (p != NULL) + memcpy(newp, p, bytes_allocated); + __wt_free(session, p); + p = newp; + + /* Clear the allocated memory (see above). */ + memset((uint8_t *)p + bytes_allocated, 0, + bytes_to_allocate - bytes_allocated); + + /* Update caller's bytes allocated value. */ + if (bytes_allocated_ret != NULL) + *bytes_allocated_ret = bytes_to_allocate; + + *(void **)retp = p; + return (0); + } + + /* + * If there is no posix_memalign function, or no alignment configured, + * fall back to realloc. + */ + return (__wt_realloc( + session, bytes_allocated_ret, bytes_to_allocate, retp)); +} + +/* + * __wt_strndup -- + * Duplicate a byte string of a given length (and NUL-terminate). + */ +int +__wt_strndup(WT_SESSION_IMPL *session, const void *str, size_t len, void *retp) +{ + void *p; + + if (str == NULL) { + *(void **)retp = NULL; + return (0); + } + + WT_RET(__wt_calloc(session, len + 1, 1, &p)); + + /* + * Don't change this to strncpy, we rely on this function to duplicate + * "strings" that contain nul bytes. + */ + memcpy(p, str, len); + + *(void **)retp = p; + return (0); +} + +/* + * __wt_strdup -- + * ANSI strdup function. + */ +int +__wt_strdup(WT_SESSION_IMPL *session, const char *str, void *retp) +{ + return (__wt_strndup( + session, str, (str == NULL) ? 0 : strlen(str), retp)); +} + +/* + * __wt_free_int -- + * ANSI free function. + */ +void +__wt_free_int(WT_SESSION_IMPL *session, const void *p_arg) +{ + void *p; + + p = *(void **)p_arg; + if (p == NULL) /* ANSI C free semantics */ + return; + + /* + * If there's a serialization bug we might race with another thread. + * We can't avoid the race (and we aren't willing to flush memory), + * but we minimize the window by clearing the free address, hoping a + * racing thread will see, and won't free, a NULL pointer. + */ + *(void **)p_arg = NULL; + + /* + * !!! + * This function MUST handle a NULL WT_SESSION_IMPL handle. + */ + if (session != NULL) + WT_STAT_FAST_CONN_INCR(session, memory_free); + + free(p); +} diff --git a/src/os_win/os_dir.c b/src/os_win/os_dir.c new file mode 100644 index 00000000000..3f1dd0102d9 --- /dev/null +++ b/src/os_win/os_dir.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_dirlist -- + * Get a list of files from a directory, optionally filtered by + * a given prefix. + */ +int +__wt_dirlist(WT_SESSION_IMPL *session, const char *dir, const char *prefix, + uint32_t flags, char ***dirlist, u_int *countp) +{ + WT_DECL_RET; + WIN32_FIND_DATA finddata; + HANDLE findhandle = INVALID_HANDLE_VALUE; + size_t dirallocsz; + u_int count, dirsz; + int match; + char **entries, *path; + int pathlen; + + count = 0; + *dirlist = NULL; + *countp = 0; + + WT_RET(__wt_filename(session, dir, &path)); + + pathlen = strlen(path); + if (path[pathlen - 1] == '\\') { + path[pathlen - 1] = '\0'; + } + + dirallocsz = 0; + dirsz = 0; + entries = NULL; + if (flags == 0) + LF_SET(WT_DIRLIST_INCLUDE); + + WT_ERR(__wt_verbose(session, WT_VERB_FILEOPS, + "wt_dirlist of %s %s prefix %s", + path, LF_ISSET(WT_DIRLIST_INCLUDE) ? "include" : "exclude", + prefix == NULL ? "all" : prefix)); + + findhandle = FindFirstFile(path, &finddata); + + if (INVALID_HANDLE_VALUE == findhandle) + WT_ERR_MSG(session, __wt_errno(), "%s: FindFirstFile", path); + else { + do { + /* + * Skip . and .. + */ + if (strcmp(finddata.cFileName, ".") == 0 || + strcmp(finddata.cFileName, "..") == 0) + continue; + match = 0; + if (prefix != NULL && + ((LF_ISSET(WT_DIRLIST_INCLUDE) && + WT_PREFIX_MATCH(finddata.cFileName, prefix)) || + (LF_ISSET(WT_DIRLIST_EXCLUDE) && + !WT_PREFIX_MATCH(finddata.cFileName, prefix)))) + match = 1; + if (prefix == NULL || match) { + /* + * We have a file name we want to return. + */ + count++; + if (count > dirsz) { + dirsz += WT_DIR_ENTRY; + WT_ERR(__wt_realloc_def( + session, &dirallocsz, dirsz, &entries)); + } + WT_ERR(__wt_strdup( + session, finddata.cFileName, &entries[count - 1])); + } + } while (FindNextFile(findhandle, &finddata) != 0); + } + + if (count > 0) + *dirlist = entries; + *countp = count; +err: + if (findhandle != NULL) + (void)FindClose(findhandle); + __wt_free(session, path); + + if (ret == 0) + return (0); + + if (*dirlist != NULL) { + for (count = dirsz; count > 0; count--) + __wt_free(session, entries[count]); + __wt_free(session, entries); + } + + WT_RET_MSG(session, ret, "dirlist %s prefix %s", dir, prefix); +} diff --git a/src/os_win/os_dlopen.c b/src/os_win/os_dlopen.c new file mode 100644 index 00000000000..71ab6e191b9 --- /dev/null +++ b/src/os_win/os_dlopen.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_dlopen -- + * Open a dynamic library. + */ +int +__wt_dlopen(WT_SESSION_IMPL *session, const char *path, WT_DLH **dlhp) +{ + WT_DECL_RET; + WT_DLH *dlh; + + WT_RET(__wt_calloc_def(session, 1, &dlh)); + WT_ERR(__wt_strdup(session, path, &dlh->name)); + + /* NULL means load from the current binary */ + if (path == NULL) { + ret = GetModuleHandleEx(0, NULL, &dlh->handle); + if (ret == FALSE) + WT_ERR_MSG( + session, __wt_errno(), "GetModuleHandleEx(%s): %s", path, 0); + } else { + // TODO: load dll here + DebugBreak(); + } + + /* Windows returns 0 on failure, WT expects 0 on success */ + ret = !ret; + + *dlhp = dlh; + if (0) { +err: __wt_free(session, dlh->name); + __wt_free(session, dlh); + } + return (ret); +} + +/* + * __wt_dlsym -- + * Lookup a symbol in a dynamic library. + */ +int +__wt_dlsym(WT_SESSION_IMPL *session, + WT_DLH *dlh, const char *name, int fail, void *sym_ret) +{ + void *sym; + + *(void **)sym_ret = NULL; + + sym = GetProcAddress(dlh->handle, name); + if (sym == NULL && fail) { + WT_RET_MSG(session, __wt_errno(), + "GetProceAddress(%s in %s): %s", name, dlh->name, 0); + } + + *(void **)sym_ret = sym; + return (0); +} + +/* + * __wt_dlclose -- + * Close a dynamic library + */ +int +__wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh) +{ + WT_DECL_RET; + + if ((ret = FreeLibrary(dlh->handle)) == FALSE) { + __wt_err(session, __wt_errno(), "FreeLibrary"); + } + + /* Windows returns 0 on failure, WT expects 0 on success */ + ret = !ret; + + __wt_free(session, dlh->name); + __wt_free(session, dlh); + return (ret); +} diff --git a/src/os_win/os_errno.c b/src/os_win/os_errno.c new file mode 100644 index 00000000000..23d006cac85 --- /dev/null +++ b/src/os_win/os_errno.c @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_errno -- + * Return errno, or WT_ERROR if errno not set. + */ +int +__wt_errno(void) +{ + /* + * Called when we know an error occurred, and we want the system + * error code, but there's some chance it's not set. + */ + DWORD err = GetLastError(); + + /* GLE should only be called if we hit an actual error */ + WT_ASSERT(NULL, err != ERROR_SUCCESS); + + return (err == ERROR_SUCCESS ? WT_ERROR : err); +} diff --git a/src/os_win/os_exist.c b/src/os_win/os_exist.c new file mode 100644 index 00000000000..5b164715321 --- /dev/null +++ b/src/os_win/os_exist.c @@ -0,0 +1,32 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_exist -- + * Return if the file exists. + */ +int +__wt_exist(WT_SESSION_IMPL *session, const char *filename, int *existp) +{ + WT_DECL_RET; + char *path; + + WT_RET(__wt_filename(session, filename, &path)); + + ret = GetFileAttributes(path); + + __wt_free(session, path); + + if (ret != INVALID_FILE_ATTRIBUTES) + *existp = 1; + else + *existp = 0; + + return (0); +} diff --git a/src/os_win/os_fallocate.c b/src/os_win/os_fallocate.c new file mode 100644 index 00000000000..f57ff693a14 --- /dev/null +++ b/src/os_win/os_fallocate.c @@ -0,0 +1,28 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_fallocate -- + * Allocate space for a file handle. + */ +int +__wt_fallocate(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, wt_off_t len) +{ + WT_DECL_RET; + + WT_RET(__wt_verbose( + session, WT_VERB_FILEOPS, "%s: fallocate", fh->name)); + + ret = 0; + + if (ret != 0) + WT_RET_MSG(session, __wt_errno(), "%s: ftruncate", fh->name); + + return (0); +} diff --git a/src/os_win/os_filesize.c b/src/os_win/os_filesize.c new file mode 100644 index 00000000000..2aebf979dc7 --- /dev/null +++ b/src/os_win/os_filesize.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_filesize -- + * Get the size of a file in bytes. + */ +int +__wt_filesize(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t *sizep) +{ + WT_DECL_RET; + LARGE_INTEGER size; + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "%s: GetFileSizeEx", fh->name)); + + if ((ret = GetFileSizeEx(fh->filehandle, &size)) != 0) { + *sizep = size.QuadPart; + return (0); + } + + WT_RET_MSG(session, __wt_errno(), "%s: GetFileSizeEx", fh->name); +} + +/* + * __wt_filesize_name -- + * Return the size of a file in bytes, given a file name. + */ +int +__wt_filesize_name(WT_SESSION_IMPL *session, const char *filename, wt_off_t *sizep) +{ + WT_DECL_RET; + WIN32_FILE_ATTRIBUTE_DATA data; + char *path; + + WT_RET(__wt_filename(session, filename, &path)); + + ret = GetFileAttributesEx(filename, GetFileExInfoStandard, &data); + + __wt_free(session, path); + + if (ret != 0) { + *sizep = ((int64_t)data.nFileSizeHigh << 32) | data.nFileSizeLow; + return (0); + } + + WT_RET_MSG(session, __wt_errno(), "%s: GetFileAttributesEx", filename); +} diff --git a/src/os_win/os_flock.c b/src/os_win/os_flock.c new file mode 100644 index 00000000000..09ca5191637 --- /dev/null +++ b/src/os_win/os_flock.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_bytelock -- + * Lock/unlock a byte in a file. + */ +int +__wt_bytelock(WT_FH *fhp, wt_off_t byte, int lock) +{ + WT_DECL_RET; + + /* + * WiredTiger requires this function be able to acquire locks past + * the end of file. + * + * Note we're using fcntl(2) locking: all fcntl locks associated with a + * file for a given process are removed when any file descriptor for the + * file is closed by the process, even if a lock was never requested for + * that file descriptor. + */ + /* + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa365202%28v=vs.85%29.aspx + * + * You can lock bytes that are beyond the end of the current file. + * This is useful to coordinate adding records to the end of a file. + */ + if (lock) { + ret = LockFile(fhp->filehandle, UINT32_MAX & byte, + UINT32_MAX & (byte >> 32), 1, 0); + } + else + { + ret = UnlockFile(fhp->filehandle, UINT32_MAX & byte, + UINT32_MAX & (byte >> 32), 1, 0); + } + + if (ret == FALSE) + WT_RET_MSG(NULL, __wt_errno(), "%s: LockFile", fhp->name); + + return (0); +} diff --git a/src/os_win/os_fsync.c b/src/os_win/os_fsync.c new file mode 100644 index 00000000000..bdb255a149b --- /dev/null +++ b/src/os_win/os_fsync.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_fsync -- + * Flush a file handle. + */ +int +__wt_fsync(WT_SESSION_IMPL *session, WT_FH *fh) +{ + WT_DECL_RET; + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "%s: FlushFileBuffers", + fh->name)); + + if ((ret = FlushFileBuffers(fh->filehandle)) == FALSE) + WT_RET_MSG(session, __wt_errno(), "%s FlushFileBuffers error", fh->name); + + return (0); +} + +/* + * __wt_fsync_async -- + * Flush a file handle and don't wait for the result. + */ +int +__wt_fsync_async(WT_SESSION_IMPL *session, WT_FH *fh) +{ + WT_UNUSED(session); + WT_UNUSED(fh); + return (0); +} diff --git a/src/os_win/os_ftruncate.c b/src/os_win/os_ftruncate.c new file mode 100644 index 00000000000..086bc34b127 --- /dev/null +++ b/src/os_win/os_ftruncate.c @@ -0,0 +1,32 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_ftruncate -- + * Truncate a file. + */ +int +__wt_ftruncate(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t len) +{ + WT_DECL_RET; + LARGE_INTEGER largeint; + + largeint.QuadPart = len; + + if ((ret = SetFilePointerEx(fh->filehandle, largeint, NULL, FILE_BEGIN)) == FALSE) + WT_RET_MSG(session, __wt_errno(), "%s SetFilePointerEx error", + fh->name); + + if ((ret = SetEndOfFile(fh->filehandle)) != FALSE) { + fh->size = fh->extend_size = len; + return (0); + } + + WT_RET_MSG(session, __wt_errno(), "%s SetEndofFile error", fh->name); +} diff --git a/src/os_win/os_getline.c b/src/os_win/os_getline.c new file mode 100644 index 00000000000..7ef4065ac3b --- /dev/null +++ b/src/os_win/os_getline.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_getline -- + * Get a line from a stream. + * + * Implementation of the POSIX getline or BSD fgetln functions (finding the + * function in a portable way is hard, it's simple enough to write it instead). + * + * Note: Unlike the standard getline calls, this function doesn't include the + * trailing newline character in the returned buffer and discards empty lines + * (so the caller's EOF marker is a returned line length of 0). + */ +int +__wt_getline(WT_SESSION_IMPL *session, WT_ITEM *buf, FILE *fp) +{ + int c; + + /* + * We always NUL-terminate the returned string (even if it's empty), + * make sure there's buffer space for a trailing NUL in all cases. + */ + WT_RET(__wt_buf_init(session, buf, 100)); + + while ((c = fgetc(fp)) != EOF) { + /* Leave space for a trailing NUL. */ + WT_RET(__wt_buf_extend(session, buf, buf->size + 2)); + if (c == '\n') { + if (buf->size == 0) + continue; + break; + } + ((char *)buf->mem)[buf->size++] = (char)c; + } + if (c == EOF && ferror(fp)) + WT_RET_MSG(session, __wt_errno(), "file read"); + + ((char *)buf->mem)[buf->size] = '\0'; + + return (0); +} diff --git a/src/os_win/os_map.c b/src/os_win/os_map.c new file mode 100644 index 00000000000..105cf47dd51 --- /dev/null +++ b/src/os_win/os_map.c @@ -0,0 +1,92 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_mmap -- + * Map a file into memory. + */ +int +__wt_mmap(WT_SESSION_IMPL *session, WT_FH *fh, void *mapp, size_t *lenp, + void** mappingcookie) +{ + void *map; + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, + "%s: MapViewOfFile %" PRIuMAX " bytes", fh->name, (uintmax_t)fh->size)); + + *mappingcookie = CreateFileMapping(fh->filehandle, NULL, PAGE_READONLY, 0, 0, NULL); + if (*mappingcookie == NULL) + WT_RET_MSG(session, __wt_errno(), + "%s CreateFileMapping error: failed to map %" PRIuMAX " bytes", + fh->name, (uintmax_t)fh->size); + + if ((map = MapViewOfFile(*mappingcookie, FILE_MAP_READ, 0, 0, fh->size)) == NULL) { + CloseHandle(*mappingcookie); + *mappingcookie = NULL; + + WT_RET_MSG(session, __wt_errno(), + "%s map error: failed to map %" PRIuMAX " bytes", + fh->name, (uintmax_t)fh->size); + } + + *(void **)mapp = map; + *lenp = (size_t)fh->size; + return (0); +} + +/* + * __wt_mmap_preload -- + * Cause a section of a memory map to be faulted in. + */ +int +__wt_mmap_preload(WT_SESSION_IMPL *session, const void *p, size_t size) +{ + WT_UNUSED(session); + WT_UNUSED(p); + WT_UNUSED(size); + + return (0); +} + +/* + * __wt_mmap_discard -- + * Discard a chunk of the memory map. + */ +int +__wt_mmap_discard(WT_SESSION_IMPL *session, void *p, size_t size) +{ + WT_UNUSED(session); + WT_UNUSED(p); + WT_UNUSED(size); + return (0); +} + +/* + * __wt_munmap -- + * Remove a memory mapping. + */ +int +__wt_munmap(WT_SESSION_IMPL *session, WT_FH *fh, void *map, size_t len, + void** mappingcookie) +{ + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, + "%s: UnmapViewOfFile %" PRIuMAX " bytes", fh->name, (uintmax_t)len)); + + if (UnmapViewOfFile(map) == 0) { + WT_RET_MSG(session, __wt_errno(), + "%s UnmapViewofFile error: failed to unmap %" PRIuMAX " bytes", + fh->name, (uintmax_t)len); + } + + CloseHandle(*mappingcookie); + + *mappingcookie = 0; + + return (0); +} diff --git a/src/os_win/os_mtx.c b/src/os_win/os_mtx.c new file mode 100644 index 00000000000..a79f01cb32f --- /dev/null +++ b/src/os_win/os_mtx.c @@ -0,0 +1,282 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_cond_alloc -- + * Allocate and initialize a condition variable. + */ +int +__wt_cond_alloc(WT_SESSION_IMPL *session, + const char *name, int is_signalled, WT_CONDVAR **condp) +{ + WT_CONDVAR *cond; + WT_DECL_RET; + + /* + * !!! + * This function MUST handle a NULL session handle. + */ + WT_RET(__wt_calloc(session, 1, sizeof(WT_CONDVAR), &cond)); + + InitializeCriticalSection(&cond->mtx); + + /* Initialize the condition variable to permit self-blocking. */ + InitializeConditionVariable(&cond->cond); + + cond->name = name; + cond->waiters = is_signalled ? -1 : 0; + + *condp = cond; + return (0); + +err: __wt_free(session, cond); + return (ret); +} + +/* + * __wt_cond_wait -- + * Wait on a mutex, optionally timing out. + */ +int +__wt_cond_wait(WT_SESSION_IMPL *session, WT_CONDVAR *cond, long usecs) +{ + WT_DECL_RET; + int locked; + int lasterror; + int milliseconds; + locked = 0; + WT_ASSERT(session, usecs >= 0); + + /* Fast path if already signalled. */ + if (WT_ATOMIC_ADD4(cond->waiters, 1) == 0) + return (0); + + /* + * !!! + * This function MUST handle a NULL session handle. + */ + if (session != NULL) { + WT_RET(__wt_verbose(session, WT_VERB_MUTEX, + "wait %s cond (%p)", cond->name, cond)); + WT_STAT_FAST_CONN_INCR(session, cond_wait); + } + + EnterCriticalSection(&cond->mtx); + locked = 1; + + if (usecs > 0) { + milliseconds = usecs / 1000; + /* 0 would mean the CV sleep becomes a TryCV which we do not want */ + if (milliseconds == 0) + milliseconds = 1; + ret = SleepConditionVariableCS(&cond->cond, &cond->mtx, milliseconds); + } else + ret = SleepConditionVariableCS(&cond->cond, &cond->mtx, INFINITE); + + if (ret == 0) { + lasterror = GetLastError(); + if (lasterror = ERROR_TIMEOUT) { + ret = 1; + } + } + + (void)WT_ATOMIC_SUB4(cond->waiters, 1); + +err: if (locked) + LeaveCriticalSection(&cond->mtx); + if (ret != 0) + return (0); + WT_RET_MSG(session, ret, "SleepConditionVariableCS"); +} + +/* + * __wt_cond_signal -- + * Signal a waiting thread. + */ +int +__wt_cond_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond) +{ + WT_DECL_RET; + int locked; + + locked = 0; + + /* + * !!! + * This function MUST handle a NULL session handle. + */ + if (session != NULL) + WT_RET(__wt_verbose(session, WT_VERB_MUTEX, + "signal %s cond (%p)", cond->name, cond)); + + /* Fast path if already signalled. */ + if (cond->waiters == -1) + return (0); + + if (cond->waiters > 0 || !WT_ATOMIC_CAS4(cond->waiters, 0, -1)) { + EnterCriticalSection(&cond->mtx); + locked = 1; + WakeAllConditionVariable(&cond->cond); + } + +err: if (locked) + LeaveCriticalSection(&cond->mtx); + if (ret == 0) + return (0); + WT_RET_MSG(session, ret, "WakeAllConditionVariable"); +} + +/* + * __wt_cond_destroy -- + * Destroy a condition variable. + */ +int +__wt_cond_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp) +{ + WT_CONDVAR *cond; + WT_DECL_RET; + + cond = *condp; + if (cond == NULL) + return (0); + + /* Do nothing to delete Condition Variable */ + DeleteCriticalSection(&cond->mtx); + __wt_free(session, *condp); + + return (ret); +} + +/* + * __wt_rwlock_alloc -- + * Allocate and initialize a read/write lock. + */ +int +__wt_rwlock_alloc( + WT_SESSION_IMPL *session, WT_RWLOCK **rwlockp, const char *name) +{ + WT_DECL_RET; + WT_RWLOCK *rwlock; + + WT_RET(__wt_calloc(session, 1, sizeof(WT_RWLOCK), &rwlock)); + InitializeSRWLock(&rwlock->rwlock); + + rwlock->exclusive_locked = 0; + rwlock->name = name; + *rwlockp = rwlock; + + WT_ERR(__wt_verbose(session, WT_VERB_MUTEX, + "rwlock: alloc %s (%p)", rwlock->name, rwlock)); + + if (0) { +err: __wt_free(session, rwlock); + } + return (ret); +} + +/* + * __wt_readlock -- + * Get a shared lock. + */ +int +__wt_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) +{ + WT_DECL_RET; + + WT_RET(__wt_verbose(session, WT_VERB_MUTEX, + "rwlock: readlock %s (%p)", rwlock->name, rwlock)); + WT_STAT_FAST_CONN_INCR(session, rwlock_read); + + AcquireSRWLockShared(&rwlock->rwlock); + + return (0); +} + +/* + * __wt_try_writelock -- + * Try to get an exclusive lock, or fail immediately if unavailable. + */ +int +__wt_try_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) +{ + WT_DECL_RET; + + WT_RET(__wt_verbose(session, WT_VERB_MUTEX, + "rwlock: try_writelock %s (%p)", rwlock->name, rwlock)); + WT_STAT_FAST_CONN_INCR(session, rwlock_write); + + ret = TryAcquireSRWLockExclusive(&rwlock->rwlock); + if (ret == 0) + return EBUSY; + + rwlock->exclusive_locked = GetCurrentThreadId(); + return (0); +} + +/* + * __wt_writelock -- + * Wait to get an exclusive lock. + */ +int +__wt_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) +{ + WT_DECL_RET; + + WT_RET(__wt_verbose(session, WT_VERB_MUTEX, + "rwlock: writelock %s (%p)", rwlock->name, rwlock)); + WT_STAT_FAST_CONN_INCR(session, rwlock_write); + + AcquireSRWLockExclusive(&rwlock->rwlock); + + rwlock->exclusive_locked = GetCurrentThreadId(); + + return 0; +} + +/* + * __wt_rwunlock -- + * Release a read/write lock. + */ +int +__wt_rwunlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) +{ + WT_DECL_RET; + + if (rwlock->exclusive_locked != 0) { + rwlock->exclusive_locked = 0; + ReleaseSRWLockExclusive(&rwlock->rwlock); + } else + ReleaseSRWLockShared(&rwlock->rwlock); + + WT_RET(__wt_verbose(session, WT_VERB_MUTEX, + "rwlock: unlock %s (%p)", rwlock->name, rwlock)); +} + +/* + * __wt_rwlock_destroy -- + * Destroy a mutex. + */ +int +__wt_rwlock_destroy(WT_SESSION_IMPL *session, WT_RWLOCK **rwlockp) +{ + WT_DECL_RET; + WT_RWLOCK *rwlock; + + rwlock = *rwlockp; /* Clear our caller's reference. */ + if (rwlock == NULL) + return (0); + + /* Nothing to delete for Slim Reader Writer lock */ + *rwlockp = NULL; + + WT_RET(__wt_verbose(session, WT_VERB_MUTEX, + "rwlock: destroy %s (%p)", rwlock->name, rwlock)); + + __wt_free(session, rwlock); +} diff --git a/src/os_win/os_once.c b/src/os_win/os_once.c new file mode 100644 index 00000000000..f7a1af75e28 --- /dev/null +++ b/src/os_win/os_once.c @@ -0,0 +1,39 @@ +/*- +* Copyright (c) 2008-2014 WiredTiger, Inc. +* All rights reserved. +* +* See the file LICENSE for redistribution information. +*/ + +#include "wt_internal.h" + +/* +* __wt_init_once_callback -- +* Global initialization, run once. +*/ +BOOL CALLBACK _wt_init_once_callback( + _Inout_ PINIT_ONCE InitOnce, + _Inout_opt_ PVOID Parameter, + _Out_opt_ PVOID *Context + ) +{ + void(*init_routine)(void) = Parameter; + + init_routine(); + + return TRUE; +} + +/* +* __wt_library_init -- +* Some things to do, before we do anything else. +*/ +int +__wt_once(void(*init_routine)(void)) +{ + INIT_ONCE once_control = INIT_ONCE_STATIC_INIT; + PVOID lpContext = NULL; + + return !InitOnceExecuteOnce(&once_control, &_wt_init_once_callback, + init_routine, lpContext); +} diff --git a/src/os_win/os_open.c b/src/os_win/os_open.c new file mode 100644 index 00000000000..b81be70ecc1 --- /dev/null +++ b/src/os_win/os_open.c @@ -0,0 +1,206 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __open_directory_sync -- + * Fsync the directory in which we created the file. + */ +static int +__open_directory_sync(WT_SESSION_IMPL *session, char *path) +{ + WT_UNUSED(session); + WT_UNUSED(path); + return (0); +} + +/* + * __wt_open -- + * Open a file handle. + */ +int +__wt_open(WT_SESSION_IMPL *session, + const char *name, int ok_create, int exclusive, int dio_type, WT_FH **fhp) +{ + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + WT_FH *fh, *tfh; + int direct_io, f, matched; + int share_mode; + DWORD dwCreationDisposition; + char *path; + HANDLE filehandle; + + conn = S2C(session); + fh = NULL; + path = NULL; + filehandle = INVALID_HANDLE_VALUE; + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "%s: open", name)); + + /* Increment the reference count if we already have the file open. */ + matched = 0; + __wt_spin_lock(session, &conn->fh_lock); + TAILQ_FOREACH(tfh, &conn->fhqh, q) + if (strcmp(name, tfh->name) == 0) { + ++tfh->refcnt; + *fhp = tfh; + matched = 1; + break; + } + __wt_spin_unlock(session, &conn->fh_lock); + if (matched) + return (0); + + WT_RET(__wt_filename(session, name, &path)); + + share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE; + /* + * Security: + * The application may spawn a new process, and we don't want another + * process to have access to our file handles. + * + * TODO: Set tighter file permissions but set bInheritHandle to false + * to prevent inheritance + */ + + f = FILE_ATTRIBUTE_NORMAL; + + dwCreationDisposition = 0; + if (ok_create) { + dwCreationDisposition = CREATE_NEW; + if (exclusive) + dwCreationDisposition = CREATE_ALWAYS; + } else + dwCreationDisposition = OPEN_EXISTING; + + direct_io = 0; + + if (dio_type && FLD_ISSET(conn->direct_io, dio_type)) { + f |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH; + direct_io = 1; + } + + if (dio_type == WT_FILE_TYPE_LOG && + FLD_ISSET(conn->txn_logsync, WT_LOG_DSYNC)) { + f |= FILE_FLAG_WRITE_THROUGH; + } + + /* Disable read-ahead on trees: it slows down random read workloads. */ + if (dio_type == WT_FILE_TYPE_DATA || + dio_type == WT_FILE_TYPE_CHECKPOINT) + f |= FILE_FLAG_RANDOM_ACCESS; + + filehandle = CreateFile(path, + (GENERIC_READ | GENERIC_WRITE), + share_mode, + NULL, + dwCreationDisposition, + f, + NULL); + if (filehandle == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_FILE_EXISTS && ok_create) + filehandle = CreateFile(path, + (GENERIC_READ | GENERIC_WRITE), + share_mode, + NULL, + OPEN_EXISTING, + f, + NULL); + + if (filehandle == INVALID_HANDLE_VALUE) + WT_ERR_MSG(session, __wt_errno(), + direct_io ? + "%s: open failed with direct I/O configured, some " + "filesystem types do not support direct I/O" : "%s", path); + } + + if (F_ISSET(conn, WT_CONN_CKPT_SYNC)) + WT_ERR(__open_directory_sync(session, path)); + + WT_ERR(__wt_calloc(session, 1, sizeof(WT_FH), &fh)); + WT_ERR(__wt_strdup(session, name, &fh->name)); + fh->filehandle = filehandle; + fh->refcnt = 1; + fh->direct_io = direct_io; + + /* Set the file's size. */ + WT_ERR(__wt_filesize(session, fh, &fh->size)); + + /* Configure file extension. */ + if (dio_type == WT_FILE_TYPE_DATA || + dio_type == WT_FILE_TYPE_CHECKPOINT) + fh->extend_len = conn->data_extend_len; + + /* + * Repeat the check for a match, but then link onto the database's list + * of files. + */ + matched = 0; + __wt_spin_lock(session, &conn->fh_lock); + TAILQ_FOREACH(tfh, &conn->fhqh, q) + if (strcmp(name, tfh->name) == 0) { + ++tfh->refcnt; + *fhp = tfh; + matched = 1; + break; + } + if (!matched) { + TAILQ_INSERT_TAIL(&conn->fhqh, fh, q); + WT_STAT_FAST_CONN_INCR(session, file_open); + + *fhp = fh; + } + __wt_spin_unlock(session, &conn->fh_lock); + if (matched) { +err: if (fh != NULL) { + __wt_free(session, fh->name); + __wt_free(session, fh); + } + if (filehandle != INVALID_HANDLE_VALUE) + (void)CloseHandle(filehandle); + } + + __wt_free(session, path); + return (ret); +} + +/* + * __wt_close -- + * Close a file handle. + */ +int +__wt_close(WT_SESSION_IMPL *session, WT_FH *fh) +{ + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + + conn = S2C(session); + + __wt_spin_lock(session, &conn->fh_lock); + if (fh == NULL || fh->refcnt == 0 || --fh->refcnt > 0) { + __wt_spin_unlock(session, &conn->fh_lock); + return (0); + } + + /* Remove from the list. */ + TAILQ_REMOVE(&conn->fhqh, fh, q); + WT_STAT_FAST_CONN_DECR(session, file_open); + + __wt_spin_unlock(session, &conn->fh_lock); + + /* Discard the memory. */ + if (!CloseHandle(fh->filehandle) != 0) { + ret = __wt_errno(); + __wt_err(session, ret, "%s", fh->name); + } + + __wt_free(session, fh->name); + __wt_free(session, fh); + return (ret); +} diff --git a/src/os_win/os_priv.c b/src/os_win/os_priv.c new file mode 100644 index 00000000000..213209bb2cf --- /dev/null +++ b/src/os_win/os_priv.c @@ -0,0 +1,19 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_has_priv -- + * Return if the process has special privileges, defined as having + * different effective and read UIDs or GIDs. + */ +int +__wt_has_priv(void) +{ + return 0; +} diff --git a/src/os_win/os_remove.c b/src/os_win/os_remove.c new file mode 100644 index 00000000000..b795f59e2d3 --- /dev/null +++ b/src/os_win/os_remove.c @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __remove_file_check -- + * Check if the file is currently open before removing it. + */ +static inline void +__remove_file_check(WT_SESSION_IMPL *session, const char *name) +{ +#ifdef HAVE_DIAGNOSTIC + WT_CONNECTION_IMPL *conn; + WT_FH *fh; + + conn = S2C(session); + fh = NULL; + + /* + * Check if the file is open: it's an error if it is, since a higher + * level should have closed it before removing. + */ + __wt_spin_lock(session, &conn->fh_lock); + TAILQ_FOREACH(fh, &conn->fhqh, q) { + if (strcmp(name, fh->name) == 0) + break; + } + __wt_spin_unlock(session, &conn->fh_lock); + + WT_ASSERT(session, fh == NULL); +#else + WT_UNUSED(session); + WT_UNUSED(name); +#endif +} + +/* + * __wt_remove -- + * Remove a file. + */ +int +__wt_remove(WT_SESSION_IMPL *session, const char *name) +{ + WT_DECL_RET; + char *path; + uint32_t lasterror; + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "%s: remove", name)); + + __remove_file_check(session, name); + + WT_RET(__wt_filename(session, name, &path)); + + if ((ret = DeleteFile(path)) == FALSE) + lasterror = __wt_errno(); + + __wt_free(session, path); + + if (ret != FALSE) + return (0); + + WT_RET_MSG(session, lasterror, "%s: remove", name); +} diff --git a/src/os_win/os_rename.c b/src/os_win/os_rename.c new file mode 100644 index 00000000000..6205256c7a4 --- /dev/null +++ b/src/os_win/os_rename.c @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_rename -- + * Rename a file. + */ +int +__wt_rename(WT_SESSION_IMPL *session, const char *from, const char *to) +{ + WT_DECL_RET; + uint32_t lasterror; + char *from_path, *to_path; + int exists; + + WT_RET(__wt_verbose( + session, WT_VERB_FILEOPS, "rename %s to %s", from, to)); + + from_path = to_path = NULL; + + WT_RET(__wt_filename(session, from, &from_path)); + WT_TRET(__wt_filename(session, to, &to_path)); + + /* Check if file exists since Windows does not override the file if it exists */ + if ((ret = GetFileAttributes(to_path)) != INVALID_FILE_ATTRIBUTES) { + if ((ret = DeleteFile(to_path)) == FALSE){ + lasterror = GetLastError(); + goto err; + } + } + + if ((MoveFile(from_path, to_path)) == FALSE) + lasterror = GetLastError(); + +err: + __wt_free(session, from_path); + __wt_free(session, to_path); + + if (ret != FALSE) + return (0); + + WT_RET_MSG(session, lasterror, "MoveFile %s to %s", from, to); +} diff --git a/src/os_win/os_rw.c b/src/os_win/os_rw.c new file mode 100644 index 00000000000..24830da49a2 --- /dev/null +++ b/src/os_win/os_rw.c @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_read -- + * Read a chunk. + */ +int +__wt_read( + WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, size_t len, void *buf) +{ + size_t chunk; + size_t nr; + uint8_t *addr; + BOOL ret; + OVERLAPPED overlapped = { 0 }; + + nr = 0; + + WT_STAT_FAST_CONN_INCR(session, read_io); + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, + "%s: read %zu bytes at offset %" PRIuMAX, + fh->name, len, (uintmax_t)offset)); + + /* Assert direct I/O is aligned and a multiple of the alignment. */ + WT_ASSERT(session, + !fh->direct_io || + S2C(session)->buffer_alignment == 0 || + (!((uintptr_t)buf & + (uintptr_t)(S2C(session)->buffer_alignment - 1)) && + len >= S2C(session)->buffer_alignment && + len % S2C(session)->buffer_alignment == 0)); + + /* Break reads larger than 1GB into 1GB chunks. */ + for (addr = buf; len > 0; addr += nr, len -= (size_t)nr, offset += nr) { + chunk = WT_MIN(len, WT_GIGABYTE); + overlapped.Offset = UINT32_MAX & offset; + overlapped.OffsetHigh = UINT32_MAX & (offset >> 32); + + if (!ReadFile(fh->filehandle, addr, chunk, &nr, &overlapped)) + WT_RET_MSG(session, nr == 0 ? WT_ERROR : __wt_errno(), + "%s read error: failed to read %zu bytes at " + "offset %" PRIuMAX, + fh->name, chunk, (uintmax_t)offset); + } + return (0); +} + +/* + * __wt_write -- + * Write a chunk. + */ +int +__wt_write(WT_SESSION_IMPL *session, + WT_FH *fh, wt_off_t offset, size_t len, const void *buf) +{ + size_t chunk; + size_t nw; + const uint8_t *addr; + OVERLAPPED overlapped = { 0 }; + + nw = 0; + + WT_STAT_FAST_CONN_INCR(session, write_io); + + WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, + "%s: write %zu bytes at offset %" PRIuMAX, + fh->name, len, (uintmax_t)offset)); + + /* Assert direct I/O is aligned and a multiple of the alignment. */ + WT_ASSERT(session, + !fh->direct_io || + S2C(session)->buffer_alignment == 0 || + (!((uintptr_t)buf & + (uintptr_t)(S2C(session)->buffer_alignment - 1)) && + len >= S2C(session)->buffer_alignment && + len % S2C(session)->buffer_alignment == 0)); + + /* Break writes larger than 1GB into 1GB chunks. */ + for (addr = buf; len > 0; addr += nw, len -= (size_t)nw, offset += nw) { + chunk = WT_MIN(len, WT_GIGABYTE); + overlapped.Offset = UINT32_MAX & offset; + overlapped.OffsetHigh = UINT32_MAX & (offset >> 32); + + if (!WriteFile(fh->filehandle, addr, chunk, &nw, &overlapped)) + WT_RET_MSG(session, __wt_errno(), + "%s write error: failed to write %zu bytes at " + "offset %" PRIuMAX, + fh->name, chunk, (uintmax_t)offset); + } + return (0); +} diff --git a/src/os_win/os_sleep.c b/src/os_win/os_sleep.c new file mode 100644 index 00000000000..b9a8cc2e545 --- /dev/null +++ b/src/os_win/os_sleep.c @@ -0,0 +1,18 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_sleep -- + * Pause the thread of control. + */ +void +__wt_sleep(long seconds, long micro_seconds) +{ + Sleep(seconds * 1000 + micro_seconds / 1000); +} diff --git a/src/os_win/os_strtouq.c b/src/os_win/os_strtouq.c new file mode 100644 index 00000000000..b2a96ac0c10 --- /dev/null +++ b/src/os_win/os_strtouq.c @@ -0,0 +1,45 @@ +/*- + * 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) +{ + WT_STATIC_ASSERT(sizeof(uint64_t) == sizeof(unsigned long long)); + + return (strtoull(nptr, endptr, base)); +} + +#undef vsnprintf + +_Check_return_opt_ int __cdecl _wt_vsnprintf( + _Out_writes_(_MaxCount) char * _DstBuf, + _In_ size_t _MaxCount, + _In_z_ _Printf_format_string_ const char * _Format, + va_list _ArgList) +{ + int len; + + len = (size_t)vsnprintf(_DstBuf, _MaxCount, _Format, _ArgList); + + /* + * The MSVC implementation returns -1 on truncation instead of what it would + * have written. We could iteratively grow the buffer, or + * just ask us how big a buffer they would like + */ + if (len == -1) + { + len = _vscprintf(_Format, _ArgList) + 1; + } + + return len; +} diff --git a/src/os_win/os_thread.c b/src/os_win/os_thread.c new file mode 100644 index 00000000000..d87c96d9816 --- /dev/null +++ b/src/os_win/os_thread.c @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_thread_create -- + * Create a new thread of control. + */ +int +__wt_thread_create(WT_SESSION_IMPL *session, + pthread_t *tidret, void *(*func)(void *), void *arg) +{ + WT_DECL_RET; + + /* Spawn a new thread of control. */ + *tidret = CreateThread(NULL, 0, func, arg, 0, NULL); + if (*tidret != NULL) + return (0); + + + WT_RET_MSG(session, __wt_errno(), "CreateThread"); +} + +/* + * __wt_thread_join -- + * Wait for a thread of control to exit. + */ +int +__wt_thread_join(WT_SESSION_IMPL *session, pthread_t tid) +{ + WT_DECL_RET; + + if ((ret = WaitForSingleObject(tid, INFINITE)) == WAIT_OBJECT_0) + return (0); + + WT_RET_MSG(session, ret, "WaitForSingleObject"); +} diff --git a/src/os_win/os_time.c b/src/os_win/os_time.c new file mode 100644 index 00000000000..9967d88259e --- /dev/null +++ b/src/os_win/os_time.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_seconds -- + * Return the seconds since the Epoch. + */ +int +__wt_seconds(WT_SESSION_IMPL *session, time_t *timep) +{ + struct timespec t; + + WT_RET(__wt_epoch(session, &t)); + + *timep = t.tv_sec; + + return (0); +} + +/* + * __wt_epoch -- + * Return the time since the Epoch. + */ +int +__wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp) +{ + WT_DECL_RET; + uint64_t ns100; + + FILETIME time; + GetSystemTimeAsFileTime(&time); + + ns100 = (((int64_t)time.dwHighDateTime << 32) + time.dwLowDateTime) + - 116444736000000000LL; + tsp->tv_sec = ns100 / 10000000; + tsp->tv_nsec = ns100 * 100; + + return 0; +} + +/* + * localtime_r -- + * Return the current local time + */ + struct tm * +localtime_r(const time_t * timer, struct tm * result) +{ + errno_t err; + + err = localtime_s(timer, result); + if (err != 0) { + __wt_err(NULL, err, "localtime_s"); + return NULL; + } + + return result; +} diff --git a/src/os_win/os_yield.c b/src/os_win/os_yield.c new file mode 100644 index 00000000000..970bfa139d0 --- /dev/null +++ b/src/os_win/os_yield.c @@ -0,0 +1,18 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __wt_yield -- + * Yield the thread of control. + */ +void +__wt_yield(void) +{ + SwitchToThread(); +} diff --git a/src/support/err.c b/src/support/err.c index 0c6ba310e19..c742fc0e87a 100644 --- a/src/support/err.c +++ b/src/support/err.c @@ -145,7 +145,11 @@ __wt_eventv(WT_SESSION_IMPL *session, int msg_event, int error, WT_EVENT_HANDLER *handler; WT_DECL_RET; WT_SESSION *wt_session; +#ifndef _WIN32 pthread_t self; +#else + DWORD self; +#endif struct timespec ts; size_t len, remain, wlen; int prefix_cnt; @@ -191,13 +195,22 @@ __wt_eventv(WT_SESSION_IMPL *session, int msg_event, int error, prefix_cnt = 0; if (__wt_epoch(session, &ts) == 0) { remain = WT_PTRDIFF(end, p); +#ifndef _WIN32 self = pthread_self(); +#else + self = GetCurrentThreadId(); +#endif __wt_raw_to_hex_mem((const uint8_t *)&self, sizeof(self), tid, sizeof(tid)); wlen = (size_t)snprintf(p, remain, "[%" PRIuMAX ":%" PRIuMAX "][%" PRIu64 ":%s]", (uintmax_t)ts.tv_sec, (uintmax_t)ts.tv_nsec / 1000, - (uint64_t)getpid(), tid); +#ifndef _WIN32 + (uint64_t)getpid(), +#else + (uint64_t)GetCurrentProcessId(), +#endif + tid); p = wlen >= remain ? end : p + wlen; prefix_cnt = 1; } diff --git a/src/support/filename.c b/src/support/filename.c index ef242fcc3bc..e62df273ec0 100644 --- a/src/support/filename.c +++ b/src/support/filename.c @@ -50,7 +50,11 @@ __wt_nfilename( else { len = strlen(conn->home) + 1 + namelen + 1; WT_RET(__wt_calloc(session, 1, len, &buf)); +#ifdef _WIN32 + snprintf(buf, len, "%s\\%.*s", conn->home, (int)namelen, name); +#else snprintf(buf, len, "%s/%.*s", conn->home, (int)namelen, name); +#endif *path = buf; } |