remove apparent race in concurrentHash.c
This commit is contained in:
parent
889311a303
commit
aa8142d708
1 changed files with 15 additions and 6 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue