summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct135
-rw-r--r--ext/compressors/snappy/snappy_compress.c7
-rw-r--r--ext/compressors/zlib/zlib_compress.c9
-rw-r--r--src/include/intpack.i5
-rw-r--r--src/include/msvc.h59
-rw-r--r--src/include/mutex.h6
-rw-r--r--src/include/mutex.i74
-rw-r--r--src/include/os.h5
-rw-r--r--src/include/os_win_wiredtiger_config.h189
-rw-r--r--src/include/os_windows.h64
-rw-r--r--src/include/wt_internal.h23
-rw-r--r--src/os_win/os_abort.c26
-rw-r--r--src/os_win/os_alloc.c234
-rw-r--r--src/os_win/os_dir.c103
-rw-r--r--src/os_win/os_dlopen.c86
-rw-r--r--src/os_win/os_errno.c27
-rw-r--r--src/os_win/os_exist.c32
-rw-r--r--src/os_win/os_fallocate.c28
-rw-r--r--src/os_win/os_filesize.c53
-rw-r--r--src/os_win/os_flock.c48
-rw-r--r--src/os_win/os_fsync.c38
-rw-r--r--src/os_win/os_ftruncate.c32
-rw-r--r--src/os_win/os_getline.c48
-rw-r--r--src/os_win/os_map.c92
-rw-r--r--src/os_win/os_mtx.c282
-rw-r--r--src/os_win/os_once.c39
-rw-r--r--src/os_win/os_open.c206
-rw-r--r--src/os_win/os_priv.c19
-rw-r--r--src/os_win/os_remove.c68
-rw-r--r--src/os_win/os_rename.c49
-rw-r--r--src/os_win/os_rw.c99
-rw-r--r--src/os_win/os_sleep.c18
-rw-r--r--src/os_win/os_strtouq.c45
-rw-r--r--src/os_win/os_thread.c42
-rw-r--r--src/os_win/os_time.c63
-rw-r--r--src/os_win/os_yield.c18
-rw-r--r--src/support/err.c15
-rw-r--r--src/support/filename.c4
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;
}