summaryrefslogtreecommitdiff
path: root/storage/tokudb/ft-index/util
diff options
context:
space:
mode:
Diffstat (limited to 'storage/tokudb/ft-index/util')
-rw-r--r--storage/tokudb/ft-index/util/CMakeLists.txt4
-rw-r--r--storage/tokudb/ft-index/util/context.cc242
-rw-r--r--storage/tokudb/ft-index/util/context.h204
-rw-r--r--storage/tokudb/ft-index/util/frwlock.cc70
-rw-r--r--storage/tokudb/ft-index/util/frwlock.h47
-rw-r--r--storage/tokudb/ft-index/util/kibbutz.cc19
-rw-r--r--storage/tokudb/ft-index/util/kibbutz.h2
-rw-r--r--storage/tokudb/ft-index/util/mempool.cc17
-rw-r--r--storage/tokudb/ft-index/util/mempool.h7
-rw-r--r--storage/tokudb/ft-index/util/scoped_malloc.cc265
-rw-r--r--storage/tokudb/ft-index/util/scoped_malloc.h153
-rw-r--r--storage/tokudb/ft-index/util/tests/test-frwlock-fair-writers.cc52
-rw-r--r--storage/tokudb/ft-index/util/tests/test-kibbutz.cc4
-rw-r--r--storage/tokudb/ft-index/util/tests/test-kibbutz2.cc4
-rw-r--r--storage/tokudb/ft-index/util/tests/test-rwlock-cheapness.cc11
-rw-r--r--storage/tokudb/ft-index/util/tests/test-rwlock-unfair-writers.cc60
-rw-r--r--storage/tokudb/ft-index/util/tests/test-rwlock.cc298
17 files changed, 1110 insertions, 349 deletions
diff --git a/storage/tokudb/ft-index/util/CMakeLists.txt b/storage/tokudb/ft-index/util/CMakeLists.txt
index abfc88cc711..08822c4a73c 100644
--- a/storage/tokudb/ft-index/util/CMakeLists.txt
+++ b/storage/tokudb/ft-index/util/CMakeLists.txt
@@ -1,8 +1,11 @@
set(util_srcs
+ context
+ frwlock
kibbutz
mempool
partitioned_counter
threadpool
+ scoped_malloc
)
add_library(util SHARED ${util_srcs})
@@ -19,6 +22,7 @@ if (NOT DEFINED MYSQL_PROJECT_NAME_DOCSTRING)
install(
FILES partitioned_counter.h
DESTINATION include
+ COMPONENT tokukv_headers
)
endif ()
diff --git a/storage/tokudb/ft-index/util/context.cc b/storage/tokudb/ft-index/util/context.cc
new file mode 100644
index 00000000000..350cac07960
--- /dev/null
+++ b/storage/tokudb/ft-index/util/context.cc
@@ -0,0 +1,242 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*
+COPYING CONDITIONS NOTICE:
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation, and provided that the
+ following conditions are met:
+
+ * Redistributions of source code must retain this COPYING
+ CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
+ DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
+ PATENT MARKING NOTICE (below), and the PATENT RIGHTS
+ GRANT (below).
+
+ * Redistributions in binary form must reproduce this COPYING
+ CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
+ DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
+ PATENT MARKING NOTICE (below), and the PATENT RIGHTS
+ GRANT (below) in the documentation and/or other materials
+ provided with the distribution.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+COPYRIGHT NOTICE:
+
+ TokuDB, Tokutek Fractal Tree Indexing Library.
+ Copyright (C) 2007-2014 Tokutek, Inc.
+
+DISCLAIMER:
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+UNIVERSITY PATENT NOTICE:
+
+ The technology is licensed by the Massachusetts Institute of
+ Technology, Rutgers State University of New Jersey, and the Research
+ Foundation of State University of New York at Stony Brook under
+ United States of America Serial No. 11/760379 and to the patents
+ and/or patent applications resulting from it.
+
+PATENT MARKING NOTICE:
+
+ This software is covered by US Patent No. 8,185,551.
+ This software is covered by US Patent No. 8,489,638.
+
+PATENT RIGHTS GRANT:
+
+ "THIS IMPLEMENTATION" means the copyrightable works distributed by
+ Tokutek as part of the Fractal Tree project.
+
+ "PATENT CLAIMS" means the claims of patents that are owned or
+ licensable by Tokutek, both currently or in the future; and that in
+ the absence of this license would be infringed by THIS
+ IMPLEMENTATION or by using or running THIS IMPLEMENTATION.
+
+ "PATENT CHALLENGE" shall mean a challenge to the validity,
+ patentability, enforceability and/or non-infringement of any of the
+ PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.
+
+ Tokutek hereby grants to you, for the term and geographical scope of
+ the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
+ irrevocable (except as stated in this section) patent license to
+ make, have made, use, offer to sell, sell, import, transfer, and
+ otherwise run, modify, and propagate the contents of THIS
+ IMPLEMENTATION, where such license applies only to the PATENT
+ CLAIMS. This grant does not include claims that would be infringed
+ only as a consequence of further modifications of THIS
+ IMPLEMENTATION. If you or your agent or licensee institute or order
+ or agree to the institution of patent litigation against any entity
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
+ THIS IMPLEMENTATION constitutes direct or contributory patent
+ infringement, or inducement of patent infringement, then any rights
+ granted to you under this License shall terminate as of the date
+ such litigation is filed. If you or your agent or exclusive
+ licensee institute or order or agree to the institution of a PATENT
+ CHALLENGE, then Tokutek may terminate any rights granted to you
+ under this License.
+*/
+
+#ident "Copyright (c) 2007-2014 Tokutek Inc. All rights reserved."
+#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
+
+#include <string.h>
+
+#include <util/context.h>
+
+namespace toku {
+
+ static const context default_context(CTX_DEFAULT);
+ static __thread const context *tl_current_context = &default_context;
+
+ // save the old context, set the current context
+ context::context(const context_id id) :
+ m_old_ctx(tl_current_context),
+ m_id(id) {
+ tl_current_context = this;
+ }
+
+ // restore the old context
+ context::~context() {
+ tl_current_context = m_old_ctx;
+ }
+
+} // namespace toku
+
+// thread local context
+
+const toku::context *toku_thread_get_context() {
+ return toku::tl_current_context;
+}
+
+// engine status
+
+static struct context_status context_status;
+#define CONTEXT_STATUS_INIT(key, legend) TOKUDB_STATUS_INIT(context_status, key, nullptr, PARCOUNT, "context: " legend, TOKU_ENGINE_STATUS)
+
+static void
+context_status_init(void) {
+ CONTEXT_STATUS_INIT(CTX_SEARCH_BLOCKED_BY_FULL_FETCH, "tree traversals blocked by a full fetch");
+ CONTEXT_STATUS_INIT(CTX_SEARCH_BLOCKED_BY_PARTIAL_FETCH, "tree traversals blocked by a partial fetch");
+ CONTEXT_STATUS_INIT(CTX_SEARCH_BLOCKED_BY_FULL_EVICTION, "tree traversals blocked by a full eviction");
+ CONTEXT_STATUS_INIT(CTX_SEARCH_BLOCKED_BY_PARTIAL_EVICTION, "tree traversals blocked by a partial eviction");
+ CONTEXT_STATUS_INIT(CTX_SEARCH_BLOCKED_BY_MESSAGE_INJECTION, "tree traversals blocked by a message injection");
+ CONTEXT_STATUS_INIT(CTX_SEARCH_BLOCKED_BY_MESSAGE_APPLICATION, "tree traversals blocked by a message application");
+ CONTEXT_STATUS_INIT(CTX_SEARCH_BLOCKED_BY_FLUSH, "tree traversals blocked by a flush");
+ CONTEXT_STATUS_INIT(CTX_SEARCH_BLOCKED_BY_CLEANER, "tree traversals blocked by a the cleaner thread");
+ CONTEXT_STATUS_INIT(CTX_SEARCH_BLOCKED_OTHER, "tree traversals blocked by something uninstrumented");
+ CONTEXT_STATUS_INIT(CTX_PROMO_BLOCKED_BY_FULL_FETCH, "promotion blocked by a full fetch (should never happen)");
+ CONTEXT_STATUS_INIT(CTX_PROMO_BLOCKED_BY_PARTIAL_FETCH, "promotion blocked by a partial fetch (should never happen)");
+ CONTEXT_STATUS_INIT(CTX_PROMO_BLOCKED_BY_FULL_EVICTION, "promotion blocked by a full eviction (should never happen)");
+ CONTEXT_STATUS_INIT(CTX_PROMO_BLOCKED_BY_PARTIAL_EVICTION, "promotion blocked by a partial eviction (should never happen)");
+ CONTEXT_STATUS_INIT(CTX_PROMO_BLOCKED_BY_MESSAGE_INJECTION, "promotion blocked by a message injection");
+ CONTEXT_STATUS_INIT(CTX_PROMO_BLOCKED_BY_MESSAGE_APPLICATION, "promotion blocked by a message application");
+ CONTEXT_STATUS_INIT(CTX_PROMO_BLOCKED_BY_FLUSH, "promotion blocked by a flush");
+ CONTEXT_STATUS_INIT(CTX_PROMO_BLOCKED_BY_CLEANER, "promotion blocked by the cleaner thread");
+ CONTEXT_STATUS_INIT(CTX_PROMO_BLOCKED_OTHER, "promotion blocked by something uninstrumented");
+ CONTEXT_STATUS_INIT(CTX_BLOCKED_OTHER, "something uninstrumented blocked by something uninstrumented");
+ context_status.initialized = true;
+}
+#undef FS_STATUS_INIT
+
+void toku_context_get_status(struct context_status *status) {
+ if (!context_status.initialized) {
+ context_status_init();
+ }
+ *status = context_status;
+}
+
+#define STATUS_INC(x, d) increment_partitioned_counter(context_status.status[x].value.parcount, d);
+
+void toku_context_note_frwlock_contention(const context_id blocked, const context_id blocking) {
+ if (!context_status.initialized) {
+ context_status_init();
+ }
+ if (blocked != CTX_SEARCH && blocked != CTX_PROMO) {
+ // Return early if this event is "unknown"
+ STATUS_INC(CTX_BLOCKED_OTHER, 1);
+ return;
+ }
+ switch (blocking) {
+ case CTX_FULL_FETCH:
+ if (blocked == CTX_SEARCH) {
+ STATUS_INC(CTX_SEARCH_BLOCKED_BY_FULL_FETCH, 1);
+ } else if (blocked == CTX_PROMO) {
+ STATUS_INC(CTX_PROMO_BLOCKED_BY_FULL_FETCH, 1);
+ }
+ break;
+ case CTX_PARTIAL_FETCH:
+ if (blocked == CTX_SEARCH) {
+ STATUS_INC(CTX_SEARCH_BLOCKED_BY_PARTIAL_FETCH, 1);
+ } else if (blocked == CTX_PROMO) {
+ STATUS_INC(CTX_PROMO_BLOCKED_BY_PARTIAL_FETCH, 1);
+ }
+ break;
+ case CTX_FULL_EVICTION:
+ if (blocked == CTX_SEARCH) {
+ STATUS_INC(CTX_SEARCH_BLOCKED_BY_FULL_EVICTION, 1);
+ } else if (blocked == CTX_PROMO) {
+ STATUS_INC(CTX_PROMO_BLOCKED_BY_FULL_EVICTION, 1);
+ }
+ break;
+ case CTX_PARTIAL_EVICTION:
+ if (blocked == CTX_SEARCH) {
+ STATUS_INC(CTX_SEARCH_BLOCKED_BY_PARTIAL_EVICTION, 1);
+ } else if (blocked == CTX_PROMO) {
+ STATUS_INC(CTX_PROMO_BLOCKED_BY_PARTIAL_EVICTION, 1);
+ }
+ break;
+ case CTX_MESSAGE_INJECTION:
+ if (blocked == CTX_SEARCH) {
+ STATUS_INC(CTX_SEARCH_BLOCKED_BY_MESSAGE_INJECTION, 1);
+ } else if (blocked == CTX_PROMO) {
+ STATUS_INC(CTX_PROMO_BLOCKED_BY_MESSAGE_INJECTION, 1);
+ }
+ break;
+ case CTX_MESSAGE_APPLICATION:
+ if (blocked == CTX_SEARCH) {
+ STATUS_INC(CTX_SEARCH_BLOCKED_BY_MESSAGE_APPLICATION, 1);
+ } else if (blocked == CTX_PROMO) {
+ STATUS_INC(CTX_PROMO_BLOCKED_BY_MESSAGE_APPLICATION, 1);
+ }
+ break;
+ case CTX_FLUSH:
+ if (blocked == CTX_SEARCH) {
+ STATUS_INC(CTX_SEARCH_BLOCKED_BY_FLUSH, 1);
+ } else if (blocked == CTX_PROMO) {
+ STATUS_INC(CTX_PROMO_BLOCKED_BY_FLUSH, 1);
+ }
+ break;
+ case CTX_CLEANER:
+ if (blocked == CTX_SEARCH) {
+ STATUS_INC(CTX_SEARCH_BLOCKED_BY_CLEANER, 1);
+ } else if (blocked == CTX_PROMO) {
+ STATUS_INC(CTX_PROMO_BLOCKED_BY_CLEANER, 1);
+ }
+ break;
+ default:
+ if (blocked == CTX_SEARCH) {
+ STATUS_INC(CTX_SEARCH_BLOCKED_OTHER, 1);
+ } else if (blocked == CTX_PROMO) {
+ STATUS_INC(CTX_PROMO_BLOCKED_OTHER, 1);
+ }
+ break;
+ }
+}
+
+void toku_context_status_destroy(void) {
+ for (int i = 0; i < CTX_STATUS_NUM_ROWS; ++i) {
+ if (context_status.status[i].type == PARCOUNT) {
+ destroy_partitioned_counter(context_status.status[i].value.parcount);
+ }
+ }
+}
diff --git a/storage/tokudb/ft-index/util/context.h b/storage/tokudb/ft-index/util/context.h
new file mode 100644
index 00000000000..3d424ff597d
--- /dev/null
+++ b/storage/tokudb/ft-index/util/context.h
@@ -0,0 +1,204 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*
+COPYING CONDITIONS NOTICE:
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation, and provided that the
+ following conditions are met:
+
+ * Redistributions of source code must retain this COPYING
+ CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
+ DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
+ PATENT MARKING NOTICE (below), and the PATENT RIGHTS
+ GRANT (below).
+
+ * Redistributions in binary form must reproduce this COPYING
+ CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
+ DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
+ PATENT MARKING NOTICE (below), and the PATENT RIGHTS
+ GRANT (below) in the documentation and/or other materials
+ provided with the distribution.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+COPYRIGHT NOTICE:
+
+ TokuDB, Tokutek Fractal Tree Indexing Library.
+ Copyright (C) 2007-2014 Tokutek, Inc.
+
+DISCLAIMER:
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+UNIVERSITY PATENT NOTICE:
+
+ The technology is licensed by the Massachusetts Institute of
+ Technology, Rutgers State University of New Jersey, and the Research
+ Foundation of State University of New York at Stony Brook under
+ United States of America Serial No. 11/760379 and to the patents
+ and/or patent applications resulting from it.
+
+PATENT MARKING NOTICE:
+
+ This software is covered by US Patent No. 8,185,551.
+ This software is covered by US Patent No. 8,489,638.
+
+PATENT RIGHTS GRANT:
+
+ "THIS IMPLEMENTATION" means the copyrightable works distributed by
+ Tokutek as part of the Fractal Tree project.
+
+ "PATENT CLAIMS" means the claims of patents that are owned or
+ licensable by Tokutek, both currently or in the future; and that in
+ the absence of this license would be infringed by THIS
+ IMPLEMENTATION or by using or running THIS IMPLEMENTATION.
+
+ "PATENT CHALLENGE" shall mean a challenge to the validity,
+ patentability, enforceability and/or non-infringement of any of the
+ PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.
+
+ Tokutek hereby grants to you, for the term and geographical scope of
+ the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
+ irrevocable (except as stated in this section) patent license to
+ make, have made, use, offer to sell, sell, import, transfer, and
+ otherwise run, modify, and propagate the contents of THIS
+ IMPLEMENTATION, where such license applies only to the PATENT
+ CLAIMS. This grant does not include claims that would be infringed
+ only as a consequence of further modifications of THIS
+ IMPLEMENTATION. If you or your agent or licensee institute or order
+ or agree to the institution of patent litigation against any entity
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
+ THIS IMPLEMENTATION constitutes direct or contributory patent
+ infringement, or inducement of patent infringement, then any rights
+ granted to you under this License shall terminate as of the date
+ such litigation is filed. If you or your agent or exclusive
+ licensee institute or order or agree to the institution of a PATENT
+ CHALLENGE, then Tokutek may terminate any rights granted to you
+ under this License.
+*/
+
+#pragma once
+
+#ident "Copyright (c) 2007-2014 Tokutek Inc. All rights reserved."
+#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
+
+#include <toku_include/toku_portability.h>
+
+#include <db.h>
+
+#include <util/status.h>
+
+enum context_id {
+ CTX_INVALID = -1,
+ CTX_DEFAULT = 0, // default context for when no context is set
+ CTX_SEARCH, // searching for a key at the bottom of the tree
+ CTX_PROMO, // promoting a message down the tree
+ CTX_FULL_FETCH, // performing full fetch (pivots + some partial fetch)
+ CTX_PARTIAL_FETCH, // performing partial fetch
+ CTX_FULL_EVICTION, // running partial eviction
+ CTX_PARTIAL_EVICTION, // running partial eviction
+ CTX_MESSAGE_INJECTION, // injecting a message into a buffer
+ CTX_MESSAGE_APPLICATION, // applying ancestor's messages to a basement node
+ CTX_FLUSH, // flushing a buffer
+ CTX_CLEANER // doing work as the cleaner thread
+};
+
+// Note a contention event in engine status
+void toku_context_note_frwlock_contention(const context_id blocking, const context_id blocked);
+
+namespace toku {
+
+ // class for tracking what a thread is doing
+ //
+ // usage:
+ //
+ // // automatically tag and document what you're doing
+ // void my_interesting_function(void) {
+ // toku::context ctx("doing something interesting", INTERESTING_FN_1);
+ // ...
+ // {
+ // toku::context inner_ctx("doing something expensive", EXPENSIVE_FN_1);
+ // my_rwlock.wrlock();
+ // expensive();
+ // my_rwlock.wrunlock();
+ // }
+ // ...
+ // }
+ //
+ // // ... so later you can write code like this.
+ // // here, we save some info to help determine why a lock could not be acquired
+ // void my_rwlock::wrlock() {
+ // r = try_acquire_write_lock();
+ // if (r == 0) {
+ // m_write_locked_context_id = get_thread_local_context()->get_id();
+ // ...
+ // } else {
+ // if (m_write_locked_context_id == EXPENSIVE_FN_1) {
+ // status.blocked_because_of_expensive_fn_1++;
+ // } else if (...) {
+ // ...
+ // }
+ // ...
+ // }
+ // }
+ class context {
+ public:
+ context(const context_id id);
+
+ ~context();
+
+ context_id get_id() const {
+ return m_id;
+ }
+
+ private:
+ // each thread has a stack of contexts, rooted at the trivial "root context"
+ const context *m_old_ctx;
+ const context_id m_id;
+ };
+
+} // namespace toku
+
+// Get the current context of this thread
+const toku::context *toku_thread_get_context();
+
+enum context_status_entry {
+ CTX_SEARCH_BLOCKED_BY_FULL_FETCH = 0,
+ CTX_SEARCH_BLOCKED_BY_PARTIAL_FETCH,
+ CTX_SEARCH_BLOCKED_BY_FULL_EVICTION,
+ CTX_SEARCH_BLOCKED_BY_PARTIAL_EVICTION,
+ CTX_SEARCH_BLOCKED_BY_MESSAGE_INJECTION,
+ CTX_SEARCH_BLOCKED_BY_MESSAGE_APPLICATION,
+ CTX_SEARCH_BLOCKED_BY_FLUSH,
+ CTX_SEARCH_BLOCKED_BY_CLEANER,
+ CTX_SEARCH_BLOCKED_OTHER,
+ CTX_PROMO_BLOCKED_BY_FULL_FETCH,
+ CTX_PROMO_BLOCKED_BY_PARTIAL_FETCH,
+ CTX_PROMO_BLOCKED_BY_FULL_EVICTION,
+ CTX_PROMO_BLOCKED_BY_PARTIAL_EVICTION,
+ CTX_PROMO_BLOCKED_BY_MESSAGE_INJECTION,
+ CTX_PROMO_BLOCKED_BY_MESSAGE_APPLICATION,
+ CTX_PROMO_BLOCKED_BY_FLUSH,
+ CTX_PROMO_BLOCKED_BY_CLEANER,
+ CTX_PROMO_BLOCKED_OTHER,
+ CTX_BLOCKED_OTHER,
+ CTX_STATUS_NUM_ROWS
+};
+
+struct context_status {
+ bool initialized;
+ TOKU_ENGINE_STATUS_ROW_S status[CTX_STATUS_NUM_ROWS];
+};
+
+void toku_context_get_status(struct context_status *status);
+
+void toku_context_status_destroy(void);
diff --git a/storage/tokudb/ft-index/util/frwlock.cc b/storage/tokudb/ft-index/util/frwlock.cc
index 7400f3c4abc..7259c776f83 100644
--- a/storage/tokudb/ft-index/util/frwlock.cc
+++ b/storage/tokudb/ft-index/util/frwlock.cc
@@ -91,8 +91,19 @@ PATENT RIGHTS GRANT:
#include <toku_assert.h>
+#include <util/context.h>
+#include <util/frwlock.h>
+
namespace toku {
+static __thread int thread_local_tid = -1;
+static int get_local_tid() {
+ if (thread_local_tid == -1) {
+ thread_local_tid = toku_os_gettid();
+ }
+ return thread_local_tid;
+}
+
void frwlock::init(toku_mutex_t *const mutex) {
m_mutex = mutex;
@@ -109,6 +120,8 @@ void frwlock::init(toku_mutex_t *const mutex) {
m_wait_read_is_in_queue = false;
m_current_writer_expensive = false;
m_read_wait_expensive = false;
+ m_current_writer_tid = -1;
+ m_blocking_writer_context_id = CTX_INVALID;
m_wait_head = nullptr;
m_wait_tail = nullptr;
@@ -118,11 +131,11 @@ void frwlock::deinit(void) {
toku_cond_destroy(&m_wait_read);
}
-inline bool frwlock::queue_is_empty(void) const {
+bool frwlock::queue_is_empty(void) const {
return m_wait_head == nullptr;
}
-inline void frwlock::enq_item(queue_item *const item) {
+void frwlock::enq_item(queue_item *const item) {
paranoid_invariant_null(item->next);
if (m_wait_tail != nullptr) {
m_wait_tail->next = item;
@@ -133,7 +146,7 @@ inline void frwlock::enq_item(queue_item *const item) {
m_wait_tail = item;
}
-inline toku_cond_t *frwlock::deq_item(void) {
+toku_cond_t *frwlock::deq_item(void) {
paranoid_invariant_notnull(m_wait_head);
paranoid_invariant_notnull(m_wait_tail);
queue_item *item = m_wait_head;
@@ -145,7 +158,7 @@ inline toku_cond_t *frwlock::deq_item(void) {
}
// Prerequisite: Holds m_mutex.
-inline void frwlock::write_lock(bool expensive) {
+void frwlock::write_lock(bool expensive) {
toku_mutex_assert_locked(m_mutex);
if (this->try_write_lock(expensive)) {
return;
@@ -160,6 +173,13 @@ inline void frwlock::write_lock(bool expensive) {
if (expensive) {
++m_num_expensive_want_write;
}
+ if (m_num_writers == 0 && m_num_want_write == 1) {
+ // We are the first to want a write lock. No new readers can get the lock.
+ // Set our thread id and context for proper instrumentation.
+ // see: toku_context_note_frwlock_contention()
+ m_current_writer_tid = get_local_tid();
+ m_blocking_writer_context_id = toku_thread_get_context()->get_id();
+ }
toku_cond_wait(&cond, m_mutex);
toku_cond_destroy(&cond);
@@ -176,9 +196,11 @@ inline void frwlock::write_lock(bool expensive) {
}
m_num_writers = 1;
m_current_writer_expensive = expensive;
+ m_current_writer_tid = get_local_tid();
+ m_blocking_writer_context_id = toku_thread_get_context()->get_id();
}
-inline bool frwlock::try_write_lock(bool expensive) {
+bool frwlock::try_write_lock(bool expensive) {
toku_mutex_assert_locked(m_mutex);
if (m_num_readers > 0 || m_num_writers > 0 || m_num_signaled_readers > 0 || m_num_want_write > 0) {
return false;
@@ -188,10 +210,12 @@ inline bool frwlock::try_write_lock(bool expensive) {
paranoid_invariant_zero(m_num_want_read);
m_num_writers = 1;
m_current_writer_expensive = expensive;
+ m_current_writer_tid = get_local_tid();
+ m_blocking_writer_context_id = toku_thread_get_context()->get_id();
return true;
}
-inline void frwlock::read_lock(void) {
+void frwlock::read_lock(void) {
toku_mutex_assert_locked(m_mutex);
if (m_num_writers > 0 || m_num_want_write > 0) {
if (!m_wait_read_is_in_queue) {
@@ -207,6 +231,12 @@ inline void frwlock::read_lock(void) {
);
}
+ // Note this contention event in engine status.
+ toku_context_note_frwlock_contention(
+ toku_thread_get_context()->get_id(),
+ m_blocking_writer_context_id
+ );
+
// Wait for our turn.
++m_num_want_read;
toku_cond_wait(&m_wait_read, m_mutex);
@@ -223,7 +253,7 @@ inline void frwlock::read_lock(void) {
++m_num_readers;
}
-inline bool frwlock::try_read_lock(void) {
+bool frwlock::try_read_lock(void) {
toku_mutex_assert_locked(m_mutex);
if (m_num_writers > 0 || m_num_want_write > 0) {
return false;
@@ -235,7 +265,7 @@ inline bool frwlock::try_read_lock(void) {
return true;
}
-inline void frwlock::maybe_signal_next_writer(void) {
+void frwlock::maybe_signal_next_writer(void) {
if (m_num_want_write > 0 && m_num_signaled_readers == 0 && m_num_readers == 0) {
toku_cond_t *cond = this->deq_item();
paranoid_invariant(cond != &m_wait_read);
@@ -245,7 +275,7 @@ inline void frwlock::maybe_signal_next_writer(void) {
}
}
-inline void frwlock::read_unlock(void) {
+void frwlock::read_unlock(void) {
toku_mutex_assert_locked(m_mutex);
paranoid_invariant(m_num_writers == 0);
paranoid_invariant(m_num_readers > 0);
@@ -253,7 +283,7 @@ inline void frwlock::read_unlock(void) {
this->maybe_signal_next_writer();
}
-inline bool frwlock::read_lock_is_expensive(void) {
+bool frwlock::read_lock_is_expensive(void) {
toku_mutex_assert_locked(m_mutex);
if (m_wait_read_is_in_queue) {
return m_read_wait_expensive;
@@ -264,7 +294,7 @@ inline bool frwlock::read_lock_is_expensive(void) {
}
-inline void frwlock::maybe_signal_or_broadcast_next(void) {
+void frwlock::maybe_signal_or_broadcast_next(void) {
paranoid_invariant(m_num_signaled_readers == 0);
if (this->queue_is_empty()) {
@@ -289,42 +319,44 @@ inline void frwlock::maybe_signal_or_broadcast_next(void) {
}
}
-inline void frwlock::write_unlock(void) {
+void frwlock::write_unlock(void) {
toku_mutex_assert_locked(m_mutex);
paranoid_invariant(m_num_writers == 1);
m_num_writers = 0;
m_current_writer_expensive = false;
+ m_current_writer_tid = -1;
+ m_blocking_writer_context_id = CTX_INVALID;
this->maybe_signal_or_broadcast_next();
}
-inline bool frwlock::write_lock_is_expensive(void) {
+bool frwlock::write_lock_is_expensive(void) {
toku_mutex_assert_locked(m_mutex);
return (m_num_expensive_want_write > 0) || (m_current_writer_expensive);
}
-inline uint32_t frwlock::users(void) const {
+uint32_t frwlock::users(void) const {
toku_mutex_assert_locked(m_mutex);
return m_num_readers + m_num_writers + m_num_want_read + m_num_want_write;
}
-inline uint32_t frwlock::blocked_users(void) const {
+uint32_t frwlock::blocked_users(void) const {
toku_mutex_assert_locked(m_mutex);
return m_num_want_read + m_num_want_write;
}
-inline uint32_t frwlock::writers(void) const {
+uint32_t frwlock::writers(void) const {
// this is sometimes called as "assert(lock->writers())" when we
// assume we have the write lock. if that's the assumption, we may
// not own the mutex, so we don't assert_locked here
return m_num_writers;
}
-inline uint32_t frwlock::blocked_writers(void) const {
+uint32_t frwlock::blocked_writers(void) const {
toku_mutex_assert_locked(m_mutex);
return m_num_want_write;
}
-inline uint32_t frwlock::readers(void) const {
+uint32_t frwlock::readers(void) const {
toku_mutex_assert_locked(m_mutex);
return m_num_readers;
}
-inline uint32_t frwlock::blocked_readers(void) const {
+uint32_t frwlock::blocked_readers(void) const {
toku_mutex_assert_locked(m_mutex);
return m_num_want_read;
}
diff --git a/storage/tokudb/ft-index/util/frwlock.h b/storage/tokudb/ft-index/util/frwlock.h
index 9ad2b6f7a9d..7811e0d2427 100644
--- a/storage/tokudb/ft-index/util/frwlock.h
+++ b/storage/tokudb/ft-index/util/frwlock.h
@@ -95,6 +95,7 @@ PATENT RIGHTS GRANT:
#include <toku_pthread.h>
#include <stdbool.h>
#include <stdint.h>
+#include <util/context.h>
//TODO: update comment, this is from rwlock.h
@@ -106,24 +107,24 @@ public:
void init(toku_mutex_t *const mutex);
void deinit(void);
- inline void write_lock(bool expensive);
- inline bool try_write_lock(bool expensive);
- inline void write_unlock(void);
+ void write_lock(bool expensive);
+ bool try_write_lock(bool expensive);
+ void write_unlock(void);
// returns true if acquiring a write lock will be expensive
- inline bool write_lock_is_expensive(void);
+ bool write_lock_is_expensive(void);
- inline void read_lock(void);
- inline bool try_read_lock(void);
- inline void read_unlock(void);
+ void read_lock(void);
+ bool try_read_lock(void);
+ void read_unlock(void);
// returns true if acquiring a read lock will be expensive
- inline bool read_lock_is_expensive(void);
+ bool read_lock_is_expensive(void);
- inline uint32_t users(void) const;
- inline uint32_t blocked_users(void) const;
- inline uint32_t writers(void) const;
- inline uint32_t blocked_writers(void) const;
- inline uint32_t readers(void) const;
- inline uint32_t blocked_readers(void) const;
+ uint32_t users(void) const;
+ uint32_t blocked_users(void) const;
+ uint32_t writers(void) const;
+ uint32_t blocked_writers(void) const;
+ uint32_t readers(void) const;
+ uint32_t blocked_readers(void) const;
private:
struct queue_item {
@@ -131,11 +132,11 @@ private:
struct queue_item *next;
};
- inline bool queue_is_empty(void) const;
- inline void enq_item(queue_item *const item);
- inline toku_cond_t *deq_item(void);
- inline void maybe_signal_or_broadcast_next(void);
- inline void maybe_signal_next_writer(void);
+ bool queue_is_empty(void) const;
+ void enq_item(queue_item *const item);
+ toku_cond_t *deq_item(void);
+ void maybe_signal_or_broadcast_next(void);
+ void maybe_signal_next_writer(void);
toku_mutex_t *m_mutex;
@@ -154,6 +155,12 @@ private:
// is expensive
// if there are currently no waiting readers, then set to false
bool m_read_wait_expensive;
+ // thread-id of the current writer
+ int m_current_writer_tid;
+ // context id describing the context of the current writer blocking
+ // new readers (either because this writer holds the write lock or
+ // is the first to want the write lock).
+ context_id m_blocking_writer_context_id;
toku_cond_t m_wait_read;
queue_item m_queue_item_read;
@@ -168,6 +175,6 @@ ENSURE_POD(frwlock);
} // namespace toku
// include the implementation here
-#include "frwlock.cc"
+// #include "frwlock.cc"
#endif // UTIL_FRWLOCK_H
diff --git a/storage/tokudb/ft-index/util/kibbutz.cc b/storage/tokudb/ft-index/util/kibbutz.cc
index e9057de7915..a84a6f4827f 100644
--- a/storage/tokudb/ft-index/util/kibbutz.cc
+++ b/storage/tokudb/ft-index/util/kibbutz.cc
@@ -118,7 +118,9 @@ struct kibbutz {
static void *work_on_kibbutz (void *);
-KIBBUTZ toku_kibbutz_create (int n_workers) {
+int toku_kibbutz_create (int n_workers, KIBBUTZ *kb_ret) {
+ int r = 0;
+ *kb_ret = NULL;
KIBBUTZ XCALLOC(k);
toku_mutex_init(&k->mutex, NULL);
toku_cond_init(&k->cond, NULL);
@@ -128,12 +130,19 @@ KIBBUTZ toku_kibbutz_create (int n_workers) {
k->n_workers = n_workers;
XMALLOC_N(n_workers, k->workers);
XMALLOC_N(n_workers, k->ids);
- for (int i=0; i<n_workers; i++) {
+ for (int i = 0; i < n_workers; i++) {
k->ids[i].k = k;
- int r = toku_pthread_create(&k->workers[i], NULL, work_on_kibbutz, &k->ids[i]);
- assert(r==0);
+ r = toku_pthread_create(&k->workers[i], NULL, work_on_kibbutz, &k->ids[i]);
+ if (r != 0) {
+ k->n_workers = i;
+ toku_kibbutz_destroy(k);
+ break;
+ }
+ }
+ if (r == 0) {
+ *kb_ret = k;
}
- return k;
+ return r;
}
static void klock (KIBBUTZ k) {
diff --git a/storage/tokudb/ft-index/util/kibbutz.h b/storage/tokudb/ft-index/util/kibbutz.h
index 06fa624b211..83e981b916c 100644
--- a/storage/tokudb/ft-index/util/kibbutz.h
+++ b/storage/tokudb/ft-index/util/kibbutz.h
@@ -100,7 +100,7 @@ typedef struct kibbutz *KIBBUTZ;
//
// create a kibbutz where n_workers is the number of threads in the threadpool
//
-KIBBUTZ toku_kibbutz_create (int n_workers);
+int toku_kibbutz_create (int n_workers, KIBBUTZ *kb);
//
// enqueue a workitem in the kibbutz. When the kibbutz is to work on this workitem,
// it calls f(extra).
diff --git a/storage/tokudb/ft-index/util/mempool.cc b/storage/tokudb/ft-index/util/mempool.cc
index 312848e6194..8a37fd41b44 100644
--- a/storage/tokudb/ft-index/util/mempool.cc
+++ b/storage/tokudb/ft-index/util/mempool.cc
@@ -114,23 +114,6 @@ void toku_mempool_zero(struct mempool *mp) {
memset(mp, 0, sizeof(*mp));
}
-/* Copy constructor. Any time a new mempool is needed, allocate 1/4 more space
- * than is currently needed.
- */
-void toku_mempool_copy_construct(struct mempool *mp, const void * const data_source, const size_t data_size) {
- // printf("mempool_copy %p %p %lu\n", mp, data_source, data_size);
- if (data_size) {
- paranoid_invariant(data_source);
- toku_mempool_construct(mp, data_size);
- memcpy(mp->base, data_source, data_size);
- mp->free_offset = data_size; // address of first available memory for new data
- }
- else {
- toku_mempool_zero(mp);
- // fprintf(stderr, "Empty mempool created (copy constructor)\n");
- }
-}
-
// TODO 4050 this is dirty, try to replace all uses of this
void toku_mempool_init(struct mempool *mp, void *base, size_t free_offset, size_t size) {
// printf("mempool_init %p %p %lu\n", mp, base, size);
diff --git a/storage/tokudb/ft-index/util/mempool.h b/storage/tokudb/ft-index/util/mempool.h
index f6a2bc6dde3..fa59d7a63ac 100644
--- a/storage/tokudb/ft-index/util/mempool.h
+++ b/storage/tokudb/ft-index/util/mempool.h
@@ -115,13 +115,6 @@ struct mempool {
*/
void toku_mempool_zero(struct mempool *mp);
-/* Copy constructor. Fill in empty mempool struct with new values, allocating
- * a new buffer and filling the buffer with data from from data_source.
- * Any time a new mempool is needed, allocate 1/4 more space
- * than is currently needed.
- */
-void toku_mempool_copy_construct(struct mempool *mp, const void * const data_source, const size_t data_size);
-
/* initialize the memory pool with the base address and size of a
contiguous chunk of memory */
void toku_mempool_init(struct mempool *mp, void *base, size_t free_offset, size_t size);
diff --git a/storage/tokudb/ft-index/util/scoped_malloc.cc b/storage/tokudb/ft-index/util/scoped_malloc.cc
new file mode 100644
index 00000000000..7fc847c3af6
--- /dev/null
+++ b/storage/tokudb/ft-index/util/scoped_malloc.cc
@@ -0,0 +1,265 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+
+/*
+COPYING CONDITIONS NOTICE:
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation, and provided that the
+ following conditions are met:
+
+ * Redistributions of source code must retain this COPYING
+ CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
+ DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
+ PATENT MARKING NOTICE (below), and the PATENT RIGHTS
+ GRANT (below).
+
+ * Redistributions in binary form must reproduce this COPYING
+ CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
+ DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
+ PATENT MARKING NOTICE (below), and the PATENT RIGHTS
+ GRANT (below) in the documentation and/or other materials
+ provided with the distribution.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+COPYRIGHT NOTICE:
+
+ TokuDB, Tokutek Fractal Tree Indexing Library.
+ Copyright (C) 2007-2013 Tokutek, Inc.
+
+DISCLAIMER:
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+UNIVERSITY PATENT NOTICE:
+
+ The technology is licensed by the Massachusetts Institute of
+ Technology, Rutgers State University of New Jersey, and the Research
+ Foundation of State University of New York at Stony Brook under
+ United States of America Serial No. 11/760379 and to the patents
+ and/or patent applications resulting from it.
+
+PATENT MARKING NOTICE:
+
+ This software is covered by US Patent No. 8,185,551.
+ This software is covered by US Patent No. 8,489,638.
+
+PATENT RIGHTS GRANT:
+
+ "THIS IMPLEMENTATION" means the copyrightable works distributed by
+ Tokutek as part of the Fractal Tree project.
+
+ "PATENT CLAIMS" means the claims of patents that are owned or
+ licensable by Tokutek, both currently or in the future; and that in
+ the absence of this license would be infringed by THIS
+ IMPLEMENTATION or by using or running THIS IMPLEMENTATION.
+
+ "PATENT CHALLENGE" shall mean a challenge to the validity,
+ patentability, enforceability and/or non-infringement of any of the
+ PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.
+
+ Tokutek hereby grants to you, for the term and geographical scope of
+ the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
+ irrevocable (except as stated in this section) patent license to
+ make, have made, use, offer to sell, sell, import, transfer, and
+ otherwise run, modify, and propagate the contents of THIS
+ IMPLEMENTATION, where such license applies only to the PATENT
+ CLAIMS. This grant does not include claims that would be infringed
+ only as a consequence of further modifications of THIS
+ IMPLEMENTATION. If you or your agent or licensee institute or order
+ or agree to the institution of patent litigation against any entity
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
+ THIS IMPLEMENTATION constitutes direct or contributory patent
+ infringement, or inducement of patent infringement, then any rights
+ granted to you under this License shall terminate as of the date
+ such litigation is filed. If you or your agent or exclusive
+ licensee institute or order or agree to the institution of a PATENT
+ CHALLENGE, then Tokutek may terminate any rights granted to you
+ under this License.
+*/
+
+#ident "Copyright (c) 2007-2013 Tokutek Inc. All rights reserved."
+#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
+
+#include <toku_include/memory.h>
+
+#include <util/scoped_malloc.h>
+
+// The __thread storage class modifier isn't well supported on osx, but we
+// aren't worried about the performance on osx, so we provide a
+// pass-through implementation of scoped mallocs.
+#ifdef __APPLE__
+
+namespace toku {
+
+ scoped_malloc::scoped_malloc(const size_t size)
+ : m_size(size),
+ m_local(false),
+ m_buf(toku_xmalloc(size)) {}
+
+ scoped_malloc::~scoped_malloc() {
+ toku_free(m_buf);
+ }
+
+} // namespace toku
+
+void toku_scoped_malloc_init(void) {}
+void toku_scoped_malloc_destroy(void) {}
+
+#else // __APPLE__
+
+#include <set>
+#include <pthread.h>
+
+#include <portability/toku_pthread.h>
+
+namespace toku {
+
+ // see pthread_key handling at the bottom
+ //
+ // when we use gcc 4.8, we can use the 'thread_local' keyword and proper c++
+ // constructors/destructors instead of this pthread / global set wizardy.
+ static pthread_key_t tl_stack_destroy_pthread_key;
+ class tl_stack;
+ std::set<tl_stack *> *global_stack_set;
+ toku_mutex_t global_stack_set_mutex = TOKU_MUTEX_INITIALIZER;
+
+ class tl_stack {
+ // 1MB
+ static const size_t STACK_SIZE = 1 * 1024 * 1024;
+
+ public:
+ void init() {
+ m_stack = reinterpret_cast<char *>(toku_xmalloc(STACK_SIZE));
+ m_current_offset = 0;
+ int r = pthread_setspecific(tl_stack_destroy_pthread_key, this);
+ invariant_zero(r);
+ }
+
+ void destroy() {
+ if (m_stack != NULL) {
+ toku_free(m_stack);
+ m_stack = NULL;
+ }
+ }
+
+ // initialize a tl_stack and insert it into the global map
+ static void init_and_register(tl_stack *st) {
+ st->init();
+ invariant_notnull(global_stack_set);
+
+ toku_mutex_lock(&global_stack_set_mutex);
+ std::pair<std::set<tl_stack *>::iterator, bool> p = global_stack_set->insert(st);
+ invariant(p.second);
+ toku_mutex_unlock(&global_stack_set_mutex);
+ }
+
+ // destruct a tl_stack and remove it from the global map
+ // passed in as void * to match the generic pthread destructor API
+ static void destroy_and_deregister(void *key) {
+ invariant_notnull(key);
+ tl_stack *st = reinterpret_cast<tl_stack *>(key);
+ st->destroy();
+
+ toku_mutex_lock(&global_stack_set_mutex);
+ invariant_notnull(global_stack_set);
+ size_t n = global_stack_set->erase(st);
+ invariant(n == 1);
+ toku_mutex_unlock(&global_stack_set_mutex);
+ }
+
+ // Allocate 'size' bytes and return a pointer to the first byte
+ void *alloc(const size_t size) {
+ if (m_stack == NULL) {
+ init_and_register(this);
+ }
+ invariant(m_current_offset + size <= STACK_SIZE);
+ void *mem = &m_stack[m_current_offset];
+ m_current_offset += size;
+ return mem;
+ }
+
+ // Give back a previously allocated region of 'size' bytes.
+ void dealloc(const size_t size) {
+ invariant(m_current_offset >= size);
+ m_current_offset -= size;
+ }
+
+ // Get the current size of free-space in bytes.
+ size_t get_free_space() const {
+ invariant(m_current_offset <= STACK_SIZE);
+ return STACK_SIZE - m_current_offset;
+ }
+
+ private:
+ // Offset of the free region in the stack
+ size_t m_current_offset;
+ char *m_stack;
+ };
+
+ // Each thread has its own local stack.
+ static __thread tl_stack local_stack;
+
+ // Memory is allocated from thread-local storage if available, otherwise from malloc(1).
+ scoped_malloc::scoped_malloc(const size_t size) :
+ m_size(size),
+ m_local(local_stack.get_free_space() >= m_size),
+ m_buf(m_local ? local_stack.alloc(m_size) : toku_xmalloc(m_size)) {
+ }
+
+ scoped_malloc::~scoped_malloc() {
+ if (m_local) {
+ local_stack.dealloc(m_size);
+ } else {
+ toku_free(m_buf);
+ }
+ }
+
+} // namespace toku
+
+// pthread key handling:
+// - there is a process-wide pthread key that is associated with the destructor for a tl_stack
+// - on process construction, we initialize the key; on destruction, we clean it up.
+// - when a thread first uses its tl_stack, it calls pthread_setspecific(&destroy_key, "some key"),
+// associating the destroy key with the tl_stack_destroy_and_deregister destructor
+// - when a thread terminates, it calls the associated destructor; tl_stack_destroy_and_deregister.
+
+void toku_scoped_malloc_init(void) {
+ toku_mutex_lock(&toku::global_stack_set_mutex);
+ invariant_null(toku::global_stack_set);
+ toku::global_stack_set = new std::set<toku::tl_stack *>();
+ toku_mutex_unlock(&toku::global_stack_set_mutex);
+
+ int r = pthread_key_create(&toku::tl_stack_destroy_pthread_key,
+ toku::tl_stack::destroy_and_deregister);
+ invariant_zero(r);
+}
+
+void toku_scoped_malloc_destroy(void) {
+ toku_mutex_lock(&toku::global_stack_set_mutex);
+ invariant_notnull(toku::global_stack_set);
+ // Destroy any tl_stacks that were registered as thread locals but did not
+ // get a chance to clean up using the pthread key destructor (because this code
+ // is now running before those threads fully shutdown)
+ for (std::set<toku::tl_stack *>::iterator i = toku::global_stack_set->begin();
+ i != toku::global_stack_set->end(); i++) {
+ (*i)->destroy();
+ }
+ delete toku::global_stack_set;
+ toku_mutex_unlock(&toku::global_stack_set_mutex);
+
+ // We're deregistering the destructor key here. When this thread exits,
+ // the tl_stack destructor won't get called, so we need to do that first.
+ int r = pthread_key_delete(toku::tl_stack_destroy_pthread_key);
+ invariant_zero(r);
+}
+
+#endif // !__APPLE__
diff --git a/storage/tokudb/ft-index/util/scoped_malloc.h b/storage/tokudb/ft-index/util/scoped_malloc.h
new file mode 100644
index 00000000000..ae8847731f3
--- /dev/null
+++ b/storage/tokudb/ft-index/util/scoped_malloc.h
@@ -0,0 +1,153 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+
+/*
+COPYING CONDITIONS NOTICE:
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation, and provided that the
+ following conditions are met:
+
+ * Redistributions of source code must retain this COPYING
+ CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
+ DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
+ PATENT MARKING NOTICE (below), and the PATENT RIGHTS
+ GRANT (below).
+
+ * Redistributions in binary form must reproduce this COPYING
+ CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
+ DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
+ PATENT MARKING NOTICE (below), and the PATENT RIGHTS
+ GRANT (below) in the documentation and/or other materials
+ provided with the distribution.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+COPYRIGHT NOTICE:
+
+ TokuDB, Tokutek Fractal Tree Indexing Library.
+ Copyright (C) 2007-2013 Tokutek, Inc.
+
+DISCLAIMER:
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+UNIVERSITY PATENT NOTICE:
+
+ The technology is licensed by the Massachusetts Institute of
+ Technology, Rutgers State University of New Jersey, and the Research
+ Foundation of State University of New York at Stony Brook under
+ United States of America Serial No. 11/760379 and to the patents
+ and/or patent applications resulting from it.
+
+PATENT MARKING NOTICE:
+
+ This software is covered by US Patent No. 8,185,551.
+ This software is covered by US Patent No. 8,489,638.
+
+PATENT RIGHTS GRANT:
+
+ "THIS IMPLEMENTATION" means the copyrightable works distributed by
+ Tokutek as part of the Fractal Tree project.
+
+ "PATENT CLAIMS" means the claims of patents that are owned or
+ licensable by Tokutek, both currently or in the future; and that in
+ the absence of this license would be infringed by THIS
+ IMPLEMENTATION or by using or running THIS IMPLEMENTATION.
+
+ "PATENT CHALLENGE" shall mean a challenge to the validity,
+ patentability, enforceability and/or non-infringement of any of the
+ PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.
+
+ Tokutek hereby grants to you, for the term and geographical scope of
+ the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
+ irrevocable (except as stated in this section) patent license to
+ make, have made, use, offer to sell, sell, import, transfer, and
+ otherwise run, modify, and propagate the contents of THIS
+ IMPLEMENTATION, where such license applies only to the PATENT
+ CLAIMS. This grant does not include claims that would be infringed
+ only as a consequence of further modifications of THIS
+ IMPLEMENTATION. If you or your agent or licensee institute or order
+ or agree to the institution of patent litigation against any entity
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
+ THIS IMPLEMENTATION constitutes direct or contributory patent
+ infringement, or inducement of patent infringement, then any rights
+ granted to you under this License shall terminate as of the date
+ such litigation is filed. If you or your agent or exclusive
+ licensee institute or order or agree to the institution of a PATENT
+ CHALLENGE, then Tokutek may terminate any rights granted to you
+ under this License.
+*/
+
+#pragma once
+
+#ident "Copyright (c) 2007-2013 Tokutek Inc. All rights reserved."
+#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
+
+
+#include <string.h>
+
+namespace toku {
+
+ class scoped_malloc {
+ public:
+ // Memory is allocated from thread-local storage if available, otherwise from malloc(3).
+ scoped_malloc(const size_t size);
+
+ ~scoped_malloc();
+
+ void *get() const {
+ return m_buf;
+ }
+
+ private:
+ // Non-copyable
+ scoped_malloc();
+
+ const size_t m_size;
+ const bool m_local;
+ void *const m_buf;
+ };
+
+ class scoped_calloc : public scoped_malloc {
+ public:
+ // A scoped malloc whose bytes are initialized to zero, as in calloc(3)
+ scoped_calloc(const size_t size) :
+ scoped_malloc(size) {
+ memset(scoped_malloc::get(), 0, size);
+ }
+ };
+
+ class scoped_malloc_aligned : public scoped_malloc {
+ public:
+ scoped_malloc_aligned(const size_t size, const size_t alignment) :
+ scoped_malloc(size + alignment) {
+ invariant(size >= alignment);
+ invariant(alignment > 0);
+ const uintptr_t addr = reinterpret_cast<uintptr_t>(scoped_malloc::get());
+ const uintptr_t aligned_addr = (addr + alignment) - (addr % alignment);
+ invariant(aligned_addr < addr + size + alignment);
+ m_aligned_buf = reinterpret_cast<char *>(aligned_addr);
+ }
+
+ void *get() const {
+ return m_aligned_buf;
+ }
+
+ private:
+ void *m_aligned_buf;
+ };
+
+} // namespace toku
+
+void toku_scoped_malloc_init(void);
+
+void toku_scoped_malloc_destroy(void);
+
diff --git a/storage/tokudb/ft-index/util/tests/test-frwlock-fair-writers.cc b/storage/tokudb/ft-index/util/tests/test-frwlock-fair-writers.cc
new file mode 100644
index 00000000000..653be1c2fbc
--- /dev/null
+++ b/storage/tokudb/ft-index/util/tests/test-frwlock-fair-writers.cc
@@ -0,0 +1,52 @@
+// check if write locks are fair
+
+#include <stdio.h>
+#include <toku_assert.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <util/frwlock.h>
+
+toku_mutex_t rwlock_mutex;
+toku::frwlock rwlock;
+volatile int killed = 0;
+
+static void *t1_func(void *arg) {
+ int i;
+ for (i = 0; !killed; i++) {
+ toku_mutex_lock(&rwlock_mutex);
+ rwlock.write_lock(false);
+ toku_mutex_unlock(&rwlock_mutex);
+ usleep(10000);
+ toku_mutex_lock(&rwlock_mutex);
+ rwlock.write_unlock();
+ toku_mutex_unlock(&rwlock_mutex);
+ }
+ printf("%lu %d\n", (unsigned long) pthread_self(), i);
+ return arg;
+}
+
+int main(void) {
+ int r;
+
+ toku_mutex_init(&rwlock_mutex, NULL);
+ rwlock.init(&rwlock_mutex);
+
+ const int nthreads = 2;
+ pthread_t tids[nthreads];
+ for (int i = 0; i < nthreads; i++) {
+ r = pthread_create(&tids[i], NULL, t1_func, NULL);
+ assert(r == 0);
+ }
+ sleep(10);
+ killed = 1;
+ for (int i = 0; i < nthreads; i++) {
+ void *ret;
+ r = pthread_join(tids[i], &ret);
+ assert(r == 0);
+ }
+
+ rwlock.deinit();
+ toku_mutex_destroy(&rwlock_mutex);
+
+ return 0;
+}
diff --git a/storage/tokudb/ft-index/util/tests/test-kibbutz.cc b/storage/tokudb/ft-index/util/tests/test-kibbutz.cc
index 4e0b6076f2d..1f73037892c 100644
--- a/storage/tokudb/ft-index/util/tests/test-kibbutz.cc
+++ b/storage/tokudb/ft-index/util/tests/test-kibbutz.cc
@@ -111,7 +111,9 @@ static void dowork (void *idv) {
}
static void kibbutz_test (bool parent_finishes_first) {
- KIBBUTZ k = toku_kibbutz_create(NT);
+ KIBBUTZ k = NULL;
+ int r = toku_kibbutz_create(NT, &k);
+ assert(r == 0);
if (verbose) printf("create\n");
int ids[ND];
for (int i=0; i<ND; i++) {
diff --git a/storage/tokudb/ft-index/util/tests/test-kibbutz2.cc b/storage/tokudb/ft-index/util/tests/test-kibbutz2.cc
index 3afc7d5f005..ce797c068d8 100644
--- a/storage/tokudb/ft-index/util/tests/test-kibbutz2.cc
+++ b/storage/tokudb/ft-index/util/tests/test-kibbutz2.cc
@@ -113,7 +113,9 @@ static void dowork (void *idv) {
}
static void kibbutz_test (void) {
- KIBBUTZ k = toku_kibbutz_create(1);
+ KIBBUTZ k = NULL;
+ int r = toku_kibbutz_create(1, &k);
+ assert(r == 0);
if (verbose) printf("create\n");
int ids[ND];
for (int i=0; i<ND; i++) {
diff --git a/storage/tokudb/ft-index/util/tests/test-rwlock-cheapness.cc b/storage/tokudb/ft-index/util/tests/test-rwlock-cheapness.cc
index b787d1983bc..de54c21efd2 100644
--- a/storage/tokudb/ft-index/util/tests/test-rwlock-cheapness.cc
+++ b/storage/tokudb/ft-index/util/tests/test-rwlock-cheapness.cc
@@ -96,13 +96,16 @@ PATENT RIGHTS GRANT:
#include <toku_portability.h>
#include <toku_assert.h>
-#include <portability/toku_fair_rwlock.h>
#include <portability/toku_pthread.h>
#include <portability/toku_time.h>
#include <util/frwlock.h>
#include <util/rwlock.h>
#include "rwlock_condvar.h"
+// We need to manually intialize partitioned counters so that the
+// ones automatically incremented by the frwlock get handled properly.
+#include <util/partitioned_counter.h>
+
toku_mutex_t mutex;
toku::frwlock w;
@@ -288,6 +291,12 @@ static void test_write_cheapness(void) {
}
int main (int UU(argc), const char* UU(argv[])) {
+ // Ultra ugly. We manually init/destroy partitioned counters
+ // and context because normally toku_ft_layer_init() does that
+ // for us, but we don't want to initialize everything.
+ partitioned_counters_init();
test_write_cheapness();
+ toku_context_status_destroy();
+ partitioned_counters_destroy();
return 0;
}
diff --git a/storage/tokudb/ft-index/util/tests/test-rwlock-unfair-writers.cc b/storage/tokudb/ft-index/util/tests/test-rwlock-unfair-writers.cc
new file mode 100644
index 00000000000..fe569e3ec85
--- /dev/null
+++ b/storage/tokudb/ft-index/util/tests/test-rwlock-unfair-writers.cc
@@ -0,0 +1,60 @@
+// check if write locks are fair
+
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+#include <pthread.h>
+
+pthread_rwlock_t rwlock;
+volatile int killed = 0;
+
+static void *t1_func(void *arg) {
+ int i;
+ for (i = 0; !killed; i++) {
+ int r;
+ r = pthread_rwlock_wrlock(&rwlock);
+ assert(r == 0);
+ usleep(10000);
+ r = pthread_rwlock_unlock(&rwlock);
+ assert(r == 0);
+ }
+ printf("%lu %d\n", (unsigned long) pthread_self(), i);
+ return arg;
+}
+
+int main(void) {
+ int r;
+#if 0
+ rwlock = PTHREAD_RWLOCK_INITIALIZER;
+#endif
+#if 0
+ pthread_rwlockattr_t attr;
+ pthread_rwlockattr_init(&attr);
+ pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
+ r = pthread_rwlock_init(&rwlock, &attr);
+#endif
+#if 0
+ pthread_rwlockattr_t attr;
+ pthread_rwlockattr_init(&attr);
+ r = pthread_rwlock_init(&rwlock, &attr);
+#endif
+#if 1
+ r = pthread_rwlock_init(&rwlock, NULL);
+ assert(r == 0);
+#endif
+
+ const int nthreads = 2;
+ pthread_t tids[nthreads];
+ for (int i = 0; i < nthreads; i++) {
+ r = pthread_create(&tids[i], NULL, t1_func, NULL);
+ assert(r == 0);
+ }
+ sleep(10);
+ killed = 1;
+ for (int i = 0; i < nthreads; i++) {
+ void *ret;
+ r = pthread_join(tids[i], &ret);
+ assert(r == 0);
+ }
+ return 0;
+}
diff --git a/storage/tokudb/ft-index/util/tests/test-rwlock.cc b/storage/tokudb/ft-index/util/tests/test-rwlock.cc
index a560ef532eb..42ceb00ad19 100644
--- a/storage/tokudb/ft-index/util/tests/test-rwlock.cc
+++ b/storage/tokudb/ft-index/util/tests/test-rwlock.cc
@@ -96,7 +96,7 @@ PATENT RIGHTS GRANT:
// Best cas time= 8.595600ns
// Best mutex time= 19.340201ns
// Best rwlock time= 34.024799ns
-// Best newbrt rwlock time= 38.680500ns
+// Best util rwlock time= 38.680500ns
// Best prelocked time= 2.148700ns
// Best fair rwlock time= 45.127600ns
// On laptop
@@ -104,7 +104,7 @@ PATENT RIGHTS GRANT:
// Best cas time= 15.362500ns
// Best mutex time= 51.951498ns
// Best rwlock time= 97.721201ns
-// Best newbrt rwlock time=110.456800ns
+// Best util rwlock time=110.456800ns
// Best prelocked time= 4.240100ns
// Best fair rwlock time=113.119102ns
//
@@ -123,7 +123,6 @@ PATENT RIGHTS GRANT:
#include <toku_portability.h>
#include <toku_assert.h>
#include <portability/toku_atomic.h>
-#include <portability/toku_fair_rwlock.h>
#include <portability/toku_pthread.h>
#include <portability/toku_time.h>
#include <util/frwlock.h>
@@ -159,10 +158,8 @@ static double best_fcall_time=1e12;
static double best_cas_time=1e12;
static double best_mutex_time=1e12;
static double best_rwlock_time=1e12;
-static double best_newbrt_time=1e12;
+static double best_util_time=1e12;
static double best_prelocked_time=1e12;
-static double best_cv_fair_rwlock_time=1e12; // fair from condition variables
-static double best_fair_rwlock_time=1e12;
static double best_frwlock_time=1e12;
static double best_frwlock_prelocked_time=1e12;
static double mind(double a, double b) { if (a<b) return a; else return b; }
@@ -287,48 +284,48 @@ void time_pthread_rwlock (void) {
{ int r = pthread_rwlock_destroy(&mutex); assert(r==0); }
}
-static void newbrt_rwlock_lock (RWLOCK rwlock, toku_mutex_t *mutex) {
+static void util_rwlock_lock (RWLOCK rwlock, toku_mutex_t *mutex) {
toku_mutex_lock(mutex);
rwlock_read_lock(rwlock, mutex);
toku_mutex_unlock(mutex);
}
-static void newbrt_rwlock_unlock (RWLOCK rwlock, toku_mutex_t *mutex) {
+static void util_rwlock_unlock (RWLOCK rwlock, toku_mutex_t *mutex) {
toku_mutex_lock(mutex);
rwlock_read_unlock(rwlock);
toku_mutex_unlock(mutex);
}
-// Time the read lock that's in newbrt/rwlock.h
-void time_newbrt_rwlock (void) __attribute((__noinline__));
-void time_newbrt_rwlock (void) {
+// Time the read lock that's in util/rwlock.h
+void time_util_rwlock (void) __attribute((__noinline__));
+void time_util_rwlock (void) {
struct rwlock rwlock;
toku_mutex_t external_mutex;
toku_mutex_init(&external_mutex, NULL);
rwlock_init(&rwlock);
struct timeval start,end;
- newbrt_rwlock_lock(&rwlock, &external_mutex);
- newbrt_rwlock_unlock(&rwlock, &external_mutex);
+ util_rwlock_lock(&rwlock, &external_mutex);
+ util_rwlock_unlock(&rwlock, &external_mutex);
for (int t=0; t<T; t++) {
gettimeofday(&start, NULL);
for (int i=0; i<N; i++) {
- newbrt_rwlock_lock(&rwlock, &external_mutex);
- newbrt_rwlock_unlock(&rwlock, &external_mutex);
+ util_rwlock_lock(&rwlock, &external_mutex);
+ util_rwlock_unlock(&rwlock, &external_mutex);
}
gettimeofday(&end, NULL);
double diff = 1e9*toku_tdiff(&end, &start)/N;
if (verbose>1)
- fprintf(stderr, "newbrt_rwlock(r) = %.6fns/(lock+unlock)\n", diff);
- best_newbrt_time=mind(best_newbrt_time,diff);
+ fprintf(stderr, "util_rwlock(r) = %.6fns/(lock+unlock)\n", diff);
+ best_util_time=mind(best_util_time,diff);
}
rwlock_destroy(&rwlock);
toku_mutex_destroy(&external_mutex);
}
-// Time the read lock that's in newbrt/rwlock.h, assuming the mutex is already held.
-void time_newbrt_prelocked_rwlock (void) __attribute__((__noinline__));
-void time_newbrt_prelocked_rwlock (void) {
+// Time the read lock that's in util/rwlock.h, assuming the mutex is already held.
+void time_util_prelocked_rwlock (void) __attribute__((__noinline__));
+void time_util_prelocked_rwlock (void) {
struct rwlock rwlock;
toku_mutex_t external_mutex;
toku_mutex_init(&external_mutex, NULL);
@@ -347,7 +344,7 @@ void time_newbrt_prelocked_rwlock (void) {
gettimeofday(&end, NULL);
double diff = 1e9*toku_tdiff(&end, &start)/N;
if (verbose>1)
- fprintf(stderr, "pre_newbrt_rwlock(r) = %.6fns/(lock+unlock)\n", diff);
+ fprintf(stderr, "pre_util_rwlock(r) = %.6fns/(lock+unlock)\n", diff);
best_prelocked_time=mind(best_prelocked_time,diff);
}
rwlock_destroy(&rwlock);
@@ -355,51 +352,6 @@ void time_newbrt_prelocked_rwlock (void) {
toku_mutex_destroy(&external_mutex);
}
-void time_toku_fair_rwlock (void) __attribute__((__noinline__));
-void time_toku_fair_rwlock (void) {
- toku_fair_rwlock_t mutex;
- toku_fair_rwlock_init(&mutex);
- struct timeval start,end;
- toku_fair_rwlock_rdlock(&mutex);
- toku_fair_rwlock_unlock(&mutex);
- for (int t=0; t<T; t++) {
- gettimeofday(&start, NULL);
- for (int i=0; i<N; i++) {
- toku_fair_rwlock_rdlock(&mutex);
- toku_fair_rwlock_unlock(&mutex);
- }
- gettimeofday(&end, NULL);
- double diff = 1e9*toku_tdiff(&end, &start)/N;
- if (verbose>1)
- fprintf(stderr, "pthread_fair(r) = %.6fns/(lock+unlock)\n", diff);
- best_fair_rwlock_time=mind(best_fair_rwlock_time,diff);
- }
- toku_fair_rwlock_destroy(&mutex);
-}
-
-/* not static*/
-void time_toku_cv_fair_rwlock(void) __attribute__((__noinline__));
-void time_toku_cv_fair_rwlock(void) {
- toku_cv_fair_rwlock_t mutex;
- toku_cv_fair_rwlock_init(&mutex);
- struct timeval start,end;
- toku_cv_fair_rwlock_rdlock(&mutex);
- toku_cv_fair_rwlock_unlock(&mutex);
- for (int t=0; t<T; t++) {
- gettimeofday(&start, NULL);
- for (int i=0; i<N; i++) {
- toku_cv_fair_rwlock_rdlock(&mutex);
- toku_cv_fair_rwlock_unlock(&mutex);
- }
- gettimeofday(&end, NULL);
- double diff = 1e9*toku_tdiff(&end, &start)/N;
- if (verbose>1)
- fprintf(stderr, "pthread_cvfair(r) = %.6fns/(lock+unlock)\n", diff);
- best_cv_fair_rwlock_time=mind(best_cv_fair_rwlock_time,diff);
- }
- toku_cv_fair_rwlock_destroy(&mutex);
-}
-
void time_frwlock_prelocked(void) __attribute__((__noinline__));
void time_frwlock_prelocked(void) {
toku_mutex_t external_mutex;
@@ -469,208 +421,6 @@ void time_frwlock(void) {
toku_mutex_destroy(&external_mutex);
}
-
-#define N 6
-#define T 150000
-#define L 5
-#define N_LOG_ENTRIES (L*N*4)
-
-static toku_fair_rwlock_t rwlock;
-
-static struct log_s {
- int threadid, loopid;
- char action;
-} actionlog[N_LOG_ENTRIES];
-static int log_counter=0;
-
-static void logit (int threadid, int loopid, char action) {
- //printf("%d %d %c\n", threadid, loopid, action);
- int my_log_counter = toku_sync_fetch_and_add(&log_counter, 1);
- assert(my_log_counter<N_LOG_ENTRIES);
- actionlog[my_log_counter].threadid = threadid;
- actionlog[my_log_counter].loopid = loopid;
- actionlog[my_log_counter].action = action;
-}
-
-// The action should look like this:
-// Threads 0-2 are reader threads.
-// Threads 3-6 are writer threads.
-// The threads all repeatedly grab the lock, wait T steps, and release.
-// If the readers can starve the writers, then most of the writers will be at the end.
-// If the writers can starve the readers, then most of the readers will be at the end.
-// The reader threads all grab the lock, wait T*2 steps, and release the lock.
-// The writer threads
-// First the writer threads wait time T while the reader threads all go for the lock.
-// Before the first one lets go, the writer threads wake up and try to grab the lock. But the readers are still
-
-// 3 threads (0-2) try to grab the lock all at once. They'll get it. They each sleep for time T*2
-// 3 threads (3-6) try to grab the write lock. They'll get it one after another.
-
-
-extern __thread int mytid;
-
-static void grab_rdlock (int threadid, int iteration) {
- logit(threadid, iteration, 't');
- { int r = toku_fair_rwlock_rdlock(&rwlock); assert(r==0); }
- logit(threadid, iteration, 'R');
-}
-
-static void release_rdlock (int threadid, int iteration) {
- logit(threadid, iteration, 'u');
- { int r = toku_fair_rwlock_unlock(&rwlock); assert(r==0); }
-}
-
-static void grab_wrlock (int threadid, int iteration) {
- logit(threadid, iteration, 'T');
- { int r = toku_fair_rwlock_wrlock(&rwlock); assert(r==0); }
- logit(threadid, iteration, 'W');
-}
-
-static void release_wrlock (int threadid, int iteration) {
- logit(threadid, iteration, 'U');
- { int r = toku_fair_rwlock_unlock(&rwlock); assert(r==0);}
-}
-
-static void *start_thread (void *vv) {
- int *vp=(int*)vv;
- int v=*vp;
-
- //printf("T%d=%ld\n", v, pthread_self());
- switch(v) {
- case 0:
- case 1:
- case 2:
- for (int i=0; i<L; i++) {
- grab_rdlock(v, i);
- usleep(T);
- release_rdlock(v, i);
- }
- break;
- case 3:
- case 4:
- case 5:
- for (int i=0; i<L; i++) {
- grab_wrlock(v, i);
- usleep(T);
- release_wrlock(v, i);
- }
- }
- return NULL;
-}
-
-static void *start_thread_random (void *vv) {
- int *vp=(int*)vv;
- int v=*vp;
-
- for (int i=0; i<L; i++) {
- if (random()%2==0) {
- grab_rdlock(v, i);
- for (int j=0; j<random()%20; j++) sched_yield();
- release_rdlock(v, i);
- for (int j=0; j<random()%20; j++) sched_yield();
- } else {
- grab_wrlock(v, i);
- for (int j=0; j<random()%20; j++) sched_yield();
- release_wrlock(v, i);
- for (int j=0; j<random()%20; j++) sched_yield();
- }
- }
- return NULL;
-}
-
-static void check_actionlog (int expected_writer_max_count,
- int expected_reader_parallelism_min,
- int expected_reader_parallelism_max)
-// Effect:
-// Make sure that writers are exclusive.
-// Make sure that anyone who asks for a lock doesn't have one.
-// Make sure that anyone granted a lock actually asked for a lock.
-// Make sure that anyone who releases a lock has it.
-// Make sure that readers don't starve writers, and writers don't starve readers. (Not sure how to code this up...)
-{
- int reader_max=0;
- int writer_max=0;
- int state=0;
- char tstate[N];
- for (int i=0; i<N; i++) tstate[i]=0;
- for (int i=0; i<log_counter; i++) {
- switch (actionlog[i].action) {
- case 't': // fall through to 'T'
- case 'T':
- assert(tstate[actionlog[i].threadid]==0);
- tstate[actionlog[i].threadid]=actionlog[i].action;
- break;
- case 'W':
- assert(tstate[actionlog[i].threadid]=='T');
- tstate[actionlog[i].threadid]=actionlog[i].action;
- assert(state==0);
- state=-1;
- writer_max = 1;
- break;
- case 'U':
- assert(tstate[actionlog[i].threadid]=='W');
- tstate[actionlog[i].threadid]=0;
- assert(state==-1);
- state=0;
- break;
- case 'R':
- assert(tstate[actionlog[i].threadid]=='t');
- tstate[actionlog[i].threadid]=actionlog[i].action;
- if (state<0) { printf("On step %d\n", i); }
- assert(state>=0);
- state++;
- if (state>reader_max) reader_max=state;
- break;
- case 'u':
- assert(tstate[actionlog[i].threadid]=='R');
- tstate[actionlog[i].threadid]=0;
- assert(state>=0);
- state--;
- break;
- default:
- abort();
- }
- }
- assert(reader_max>=expected_reader_parallelism_min);
- assert(reader_max<=expected_reader_parallelism_max);
- assert(writer_max==expected_writer_max_count);
-}
-
-
-static void test_rwlock_internal (void *(*start_th)(void*), int max_wr, int min_rd, int max_rd) {
- if (verbose>=2) printf("Running threads:\n");
- log_counter=0;
- pthread_t threads[N];
- int v[N];
- toku_fair_rwlock_init(&rwlock);
- for (int i=0; i<N; i++) {
- v[i]=i;
- int r = pthread_create(&threads[i], NULL, start_th, &v[i]);
- assert(r==0);
- }
- for (int i=0; i<N; i++) {
- void *rv;
- int r = pthread_join(threads[i], &rv);
- assert(rv==NULL);
- assert(r==0);
- }
- if (verbose>1) {
- for (int i=0; i<log_counter; i++) {
- printf("%d: %*s%c%d\n", i, actionlog[i].threadid*4, "", actionlog[i].action, actionlog[i].loopid);
- }
- }
- check_actionlog(max_wr, min_rd, max_rd);
- toku_fair_rwlock_destroy(&rwlock);
- if (verbose>2) printf("OK\n");
-}
-
-static void test_rwlock (void) {
- test_rwlock_internal(start_thread, 1, 2, 3);
- for (int i=0; i<10; i++) {
- test_rwlock_internal(start_thread_random, 1, 0, N);
- }
-}
-
int main (int argc, const char *argv[]) {
parse_args(argc, argv);
if (timing_only) {
@@ -680,10 +430,8 @@ int main (int argc, const char *argv[]) {
time_cas();
time_pthread_mutex();
time_pthread_rwlock();
- time_newbrt_rwlock();
- time_newbrt_prelocked_rwlock();
- time_toku_cv_fair_rwlock();
- time_toku_fair_rwlock();
+ time_util_rwlock();
+ time_util_prelocked_rwlock();
}
time_frwlock();
time_frwlock_prelocked();
@@ -694,16 +442,12 @@ int main (int argc, const char *argv[]) {
printf("// Best cas time=%10.6fns\n", best_cas_time);
printf("// Best mutex time=%10.6fns\n", best_mutex_time);
printf("// Best rwlock time=%10.6fns\n", best_rwlock_time);
- printf("// Best newbrt rwlock time=%10.6fns\n", best_newbrt_time);
+ printf("// Best util rwlock time=%10.6fns\n", best_util_time);
printf("// Best prelocked time=%10.6fns\n", best_prelocked_time);
- printf("// Best fair cv rwlock time=%10.6fns\n", best_cv_fair_rwlock_time);
- printf("// Best fair fast rwlock time=%10.6fns\n", best_fair_rwlock_time);
}
printf("// Best frwlock time=%10.6fns\n", best_frwlock_time);
printf("// Best frwlock_pre time=%10.6fns\n", best_frwlock_prelocked_time);
}
- } else {
- test_rwlock();
}
return 0;
}