summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Bostic <keith@wiredtiger.com>2015-01-06 19:10:41 -0500
committerKeith Bostic <keith@wiredtiger.com>2015-01-06 19:10:41 -0500
commita02d92f9a546d6c326958cd24c2a0276e9bf72ee (patch)
treecff7ea367b546dc44910228dc1dc1ca667a97a20
parent94ac47877329d2e399ac52a110c2fc31814c815f (diff)
parentd9621cb4ba0d66f4b8a73a417dcc7b0635543c55 (diff)
downloadmongo-a02d92f9a546d6c326958cd24c2a0276e9bf72ee.tar.gz
Merge branch 'develop' into mongodb-2.8
-rw-r--r--dist/api_err.py84
-rw-r--r--dist/s_string.ok2
-rw-r--r--dist/s_symbols.list1
-rw-r--r--examples/c/ex_all.c16
-rw-r--r--src/conn/api_strerror.c77
-rw-r--r--src/include/extern.h2
-rw-r--r--src/include/wiredtiger.in19
-rw-r--r--src/lsm/lsm_cursor.c5
-rw-r--r--src/os_posix/os_errno.c46
-rw-r--r--src/os_win/os_errno.c98
-rw-r--r--src/os_win/os_ftruncate.c7
-rw-r--r--src/os_win/os_mtx_cond.c4
-rw-r--r--src/os_win/os_rename.c4
-rw-r--r--test/suite/test_config02.py2
-rw-r--r--test/suite/test_config03.py6
15 files changed, 306 insertions, 67 deletions
diff --git a/dist/api_err.py b/dist/api_err.py
index cb2c8cc588e..6c893c9af82 100644
--- a/dist/api_err.py
+++ b/dist/api_err.py
@@ -78,7 +78,7 @@ for line in open('../src/include/wiredtiger.in', 'r'):
tfile.close()
compare_srcfile(tmp_file, '../src/include/wiredtiger.in')
-# Output the wiredtiger_strerror code.
+# Output the wiredtiger_strerror and wiredtiger_sterror_r code.
tmp_file = '__tmp'
tfile = open(tmp_file, 'w')
tfile.write('''/* DO NOT EDIT: automatically built by dist/api_err.py. */
@@ -86,18 +86,22 @@ tfile.write('''/* DO NOT EDIT: automatically built by dist/api_err.py. */
#include "wt_internal.h"
/*
- * wiredtiger_strerror --
- *\tReturn a string for any error value.
+ * Historically, there was only the wiredtiger_strerror call because the POSIX
+ * port didn't need anything more complex; Windows requires memory allocation
+ * of error strings, so we added the wiredtiger_strerror_r call. Because we
+ * want wiredtiger_strerror to continue to be as thread-safe as possible, errors
+ * are split into three categories: WiredTiger constant strings, system constant
+ * strings and Everything Else, and we check constant strings before Everything
+ * Else.
*/
-const char *
-wiredtiger_strerror(int error)
-{
-\tstatic char errbuf[64];
-\tchar *p;
-
-\tif (error == 0)
-\t\treturn ("Successful return: 0");
+/*
+ * __wiredtiger_error --
+ *\tReturn a constant string for the WiredTiger errors.
+ */
+static const char *
+__wiredtiger_error(int error)
+{
\tswitch (error) {
''')
@@ -105,19 +109,51 @@ for err in errors:
tfile.write('\tcase ' + err.name + ':\n')
tfile.write('\t\treturn ("' + err.name + ': ' + err.desc + '");\n')
-tfile.write('''\
-\tdefault:
-\t\tif (error > 0 && (p = strerror(error)) != NULL)
-\t\t\treturn (p);
-\t\tbreak;
-\t}
-
-\t/*
-\t * !!!
-\t * Not thread-safe, but this is never supposed to happen.
-\t */
-\t(void)snprintf(errbuf, sizeof(errbuf), "Unknown error: %d", error);
-\treturn (errbuf);
+tfile.write('''\t}
+\treturn (NULL);
+}
+
+/*
+ * wiredtiger_strerror --
+ *\tReturn a string for any error value, non-thread-safe version.
+ */
+const char *
+wiredtiger_strerror(int error)
+{
+\tstatic char buf[128];
+\tconst char *p;
+
+\t/* Check for a constant string. */
+\tif ((p = __wiredtiger_error(error)) != NULL ||
+\t (p = __wt_strerror(error)) != NULL)
+\t\treturn (p);
+
+\t/* Else, fill in the non-thread-safe static buffer. */
+\tif (wiredtiger_strerror_r(error, buf, sizeof(buf)) != 0)
+\t\t(void)snprintf(buf, sizeof(buf), "error return: %d", error);
+
+\treturn (buf);
+}
+
+/*
+ * wiredtiger_strerror_r --
+ *\tReturn a string for any error value, thread-safe version.
+ */
+int
+wiredtiger_strerror_r(int error, char *buf, size_t buflen)
+{
+\tconst char *p;
+
+\t/* Require at least 2 bytes, printable character and trailing nul. */
+\tif (buflen < 2)
+\t\treturn (ENOMEM);
+
+\t/* Check for a constant string. */
+\tif ((p = __wiredtiger_error(error)) != NULL ||
+\t (p = __wt_strerror(error)) != NULL)
+\t\treturn (snprintf(buf, buflen, "%s", p) > 0 ? 0 : ENOMEM);
+
+\treturn (__wt_strerror_r(error, buf, buflen));
}
''')
tfile.close()
diff --git a/dist/s_string.ok b/dist/s_string.ok
index db1114b77de..d3717d27331 100644
--- a/dist/s_string.ok
+++ b/dist/s_string.ok
@@ -181,6 +181,7 @@ KV
KVS
Kanowski's
Kounavis
+LANGID
LEX
LF
LIBBZ
@@ -437,6 +438,7 @@ btmem
btree
btrees
buf
+buflen
bufs
bufsz
builtin
diff --git a/dist/s_symbols.list b/dist/s_symbols.list
index d3803bc3afa..8f469e94433 100644
--- a/dist/s_symbols.list
+++ b/dist/s_symbols.list
@@ -8,6 +8,7 @@ wiredtiger_pack_start
wiredtiger_pack_str
wiredtiger_pack_uint
wiredtiger_strerror
+wiredtiger_strerror_r
wiredtiger_struct_pack
wiredtiger_struct_size
wiredtiger_struct_unpack
diff --git a/examples/c/ex_all.c b/examples/c/ex_all.c
index 23e682c5072..31ad812e6f6 100644
--- a/examples/c/ex_all.c
+++ b/examples/c/ex_all.c
@@ -343,6 +343,22 @@ cursor_ops(WT_SESSION *session)
/*! [Display an error] */
}
+ {
+ /*! [Display an error thread safe] */
+ const char *key = "non-existent key";
+ cursor->set_key(cursor, key);
+ if ((ret = cursor->remove(cursor)) != 0) {
+ char buf[128];
+
+ if (wiredtiger_strerror_r(ret, buf, sizeof(buf)) != 0)
+ (void)snprintf(
+ buf, sizeof(buf), "error value: %d\n", ret);
+ fprintf(stderr, "cursor.remove: %s\n", buf);
+ return (ret);
+ }
+ /*! [Display an error thread safe] */
+ }
+
/*! [Close the cursor] */
ret = cursor->close(cursor);
/*! [Close the cursor] */
diff --git a/src/conn/api_strerror.c b/src/conn/api_strerror.c
index caf536b24f7..396ae7a3e0f 100644
--- a/src/conn/api_strerror.c
+++ b/src/conn/api_strerror.c
@@ -3,18 +3,22 @@
#include "wt_internal.h"
/*
- * wiredtiger_strerror --
- * Return a string for any error value.
+ * Historically, there was only the wiredtiger_strerror call because the POSIX
+ * port didn't need anything more complex; Windows requires memory allocation
+ * of error strings, so we added the wiredtiger_strerror_r call. Because we
+ * want wiredtiger_strerror to continue to be as thread-safe as possible, errors
+ * are split into three categories: WiredTiger constant strings, system constant
+ * strings and Everything Else, and we check constant strings before Everything
+ * Else.
*/
-const char *
-wiredtiger_strerror(int error)
-{
- static char errbuf[64];
- char *p;
-
- if (error == 0)
- return ("Successful return: 0");
+/*
+ * __wiredtiger_error --
+ * Return a constant string for the WiredTiger errors.
+ */
+static const char *
+__wiredtiger_error(int error)
+{
switch (error) {
case WT_ROLLBACK:
return ("WT_ROLLBACK: conflict between concurrent operations");
@@ -28,16 +32,49 @@ wiredtiger_strerror(int error)
return ("WT_PANIC: WiredTiger library panic");
case WT_RESTART:
return ("WT_RESTART: restart the operation (internal)");
- default:
- if (error > 0 && (p = strerror(error)) != NULL)
- return (p);
- break;
}
+ return (NULL);
+}
+
+/*
+ * wiredtiger_strerror --
+ * Return a string for any error value, non-thread-safe version.
+ */
+const char *
+wiredtiger_strerror(int error)
+{
+ static char buf[128];
+ const char *p;
+
+ /* Check for a constant string. */
+ if ((p = __wiredtiger_error(error)) != NULL ||
+ (p = __wt_strerror(error)) != NULL)
+ return (p);
+
+ /* Else, fill in the non-thread-safe static buffer. */
+ if (wiredtiger_strerror_r(error, buf, sizeof(buf)) != 0)
+ (void)snprintf(buf, sizeof(buf), "error return: %d", error);
+
+ return (buf);
+}
+
+/*
+ * wiredtiger_strerror_r --
+ * Return a string for any error value, thread-safe version.
+ */
+int
+wiredtiger_strerror_r(int error, char *buf, size_t buflen)
+{
+ const char *p;
+
+ /* Require at least 2 bytes, printable character and trailing nul. */
+ if (buflen < 2)
+ return (ENOMEM);
+
+ /* Check for a constant string. */
+ if ((p = __wiredtiger_error(error)) != NULL ||
+ (p = __wt_strerror(error)) != NULL)
+ return (snprintf(buf, buflen, "%s", p) > 0 ? 0 : ENOMEM);
- /*
- * !!!
- * Not thread-safe, but this is never supposed to happen.
- */
- (void)snprintf(errbuf, sizeof(errbuf), "Unknown error: %d", error);
- return (errbuf);
+ return (__wt_strerror_r(error, buf, buflen));
}
diff --git a/src/include/extern.h b/src/include/extern.h
index b80719de7c0..d8ed3f5cef1 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -432,6 +432,8 @@ extern int __wt_dlopen(WT_SESSION_IMPL *session, const char *path, WT_DLH **dlhp
extern int __wt_dlsym(WT_SESSION_IMPL *session, WT_DLH *dlh, const char *name, int fail, void *sym_ret);
extern int __wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh);
extern int __wt_errno(void);
+extern const char *__wt_strerror(int error);
+extern int __wt_strerror_r(int error, char *buf, size_t buflen);
extern int __wt_exist(WT_SESSION_IMPL *session, const char *filename, int *existp);
extern void __wt_fallocate_config(WT_SESSION_IMPL *session, WT_FH *fh);
extern int __wt_fallocate( WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, wt_off_t len);
diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in
index ee9c58e4278..c8b242b8f14 100644
--- a/src/include/wiredtiger.in
+++ b/src/include/wiredtiger.in
@@ -2020,15 +2020,26 @@ int wiredtiger_open(const char *home,
WT_CONNECTION **connectionp);
/*!
- * Return information about an error as a string; wiredtiger_strerror is a
- * superset of the ISO C99/POSIX 1003.1-2001 function strerror.
+ * Return information about a WiredTiger error as a string, not thread-safe.
*
* @snippet ex_all.c Display an error
*
- * @param err a return value from a WiredTiger, C library or POSIX function
+ * @param error a return value from a WiredTiger call
* @returns a string representation of the error
*/
-const char *wiredtiger_strerror(int err);
+const char *wiredtiger_strerror(int error);
+
+/*!
+ * Return information about a WiredTiger error as a string, thread-safe version.
+ *
+ * @snippet ex_all.c Display an error thread safe
+ *
+ * @param error a return value from a WiredTiger call
+ * @param buf a buffer of at least \c buflen bytes
+ * @param buflen the length of the buffer
+ * @returns zero for success, non-zero to indicate an error.
+ */
+int wiredtiger_strerror_r(int error, char *buf, size_t buflen);
#if !defined(SWIG)
/*!
diff --git a/src/lsm/lsm_cursor.c b/src/lsm/lsm_cursor.c
index 2dfaea1ec3a..52bd3e9373d 100644
--- a/src/lsm/lsm_cursor.c
+++ b/src/lsm/lsm_cursor.c
@@ -1484,11 +1484,8 @@ __wt_clsm_open(WT_SESSION_IMPL *session,
WT_ERR(__wt_cursor_init(cursor, cursor->uri, owner, cfg, cursorp));
if (0) {
-err: __wt_lsm_tree_release(session, lsm_tree);
- if (clsm != NULL) {
- clsm->lsm_tree = NULL;
+err: if (clsm != NULL)
WT_TRET(__clsm_close(cursor));
- }
}
return (ret);
diff --git a/src/os_posix/os_errno.c b/src/os_posix/os_errno.c
index ed3451a9c1c..a58f13583ce 100644
--- a/src/os_posix/os_errno.c
+++ b/src/os_posix/os_errno.c
@@ -21,3 +21,49 @@ __wt_errno(void)
*/
return (errno == 0 ? WT_ERROR : errno);
}
+
+/*
+ * __wt_strerror --
+ * POSIX implementation of wiredtiger_strerror.
+ */
+const char *
+__wt_strerror(int error)
+{
+ const char *p;
+
+ /*
+ * POSIX errors are non-negative integers; check for 0 explicitly
+ * in-case the underlying strerror doesn't handle 0, some don't.
+ */
+ if (error == 0)
+ return ("Successful return: 0");
+ if (error > 0 && (p = strerror(error)) != NULL)
+ return (p);
+ return (NULL);
+}
+
+/*
+ * __wt_strerror_r --
+ * POSIX implementation of wiredtiger_strerror_r.
+ */
+int
+__wt_strerror_r(int error, char *buf, size_t buflen)
+{
+ const char *p;
+
+ /* Require at least 2 bytes, printable character and trailing nul. */
+ if (buflen < 2)
+ return (ENOMEM);
+
+ /*
+ * Check for POSIX errors then fallback to something generic. Copy the
+ * string into the user's buffer, return success if anything printed.
+ */
+ p = __wt_strerror(error);
+ if (p != NULL && snprintf(buf, buflen, "%s", p) > 0)
+ return (0);
+
+ /* Fallback to a generic message, then guess it's a memory problem. */
+ return (
+ snprintf(buf, buflen, "error return: %d", error) > 0 ? 0 : ENOMEM);
+}
diff --git a/src/os_win/os_errno.c b/src/os_win/os_errno.c
index e321912d829..00ee638fbe3 100644
--- a/src/os_win/os_errno.c
+++ b/src/os_win/os_errno.c
@@ -8,6 +8,34 @@
#include "wt_internal.h"
+static const int windows_error_offset = -29000;
+
+/*
+ * __wt_map_error_to_windows_error --
+ * Return a negative integer, an encoded Windows error
+ * Standard C errors are positive integers from 0 - ~200
+ * Windows errors are from 0 - 15999 according to the documentation
+ */
+static DWORD
+__wt_map_error_to_windows_error(int error) {
+ /* Ensure we do not exceed the error range
+ Also validate he do not get any COM errors
+ (which are negative integers)
+ */
+ WT_ASSERT(NULL, error > 0 && error > -(windows_error_offset));
+
+ return (error + -(windows_error_offset));
+}
+
+/*
+ * __wt_map_error_to_windows_error --
+ * Return a positive integer, a decoded Windows error
+ */
+static int
+__wt_map_windows_error_to_error(DWORD winerr) {
+ return (winerr + windows_error_offset);
+}
+
/*
* __wt_errno --
* Return errno, or WT_ERROR if errno not set.
@@ -24,5 +52,73 @@ __wt_errno(void)
/* GetLastError should only be called if we hit an actual error */
WT_ASSERT(NULL, err != ERROR_SUCCESS);
- return (err == ERROR_SUCCESS ? WT_ERROR : err);
+ return (err == ERROR_SUCCESS ?
+ WT_ERROR : __wt_map_windows_error_to_error(err));
+}
+
+/*
+ * __wt_strerror --
+ * Windows implementation of wiredtiger_strerror.
+ */
+const char *
+__wt_strerror(int error)
+{
+ const char *p;
+
+ /*
+ * POSIX errors are non-negative integers; check for 0 explicitly
+ * in-case the underlying strerror doesn't handle 0, some don't.
+ */
+ if (error == 0)
+ return ("Successful return: 0");
+ if (error > 0 && (p = strerror(error)) != NULL)
+ return (p);
+ return (NULL);
+}
+
+/*
+ * __wt_strerror_r --
+ * Windows implementation of wiredtiger_strerror_r.
+ */
+int
+__wt_strerror_r(int error, char *buf, size_t buflen)
+{
+ DWORD lasterror;
+ const char *p;
+
+ /* Require at least 2 bytes, printable character and trailing nul. */
+ if (buflen < 2)
+ return (ENOMEM);
+
+ /*
+ * Check for POSIX errors, Windows errors, then fallback to something
+ * generic. Copy the string into the user's buffer, return success if
+ * anything printed.
+ */
+ p = __wt_strerror(error);
+ if (p != NULL && snprintf(buf, buflen, "%s", p) > 0)
+ return (0);
+
+ if (error < 0) {
+ error = __wt_map_error_to_windows_error(error);
+
+ lasterror = FormatMessageA(
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error,
+ 0, /* let system choose the correct LANGID */
+ buf,
+ buflen,
+ NULL);
+
+ if (lasterror != 0)
+ return (0);
+
+ /* Fall through to the fallback error code */
+ }
+
+ /* Fallback to a generic message, then guess it's a memory problem. */
+ return (
+ snprintf(buf, buflen, "error return: %d", error) > 0 ? 0 : ENOMEM);
}
diff --git a/src/os_win/os_ftruncate.c b/src/os_win/os_ftruncate.c
index e80308536f1..d9b43e4596f 100644
--- a/src/os_win/os_ftruncate.c
+++ b/src/os_win/os_ftruncate.c
@@ -17,7 +17,6 @@ __wt_ftruncate(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t len)
{
WT_DECL_RET;
LARGE_INTEGER largeint;
- uint32_t lasterror;
largeint.QuadPart = len;
@@ -32,10 +31,8 @@ __wt_ftruncate(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t len)
return (0);
}
- lasterror = GetLastError();
-
- if (lasterror = ERROR_USER_MAPPED_FILE)
+ if (GetLastError() == ERROR_USER_MAPPED_FILE)
return (EBUSY);
- WT_RET_MSG(session, lasterror, "%s SetEndOfFile error", fh->name);
+ WT_RET_MSG(session, __wt_errno(), "%s SetEndOfFile error", fh->name);
}
diff --git a/src/os_win/os_mtx_cond.c b/src/os_win/os_mtx_cond.c
index 71ea8ed49a2..36de49d1aae 100644
--- a/src/os_win/os_mtx_cond.c
+++ b/src/os_win/os_mtx_cond.c
@@ -45,7 +45,6 @@ __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);
@@ -82,8 +81,7 @@ __wt_cond_wait(WT_SESSION_IMPL *session, WT_CONDVAR *cond, long usecs)
&cond->cond, &cond->mtx, INFINITE);
if (ret == 0) {
- lasterror = GetLastError();
- if (lasterror == ERROR_TIMEOUT) {
+ if (GetLastError() == ERROR_TIMEOUT) {
ret = 1;
}
}
diff --git a/src/os_win/os_rename.c b/src/os_win/os_rename.c
index 8c2784457c4..a0f33843218 100644
--- a/src/os_win/os_rename.c
+++ b/src/os_win/os_rename.c
@@ -33,13 +33,13 @@ __wt_rename(WT_SESSION_IMPL *session, const char *from, const char *to)
*/
if ((ret = GetFileAttributesA(to_path)) != INVALID_FILE_ATTRIBUTES) {
if ((ret = DeleteFileA(to_path)) == FALSE) {
- lasterror = GetLastError();
+ lasterror = __wt_errno();
goto err;
}
}
if ((MoveFileA(from_path, to_path)) == FALSE)
- lasterror = GetLastError();
+ lasterror = __wt_errno();
err:
__wt_free(session, from_path);
diff --git a/test/suite/test_config02.py b/test/suite/test_config02.py
index c4a6d48f8b4..7e3570a1a37 100644
--- a/test/suite/test_config02.py
+++ b/test/suite/test_config02.py
@@ -147,7 +147,7 @@ class test_config02(wttest.WiredTigerTestCase):
dir = 'nondir'
self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
lambda: wiredtiger.wiredtiger_open(dir, 'create'),
- '/No such file or directory/')
+ '/(No such file or directory|The system cannot find the path specified)/')
def test_home_not_writeable(self):
if os.name == "nt":
diff --git a/test/suite/test_config03.py b/test/suite/test_config03.py
index b1cb328e093..3a1bbd76773 100644
--- a/test/suite/test_config03.py
+++ b/test/suite/test_config03.py
@@ -103,12 +103,12 @@ class test_config03(test_base03.test_base03):
if self.s_create == False:
successargs = successargs.replace(',create=false,',',create,')
expect_fail = True
- fail_msg = '/No such file or directory/'
+ fail_msg = '/(No such file or directory|The system cannot find the file specified)/'
elif self.s_create == None:
successargs = successargs + 'create=true,'
expect_fail = True
- fail_msg = '/No such file or directory/'
-
+ fail_msg = '/(No such file or directory|The system cannot find the file specified)/'
+
if self.s_eviction_target >= self.s_eviction_trigger:
# construct args that guarantee that target < trigger
# we know that trigger >= 1