diff options
author | Alex Gorrod <alexg@wiredtiger.com> | 2012-10-29 16:15:55 +1100 |
---|---|---|
committer | Alex Gorrod <alexg@wiredtiger.com> | 2012-10-29 16:15:55 +1100 |
commit | 60afcdd47d9cf437bff99a4670c0fc8ebbefc5f6 (patch) | |
tree | 8eae8d308f5ad3bd04048f2ed2cfa8093fe76679 | |
parent | 45588e93ac172bd5ecf089b7c744aa579134cbfd (diff) | |
download | mongo-60afcdd47d9cf437bff99a4670c0fc8ebbefc5f6.tar.gz |
Add a Python test for cache pool, fix some bugs, and remove
example that was actually a test case.
-rw-r--r-- | examples/c/Makefile.am | 1 | ||||
-rw-r--r-- | examples/c/ex_cache_pool.c | 135 | ||||
-rw-r--r-- | src/conn/cache_pool.c | 11 | ||||
-rw-r--r-- | test/suite/test_cache_pool.py | 200 |
4 files changed, 211 insertions, 136 deletions
diff --git a/examples/c/Makefile.am b/examples/c/Makefile.am index 0638c400cfa..6f26d01a35c 100644 --- a/examples/c/Makefile.am +++ b/examples/c/Makefile.am @@ -3,7 +3,6 @@ LDADD = $(top_builddir)/libwiredtiger.la noinst_PROGRAMS = \ ex_access \ ex_all \ - ex_cache_pool \ ex_call_center \ ex_config \ ex_cursor \ diff --git a/examples/c/ex_cache_pool.c b/examples/c/ex_cache_pool.c deleted file mode 100644 index aa6c9937cb7..00000000000 --- a/examples/c/ex_cache_pool.c +++ /dev/null @@ -1,135 +0,0 @@ -/*- - * Public Domain 2008-2012 WiredTiger, Inc. - * - * This is free and unencumbered software released into the public domain. - * - * Anyone is free to copy, modify, publish, use, compile, sell, or - * distribute this software, either in source code form or as a compiled - * binary, for any purpose, commercial or non-commercial, and by any - * means. - * - * In jurisdictions that recognize copyright laws, the author or authors - * of this software dedicate any and all copyright interest in the - * software to the public domain. We make this dedication for the benefit - * of the public at large and to the detriment of our heirs and - * successors. We intend this dedication to be an overt act of - * relinquishment in perpetuity of all present and future rights to this - * software under copyright law. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * ex_cache_pool.c - * demonstrates how to create multiple databases using a cache pool - */ -#include <stdio.h> -#include <sys/stat.h> -#include <string.h> - -#include <wiredtiger.h> - -int populate_table(WT_SESSION *, const char *, uint64_t); - -#define home "WT_TEST" -#define table_name "table:cache_pool" -const char *pool_name = "pool"; - -int main(void) -{ - WT_CONNECTION *conn1, *conn2; - WT_CURSOR *cursor; - WT_SESSION *session1, *session2; - int i, ret; - - /* TODO: Is this OK? It's horrible. */ - ret = mkdir(home "/" home "1", 755); - ret = mkdir(home "/" home "2", 755); - - /* Create cache that can be shared between multiple databases. */ - if ((ret = wiredtiger_open( - home "/" home "1", NULL, - "create,cache_pool=pool,cache_pool_size=250M,cache_pool_chunk=50M," - "cache_pool_quota=150M,verbose=[cache_pool]", - &conn1)) != 0) - fprintf(stderr, "Error connecting to %s: %s\n", - home "1", wiredtiger_strerror(ret)); - - if ((ret = conn1->open_session(conn1, NULL, NULL, &session1)) != 0) - fprintf(stderr, "Error opening session for %s: %s\n", - home, wiredtiger_strerror(ret)); - - ret = session1->create(session1, - table_name "1", "key_format=L,value_format=S"); - populate_table(session1, table_name "1", 100000); - - /* Create a second connection that shares the cache pool. */ - if ((ret = wiredtiger_open( - home "/" home "2", NULL, - "create,cache_pool=pool,verbose=[cache_pool]", - &conn2)) != 0) - fprintf(stderr, "Error connecting to %s: %s\n", - home "2", wiredtiger_strerror(ret)); - - if ((ret = conn2->open_session(conn2, NULL, NULL, &session2)) != 0) - fprintf(stderr, "Error opening session for %s: %s\n", - home "2", wiredtiger_strerror(ret)); - - ret = session2->create(session2, - table_name "2", "key_format=L,value_format=S"); - populate_table(session2, table_name "2", 100000); - - /* Force session one to require more cache. */ - ret = session1->create(session1, - table_name "1", "key_format=L,value_format=S"); - populate_table(session1, table_name "1", 1000000); - - printf("Entering populate phase.\n"); - for (i = 0; i < 20; i++) { - populate_table(session1, table_name "1", 250000); - populate_table(session2, table_name "2", 250000); - } - /* Stop using the second connection - see if the cache is reduced. */ - printf("Entering single connection update phase.\n"); - for (i = 0; i < 15; i++) - populate_table(session1, table_name "1", 250000); - printf("Entering single connection read phase.\n"); - for (i = 0; i < 5; i++) { - ret = session2->open_cursor( - session2, table_name "2", NULL, NULL, &cursor); - while (cursor->next(cursor) == 0) {} - cursor->close(cursor); - } - - ret = conn1->close(conn1, NULL); - ret = conn2->close(conn2, NULL); - - return (ret); -} - -int populate_table(WT_SESSION *session, const char *table, uint64_t nops) -{ - WT_CURSOR *cursor; - int ret; - uint64_t i, start; - - ret = session->open_cursor(session, table, NULL, NULL, &cursor); - start = 0; - if (cursor->prev(cursor) != WT_NOTFOUND) { - cursor->get_key(cursor, &start); - cursor->reset(cursor); - } - - cursor->set_value(cursor, - "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); - for (i = start + 1; i < nops + start; i++) { - cursor->set_key(cursor, i); - ret = cursor->insert(cursor); - } - cursor->close(cursor); - return (ret); -} diff --git a/src/conn/cache_pool.c b/src/conn/cache_pool.c index 902c24833d0..5d3388543a1 100644 --- a/src/conn/cache_pool.c +++ b/src/conn/cache_pool.c @@ -179,6 +179,11 @@ __wt_conn_cache_pool_destroy(WT_CONNECTION_IMPL *conn) return (0); } WT_VERBOSE_VOID(session, cache_pool, "Destroying cache pool."); + /* Shut down the cache pool worker. */ + __wt_cond_signal( + conn->default_session, cp->cache_pool_cond); + WT_TRET(__wt_thread_join(cp->cache_pool_tid)); + /* * Get the pool lock out of paranoia there should not be * any connections accessing the contents. @@ -219,6 +224,12 @@ __wt_cache_pool_server(void *arg) */ while (F_SET(cp, WT_CACHE_POOL_RUN)) { __wt_cond_wait(NULL, cp->cache_pool_cond, 1000000); + /* + * Re-check pool run flag - since we want to avoid getting the + * lock on shutdown. + */ + if (!F_ISSET(cp, WT_CACHE_POOL_RUN)) + break; __wt_spin_lock(NULL, &cp->cache_pool_lock); entry = NULL; if (!TAILQ_EMPTY(&cp->cache_pool_qh)) diff --git a/test/suite/test_cache_pool.py b/test/suite/test_cache_pool.py new file mode 100644 index 00000000000..f402afb2b6b --- /dev/null +++ b/test/suite/test_cache_pool.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python +# +# Public Domain 2008-2012 WiredTiger, Inc. +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# If unittest2 is available, use it in preference to (the old) unittest +try: + import unittest2 as unittest +except ImportError: + import unittest + +import os +import shutil +import wiredtiger, wttest +from helper import key_populate, simple_populate + +# test_cache_pool.py +# Checkpoint tests +# Test cache pool shared amongst multiple connections. +class test_cache_pool(wttest.WiredTigerTestCase): + + uri = 'table:test_cache_pool' + # Setup fairly large items to use up cache + data_str = 'abcdefghijklmnopqrstuvwxyz' * 20 + + # Add a set of records + def add_records(self, session, start, stop): + cursor = session.open_cursor(self.uri, None, "overwrite") + for i in range(start, stop+1): + cursor.set_key("%010d KEY------" % i) + cursor.set_value("%010d VALUE "% i + self.data_str) + self.assertEqual(cursor.insert(), 0) + cursor.close() + + # Disable default setup/shutdown steps - connections are managed manually. + def setUpSessionOpen(self, conn): + return None + + def close_conn(self): + return None + + def setUpConnectionOpen(self, dir): + return None + + def openConnections( + self, + connections, + pool_opts = ',cache_pool=pool,cache_pool_size=200M,cache_pool_chunk=20M,cache_pool_quota=100M,', + extra_opts = '', + add=0): + if add == 0: + self.conns = [] + self.sessions = [] + # Open the set of connections. + for name in connections: + shutil.rmtree(name, True) + os.mkdir(name) + next_conn = wiredtiger.wiredtiger_open( + name, + 'create,error_prefix="' + self.shortid() + ': "' + + pool_opts + extra_opts) + self.conns.append(next_conn) + self.sessions.append(next_conn.open_session(None)) + return None + + def closeConnections(self): + for tmp_conn in self.conns: + tmp_conn.close() + self.conns = [] + self.sessions = [] # Implicitly closed when closing sessions. + + # Basic test of cache pool + def test_cache_pool1(self): + nops = 1000 + self.openConnections(['WT_TEST1', 'WT_TEST2']) + + for sess in self.sessions: + sess.create(self.uri, "key_format=S,value_format=S") + self.add_records(sess, 0, nops) + self.closeConnections() + + # Test of cache pool with more connections + def test_cache_pool2(self): + nops = 1000 + self.openConnections(['WT_TEST1', 'WT_TEST2', 'WT_TEST3', 'WT_TEST4']) + + for sess in self.sessions: + sess.create(self.uri, "key_format=S,value_format=S") + self.add_records(sess, 0, nops) + self.closeConnections() + + # Do enough work, so that the cache pool gets used. + def test_cache_pool3(self): + nops = 10000 + self.openConnections(['WT_TEST1', 'WT_TEST2']) + for sess in self.sessions: + sess.create(self.uri, "key_format=S,value_format=S") + + for i in range(20): + for sess in self.sessions: + self.add_records(sess, i * nops, (i + 1) * nops) + self.closeConnections() + + # Switch the work between connections, to test rebalancing. + def test_cache_pool4(self): + # About 100 MB of data with ~250 byte values. + nops = 200000 + self.openConnections(['WT_TEST1', 'WT_TEST2']) + + for sess in self.sessions: + sess.create(self.uri, "key_format=S,value_format=S") + self.add_records(sess, 0, nops) + self.closeConnections() + + # Add a new connection once the pool is already established. + def test_cache_pool5(self): + nops = 1000 + self.openConnections(['WT_TEST1', 'WT_TEST2']) + + for sess in self.sessions: + sess.create(self.uri, "key_format=S,value_format=S") + self.add_records(sess, 0, nops) + + self.openConnections(['WT_TEST3'], add=1) + for sess in self.sessions: + sess.create(self.uri, "key_format=S,value_format=S") + self.add_records(sess, 0, nops) + self.closeConnections() + + # Close a connection and keep using other connections. + def test_cache_pool6(self): + nops = 10000 + self.openConnections(['WT_TEST1', 'WT_TEST2', 'WT_TEST3']) + + for sess in self.sessions: + sess.create(self.uri, "key_format=S,value_format=S") + self.add_records(sess, 0, nops) + conn = self.conns.pop() + conn.close() + self.sessions.pop() + for sess in self.sessions: + self.add_records(sess, 0, nops) + self.closeConnections() + + # Test verbose output + @unittest.skip("Verbose output handling") + def test_cache_pool7(self): + nops = 1000 + self.openConnections( + ['WT_TEST1', 'WT_TEST2'], extra_opts="verbose=[cache_pool]") + + for sess in self.sessions: + sess.create(self.uri, "key_format=S,value_format=S") + self.add_records(sess, 0, nops) + self.closeConnections() + + # Test opening a connection outside of the cache pool + def test_cache_pool8(self): + nops = 1000 + self.openConnections(['WT_TEST1', 'WT_TEST2']) + + self.openConnections(['WT_TEST3'], add=1, pool_opts=',cache_size=50M') + for sess in self.sessions: + sess.create(self.uri, "key_format=S,value_format=S") + self.add_records(sess, 0, nops) + self.closeConnections() + + # Test default config values + def test_cache_pool9(self): + nops = 1000 + self.openConnections(['WT_TEST1', 'WT_TEST2'], pool_opts=',cache_pool=pool,cache_pool_size=200M') + + for sess in self.sessions: + sess.create(self.uri, "key_format=S,value_format=S") + self.add_records(sess, 0, nops) + self.closeConnections() + +if __name__ == '__main__': + wttest.run() |