diff options
author | Eliot Horowitz <eliot@10gen.com> | 2014-11-04 15:46:40 -0500 |
---|---|---|
committer | Eliot Horowitz <eliot@10gen.com> | 2014-11-05 11:21:19 -0500 |
commit | 5ca2daf551a2c631a5f573cb054406f5d49fbef5 (patch) | |
tree | b0a23d34ffdb376bac0b79ed17b5619cfc0d9b47 /src/third_party/wiredtiger/src/support/err.c | |
parent | 017704acdfc7517efadb3fab167bba06c025c01a (diff) | |
download | mongo-5ca2daf551a2c631a5f573cb054406f5d49fbef5.tar.gz |
SERVER-15953: add wiredtiger to third_party
Diffstat (limited to 'src/third_party/wiredtiger/src/support/err.c')
-rw-r--r-- | src/third_party/wiredtiger/src/support/err.c | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/src/support/err.c b/src/third_party/wiredtiger/src/support/err.c new file mode 100644 index 00000000000..3e874078fbf --- /dev/null +++ b/src/third_party/wiredtiger/src/support/err.c @@ -0,0 +1,527 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __handle_error_default -- + * Default WT_EVENT_HANDLER->handle_error implementation: send to stderr. + */ +static int +__handle_error_default(WT_EVENT_HANDLER *handler, + WT_SESSION *session, int error, const char *errmsg) +{ + WT_UNUSED(handler); + WT_UNUSED(session); + WT_UNUSED(error); + + return (fprintf(stderr, "%s\n", errmsg) >= 0 && + fflush(stderr) == 0 ? 0 : __wt_errno()); +} + +/* + * __handle_message_default -- + * Default WT_EVENT_HANDLER->handle_message implementation: send to stdout. + */ +static int +__handle_message_default(WT_EVENT_HANDLER *handler, + WT_SESSION *session, const char *message) +{ + WT_UNUSED(handler); + WT_UNUSED(session); + + return (printf("%s\n", message) >= 0 && + fflush(stdout) == 0 ? 0 : __wt_errno()); +} + +/* + * __handle_progress_default -- + * Default WT_EVENT_HANDLER->handle_progress implementation: ignore. + */ +static int +__handle_progress_default(WT_EVENT_HANDLER *handler, + WT_SESSION *session, const char *operation, uint64_t progress) +{ + WT_UNUSED(handler); + WT_UNUSED(session); + WT_UNUSED(operation); + WT_UNUSED(progress); + + return (0); +} + +/* + * __handle_close_default -- + * Default WT_EVENT_HANDLER->handle_close implementation: ignore. + */ +static int +__handle_close_default(WT_EVENT_HANDLER *handler, + WT_SESSION *session, WT_CURSOR *cursor) +{ + WT_UNUSED(handler); + WT_UNUSED(session); + WT_UNUSED(cursor); + + return (0); +} + +static WT_EVENT_HANDLER __event_handler_default = { + __handle_error_default, + __handle_message_default, + __handle_progress_default, + __handle_close_default +}; + +/* + * __handler_failure -- + * Report the failure of an application-configured event handler. + */ +static void +__handler_failure(WT_SESSION_IMPL *session, + int error, const char *which, int error_handler_failed) +{ + WT_EVENT_HANDLER *handler; + WT_SESSION *wt_session; + + /* + * !!! + * SECURITY: + * Buffer placed at the end of the stack in case snprintf overflows. + */ + char s[256]; + + (void)snprintf(s, sizeof(s), + "application %s event handler failed: %s", + which, wiredtiger_strerror(error)); + + /* + * Use the error handler to report the failure, unless it was the error + * handler that failed. If it was the error handler that failed, or a + * call to the error handler fails, use the default error handler. + */ + wt_session = (WT_SESSION *)session; + handler = session->event_handler; + if (!error_handler_failed && + handler->handle_error != __handle_error_default && + handler->handle_error(handler, wt_session, error, s) == 0) + return; + + (void)__handle_error_default(NULL, wt_session, error, s); +} + +/* + * __wt_event_handler_set -- + * Set an event handler, fill in any NULL methods with the defaults. + */ +void +__wt_event_handler_set(WT_SESSION_IMPL *session, WT_EVENT_HANDLER *handler) +{ + if (handler == NULL) + handler = &__event_handler_default; + else { + if (handler->handle_error == NULL) + handler->handle_error = __handle_error_default; + if (handler->handle_message == NULL) + handler->handle_message = __handle_message_default; + if (handler->handle_progress == NULL) + handler->handle_progress = __handle_progress_default; + } + + session->event_handler = handler; +} + +/* + * __wt_eventv -- + * Report a message to an event handler. + */ +int +__wt_eventv(WT_SESSION_IMPL *session, int msg_event, int error, + const char *file_name, int line_number, const char *fmt, va_list ap) +{ + WT_EVENT_HANDLER *handler; + WT_DECL_RET; + WT_SESSION *wt_session; + struct timespec ts; + size_t len, remain, wlen; + int prefix_cnt; + const char *err, *prefix; + char *end, *p, tid[128]; + + /* + * We're using a stack buffer because we want error messages no matter + * what, and allocating a WT_ITEM, or the memory it needs, might fail. + * + * !!! + * SECURITY: + * Buffer placed at the end of the stack in case snprintf overflows. + */ + char s[2048]; + + /* + * !!! + * This function MUST handle a NULL WT_SESSION_IMPL handle. + * + * Without a session, we don't have event handlers or prefixes for the + * error message. Write the error to stderr and call it a day. (It's + * almost impossible for that to happen given how early we allocate the + * first session, but if the allocation of the first session fails, for + * example, we can end up here without a session.) + */ + if (session == NULL) + return (fprintf(stderr, "WiredTiger Error%s%s\n", + error == 0 ? "" : ": ", + error == 0 ? "" : wiredtiger_strerror(error)) >= 0 && + fflush(stderr) == 0 ? 0 : __wt_errno()); + + p = s; + end = s + sizeof(s); + + /* + * We have several prefixes for the error message: + * a timestamp and the process and thread ids, the database error + * prefix, the data-source's name, and the session's name. Write them + * as a comma-separate list, followed by a colon. + */ + prefix_cnt = 0; + if (__wt_epoch(session, &ts) == 0) { + __wt_thread_id(tid, sizeof(tid)); + remain = WT_PTRDIFF(end, p); + wlen = (size_t)snprintf(p, remain, + "[%" PRIuMAX ":%" PRIuMAX "][%s]", + (uintmax_t)ts.tv_sec, (uintmax_t)ts.tv_nsec / 1000, tid); + p = wlen >= remain ? end : p + wlen; + prefix_cnt = 1; + } + if ((prefix = S2C(session)->error_prefix) != NULL) { + remain = WT_PTRDIFF(end, p); + wlen = (size_t)snprintf(p, remain, + "%s%s", prefix_cnt == 0 ? "" : ", ", prefix); + p = wlen >= remain ? end : p + wlen; + prefix_cnt = 1; + } + prefix = session->dhandle == NULL ? NULL : session->dhandle->name; + if (prefix != NULL) { + remain = WT_PTRDIFF(end, p); + wlen = (size_t)snprintf(p, remain, + "%s%s", prefix_cnt == 0 ? "" : ", ", prefix); + p = wlen >= remain ? end : p + wlen; + prefix_cnt = 1; + } + if ((prefix = session->name) != NULL) { + remain = WT_PTRDIFF(end, p); + wlen = (size_t)snprintf(p, remain, + "%s%s", prefix_cnt == 0 ? "" : ", ", prefix); + p = wlen >= remain ? end : p + wlen; + prefix_cnt = 1; + } + if (prefix_cnt != 0) { + remain = WT_PTRDIFF(end, p); + wlen = (size_t)snprintf(p, remain, ": "); + p = wlen >= remain ? end : p + wlen; + } + + if (file_name != NULL) { + remain = WT_PTRDIFF(end, p); + wlen = (size_t) + snprintf(p, remain, "%s, %d: ", file_name, line_number); + p = wlen >= remain ? end : p + wlen; + } + + remain = WT_PTRDIFF(end, p); + wlen = (size_t)vsnprintf(p, remain, fmt, ap); + p = wlen >= remain ? end : p + wlen; + + if (error != 0) { + /* + * When the engine calls __wt_err on error, it often outputs an + * error message including the string associated with the error + * it's returning. We could change the calls to call __wt_errx, + * but it's simpler to not append an error string if all we are + * doing is duplicating an existing error string. + * + * Use strcmp to compare: both strings are nul-terminated, and + * we don't want to run past the end of the buffer. + */ + err = wiredtiger_strerror(error); + len = strlen(err); + if (WT_PTRDIFF(p, s) < len || strcmp(p - len, err) != 0) { + remain = WT_PTRDIFF(end, p); + (void)snprintf(p, remain, ": %s", err); + } + } + + /* + * If a handler fails, return the error status: if we're in the process + * of handling an error, any return value we provide will be ignored by + * our caller, our caller presumably already has an error value it will + * be returning. + * + * If an application-specified or default informational message handler + * fails, complain using the application-specified or default error + * handler. + * + * If an application-specified error message handler fails, complain + * using the default error handler. If the default error handler fails, + * there's nothing to do. + */ + wt_session = (WT_SESSION *)session; + handler = session->event_handler; + if (msg_event) { + ret = handler->handle_message(handler, wt_session, s); + if (ret != 0) + __handler_failure(session, ret, "message", 0); + } else { + ret = handler->handle_error(handler, wt_session, error, s); + if (ret != 0 && handler->handle_error != __handle_error_default) + __handler_failure(session, ret, "error", 1); + } + + return (ret); +} + +/* + * __wt_err -- + * Report an error. + */ +void +__wt_err(WT_SESSION_IMPL *session, int error, const char *fmt, ...) + WT_GCC_FUNC_ATTRIBUTE((format (printf, 3, 4))) +{ + va_list ap; + + /* + * Ignore error returns from underlying event handlers, we already have + * an error value to return. + */ + va_start(ap, fmt); + (void)__wt_eventv(session, 0, error, NULL, 0, fmt, ap); + va_end(ap); +} + +/* + * __wt_errx -- + * Report an error with no error code. + */ +void +__wt_errx(WT_SESSION_IMPL *session, const char *fmt, ...) + WT_GCC_FUNC_ATTRIBUTE((format (printf, 2, 3))) +{ + va_list ap; + + /* + * Ignore error returns from underlying event handlers, we already have + * an error value to return. + */ + va_start(ap, fmt); + (void)__wt_eventv(session, 0, 0, NULL, 0, fmt, ap); + va_end(ap); +} + +/* + * __wt_ext_err_printf -- + * Extension API call to print to the error stream. + */ +int +__wt_ext_err_printf( + WT_EXTENSION_API *wt_api, WT_SESSION *wt_session, const char *fmt, ...) + WT_GCC_FUNC_ATTRIBUTE((format (printf, 3, 4))) +{ + WT_DECL_RET; + WT_SESSION_IMPL *session; + va_list ap; + + if ((session = (WT_SESSION_IMPL *)wt_session) == NULL) + session = ((WT_CONNECTION_IMPL *)wt_api->conn)->default_session; + + va_start(ap, fmt); + ret = __wt_eventv(session, 0, 0, NULL, 0, fmt, ap); + va_end(ap); + return (ret); +} + +/* + * info_msg -- + * Informational message. + */ +static int +info_msg(WT_SESSION_IMPL *session, const char *fmt, va_list ap) +{ + WT_EVENT_HANDLER *handler; + WT_SESSION *wt_session; + + /* + * !!! + * SECURITY: + * Buffer placed at the end of the stack in case snprintf overflows. + */ + char s[2048]; + + (void)vsnprintf(s, sizeof(s), fmt, ap); + + wt_session = (WT_SESSION *)session; + handler = session->event_handler; + return (handler->handle_message(handler, wt_session, s)); +} + +/* + * __wt_msg -- + * Informational message. + */ +int +__wt_msg(WT_SESSION_IMPL *session, const char *fmt, ...) + WT_GCC_FUNC_ATTRIBUTE((format (printf, 2, 3))) +{ + WT_DECL_RET; + va_list ap; + + va_start(ap, fmt); + ret = info_msg(session, fmt, ap); + va_end(ap); + + return (ret); +} + +/* + * __wt_ext_msg_printf -- + * Extension API call to print to the message stream. + */ +int +__wt_ext_msg_printf( + WT_EXTENSION_API *wt_api, WT_SESSION *wt_session, const char *fmt, ...) + WT_GCC_FUNC_ATTRIBUTE((format (printf, 3, 4))) +{ + WT_DECL_RET; + WT_SESSION_IMPL *session; + va_list ap; + + if ((session = (WT_SESSION_IMPL *)wt_session) == NULL) + session = ((WT_CONNECTION_IMPL *)wt_api->conn)->default_session; + + va_start(ap, fmt); + ret = info_msg(session, fmt, ap); + va_end(ap); + return (ret); +} + +/* + * __wt_progress -- + * Progress message. + */ +int +__wt_progress(WT_SESSION_IMPL *session, const char *s, uint64_t v) +{ + WT_DECL_RET; + WT_EVENT_HANDLER *handler; + WT_SESSION *wt_session; + + wt_session = (WT_SESSION *)session; + handler = session->event_handler; + if (handler != NULL && handler->handle_progress != NULL) + if ((ret = handler->handle_progress(handler, + wt_session, s == NULL ? session->name : s, v)) != 0) + __handler_failure(session, ret, "progress", 0); + return (0); +} + +/* + * __wt_assert -- + * Assert and other unexpected failures, includes file/line information + * for debugging. + */ +void +__wt_assert(WT_SESSION_IMPL *session, + int error, const char *file_name, int line_number, const char *fmt, ...) + WT_GCC_FUNC_ATTRIBUTE((format (printf, 5, 6))) +{ + va_list ap; + + va_start(ap, fmt); + (void)__wt_eventv(session, 0, error, file_name, line_number, fmt, ap); + va_end(ap); + +#ifdef HAVE_DIAGNOSTIC + __wt_abort(session); /* Drop core if testing. */ + /* NOTREACHED */ +#endif +} + +/* + * __wt_panic -- + * A standard error message when we panic. + */ +int +__wt_panic(WT_SESSION_IMPL *session) +{ + F_SET(S2C(session), WT_CONN_PANIC); + __wt_errx(session, "%s", + "the WiredTiger library cannot continue; the process must exit " + "and restart"); + +#if !defined(HAVE_DIAGNOSTIC) + /* + * Chaos reigns within. + * Reflect, repent, and reboot. + * Order shall return. + */ + return (WT_PANIC); +#endif + + __wt_abort(session); /* Drop core if testing. */ + /* NOTREACHED */ +} + +/* + * __wt_illegal_value -- + * A standard error message when we detect an illegal value. + */ +int +__wt_illegal_value(WT_SESSION_IMPL *session, const char *name) +{ + __wt_errx(session, "%s%s%s", + name == NULL ? "" : name, name == NULL ? "" : ": ", + "encountered an illegal file format or internal value"); + +#if !defined(HAVE_DIAGNOSTIC) + return (__wt_panic(session)); +#endif + + __wt_abort(session); /* Drop core if testing. */ + /* NOTREACHED */ +} + +/* + * __wt_object_unsupported -- + * Print a standard error message for an object that doesn't support a + * particular operation. + */ +int +__wt_object_unsupported(WT_SESSION_IMPL *session, const char *uri) +{ + WT_RET_MSG(session, ENOTSUP, "unsupported object operation: %s", uri); +} + +/* + * __wt_bad_object_type -- + * Print a standard error message when given an unknown or unsupported + * object type. + */ +int +__wt_bad_object_type(WT_SESSION_IMPL *session, const char *uri) +{ + if (WT_PREFIX_MATCH(uri, "backup:") || + WT_PREFIX_MATCH(uri, "colgroup:") || + WT_PREFIX_MATCH(uri, "config:") || + WT_PREFIX_MATCH(uri, "file:") || + WT_PREFIX_MATCH(uri, "index:") || + WT_PREFIX_MATCH(uri, "log:") || + WT_PREFIX_MATCH(uri, "lsm:") || + WT_PREFIX_MATCH(uri, "statistics:") || + WT_PREFIX_MATCH(uri, "table:")) + return (__wt_object_unsupported(session, uri)); + + WT_RET_MSG(session, ENOTSUP, "unknown object type: %s", uri); +} |