Skip to content
This repository was archived by the owner on Feb 16, 2026. It is now read-only.

Commit 445a843

Browse files
committed
cache_hash: scale the private_oh
With a lot of objects on the private objhead, the mtx would become contended. We solve this contention by using an array of private objheads and spreading objects over the array elements using a fibonacci hash. The choice of an array of objheads rather than an array of objhead pointers is motivated by hsh_deref_objhead_unlock(), which behaves differently for private objects. An alternative to the address check would be to add a flag field to struct objhead, but that would require to grow the struct (really not a good option for such a central data structure which, in many cases, is required once per object) or reduce the size of the magic value to 16 bits. The drawback of the chosen solution is that flexelint thinks all objheads would need to be from the array, and hence reports out of bounds access all over the place. These warnings are suppressed somehow specifically (see comment inline).
1 parent be83e3d commit 445a843

1 file changed

Lines changed: 37 additions & 10 deletions

File tree

bin/varnishd/cache/cache_hash.c

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ struct rush {
7373
};
7474

7575
static const struct hash_slinger *hash;
76-
static struct objhead *private_oh;
76+
#define PRIVATE_OH_EXP 7
77+
static struct objhead private_ohs[1 << PRIVATE_OH_EXP];
7778

7879
static void hsh_rush1(const struct worker *, struct objhead *,
7980
struct rush *, int);
@@ -137,22 +138,37 @@ hsh_prealloc(struct worker *wrk)
137138

138139
/*---------------------------------------------------------------------*/
139140

141+
// https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization-that-the-world-forgot-or-a-better-alternative-to-integer-modulo/
142+
static inline size_t
143+
fib(uint64_t n, uint8_t bits)
144+
{
145+
const uint64_t gr = 11400714819323198485LLU;
146+
uint64_t r;
147+
148+
r = n * gr;
149+
r >>= (sizeof(gr) * 8) - bits;
150+
assert(r < (size_t)1 << bits);
151+
return ((size_t)r);
152+
}
153+
140154
struct objcore *
141155
HSH_Private(const struct worker *wrk)
142156
{
143157
struct objcore *oc;
158+
struct objhead *oh;
144159

145-
CHECK_OBJ_NOTNULL(private_oh, OBJHEAD_MAGIC);
160+
oh = &private_ohs[fib((uintptr_t)wrk, PRIVATE_OH_EXP)];
161+
CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
146162

147163
oc = ObjNew(wrk);
148164
AN(oc);
149165
oc->refcnt = 1;
150-
oc->objhead = private_oh;
166+
oc->objhead = oh;
151167
oc->flags |= OC_F_PRIVATE;
152-
Lck_Lock(&private_oh->mtx);
153-
VTAILQ_INSERT_TAIL(&private_oh->objcs, oc, hsh_list);
154-
private_oh->refcnt++;
155-
Lck_Unlock(&private_oh->mtx);
168+
Lck_Lock(&oh->mtx);
169+
VTAILQ_INSERT_TAIL(&oh->objcs, oc, hsh_list);
170+
oh->refcnt++;
171+
Lck_Unlock(&oh->mtx);
156172
return (oc);
157173
}
158174

@@ -1114,14 +1130,21 @@ hsh_deref_objhead_unlock(struct worker *wrk, struct objhead **poh, int max)
11141130

11151131
Lck_AssertHeld(&oh->mtx);
11161132

1117-
if (oh == private_oh) {
1133+
if (oh >= private_ohs && oh < private_ohs + vcountof(private_ohs)) {
11181134
assert(VTAILQ_EMPTY(&oh->waitinglist));
11191135
assert(oh->refcnt > 1);
11201136
oh->refcnt--;
11211137
Lck_Unlock(&oh->mtx);
11221138
return (1);
11231139
}
11241140

1141+
//lint --e{661}
1142+
//lint -specific(-e661)
1143+
//
1144+
// because of the static array, flexelint thinks that all ohs were from
1145+
// the static array :( the above suppression applies to the remainder of
1146+
// this function body and specific walks involving this function
1147+
11251148
INIT_OBJ(&rush, RUSH_MAGIC);
11261149
if (!VTAILQ_EMPTY(&oh->waitinglist)) {
11271150
assert(oh->refcnt > 1);
@@ -1157,6 +1180,10 @@ HSH_Init(const struct hash_slinger *slinger)
11571180
hash = slinger;
11581181
if (hash->start != NULL)
11591182
hash->start();
1160-
private_oh = hsh_newobjhead();
1161-
private_oh->refcnt = 1;
1183+
for (struct objhead *oh = private_ohs;
1184+
oh < private_ohs + vcountof(private_ohs);
1185+
oh++) {
1186+
hsh_initobjhead(oh);
1187+
assert(oh->refcnt == 1);
1188+
}
11621189
}

0 commit comments

Comments
 (0)