summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gorrod <alexg@wiredtiger.com>2012-10-29 16:15:55 +1100
committerAlex Gorrod <alexg@wiredtiger.com>2012-10-29 16:15:55 +1100
commit60afcdd47d9cf437bff99a4670c0fc8ebbefc5f6 (patch)
tree8eae8d308f5ad3bd04048f2ed2cfa8093fe76679
parent45588e93ac172bd5ecf089b7c744aa579134cbfd (diff)
downloadmongo-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.am1
-rw-r--r--examples/c/ex_cache_pool.c135
-rw-r--r--src/conn/cache_pool.c11
-rw-r--r--test/suite/test_cache_pool.py200
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()