remove apparent race in concurrentHash.c

This commit is contained in:
Sears Russell 2010-09-17 01:38:40 +00:00
parent 889311a303
commit aa8142d708

View file

@ -146,19 +146,25 @@ void hashtable_end_op(hashtable_mode mode, hashtable_t *ht, void *val, hashtable
b2->val = NULL; b2->val = NULL;
break; break;
} else { } else {
pageid_t newidx = hashtable_func(ht, b1->key);
// Case 2: b1 belongs "after" b2 // Case 2: b1 belongs "after" b2
pageid_t newidx = hashtable_func(ht, b1->key);
// Subcase 1: newidx is higher than idx2, so newidx should stay where it is. // Subcase 1: newidx is higher than idx2, so newidx should stay where it is.
// Subcase 2: newidx wrapped, so it is less than idx2, but more than half way around the ring. // Subcase 2: newidx wrapped, so it is less than idx2, but more than half way around the ring.
if(idx2 < newidx || (idx2 > newidx + (ht->maxbucketid/2))) { if(idx2 < newidx || (idx2 > newidx + (ht->maxbucketid/2))) {
// skip this b1. // skip this b1.
// printf("s\n"); fflush(0); // printf("s\n"); fflush(0);
idx = hashtable_wrap(ht, idx+1); idx = hashtable_wrap(ht, idx+1);
bucket_t * b0 = &ht->buckets[idx];
// Here we have to hold three buckets momentarily. If we released b1 before latching its successor, then
// b1 could be deleted by another thread, and the successor could be compacted before we latched it.
pthread_mutex_lock(&b0->mut);
pthread_mutex_unlock(&b1->mut); pthread_mutex_unlock(&b1->mut);
b1 = &ht->buckets[idx]; b1 = b0;
pthread_mutex_lock(&b1->mut);
// Case 3: we can compact b1 into b2's slot.
} else { } else {
// Case 3: we can compact b1 into b2's slot.
// printf("c %lld %lld %lld %lld\n", startidx, idx2, newidx, ht->maxbucketid); fflush(0); // printf("c %lld %lld %lld %lld\n", startidx, idx2, newidx, ht->maxbucketid); fflush(0);
b2->key = b1->key; b2->key = b1->key;
b2->val = b1->val; b2->val = b1->val;
@ -184,7 +190,10 @@ static inline void * hashtable_op(hashtable_mode mode, hashtable_t *ht, pageid_t
} }
static inline void * hashtable_op_lock(hashtable_mode mode, hashtable_t *ht, pageid_t p, void *val, hashtable_bucket_handle_t *h) { static inline void * hashtable_op_lock(hashtable_mode mode, hashtable_t *ht, pageid_t p, void *val, hashtable_bucket_handle_t *h) {
void * ret = hashtable_begin_op(mode, ht, p, val, h); void * ret = hashtable_begin_op(mode, ht, p, val, h);
pthread_mutex_lock(&h->b1->mut); // XXX evil // Nasty for a few reasons. This forces us to use (slow) recursive mutexes.
// Also, if someone tries to crab over this bucket in order to get to an
// unrelated key, then it will block.
pthread_mutex_lock(&h->b1->mut);
hashtable_end_op(mode, ht, val, h); hashtable_end_op(mode, ht, val, h);
return ret; return ret;
} }