Skip to content

Commit a1ae21d

Browse files
committed
Fix reference counting failure in the dict. This is caused by std::swap also swapping refcounts
1 parent 91327df commit a1ae21d

File tree

3 files changed

+36
-13
lines changed

3 files changed

+36
-13
lines changed

src/dict.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,15 +204,15 @@ int dictMerge(dict *dst, dict *src)
204204

205205
if (dictSize(dst) == 0)
206206
{
207-
std::swap(*dst, *src);
207+
dict::swap(*dst, *src);
208208
std::swap(dst->pauserehash, src->pauserehash);
209209
return DICT_OK;
210210
}
211211

212212
size_t expectedSize = dictSize(src) + dictSize(dst);
213213
if (dictSize(src) > dictSize(dst) && src->asyncdata == nullptr && dst->asyncdata == nullptr)
214214
{
215-
std::swap(*dst, *src);
215+
dict::swap(*dst, *src);
216216
std::swap(dst->pauserehash, src->pauserehash);
217217
}
218218

@@ -465,6 +465,18 @@ bool dictRehashSomeAsync(dictAsyncRehashCtl *ctl, size_t hashes) {
465465
return ctl->hashIdx < ctl->queue.size();
466466
}
467467

468+
469+
void discontinueAsyncRehash(dict *d) {
470+
if (d->asyncdata != nullptr) {
471+
auto adata = d->asyncdata;
472+
while (adata != nullptr) {
473+
adata->abondon = true;
474+
adata = adata->next;
475+
}
476+
d->rehashidx = 0;
477+
}
478+
}
479+
468480
void dictCompleteRehashAsync(dictAsyncRehashCtl *ctl, bool fFree) {
469481
dict *d = ctl->dict;
470482
assert(ctl->done);

src/dict.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,16 @@ struct dictAsyncRehashCtl {
110110
std::atomic<bool> abondon { false };
111111

112112
dictAsyncRehashCtl(struct dict *d, dictAsyncRehashCtl *next);
113+
dictAsyncRehashCtl(const dictAsyncRehashCtl&) = delete;
114+
dictAsyncRehashCtl(dictAsyncRehashCtl&&) = delete;
113115
~dictAsyncRehashCtl();
114116
};
115117
#else
116118
struct dictAsyncRehashCtl;
117119
#endif
118120

121+
void discontinueAsyncRehash(dict *d);
122+
119123
typedef struct dict {
120124
dictType *type;
121125
void *privdata;
@@ -125,6 +129,24 @@ typedef struct dict {
125129
dictAsyncRehashCtl *asyncdata;
126130
int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) */
127131
uint8_t noshrink = false;
132+
133+
#ifdef __cplusplus
134+
dict() = default;
135+
dict(dict &) = delete; // No Copy Ctor
136+
137+
static void swap(dict& a, dict& b) {
138+
discontinueAsyncRehash(&a);
139+
discontinueAsyncRehash(&b);
140+
std::swap(a.type, b.type);
141+
std::swap(a.privdata, b.privdata);
142+
std::swap(a.ht[0], b.ht[0]);
143+
std::swap(a.ht[1], b.ht[1]);
144+
std::swap(a.rehashidx, b.rehashidx);
145+
// Never swap refcount - they are attached to the specific dict obj
146+
std::swap(a.pauserehash, b.pauserehash);
147+
std::swap(a.noshrink, b.noshrink);
148+
}
149+
#endif
128150
} dict;
129151

130152
/* If safe is set to 1 this is a safe iterator, that means, you can call

src/snapshot.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,6 @@ class LazyFree : public ICollectable
2626
std::vector<dictEntry*> vecde;
2727
};
2828

29-
void discontinueAsyncRehash(dict *d) {
30-
if (d->asyncdata != nullptr) {
31-
auto adata = d->asyncdata;
32-
while (adata != nullptr) {
33-
adata->abondon = true;
34-
adata = adata->next;
35-
}
36-
d->rehashidx = 0;
37-
}
38-
}
39-
4029
const redisDbPersistentDataSnapshot *redisDbPersistentData::createSnapshot(uint64_t mvccCheckpoint, bool fOptional)
4130
{
4231
serverAssert(GlobalLocksAcquired());

0 commit comments

Comments
 (0)