summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cahill <michael.cahill@wiredtiger.com>2012-04-18 15:45:24 +1000
committerMichael Cahill <michael.cahill@wiredtiger.com>2012-04-18 15:45:24 +1000
commitae445ce51f65df2cdbc92392b130aa86ae76cfae (patch)
treeeca5cf23f5b5142ec2a09b9f1100ab46d3070f80
parente9bd1b3cbeff3239b64160e50dba81a32484c234 (diff)
downloadmongo-ae445ce51f65df2cdbc92392b130aa86ae76cfae.tar.gz
Add an operation to set a flag atomically, use it to avoid racing on page flags.
-rw-r--r--src/btree/bt_curprev.c2
-rw-r--r--src/btree/bt_debug.c2
-rw-r--r--src/btree/bt_discard.c2
-rw-r--r--src/btree/bt_evict.c12
-rw-r--r--src/btree/row_key.c4
-rw-r--r--src/include/mutex.h20
6 files changed, 31 insertions, 11 deletions
diff --git a/src/btree/bt_curprev.c b/src/btree/bt_curprev.c
index 39d0aa8aed3..0347a3f836a 100644
--- a/src/btree/bt_curprev.c
+++ b/src/btree/bt_curprev.c
@@ -344,7 +344,7 @@ __cursor_row_prev(WT_CURSOR_BTREE *cbt, int newpage)
* If we haven't instantiated keys on this page, do so, else it
* is a very, very slow traversal.
*/
- if (!F_ISSET(cbt->page, WT_PAGE_BUILD_KEYS))
+ if (!F_ISSET_ATOMIC(cbt->page, WT_PAGE_BUILD_KEYS))
WT_RET(__wt_row_leaf_keys(session, cbt->page));
if (cbt->page->entries == 0)
diff --git a/src/btree/bt_debug.c b/src/btree/bt_debug.c
index 06fc37189a4..2799637c4b3 100644
--- a/src/btree/bt_debug.c
+++ b/src/btree/bt_debug.c
@@ -442,7 +442,7 @@ __debug_page_hdr(WT_DBG *ds, WT_PAGE *page)
__dmsg(ds, ": %s", __wt_page_type_string(page->type));
__dmsg(ds, " (%s", __wt_page_is_modified(page) ? "dirty" : "clean");
- if (F_ISSET(page, WT_PAGE_BUILD_KEYS))
+ if (F_ISSET_ATOMIC(page, WT_PAGE_BUILD_KEYS))
__dmsg(ds, ", keys-built");
if (page->modify != NULL) {
if (F_ISSET(page->modify, WT_PM_REC_EMPTY))
diff --git a/src/btree/bt_discard.c b/src/btree/bt_discard.c
index 0b65ebd43c8..a564e3cbc9c 100644
--- a/src/btree/bt_discard.c
+++ b/src/btree/bt_discard.c
@@ -32,7 +32,7 @@ __wt_page_out(WT_SESSION_IMPL *session, WT_PAGE *page, uint32_t flags)
page->parent = NULL;
page->ref = NULL;
- WT_ASSERT(session, !F_ISSET(page, WT_PAGE_EVICT_LRU));
+ WT_ASSERT(session, !F_ISSET_ATOMIC(page, WT_PAGE_EVICT_LRU));
/* If not a split merged into its parent, the page must be clean. */
WT_ASSERT(session,
diff --git a/src/btree/bt_evict.c b/src/btree/bt_evict.c
index cc265215647..80694247207 100644
--- a/src/btree/bt_evict.c
+++ b/src/btree/bt_evict.c
@@ -42,8 +42,8 @@ static inline void
__evict_clr(WT_SESSION_IMPL *session, WT_EVICT_LIST *e)
{
if (e->page != NULL) {
- WT_ASSERT(session, F_ISSET(e->page, WT_PAGE_EVICT_LRU));
- F_CLR(e->page, WT_PAGE_EVICT_LRU);
+ WT_ASSERT(session, F_ISSET_ATOMIC(e->page, WT_PAGE_EVICT_LRU));
+ F_CLR_ATOMIC(e->page, WT_PAGE_EVICT_LRU);
}
e->page = NULL;
e->btree = WT_DEBUG_POINT;
@@ -85,7 +85,7 @@ __wt_evict_clr_page(WT_SESSION_IMPL *session, WT_PAGE *page)
page->ref->state == WT_REF_LOCKED);
/* Fast path: if the page isn't on the queue, don't bother searching. */
- if (!F_ISSET(page, WT_PAGE_EVICT_LRU))
+ if (!F_ISSET_ATOMIC(page, WT_PAGE_EVICT_LRU))
return;
cache = S2C(session)->cache;
@@ -98,7 +98,7 @@ __wt_evict_clr_page(WT_SESSION_IMPL *session, WT_PAGE *page)
break;
}
- WT_ASSERT(session, !F_ISSET(page, WT_PAGE_EVICT_LRU));
+ WT_ASSERT(session, !F_ISSET_ATOMIC(page, WT_PAGE_EVICT_LRU));
__wt_spin_unlock(session, &cache->lru_lock);
}
@@ -670,7 +670,7 @@ __evict_walk_file(WT_SESSION_IMPL *session, u_int *slotp)
* really be skipped.
*/
if (WT_PAGE_IS_ROOT(page) ||
- F_ISSET(page, WT_PAGE_EVICT_LRU) ||
+ F_ISSET_ATOMIC(page, WT_PAGE_EVICT_LRU) ||
(page->modify != NULL &&
F_ISSET(page->modify, WT_PM_REC_SPLIT_MERGE)))
continue;
@@ -686,7 +686,7 @@ __evict_walk_file(WT_SESSION_IMPL *session, u_int *slotp)
++evict;
/* Mark the page on the list */
- F_SET(page, WT_PAGE_EVICT_LRU);
+ F_SET_ATOMIC(page, WT_PAGE_EVICT_LRU);
}
*slotp += (u_int)(evict - start);
diff --git a/src/btree/row_key.c b/src/btree/row_key.c
index 9cff462ed22..fb4458d083d 100644
--- a/src/btree/row_key.c
+++ b/src/btree/row_key.c
@@ -26,7 +26,7 @@ __wt_row_leaf_keys(WT_SESSION_IMPL *session, WT_PAGE *page)
ret = 0;
if (page->entries == 0) { /* Just checking... */
- F_SET(page, WT_PAGE_BUILD_KEYS);
+ F_SET_ATOMIC(page, WT_PAGE_BUILD_KEYS);
return (0);
}
@@ -57,7 +57,7 @@ __wt_row_leaf_keys(WT_SESSION_IMPL *session, WT_PAGE *page)
if (__bit_test(tmp->mem, i))
WT_ERR(__wt_row_key(session, page, rip, NULL));
- F_SET(page, WT_PAGE_BUILD_KEYS);
+ F_SET_ATOMIC(page, WT_PAGE_BUILD_KEYS);
err: __wt_scr_free(&tmp);
return (ret);
diff --git a/src/include/mutex.h b/src/include/mutex.h
index 539795ea404..93f1d597b45 100644
--- a/src/include/mutex.h
+++ b/src/include/mutex.h
@@ -127,6 +127,26 @@
} while (0)
/*
+ * Atomic versions of F_ISSET, F_SET and F_CLR.
+ * Spin until the new value can be swapped into place.
+ */
+#define F_ISSET_ATOMIC(p, mask) ((p)->flags_atomic & (mask))
+
+#define F_SET_ATOMIC(p, mask) do { \
+ uint32_t __orig; \
+ do { \
+ __orig = (p)->flags_atomic; \
+ } while (!WT_ATOMIC_CAS((p)->flags_atomic, __orig, __orig | (mask)));\
+} while (0)
+
+#define F_CLR_ATOMIC(p, mask) do { \
+ uint32_t __orig; \
+ do { \
+ __orig = (p)->flags_atomic; \
+ } while (!WT_ATOMIC_CAS((p)->flags_atomic, __orig, __orig & ~(mask)));\
+} while (0)
+
+/*
* Condition variables:
*
* WiredTiger uses standard pthread condition variables to signal between