Commit 07b6add0 authored by Keith Randall's avatar Keith Randall

runtime: do hashmap grow work during reads.

Before this change, grow work was done only
during map writes to ensure multithreaded safety.
This can lead to maps remaining in a partially
grown state for a long time, potentially forever.
This change allows grow work to happen during reads,
which will lead to grow work finishing sooner, making
the resulting map smaller and faster.

Grow work is not done in parallel.  Reads can
happen in parallel while grow work is happening.

R=golang-dev, dvyukov, khr, iant
CC=golang-dev
https://golang.org/cl/8852047
parent 71f06104
This diff is collapsed.
......@@ -17,7 +17,7 @@ void
HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
{
uintptr hash;
uintptr bucket, oldbucket;
uintptr bucket;
Bucket *b;
uintptr i;
KEYTYPE *k;
......@@ -83,13 +83,14 @@ dohash:
hash = h->hash0;
HASHFUNC(&hash, sizeof(KEYTYPE), &key);
bucket = hash & (((uintptr)1 << h->B) - 1);
if(h->oldbuckets != nil) {
oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
if(evacuated(b)) {
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
}
b = runtime·atomicloadp(&h->oldbuckets);
if(b != nil) {
grow_work_read(t, h);
b = (Bucket*)((byte*)b + (bucket & (((uintptr)1 << (h->B - 1)) - 1)) * h->bucketsize);
if(((uintptr)runtime·atomicloadp(&b->overflow) & 1) != 0)
goto newbucket;
} else {
newbucket:
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
}
top = hash >> (sizeof(uintptr)*8 - 8);
......@@ -103,7 +104,7 @@ dohash:
return;
}
}
b = b->overflow;
b = overflowptr(b);
} while(b != nil);
}
value = empty_value;
......@@ -115,7 +116,7 @@ void
HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
{
uintptr hash;
uintptr bucket, oldbucket;
uintptr bucket;
Bucket *b;
uintptr i;
KEYTYPE *k;
......@@ -187,13 +188,14 @@ dohash:
hash = h->hash0;
HASHFUNC(&hash, sizeof(KEYTYPE), &key);
bucket = hash & (((uintptr)1 << h->B) - 1);
if(h->oldbuckets != nil) {
oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
if(evacuated(b)) {
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
}
b = runtime·atomicloadp(&h->oldbuckets);
if(b != nil) {
grow_work_read(t, h);
b = (Bucket*)((byte*)b + (bucket & (((uintptr)1 << (h->B - 1)) - 1)) * h->bucketsize);
if(((uintptr)runtime·atomicloadp(&b->overflow) & 1) != 0)
goto newbucket;
} else {
newbucket:
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
}
top = hash >> (sizeof(uintptr)*8 - 8);
......@@ -209,7 +211,7 @@ dohash:
return;
}
}
b = b->overflow;
b = overflowptr(b);
} while(b != nil);
}
value = empty_value;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment