diff options
author | dormando <dormando@rydia.net> | 2012-01-06 00:20:34 -0800 |
---|---|---|
committer | dormando <dormando@rydia.net> | 2012-01-06 00:20:34 -0800 |
commit | 193a653e9678080f5ef7841ce93dca8e24116949 (patch) | |
tree | 45542c94b6fd51ba96c389b406853b9df0739702 | |
parent | b3630e1a2c7eae28d758a3e4786d1c486aa4e258 (diff) | |
download | memcached-193a653e9678080f5ef7841ce93dca8e24116949.tar.gz |
close some idiotic race conditions
do_item_update could decide to update an item, then wait on the cache_lock,
but the item could be unlinked in the meantime.
caused this to happen on purpose by flooding with sets, then flushing
repeatedly. flush has to unlink items until it hits the previous second.
-rw-r--r-- | items.c | 11 |
1 files changed, 7 insertions, 4 deletions
@@ -293,18 +293,18 @@ int do_item_link(item *it, const uint32_t hv) { void do_item_unlink(item *it, const uint32_t hv) { MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nkey, it->nbytes); + mutex_lock(&cache_lock); if ((it->it_flags & ITEM_LINKED) != 0) { it->it_flags &= ~ITEM_LINKED; STATS_LOCK(); stats.curr_bytes -= ITEM_ntotal(it); stats.curr_items -= 1; STATS_UNLOCK(); - mutex_lock(&cache_lock); assoc_delete(ITEM_key(it), it->nkey, hv); item_unlink_q(it); - pthread_mutex_unlock(&cache_lock); if (it->refcount == 0) item_free(it); } + pthread_mutex_unlock(&cache_lock); } /* FIXME: Is it necessary to keep this copy/pasted code? */ @@ -325,6 +325,8 @@ void do_item_unlink_nolock(item *it, const uint32_t hv) { void do_item_remove(item *it) { MEMCACHED_ITEM_REMOVE(ITEM_key(it), it->nkey, it->nbytes); assert((it->it_flags & ITEM_SLABBED) == 0); + + mutex_lock(&cache_lock); if (it->refcount != 0) { it->refcount--; DEBUG_REFCNT(it, '-'); @@ -332,6 +334,7 @@ void do_item_remove(item *it) { if (it->refcount == 0 && (it->it_flags & ITEM_LINKED) == 0) { item_free(it); } + pthread_mutex_unlock(&cache_lock); } void do_item_update(item *it) { @@ -339,13 +342,13 @@ void do_item_update(item *it) { if (it->time < current_time - ITEM_UPDATE_INTERVAL) { assert((it->it_flags & ITEM_SLABBED) == 0); + mutex_lock(&cache_lock); if ((it->it_flags & ITEM_LINKED) != 0) { - mutex_lock(&cache_lock); item_unlink_q(it); it->time = current_time; item_link_q(it); - pthread_mutex_unlock(&cache_lock); } + pthread_mutex_unlock(&cache_lock); } } |