Skip to content

Commit bee4fc5

Browse files
committed
Replace dict with thin wrapper around hashtable
Replace the dict.c implementation with a header-only wrapper (dict.h) around the hashtable API. The dict types, iterators and API functions are now typedefs, macros and inline functions that delegate to hashtable. This unifies the hashtable implementations in the project and removes duplicated logic. Changes to dict: - Remove dict.c; dict.h is now the entire implementation - dict, dictType and dictIterator are direct aliases for the hashtable counterparts. - dictEntry is a struct allocated by dict wrapper functions to hold key and value. It doesn't have a next pointer anymore. - Fix key duplication for dictTypes that had keyDup callback by calling sdsdup() at call sites in functions.c - Remove unused functions, macros, includes and casts - Move some dict defrag logic to defrag.c - Remove obsolete dict unit tests (covered by test_hashtable.cpp) Changes to hashtable: - Change hashtable keyCompare convention to match dict: non-zero means keys are equal, so existing dict compare functions can be reused - Add const to hashtableMemUsage parameter Changes to server implementation: - Deduplicate common dict/hashtable callbacks in server.c Signed-off-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
1 parent 16a8d4b commit bee4fc5

27 files changed

+614
-2317
lines changed

cmake/Modules/SourceFiles.cmake

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ set(VALKEY_SERVER_SRCS
1010
${CMAKE_SOURCE_DIR}/src/quicklist.c
1111
${CMAKE_SOURCE_DIR}/src/ae.c
1212
${CMAKE_SOURCE_DIR}/src/anet.c
13-
${CMAKE_SOURCE_DIR}/src/dict.c
1413
${CMAKE_SOURCE_DIR}/src/hashtable.c
1514
${CMAKE_SOURCE_DIR}/src/kvstore.c
1615
${CMAKE_SOURCE_DIR}/src/sds.c
@@ -128,7 +127,7 @@ set(VALKEY_SERVER_SRCS
128127
set(VALKEY_CLI_SRCS
129128
${CMAKE_SOURCE_DIR}/src/anet.c
130129
${CMAKE_SOURCE_DIR}/src/adlist.c
131-
${CMAKE_SOURCE_DIR}/src/dict.c
130+
${CMAKE_SOURCE_DIR}/src/hashtable.c
132131
${CMAKE_SOURCE_DIR}/src/sds.c
133132
${CMAKE_SOURCE_DIR}/src/sha256.c
134133
${CMAKE_SOURCE_DIR}/src/util.c
@@ -159,7 +158,7 @@ set(VALKEY_BENCHMARK_SRCS
159158
${CMAKE_SOURCE_DIR}/src/valkey-benchmark.c
160159
${CMAKE_SOURCE_DIR}/src/valkey_strtod.c
161160
${CMAKE_SOURCE_DIR}/src/adlist.c
162-
${CMAKE_SOURCE_DIR}/src/dict.c
161+
${CMAKE_SOURCE_DIR}/src/hashtable.c
163162
${CMAKE_SOURCE_DIR}/src/zmalloc.c
164163
${CMAKE_SOURCE_DIR}/src/serverassert.c
165164
${CMAKE_SOURCE_DIR}/src/release.c

src/Makefile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,6 @@ ENGINE_SERVER_OBJ = \
478478
db.o \
479479
debug.o \
480480
defrag.o \
481-
dict.o \
482481
entry.o \
483482
eval.o \
484483
evict.o \
@@ -574,7 +573,7 @@ ENGINE_CLI_OBJ = \
574573
crc64.o \
575574
crccombine.o \
576575
crcspeed.o \
577-
dict.o \
576+
hashtable.o \
578577
monotonic.o \
579578
mt19937-64.o \
580579
release.o \
@@ -598,9 +597,9 @@ ENGINE_BENCHMARK_OBJ = \
598597
crc64.o \
599598
crccombine.o \
600599
crcspeed.o \
601-
dict.o \
602600
fuzzer_client.o \
603601
fuzzer_command_generator.o \
602+
hashtable.o \
604603
monotonic.o \
605604
mt19937-64.o \
606605
release.o \

src/cluster_legacy.c

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -236,39 +236,33 @@ static_assert(offsetof(clusterMsg, type) + sizeof(uint16_t) == RCVBUF_MIN_READ_L
236236
/* Cluster nodes hash table, mapping nodes addresses 1.2.3.4:6379 to
237237
* clusterNode structures. */
238238
dictType clusterNodesDictType = {
239-
dictSdsHash, /* hash function */
240-
NULL, /* key dup */
241-
dictSdsKeyCompare, /* key compare */
242-
dictSdsDestructor, /* key destructor */
243-
NULL, /* val destructor */
244-
NULL /* allow to expand */
239+
.entryGetKey = dictEntryGetKey,
240+
.hashFunction = dictSdsHash,
241+
.keyCompare = dictSdsKeyCompare,
242+
.entryDestructor = dictEntryDestructorSdsKey,
245243
};
246244

247245
/* Cluster re-addition blacklist. This maps node IDs to the time
248246
* we can re-add this node. The goal is to avoid reading a removed
249247
* node for some time. */
250248
dictType clusterNodesBlackListDictType = {
251-
dictSdsCaseHash, /* hash function */
252-
NULL, /* key dup */
253-
dictSdsKeyCaseCompare, /* key compare */
254-
dictSdsDestructor, /* key destructor */
255-
NULL, /* val destructor */
256-
NULL /* allow to expand */
249+
.entryGetKey = dictEntryGetKey,
250+
.hashFunction = dictSdsCaseHash,
251+
.keyCompare = dictSdsKeyCaseCompare,
252+
.entryDestructor = dictEntryDestructorSdsKey,
257253
};
258254

259255
/* Cluster shards hash table, mapping shard id to list of nodes */
260256
dictType clusterSdsToListType = {
261-
dictSdsHash, /* hash function */
262-
NULL, /* key dup */
263-
dictSdsKeyCompare, /* key compare */
264-
dictSdsDestructor, /* key destructor */
265-
dictListDestructor, /* val destructor */
266-
NULL /* allow to expand */
257+
.entryGetKey = dictEntryGetKey,
258+
.hashFunction = dictSdsHash,
259+
.keyCompare = dictSdsKeyCompare,
260+
.entryDestructor = dictEntryDestructorSdsKeyListValue,
267261
};
268262

269263
static uint64_t dictPtrHash(const void *key) {
270264
/* We hash the pointer value itself. */
271-
return dictGenHashFunction(&key, sizeof(key));
265+
return dictGenHashFunction((const char *)&key, sizeof(key));
272266
}
273267

274268
static int dictPtrCompare(const void *key1, const void *key2) {
@@ -278,12 +272,10 @@ static int dictPtrCompare(const void *key1, const void *key2) {
278272
/* Dictionary type for mapping hash slots to cluster nodes.
279273
* Keys are slot numbers encoded directly as pointer values, values are clusterNode pointers. */
280274
dictType clusterSlotDictType = {
281-
dictPtrHash, /* hash function */
282-
NULL, /* key dup */
283-
dictPtrCompare, /* key compare */
284-
NULL, /* key destructor */
285-
NULL, /* val destructor */
286-
NULL /* allow to expand */
275+
.entryGetKey = dictEntryGetKey,
276+
.hashFunction = dictPtrHash,
277+
.keyCompare = dictPtrCompare,
278+
.entryDestructor = zfree,
287279
};
288280

289281
typedef struct {
@@ -4852,7 +4844,7 @@ void clusterSendPing(clusterLink *link, int type) {
48524844
int candidates_wanted = wanted + 2; /* +2 for myself and link->node */
48534845
if (candidates_wanted > (int)dictSize(server.cluster->nodes))
48544846
candidates_wanted = dictSize(server.cluster->nodes);
4855-
dictEntry **candidates = zmalloc(sizeof(dictEntry *) * candidates_wanted);
4847+
void **candidates = zmalloc(sizeof(void *) * candidates_wanted);
48564848
unsigned int ncandidates = dictGetSomeKeys(server.cluster->nodes, candidates, candidates_wanted);
48574849

48584850
for (unsigned int i = 0; i < ncandidates && gossipcount < wanted; i++) {

src/config.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,21 +1041,17 @@ void rewriteConfigSentinelOption(struct rewriteConfigState *state);
10411041
* like "maxmemory" -> list of line numbers (first line is zero).
10421042
*/
10431043
dictType optionToLineDictType = {
1044-
dictSdsCaseHash, /* hash function */
1045-
NULL, /* key dup */
1046-
dictSdsKeyCaseCompare, /* key compare */
1047-
dictSdsDestructor, /* key destructor */
1048-
dictListDestructor, /* val destructor */
1049-
NULL /* allow to expand */
1044+
.entryGetKey = dictEntryGetKey,
1045+
.hashFunction = dictSdsCaseHash,
1046+
.keyCompare = dictSdsKeyCaseCompare,
1047+
.entryDestructor = dictEntryDestructorSdsKeyListValue,
10501048
};
10511049

10521050
dictType optionSetDictType = {
1053-
dictSdsCaseHash, /* hash function */
1054-
NULL, /* key dup */
1055-
dictSdsKeyCaseCompare, /* key compare */
1056-
dictSdsDestructor, /* key destructor */
1057-
NULL, /* val destructor */
1058-
NULL /* allow to expand */
1051+
.entryGetKey = dictEntryGetKey,
1052+
.hashFunction = dictSdsCaseHash,
1053+
.keyCompare = dictSdsKeyCaseCompare,
1054+
.entryDestructor = dictEntryDestructorSdsKey,
10591055
};
10601056

10611057
/* The config rewrite state. */

src/defrag.c

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,24 +299,50 @@ static void activeDefragZsetNode(void *privdata, void *entry_ref) {
299299
#define DEFRAG_SDS_DICT_VAL_VOID_PTR 3
300300
#define DEFRAG_SDS_DICT_VAL_LUA_SCRIPT 4
301301

302-
static void activeDefragSdsDictCallback(void *privdata, const dictEntry *de) {
303-
UNUSED(privdata);
304-
UNUSED(de);
302+
typedef void *(dictDefragAllocFunction)(void *ptr);
303+
typedef struct {
304+
dictDefragAllocFunction *defragKey;
305+
dictDefragAllocFunction *defragVal;
306+
} dictDefragFunctions;
307+
308+
static void activeDefragDictCallback(void *privdata, void *entry_ref) {
309+
dictDefragFunctions *defragfns = privdata;
310+
dictEntry **de_ref = (dictEntry **)entry_ref;
311+
dictEntry *de = *de_ref;
312+
313+
/* Defrag the entry itself */
314+
dictEntry *newentry = activeDefragAlloc(de);
315+
if (newentry) {
316+
de = newentry;
317+
*de_ref = newentry;
318+
}
319+
320+
/* Defrag the key */
321+
if (defragfns->defragKey) {
322+
void *newkey = defragfns->defragKey(de->key);
323+
if (newkey) de->key = newkey;
324+
}
325+
326+
/* Defrag the value */
327+
if (defragfns->defragVal) {
328+
void *newval = defragfns->defragVal(de->v.val);
329+
if (newval) de->v.val = newval;
330+
}
305331
}
306332

307333
/* Defrag a dict with sds key and optional value (either ptr, sds or robj string) */
308334
static void activeDefragSdsDict(dict *d, int val_type) {
309335
unsigned long cursor = 0;
310336
dictDefragFunctions defragfns = {
311-
.defragAlloc = activeDefragAlloc,
312337
.defragKey = (dictDefragAllocFunction *)activeDefragSds,
313338
.defragVal = (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS ? (dictDefragAllocFunction *)activeDefragSds
314339
: val_type == DEFRAG_SDS_DICT_VAL_IS_STROB ? (dictDefragAllocFunction *)activeDefragStringOb
315340
: val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR ? (dictDefragAllocFunction *)activeDefragAlloc
316341
: val_type == DEFRAG_SDS_DICT_VAL_LUA_SCRIPT ? (dictDefragAllocFunction *)evalActiveDefragScript
317342
: NULL)};
318343
do {
319-
cursor = dictScanDefrag(d, cursor, activeDefragSdsDictCallback, &defragfns, NULL);
344+
cursor = hashtableScanDefrag(d, cursor, activeDefragDictCallback,
345+
&defragfns, activeDefragAlloc, HASHTABLE_SCAN_EMIT_REF);
320346
} while (cursor != 0);
321347
}
322348

0 commit comments

Comments
 (0)