diff options
Diffstat (limited to 'src/third_party/wiredtiger/src/conn/conn_sweep.c')
-rw-r--r-- | src/third_party/wiredtiger/src/conn/conn_sweep.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/src/conn/conn_sweep.c b/src/third_party/wiredtiger/src/conn/conn_sweep.c new file mode 100644 index 00000000000..3bccc5814be --- /dev/null +++ b/src/third_party/wiredtiger/src/conn/conn_sweep.c @@ -0,0 +1,187 @@ +/*- + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __sweep -- + * Close unused dhandles on the connection dhandle list. + */ +static int +__sweep(WT_SESSION_IMPL *session) +{ + WT_CONNECTION_IMPL *conn; + WT_DATA_HANDLE *dhandle, *dhandle_next; + WT_DECL_RET; + time_t now; + + conn = S2C(session); + + /* + * Session's cache handles unless the session itself is closed, at which + * time the handle reference counts are immediately decremented. Don't + * discard handles that have been open recently. + */ + WT_RET(__wt_seconds(session, &now)); + + dhandle = SLIST_FIRST(&conn->dhlh); + for (; dhandle != NULL; dhandle = dhandle_next) { + dhandle_next = SLIST_NEXT(dhandle, l); + if (dhandle->session_ref != 0 || + now - dhandle->timeofdeath <= WT_DHANDLE_SWEEP_WAIT) + continue; + + /* + * We have a candidate for closing; if it's open, flush dirty + * leaf pages, then acquire an exclusive lock on the handle + * and close it. We might be blocking opens for a long time + * (over disk I/O), but the handle was quiescent for awhile. + * + * The close can fail if an update cannot be written (updates in + * a no-longer-referenced file might not yet be globally visible + * if sessions have disjoint sets of files open). If the handle + * is busy, skip it, we'll retry the close the next time, after + * the transaction state has progressed. + */ + if (F_ISSET(dhandle, WT_DHANDLE_OPEN)) { + WT_WITH_DHANDLE(session, dhandle, + ret = __wt_cache_op( + session, NULL, WT_SYNC_WRITE_LEAVES)); + WT_RET(ret); + + /* + * We don't set WT_DHANDLE_EXCLUSIVE deliberately, we + * want opens to block on us rather than returning an + * EBUSY error to the application. + */ + ret = __wt_try_writelock(session, dhandle->rwlock); + if (ret == EBUSY) { + ret = 0; + continue; + } + WT_RET(ret); + + WT_WITH_DHANDLE(session, dhandle, + ret = __wt_conn_btree_sync_and_close(session, 0)); + if (ret == EBUSY) + ret = 0; + + WT_TRET(__wt_writeunlock(session, dhandle->rwlock)); + WT_RET(ret); + } + + /* + * Attempt to discard the handle (the called function checks the + * handle-open flag after acquiring appropriate locks, which is + * why we don't do any special handling of EBUSY returns above, + * that path never cleared the handle-open flag. + */ + ret = __wt_conn_dhandle_discard_single(session, dhandle, 0); + if (ret == EBUSY) + ret = 0; + WT_RET(ret); + } + return (0); +} + +/* + * __sweep_server -- + * The handle sweep server thread. + */ +static void * +__sweep_server(void *arg) +{ + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + WT_SESSION_IMPL *session; + + session = arg; + conn = S2C(session); + + /* + * Sweep for dead handles. + */ + while (F_ISSET(conn, WT_CONN_SERVER_RUN) && + F_ISSET(conn, WT_CONN_SERVER_SWEEP)) { + + /* Wait until the next event. */ + WT_ERR( + __wt_cond_wait(session, conn->sweep_cond, 30 * WT_MILLION)); + + /* Sweep the handles. */ + WT_ERR(__sweep(session)); + } + + if (0) { +err: __wt_err(session, ret, "handle sweep server error"); + } + return (NULL); +} + +/* + * __wt_sweep_create -- + * Start the handle sweep thread. + */ +int +__wt_sweep_create(WT_SESSION_IMPL *session) +{ + WT_CONNECTION_IMPL *conn; + + conn = S2C(session); + + /* Set first, the thread might run before we finish up. */ + F_SET(conn, WT_CONN_SERVER_SWEEP); + + WT_RET(__wt_open_internal_session( + conn, "sweep-server", 1, 1, &conn->sweep_session)); + session = conn->sweep_session; + + /* + * Handle sweep does enough I/O it may be called upon to perform slow + * operations for the block manager. + */ + F_SET(session, WT_SESSION_CAN_WAIT); + + WT_RET(__wt_cond_alloc( + session, "handle sweep server", 0, &conn->sweep_cond)); + + WT_RET(__wt_thread_create( + session, &conn->sweep_tid, __sweep_server, session)); + conn->sweep_tid_set = 1; + + return (0); +} + +/* + * __wt_sweep_destroy -- + * Destroy the handle-sweep thread. + */ +int +__wt_sweep_destroy(WT_SESSION_IMPL *session) +{ + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + WT_SESSION *wt_session; + + conn = S2C(session); + + F_CLR(conn, WT_CONN_SERVER_SWEEP); + if (conn->sweep_tid_set) { + WT_TRET(__wt_cond_signal(session, conn->sweep_cond)); + WT_TRET(__wt_thread_join(session, conn->sweep_tid)); + conn->sweep_tid_set = 0; + } + WT_TRET(__wt_cond_destroy(session, &conn->sweep_cond)); + + if (conn->sweep_session != NULL) { + wt_session = &conn->sweep_session->iface; + WT_TRET(wt_session->close(wt_session, NULL)); + + conn->sweep_session = NULL; + } + return (ret); +} |