diff options
author | Michael Cahill <mjc@wiredtiger.com> | 2014-08-11 15:05:14 +1000 |
---|---|---|
committer | Michael Cahill <mjc@wiredtiger.com> | 2014-08-11 15:05:14 +1000 |
commit | 5fefbfa194b48d7c18b573f8909c00376cc326b5 (patch) | |
tree | f1b16e6252755ae9f817349adbb89d3a1f92a5e3 | |
parent | 4271d44445fff4901abbf53423a7ce1eedc3b202 (diff) | |
parent | e1cba5463d0e9e78d059f6a19f50ea04d9536c63 (diff) | |
download | mongo-5fefbfa194b48d7c18b573f8909c00376cc326b5.tar.gz |
Merge pull request #1143 from wiredtiger/dynamic-evict-workers
Start and stop eviction worker threads based on demand.
-rw-r--r-- | api/leveldb/leveldb_wt.h | 7 | ||||
-rw-r--r-- | dist/api_data.py | 17 | ||||
-rw-r--r-- | examples/c/ex_all.c | 4 | ||||
-rw-r--r-- | src/btree/bt_evict.c | 92 | ||||
-rw-r--r-- | src/config/config_def.c | 32 | ||||
-rw-r--r-- | src/conn/conn_cache.c | 24 | ||||
-rw-r--r-- | src/docs/tune-cache.dox | 9 | ||||
-rw-r--r-- | src/docs/upgrading.dox | 16 | ||||
-rw-r--r-- | src/include/cache.h | 13 | ||||
-rw-r--r-- | src/include/connection.h | 4 | ||||
-rw-r--r-- | src/include/wiredtiger.in | 26 | ||||
-rw-r--r-- | src/include/wt_internal.h | 2 |
12 files changed, 188 insertions, 58 deletions
diff --git a/api/leveldb/leveldb_wt.h b/api/leveldb/leveldb_wt.h index 0d169f81782..5e18346ce3b 100644 --- a/api/leveldb/leveldb_wt.h +++ b/api/leveldb/leveldb_wt.h @@ -45,9 +45,10 @@ #include "wiredtiger.h" #define WT_URI "table:data" -#define WT_CONN_CONFIG "log=(enabled),checkpoint=(wait=180),checkpoint_sync=false," \ - "session_max=8192,mmap=false,eviction_workers=4," \ - "transaction_sync=(enabled=true,method=none)," +#define WT_CONN_CONFIG \ + "log=(enabled),checkpoint=(wait=180),checkpoint_sync=false," \ + "session_max=8192,mmap=false," \ + "transaction_sync=(enabled=true,method=none)," // Note: LSM doesn't split, build full pages from the start #define WT_TABLE_CONFIG "type=lsm,split_pct=100,leaf_item_max=1KB," \ "lsm=(chunk_size=100MB,bloom_config=(leaf_page_max=8MB))," diff --git a/dist/api_data.py b/dist/api_data.py index 3e7fd6e9790..45b2655d8f0 100644 --- a/dist/api_data.py +++ b/dist/api_data.py @@ -340,9 +340,20 @@ connection_runtime_config = [ Config('eviction_trigger', '95', r''' trigger eviction when the cache is using this much memory, as a percentage of the total cache size''', min=10, max=99), - Config('eviction_workers', '0', r''' - additional threads to help evict pages from cache''', - min=0, max=20), + Config('eviction', '', r''' + eviction configuration options.''', + type='category', subconfig=[ + Config('threads_max', '3', r''' + maximum number of threads WiredTiger will start to help + evict pages from cache. The number of threads currently running + will vary depending on the current eviction load''', + min=1, max=20), + Config('threads_min', '1', r''' + minimum number of threads WiredTiger will start to help evict + pages from cache. The number of threads currently running will + vary depending on the current eviction load''', + min=1, max=20), + ]), Config('shared_cache', '', r''' shared cache configuration options. A database should configure either a cache_size or a shared_cache not both''', diff --git a/examples/c/ex_all.c b/examples/c/ex_all.c index 91551fb1532..278c8bb8750 100644 --- a/examples/c/ex_all.c +++ b/examples/c/ex_all.c @@ -1019,9 +1019,9 @@ main(void) (void)conn->close(conn, NULL); /*! [Eviction worker configuration] */ - /* Configure an additional 4 eviction support threads. */ + /* Configure up to four eviction threads */ ret = wiredtiger_open(home, NULL, - "create,eviction_trigger=90,eviction_workers=4", &conn); + "create,eviction_trigger=90,eviction=(threads_max=4)", &conn); /*! [Eviction worker configuration] */ if (ret == 0) (void)conn->close(conn, NULL); diff --git a/src/btree/bt_evict.c b/src/btree/bt_evict.c index 5e1856a40da..aa585af0ec5 100644 --- a/src/btree/bt_evict.c +++ b/src/btree/bt_evict.c @@ -17,13 +17,6 @@ static int __evict_walk(WT_SESSION_IMPL *, uint32_t *, uint32_t); static int __evict_walk_file(WT_SESSION_IMPL *, u_int *, uint32_t); static void *__evict_worker(void *); -typedef struct { - WT_SESSION_IMPL *session; - u_int id; - - pthread_t tid; -} WT_EVICTION_WORKER; - /* * __evict_read_gen -- * Get the adjusted read generation for an eviction entry. @@ -157,6 +150,7 @@ __evict_server(void *arg) WT_CACHE *cache; WT_CONNECTION_IMPL *conn; WT_DECL_RET; + WT_EVICT_WORKER *worker; WT_SESSION_IMPL *session; session = arg; @@ -170,6 +164,30 @@ __evict_server(void *arg) if (!F_ISSET(conn, WT_CONN_EVICTION_RUN)) break; + /* + * If we have caught up and there are more than the minimum + * number of eviction workers running, shut one down. + */ + if (conn->evict_workers > conn->evict_workers_min) { + WT_TRET(__wt_verbose(session, WT_VERB_EVICTSERVER, + "Stopping evict worker: %"PRIu32"\n", + conn->evict_workers)); + worker = &conn->evict_workctx[--conn->evict_workers]; + F_CLR(worker, WT_EVICT_WORKER_RUN); + WT_TRET(__wt_cond_signal( + session, cache->evict_waiter_cond)); + WT_TRET(__wt_thread_join(session, worker->tid)); + /* + * Flag errors here with a message, but don't shut down + * the eviction server - that's fatal. + */ + WT_ASSERT(session, ret == 0); + if (ret != 0) { + (void)__wt_msg(session, + "Error stopping eviction worker: %d", ret); + ret = 0; + } + } F_CLR(cache, WT_EVICT_ACTIVE); WT_ERR(__wt_verbose(session, WT_VERB_EVICTSERVER, "sleeping")); /* Don't rely on signals: check periodically. */ @@ -213,7 +231,7 @@ int __wt_evict_create(WT_CONNECTION_IMPL *conn) { WT_SESSION_IMPL *session; - WT_EVICTION_WORKER *workers; + WT_EVICT_WORKER *workers; u_int i; /* Set first, the thread might run before we finish up. */ @@ -224,16 +242,22 @@ __wt_evict_create(WT_CONNECTION_IMPL *conn) conn, "eviction-server", 0, 0, &session)); conn->evict_session = session; - if (conn->evict_workers > 0) { - WT_RET(__wt_calloc_def(session, conn->evict_workers, &workers)); + if (conn->evict_workers_max > 0) { + WT_RET(__wt_calloc_def( + session, conn->evict_workers_max, &workers)); conn->evict_workctx = workers; - for (i = 0; i < conn->evict_workers; i++) { + for (i = 0; i < conn->evict_workers_max; i++) { WT_RET(__wt_open_internal_session(conn, "eviction-worker", 0, 0, &workers[i].session)); workers[i].id = i; - WT_RET(__wt_thread_create(session, - &workers[i].tid, __evict_worker, &workers[i])); + if (i < conn->evict_workers_min) { + ++conn->evict_workers; + F_SET(&workers[i], WT_EVICT_WORKER_RUN); + WT_RET(__wt_thread_create( + session, &workers[i].tid, + __evict_worker, &workers[i])); + } } } @@ -253,7 +277,7 @@ __wt_evict_destroy(WT_CONNECTION_IMPL *conn) { WT_CACHE *cache; WT_DECL_RET; - WT_EVICTION_WORKER *workers; + WT_EVICT_WORKER *workers; WT_SESSION *wt_session; WT_SESSION_IMPL *session; u_int i; @@ -270,7 +294,14 @@ __wt_evict_destroy(WT_CONNECTION_IMPL *conn) WT_TRET(__wt_cond_signal(session, cache->evict_waiter_cond)); WT_TRET(__wt_thread_join(session, workers[i].tid)); } - __wt_free(session, conn->evict_workctx); + /* Handle shutdown when cleaning up after a failed open */ + if (conn->evict_workctx != NULL) { + for (i = 0; i < conn->evict_workers_max; i++) { + wt_session = &conn->evict_workctx[i].session->iface; + WT_TRET(wt_session->close(wt_session, NULL)); + } + __wt_free(session, conn->evict_workctx); + } if (conn->evict_tid_set) { WT_TRET(__wt_evict_server_wake(session)); @@ -298,7 +329,7 @@ __evict_worker(void *arg) WT_CACHE *cache; WT_CONNECTION_IMPL *conn; WT_DECL_RET; - WT_EVICTION_WORKER *worker; + WT_EVICT_WORKER *worker; WT_SESSION_IMPL *session; uint32_t flags; @@ -307,15 +338,14 @@ __evict_worker(void *arg) conn = S2C(session); cache = conn->cache; - while (F_ISSET(conn, WT_CONN_EVICTION_RUN)) { + while (F_ISSET(conn, WT_CONN_EVICTION_RUN) && + F_ISSET(worker, WT_EVICT_WORKER_RUN)) { /* Don't spin in a busy loop if there is no work to do */ WT_ERR(__evict_has_work(session, &flags)); - if (flags == 0) { + if (flags == 0) WT_ERR(__wt_cond_wait( session, cache->evict_waiter_cond, 10000)); - if (!F_ISSET(conn, WT_CONN_EVICTION_RUN)) - break; - } else + else WT_ERR(__evict_lru_pages(session, 1)); } @@ -325,9 +355,6 @@ err: __wt_err(session, ret, "cache eviction helper error"); WT_TRET(__wt_verbose(session, WT_VERB_EVICTSERVER, "helper exiting")); - if (session != conn->default_session) - (void)session->iface.close(&session->iface, NULL); - return (NULL); } @@ -383,6 +410,7 @@ __evict_pass(WT_SESSION_IMPL *session) { WT_CACHE *cache; WT_CONNECTION_IMPL *conn; + WT_EVICT_WORKER *worker; int loop; uint32_t flags; uint64_t bytes_inuse; @@ -416,11 +444,23 @@ __evict_pass(WT_SESSION_IMPL *session) * evicted. This will be cleared by the next thread to * successfully evict a page. */ - if (bytes_inuse > conn->cache_size) + if (bytes_inuse > conn->cache_size) { F_SET(cache, WT_EVICT_NO_PROGRESS); - else + } else F_CLR(cache, WT_EVICT_NO_PROGRESS); + /* Start a worker if we have capacity and the cache is full. */ + if (bytes_inuse > conn->cache_size && + conn->evict_workers < conn->evict_workers_max) { + WT_RET(__wt_verbose(session, WT_VERB_EVICTSERVER, + "Starting evict worker: %"PRIu32"\n", + conn->evict_workers)); + worker = &conn->evict_workctx[conn->evict_workers++]; + F_SET(worker, WT_EVICT_WORKER_RUN); + WT_RET(__wt_thread_create(session, + &worker->tid, __evict_worker, worker)); + } + F_SET(cache, WT_EVICT_ACTIVE); WT_RET(__wt_verbose(session, WT_VERB_EVICTSERVER, "Eviction pass with: Max: %" PRIu64 diff --git a/src/config/config_def.c b/src/config/config_def.c index 9424c9d29c6..52b4199ee0a 100644 --- a/src/config/config_def.c +++ b/src/config/config_def.c @@ -49,6 +49,12 @@ static const WT_CONFIG_CHECK confchk_checkpoint_subconfigs[] = { { NULL, NULL, NULL, NULL } }; +static const WT_CONFIG_CHECK confchk_eviction_subconfigs[] = { + { "threads_max", "int", "min=1,max=20", NULL }, + { "threads_min", "int", "min=1,max=20", NULL }, + { NULL, NULL, NULL, NULL } +}; + static const WT_CONFIG_CHECK confchk_shared_cache_subconfigs[] = { { "chunk", "int", "min=1MB,max=10TB", NULL }, { "name", "string", NULL, NULL }, @@ -72,10 +78,10 @@ static const WT_CONFIG_CHECK confchk_connection_reconfigure[] = { { "checkpoint", "category", NULL, confchk_checkpoint_subconfigs }, { "error_prefix", "string", NULL, NULL }, + { "eviction", "category", NULL, confchk_eviction_subconfigs }, { "eviction_dirty_target", "int", "min=10,max=99", NULL }, { "eviction_target", "int", "min=10,max=99", NULL }, { "eviction_trigger", "int", "min=10,max=99", NULL }, - { "eviction_workers", "int", "min=0,max=20", NULL }, { "shared_cache", "category", NULL, confchk_shared_cache_subconfigs }, { "statistics", "list", @@ -296,10 +302,10 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open[] = { "choices=[\"checkpoint\",\"data\",\"log\"]", NULL }, { "error_prefix", "string", NULL, NULL }, + { "eviction", "category", NULL, confchk_eviction_subconfigs }, { "eviction_dirty_target", "int", "min=10,max=99", NULL }, { "eviction_target", "int", "min=10,max=99", NULL }, { "eviction_trigger", "int", "min=10,max=99", NULL }, - { "eviction_workers", "int", "min=0,max=20", NULL }, { "exclusive", "boolean", NULL, NULL }, { "extensions", "list", NULL, NULL }, { "file_extend", "list", "choices=[\"data\",\"log\"]", NULL }, @@ -370,11 +376,11 @@ static const WT_CONFIG_ENTRY config_entries[] = { { "connection.reconfigure", "async=(enabled=0,ops_max=1024,threads=2),cache_size=100MB," "checkpoint=(name=\"WiredTigerCheckpoint\",wait=0),error_prefix=," - "eviction_dirty_target=80,eviction_target=80,eviction_trigger=95," - "eviction_workers=0,shared_cache=(chunk=10MB,name=,reserve=0," - "size=500MB),statistics=none,statistics_log=(on_close=0," - "path=\"WiredTigerStat.%d.%H\",sources=," - "timestamp=\"%b %d %H:%M:%S\",wait=0),verbose=", + "eviction=(threads_max=3,threads_min=1),eviction_dirty_target=80," + "eviction_target=80,eviction_trigger=95,shared_cache=(chunk=10MB," + "name=,reserve=0,size=500MB),statistics=none," + "statistics_log=(on_close=0,path=\"WiredTigerStat.%d.%H\"," + "sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),verbose=", confchk_connection_reconfigure }, { "cursor.close", @@ -480,12 +486,12 @@ static const WT_CONFIG_ENTRY config_entries[] = { "async=(enabled=0,ops_max=1024,threads=2),buffer_alignment=-1," "cache_size=100MB,checkpoint=(name=\"WiredTigerCheckpoint\"," "wait=0),checkpoint_sync=,create=0,direct_io=,error_prefix=," - "eviction_dirty_target=80,eviction_target=80,eviction_trigger=95," - "eviction_workers=0,exclusive=0,extensions=,file_extend=," - "hazard_max=1000,log=(archive=,enabled=0,file_max=100MB," - "path=\"\"),lsm_merge=,mmap=,multiprocess=0,session_max=100," - "shared_cache=(chunk=10MB,name=,reserve=0,size=500MB)," - "statistics=none,statistics_log=(on_close=0," + "eviction=(threads_max=3,threads_min=1),eviction_dirty_target=80," + "eviction_target=80,eviction_trigger=95,exclusive=0,extensions=," + "file_extend=,hazard_max=1000,log=(archive=,enabled=0," + "file_max=100MB,path=\"\"),lsm_merge=,mmap=,multiprocess=0," + "session_max=100,shared_cache=(chunk=10MB,name=,reserve=0," + "size=500MB),statistics=none,statistics_log=(on_close=0," "path=\"WiredTigerStat.%d.%H\",sources=," "timestamp=\"%b %d %H:%M:%S\",wait=0),transaction_sync=(enabled=0" ",method=fsync),use_environment_priv=0,verbose=", diff --git a/src/conn/conn_cache.c b/src/conn/conn_cache.c index 9af9ab98b19..42e45a9c58b 100644 --- a/src/conn/conn_cache.c +++ b/src/conn/conn_cache.c @@ -54,10 +54,28 @@ __wt_cache_config(WT_CONNECTION_IMPL *conn, const char *cfg[]) cache->eviction_dirty_target = (u_int)cval.val; WT_RET_NOTFOUND_OK(ret); - if ((ret = - __wt_config_gets(session, cfg, "eviction_workers", &cval)) == 0) - conn->evict_workers = (u_int)cval.val; + /* + * The eviction thread configuration options include the main eviction + * thread and workers. Our implementation splits them out. Adjust for + * the difference when parsing the configuration. + */ + if ((ret = __wt_config_gets( + session, cfg, "eviction.threads_max", &cval)) == 0) { + WT_ASSERT(session, cval.val > 0); + conn->evict_workers_max = (u_int)cval.val - 1; + } WT_RET_NOTFOUND_OK(ret); + if ((ret = __wt_config_gets( + session, cfg, "eviction.threads_min", &cval)) == 0) { + WT_ASSERT(session, cval.val > 0); + conn->evict_workers_min = (u_int)cval.val - 1; + } + WT_RET_NOTFOUND_OK(ret); + + if (conn->evict_workers_min > conn->evict_workers_max) + WT_RET_MSG(session, EINVAL, + "eviction=(threads_min) cannot be greater than " + "eviction=(threads_max)"); return (0); } diff --git a/src/docs/tune-cache.dox b/src/docs/tune-cache.dox index 7cd977dce70..eb3cf3f18f7 100644 --- a/src/docs/tune-cache.dox +++ b/src/docs/tune-cache.dox @@ -59,9 +59,12 @@ By default, WiredTiger cache eviction is handled by a single, separate thread. In a large, busy cache, a single thread will be insufficient (especially when the eviction thread must wait for I/O). Further, if the eviction thread falls behind, application threads will be taken and -used for eviction, potentially resulting in latency spikes. The \c -eviction_workers configuration value can be used to configure additional -WiredTiger threads to support eviction. +used for eviction, potentially resulting in latency spikes. The +\c eviction=(threads_min) and \c eviction=(threads_max) configuration values +can be used to configure the number of threads WiredTiger can use to keep +up with the application eviction load. If WiredTiger eviction threads are +unable to evict enough space in the cache to keep up with application +demand, application threads will be do eviction as well. @snippet ex_all.c Eviction worker configuration diff --git a/src/docs/upgrading.dox b/src/docs/upgrading.dox index de0b9199a31..eaecc3e6b42 100644 --- a/src/docs/upgrading.dox +++ b/src/docs/upgrading.dox @@ -1,5 +1,21 @@ /*! @page upgrading Upgrading WiredTiger applications +@section version_231 Upgrading to Version 2.3.1 + +<dl> +<dt>::wiredtiger_open eviction_workers configuration changed</dt> +<dd> +The \c eviction_workers configuration setting has been replaced by +\c eviction=(threads_min) and \c eviction=(threads_max) settings. To +replicate the old default behavior set +<code>eviction=(threads_min=1,threads_max=1)</code>. + +There is also a semantic change \c eviction_workers used to configure +additional threads whereas the new settings configure the total number +of threads involved with eviction. +</dd> +</dl> + @section version_230 Upgrading to Version 2.3.0 There are no special upgrade steps required. diff --git a/src/include/cache.h b/src/include/cache.h index eb081225ea3..1bc4a0d626e 100644 --- a/src/include/cache.h +++ b/src/include/cache.h @@ -30,6 +30,19 @@ struct __wt_evict_entry { }; /* + * WT_EVICT_WORKER -- + * Encapsulation of an eviction worker thread. + */ + +struct __wt_evict_worker { + WT_SESSION_IMPL *session; + u_int id; + pthread_t tid; +#define WT_EVICT_WORKER_RUN 0x01 + uint32_t flags; +}; + +/* * WiredTiger cache structure. */ struct __wt_cache { diff --git a/src/include/connection.h b/src/include/connection.h index 0f8c69e13b2..b07ece5a9aa 100644 --- a/src/include/connection.h +++ b/src/include/connection.h @@ -203,8 +203,10 @@ struct __wt_connection_impl { pthread_t evict_tid; /* Eviction server thread ID */ int evict_tid_set; /* Eviction server thread ID set */ + uint32_t evict_workers_max;/* Max eviction workers */ + uint32_t evict_workers_min;/* Min eviction workers */ uint32_t evict_workers; /* Number of eviction workers */ - void *evict_workctx; /* Eviction worker context */ + WT_EVICT_WORKER *evict_workctx; /* Eviction worker context */ WT_SESSION_IMPL *stat_session; /* Statistics log session */ pthread_t stat_tid; /* Statistics log thread */ diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in index 5831d9b3591..d5da1249457 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -1518,6 +1518,17 @@ struct __wt_connection { * @config{ ),,} * @config{error_prefix, prefix string for error messages., a string; * default empty.} + * @config{eviction = (, eviction configuration options., a set of + * related configuration options defined below.} + * @config{ threads_max, maximum number of + * threads WiredTiger will start to help evict pages from cache. The + * number of threads currently running will vary depending on the + * current eviction load., an integer between 1 and 20; default \c 3.} + * @config{ threads_min, minimum number of + * threads WiredTiger will start to help evict pages from cache. The + * number of threads currently running will vary depending on the + * current eviction load., an integer between 1 and 20; default \c 1.} + * @config{ ),,} * @config{eviction_dirty_target, continue evicting until the cache has * less dirty memory than the value\, as a percentage of the total cache * size. Dirty pages will only be evicted if the cache is full enough @@ -1529,8 +1540,6 @@ struct __wt_connection { * @config{eviction_trigger, trigger eviction when the cache is using * this much memory\, as a percentage of the total cache size., an * integer between 10 and 99; default \c 95.} - * @config{eviction_workers, additional threads to help evict pages from - * cache., an integer between 0 and 20; default \c 0.} * @config{shared_cache = (, shared cache configuration options. A * database should configure either a cache_size or a shared_cache not * both., a set of related configuration options defined below.} @@ -1833,6 +1842,17 @@ struct __wt_connection { * "log"; default empty.} * @config{error_prefix, prefix string for error messages., a string; default * empty.} + * @config{eviction = (, eviction configuration options., a set of related + * configuration options defined below.} + * @config{ threads_max, maximum number of threads + * WiredTiger will start to help evict pages from cache. The number of threads + * currently running will vary depending on the current eviction load., an + * integer between 1 and 20; default \c 3.} + * @config{ threads_min, minimum number of threads + * WiredTiger will start to help evict pages from cache. The number of threads + * currently running will vary depending on the current eviction load., an + * integer between 1 and 20; default \c 1.} + * @config{ ),,} * @config{eviction_dirty_target, continue evicting until the cache has less * dirty memory than the value\, as a percentage of the total cache size. Dirty * pages will only be evicted if the cache is full enough to trigger eviction., @@ -1843,8 +1863,6 @@ struct __wt_connection { * @config{eviction_trigger, trigger eviction when the cache is using this much * memory\, as a percentage of the total cache size., an integer between 10 and * 99; default \c 95.} - * @config{eviction_workers, additional threads to help evict pages from cache., - * an integer between 0 and 20; default \c 0.} * @config{exclusive, fail if the database already exists\, generally used with * the \c create option., a boolean flag; default \c false.} * @config{extensions, list of shared library extensions to load (using dlopen). diff --git a/src/include/wt_internal.h b/src/include/wt_internal.h index 4c682c553c1..432d42aade9 100644 --- a/src/include/wt_internal.h +++ b/src/include/wt_internal.h @@ -149,6 +149,8 @@ struct __wt_dsrc_stats; typedef struct __wt_dsrc_stats WT_DSRC_STATS; struct __wt_evict_entry; typedef struct __wt_evict_entry WT_EVICT_ENTRY; +struct __wt_evict_worker; + typedef struct __wt_evict_worker WT_EVICT_WORKER; struct __wt_ext; typedef struct __wt_ext WT_EXT; struct __wt_extlist; |