7b070423b8
After #13072, there is an use-after-free error. In expireScanCallback, we will delete the dict, and then in dictScan we will continue to use the dict, like we will doing `dictResumeRehashing(d)` in the end, this casued an error. In this PR, in freeDictIfNeeded, if the dict's pauserehash is set, don't delete the dict yet, and then when scan returns try to delete it again. At the same time, we noticed that there will be similar problems in iterator. We may also delete elements during the iteration process, causing the dict to be deleted, so the part related to iter in the PR has also been modified. dictResetIterator was also missing from the previous kvstoreIteratorNextDict, we currently have no scenario that elements will be deleted in kvstoreIterator process, deal with it together to avoid future problems. Added some simple tests to verify the changes. In addition, the modification in #13072 omitted initTempDb and emptyDbAsync, and they were also added. This PR also remove the slow flag from the expire test (consumes 1.3s) so that problems can be found in CI in the future.
80 lines
3.9 KiB
C
80 lines
3.9 KiB
C
#ifndef DICTARRAY_H_
|
|
#define DICTARRAY_H_
|
|
|
|
#include "dict.h"
|
|
#include "adlist.h"
|
|
|
|
typedef struct _kvstore kvstore;
|
|
typedef struct _kvstoreIterator kvstoreIterator;
|
|
typedef struct _kvstoreDictIterator kvstoreDictIterator;
|
|
|
|
typedef int (kvstoreScanShouldSkipDict)(dict *d);
|
|
typedef int (kvstoreExpandShouldSkipDictIndex)(int didx);
|
|
|
|
#define KVSTORE_ALLOCATE_DICTS_ON_DEMAND (1<<0)
|
|
#define KVSTORE_FREE_EMPTY_DICTS (1<<1)
|
|
kvstore *kvstoreCreate(dictType *type, int num_dicts_bits, int flags);
|
|
void kvstoreEmpty(kvstore *kvs, void(callback)(dict*));
|
|
void kvstoreRelease(kvstore *kvs);
|
|
unsigned long long kvstoreSize(kvstore *kvs);
|
|
unsigned long kvstoreBuckets(kvstore *kvs);
|
|
size_t kvstoreMemUsage(kvstore *kvs);
|
|
unsigned long long kvstoreScan(kvstore *kvs, unsigned long long cursor,
|
|
int onlydidx, dictScanFunction *scan_cb,
|
|
kvstoreScanShouldSkipDict *skip_cb,
|
|
void *privdata);
|
|
int kvstoreExpand(kvstore *kvs, uint64_t newsize, int try_expand, kvstoreExpandShouldSkipDictIndex *skip_cb);
|
|
int kvstoreGetFairRandomDictIndex(kvstore *kvs);
|
|
void kvstoreGetStats(kvstore *kvs, char *buf, size_t bufsize, int full);
|
|
|
|
int kvstoreFindDictIndexByKeyIndex(kvstore *kvs, unsigned long target);
|
|
int kvstoreGetFirstNonEmptyDictIndex(kvstore *kvs);
|
|
int kvstoreGetNextNonEmptyDictIndex(kvstore *kvs, int didx);
|
|
int kvstoreNumNonEmptyDicts(kvstore *kvs);
|
|
int kvstoreNumAllocatedDicts(kvstore *kvs);
|
|
int kvstoreNumDicts(kvstore *kvs);
|
|
uint64_t kvstoreGetHash(kvstore *kvs, const void *key);
|
|
|
|
/* kvstore iterator specific functions */
|
|
kvstoreIterator *kvstoreIteratorInit(kvstore *kvs);
|
|
void kvstoreIteratorRelease(kvstoreIterator *kvs_it);
|
|
dict *kvstoreIteratorNextDict(kvstoreIterator *kvs_it);
|
|
int kvstoreIteratorGetCurrentDictIndex(kvstoreIterator *kvs_it);
|
|
dictEntry *kvstoreIteratorNext(kvstoreIterator *kvs_it);
|
|
|
|
/* Rehashing */
|
|
void kvstoreTryResizeDicts(kvstore *kvs, int limit);
|
|
uint64_t kvstoreIncrementallyRehash(kvstore *kvs, uint64_t threshold_us);
|
|
size_t kvstoreOverheadHashtableLut(kvstore *kvs);
|
|
size_t kvstoreOverheadHashtableRehashing(kvstore *kvs);
|
|
unsigned long kvstoreDictRehashingCount(kvstore *kvs);
|
|
|
|
/* Specific dict access by dict-index */
|
|
unsigned long kvstoreDictSize(kvstore *kvs, int didx);
|
|
kvstoreDictIterator *kvstoreGetDictIterator(kvstore *kvs, int didx);
|
|
kvstoreDictIterator *kvstoreGetDictSafeIterator(kvstore *kvs, int didx);
|
|
void kvstoreReleaseDictIterator(kvstoreDictIterator *kvs_id);
|
|
dictEntry *kvstoreDictIteratorNext(kvstoreDictIterator *kvs_di);
|
|
dictEntry *kvstoreDictGetRandomKey(kvstore *kvs, int didx);
|
|
dictEntry *kvstoreDictGetFairRandomKey(kvstore *kvs, int didx);
|
|
dictEntry *kvstoreDictFindEntryByPtrAndHash(kvstore *kvs, int didx, const void *oldptr, uint64_t hash);
|
|
unsigned int kvstoreDictGetSomeKeys(kvstore *kvs, int didx, dictEntry **des, unsigned int count);
|
|
int kvstoreDictExpand(kvstore *kvs, int didx, unsigned long size);
|
|
unsigned long kvstoreDictScanDefrag(kvstore *kvs, int didx, unsigned long v, dictScanFunction *fn, dictDefragFunctions *defragfns, void *privdata);
|
|
typedef dict *(kvstoreDictLUTDefragFunction)(dict *d);
|
|
void kvstoreDictLUTDefrag(kvstore *kvs, kvstoreDictLUTDefragFunction *defragfn);
|
|
void *kvstoreDictFetchValue(kvstore *kvs, int didx, const void *key);
|
|
dictEntry *kvstoreDictFind(kvstore *kvs, int didx, void *key);
|
|
dictEntry *kvstoreDictAddRaw(kvstore *kvs, int didx, void *key, dictEntry **existing);
|
|
void kvstoreDictSetKey(kvstore *kvs, int didx, dictEntry* de, void *key);
|
|
void kvstoreDictSetVal(kvstore *kvs, int didx, dictEntry *de, void *val);
|
|
dictEntry *kvstoreDictTwoPhaseUnlinkFind(kvstore *kvs, int didx, const void *key, dictEntry ***plink, int *table_index);
|
|
void kvstoreDictTwoPhaseUnlinkFree(kvstore *kvs, int didx, dictEntry *he, dictEntry **plink, int table_index);
|
|
int kvstoreDictDelete(kvstore *kvs, int didx, const void *key);
|
|
|
|
#ifdef REDIS_TEST
|
|
int kvstoreTest(int argc, char *argv[], int flags);
|
|
#endif
|
|
|
|
#endif /* DICTARRAY_H_ */
|