From 35f6b6ed409e06b68667d8a281684b2d6ef09e0f Mon Sep 17 00:00:00 2001 From: NadavGigi Date: Thu, 9 Jan 2025 10:05:37 +0000 Subject: [PATCH] Improving iterator using prefetch values Signed-off-by: NadavGigi --- src/acl.c | 8 ++++---- src/aof.c | 4 ++-- src/db.c | 2 +- src/debug.c | 4 ++-- src/hashtable.c | 28 ++++++++++++++++++++++++++-- src/hashtable.h | 7 ++++++- src/kvstore.c | 11 ++++++----- src/kvstore.h | 2 +- src/latency.c | 4 ++-- src/module.c | 4 ++-- src/object.c | 8 ++++---- src/rdb.c | 6 +++--- src/server.c | 34 +++++++++++++++++++++++++--------- src/sort.c | 2 +- src/t_hash.c | 2 +- src/t_set.c | 4 ++-- src/t_zset.c | 6 +++--- src/unit/test_hashtable.c | 6 +++--- src/unit/test_kvstore.c | 4 ++-- 19 files changed, 96 insertions(+), 50 deletions(-) diff --git a/src/acl.c b/src/acl.c index 184fa54116..cf200dcebf 100644 --- a/src/acl.c +++ b/src/acl.c @@ -657,7 +657,7 @@ void ACLChangeSelectorPerm(aclSelector *selector, struct serverCommand *cmd, int hashtableIterator iter; hashtableInitSafeIterator(&iter, cmd->subcommands_ht); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *sub = next; ACLSetSelectorCommandBit(selector, sub->id, allow); } @@ -675,7 +675,7 @@ void ACLSetSelectorCommandBitsForCategory(hashtable *commands, aclSelector *sele hashtableIterator iter; hashtableInitIterator(&iter, commands); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *cmd = next; if (cmd->acl_categories & cflag) { ACLChangeSelectorPerm(selector, cmd, value); @@ -743,7 +743,7 @@ void ACLCountCategoryBitsForCommands(hashtable *commands, hashtableIterator iter; hashtableInitIterator(&iter, commands); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *cmd = next; if (cmd->acl_categories & cflag) { if (ACLGetSelectorCommandBit(selector, cmd->id)) @@ -2767,7 +2767,7 @@ void aclCatWithFlags(client *c, hashtable *commands, uint64_t cflag, int *arrayl hashtableIterator iter; hashtableInitIterator(&iter, commands); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *cmd = next; if (cmd->acl_categories & cflag) { addReplyBulkCBuffer(c, cmd->fullname, sdslen(cmd->fullname)); diff --git a/src/aof.c b/src/aof.c index 024cdb2771..f6bbc3ce9b 100644 --- a/src/aof.c +++ b/src/aof.c @@ -1893,7 +1893,7 @@ int rewriteSortedSetObject(rio *r, robj *key, robj *o) { hashtableIterator iter; hashtableInitIterator(&iter, zs->ht); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { zskiplistNode *node = next; if (count == 0) { int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ? AOF_REWRITE_ITEMS_PER_CMD : items; @@ -2220,7 +2220,7 @@ int rewriteAppendOnlyFileRio(rio *aof) { kvs_it = kvstoreIteratorInit(db->keys); /* Iterate this DB writing every entry */ void *next; - while (kvstoreIteratorNext(kvs_it, &next)) { + while (kvstoreIteratorNext(kvs_it, &next, HASHTABLE_ITER_PREFETCH_VALUES)) { robj *o = next; sds keystr; robj key; diff --git a/src/db.c b/src/db.c index 94074bf668..f71e38ce74 100644 --- a/src/db.c +++ b/src/db.c @@ -900,7 +900,7 @@ void keysCommand(client *c) { kvs_it = kvstoreIteratorInit(c->db->keys); } void *next; - while (kvs_di ? kvstoreHashtableIteratorNext(kvs_di, &next) : kvstoreIteratorNext(kvs_it, &next)) { + while (kvs_di ? kvstoreHashtableIteratorNext(kvs_di, &next) : kvstoreIteratorNext(kvs_it, &next, 0)) { robj *val = next; sds key = objectGetKey(val); if (allkeys || stringmatchlen(pattern, plen, key, sdslen(key), 0)) { diff --git a/src/debug.c b/src/debug.c index 915e0c264d..31fec9e935 100644 --- a/src/debug.c +++ b/src/debug.c @@ -210,7 +210,7 @@ void xorObjectDigest(serverDb *db, robj *keyobj, unsigned char *digest, robj *o) hashtableInitIterator(&iter, zs->ht); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { zskiplistNode *node = next; const int len = fpconv_dtoa(node->score, buf); buf[len] = '\0'; @@ -299,7 +299,7 @@ void computeDatasetDigest(unsigned char *final) { /* Iterate this DB writing every entry */ void *next; - while (kvstoreIteratorNext(kvs_it, &next)) { + while (kvstoreIteratorNext(kvs_it, &next, HASHTABLE_ITER_PREFETCH_VALUES)) { robj *o = next; sds key; robj *keyobj; diff --git a/src/hashtable.c b/src/hashtable.c index 3f1eff19c1..d5e119dd17 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -379,6 +379,12 @@ static inline int compareKeys(hashtable *ht, const void *key1, const void *key2) } } +static inline void entryPrefetchValue(hashtable *ht, const void *entry) { + if (ht->type->entryPrefetchValue != NULL) { + ht->type->entryPrefetchValue(entry); + } +} + static inline const void *entryGetKey(hashtable *ht, const void *entry) { if (ht->type->entryGetKey != NULL) { return ht->type->entryGetKey(entry); @@ -979,6 +985,15 @@ static void prefetchNextBucketEntries(iter *iter, bucket *current_bucket) { } } +/* Prefetches the values associated with filled entries in the given bucket. */ +static void prefetchBucketValues(bucket *b, hashtable *ht) { + for (int pos = 0; pos < numBucketPositions(b); pos++) { + if (isPositionFilled(b, pos)) { + entryPrefetchValue(ht, b->entries[pos]); + } + } +} + /* --- API functions --- */ /* Allocates and initializes a new hashtable specified by the given type. */ @@ -1874,8 +1889,14 @@ void hashtableReleaseIterator(hashtableIterator *iterator) { } /* Points elemptr to the next entry and returns 1 if there is a next entry. - * Returns 0 if there are no more entries. */ -int hashtableNext(hashtableIterator *iterator, void **elemptr) { + * Returns 0 if there are no more entries. + * The 'flags' argument can be used to tweak the behavior of the iterator: + * - HASHTABLE_ITER_PREFETCH_VALUES: Enables prefetching of entries values, + * which can improve performance in some scenarios. Because the hashtable is generic and + * doesn't care which object we store, the callback entryPrefetchValue helps + * us prefetch necessary fields of specific object types stored in the hashtable. + */ +int hashtableNext(hashtableIterator *iterator, void **elemptr, int flags) { iter *iter = iteratorFromOpaque(iterator); while (1) { if (iter->index == -1 && iter->table == 0) { @@ -1936,6 +1957,9 @@ int hashtableNext(hashtableIterator *iterator, void **elemptr) { } bucket *b = iter->bucket; if (iter->pos_in_bucket == 0) { + if (b->presence && (flags & HASHTABLE_ITER_PREFETCH_VALUES)) { + prefetchBucketValues(b, iter->hashtable); + } prefetchNextBucketEntries(iter, b); } if (!isPositionFilled(b, iter->pos_in_bucket)) { diff --git a/src/hashtable.h b/src/hashtable.h index 4291cf5a5d..60febe09ac 100644 --- a/src/hashtable.h +++ b/src/hashtable.h @@ -48,6 +48,8 @@ typedef uint64_t hashtableIncrementalFindState[5]; * optional. With all callbacks omitted, the hashtable is effectively a set of * pointer-sized integers. */ typedef struct { + /* Callback to prefetch the value associated with a hashtable entry. */ + void (*entryPrefetchValue)(const void *entry); /* If the type of an entry is not the same as the type of a key used for * lookup, this callback needs to return the key within an entry. */ const void *(*entryGetKey)(const void *entry); @@ -91,6 +93,9 @@ typedef void (*hashtableScanFunction)(void *privdata, void *entry); /* Scan flags */ #define HASHTABLE_SCAN_EMIT_REF (1 << 0) +/* Iterator flags */ +#define HASHTABLE_ITER_PREFETCH_VALUES (1 << 0) /* When set, prefetch entries inner data during iteration to reduce latency */ + /* --- Prototypes --- */ /* Hash function (global seed) */ @@ -150,7 +155,7 @@ void hashtableResetIterator(hashtableIterator *iter); hashtableIterator *hashtableCreateIterator(hashtable *ht); hashtableIterator *hashtableCreateSafeIterator(hashtable *ht); void hashtableReleaseIterator(hashtableIterator *iter); -int hashtableNext(hashtableIterator *iter, void **elemptr); +int hashtableNext(hashtableIterator *iter, void **elemptr, int flags); /* Random entries */ int hashtableRandomEntry(hashtable *ht, void **found); diff --git a/src/kvstore.c b/src/kvstore.c index d6db4d3fe1..ebeb5cd9b2 100644 --- a/src/kvstore.c +++ b/src/kvstore.c @@ -617,16 +617,17 @@ int kvstoreIteratorGetCurrentHashtableIndex(kvstoreIterator *kvs_it) { return kvs_it->didx; } -/* Fetches the next element and returns 1. Returns 0 if there are no more elements. */ -int kvstoreIteratorNext(kvstoreIterator *kvs_it, void **next) { - if (kvs_it->didx != -1 && hashtableNext(&kvs_it->di, next)) { +/* Fetches the next element and returns 1. Returns 0 if there are no more elements. + * The 'flags' argument can be used to tweak the behavior of the iterator. */ +int kvstoreIteratorNext(kvstoreIterator *kvs_it, void **next, int flags) { + if (kvs_it->didx != -1 && hashtableNext(&kvs_it->di, next, flags)) { return 1; } else { /* No current hashtable or reached the end of the hash table. */ hashtable *ht = kvstoreIteratorNextHashtable(kvs_it); if (!ht) return 0; hashtableInitSafeIterator(&kvs_it->di, ht); - return hashtableNext(&kvs_it->di, next); + return hashtableNext(&kvs_it->di, next, flags); } } @@ -724,7 +725,7 @@ int kvstoreHashtableIteratorNext(kvstoreHashtableIterator *kvs_di, void **next) /* The hashtable may be deleted during the iteration process, so here need to check for NULL. */ hashtable *ht = kvstoreGetHashtable(kvs_di->kvs, kvs_di->didx); if (!ht) return 0; - return hashtableNext(&kvs_di->di, next); + return hashtableNext(&kvs_di->di, next, 0); } int kvstoreHashtableRandomEntry(kvstore *kvs, int didx, void **entry) { diff --git a/src/kvstore.h b/src/kvstore.h index 1a8c74a6b9..c9f7fd0de2 100644 --- a/src/kvstore.h +++ b/src/kvstore.h @@ -46,7 +46,7 @@ size_t kvstoreHashtableMetadataSize(void); kvstoreIterator *kvstoreIteratorInit(kvstore *kvs); void kvstoreIteratorRelease(kvstoreIterator *kvs_it); int kvstoreIteratorGetCurrentHashtableIndex(kvstoreIterator *kvs_it); -int kvstoreIteratorNext(kvstoreIterator *kvs_it, void **next); +int kvstoreIteratorNext(kvstoreIterator *kvs_it, void **next, int flags); /* Rehashing */ void kvstoreTryResizeHashtables(kvstore *kvs, int limit); diff --git a/src/latency.c b/src/latency.c index 2beb4859d1..b934d6fc55 100644 --- a/src/latency.c +++ b/src/latency.c @@ -530,7 +530,7 @@ void latencyAllCommandsFillCDF(client *c, hashtable *commands, int *command_with hashtableIterator iter; hashtableInitSafeIterator(&iter, commands); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *cmd = next; if (cmd->latency_histogram) { addReplyBulkCBuffer(c, cmd->fullname, sdslen(cmd->fullname)); @@ -567,7 +567,7 @@ void latencySpecificCommandsFillCDF(client *c) { hashtableIterator iter; hashtableInitSafeIterator(&iter, cmd->subcommands_ht); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *sub = next; if (sub->latency_histogram) { addReplyBulkCBuffer(c, sub->fullname, sdslen(sub->fullname)); diff --git a/src/module.c b/src/module.c index fa60335837..11cd0977a2 100644 --- a/src/module.c +++ b/src/module.c @@ -12163,7 +12163,7 @@ int moduleFreeCommand(struct ValkeyModule *module, struct serverCommand *cmd) { hashtableIterator iter; void *next; hashtableInitSafeIterator(&iter, cmd->subcommands_ht); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *sub = next; if (moduleFreeCommand(module, sub) != C_OK) continue; @@ -12186,7 +12186,7 @@ void moduleUnregisterCommands(struct ValkeyModule *module) { hashtableIterator iter; void *next; hashtableInitSafeIterator(&iter, server.commands); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *cmd = next; if (moduleFreeCommand(module, cmd) != C_OK) continue; diff --git a/src/object.c b/src/object.c index b8200dd815..50da4398e2 100644 --- a/src/object.c +++ b/src/object.c @@ -632,7 +632,7 @@ void dismissSetObject(robj *o, size_t size_hint) { hashtableIterator iter; hashtableInitIterator(&iter, ht); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { sds item = next; dismissSds(item); } @@ -684,7 +684,7 @@ void dismissHashObject(robj *o, size_t size_hint) { hashtableIterator iter; hashtableInitIterator(&iter, ht); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { dismissHashTypeEntry(next); } hashtableResetIterator(&iter); @@ -1158,7 +1158,7 @@ size_t objectComputeSize(robj *key, robj *o, size_t sample_size, int dbid) { hashtableIterator iter; hashtableInitIterator(&iter, ht); void *next; - while (hashtableNext(&iter, &next) && samples < sample_size) { + while (hashtableNext(&iter, &next, 0) && samples < sample_size) { sds element = next; elesize += sdsAllocSize(element); samples++; @@ -1201,7 +1201,7 @@ size_t objectComputeSize(robj *key, robj *o, size_t sample_size, int dbid) { void *next; asize = sizeof(*o) + hashtableMemUsage(ht); - while (hashtableNext(&iter, &next) && samples < sample_size) { + while (hashtableNext(&iter, &next, 0) && samples < sample_size) { elesize += hashTypeEntryAllocSize(next); samples++; } diff --git a/src/rdb.c b/src/rdb.c index 0bb5d7d45d..7c1a98d17a 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -889,7 +889,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key, int dbid) { hashtableIterator iterator; hashtableInitIterator(&iterator, set); void *next; - while (hashtableNext(&iterator, &next)) { + while (hashtableNext(&iterator, &next, 0)) { sds ele = next; if ((n = rdbSaveRawString(rdb, (unsigned char *)ele, sdslen(ele))) == -1) { hashtableResetIterator(&iterator); @@ -961,7 +961,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key, int dbid) { hashtableIterator iter; hashtableInitIterator(&iter, ht); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, HASHTABLE_ITER_PREFETCH_VALUES)) { sds field = hashTypeEntryGetField(next); sds value = hashTypeEntryGetValue(next); @@ -1353,7 +1353,7 @@ ssize_t rdbSaveDb(rio *rdb, int dbid, int rdbflags, long *key_counter) { int last_slot = -1; /* Iterate this DB writing every entry */ void *next; - while (kvstoreIteratorNext(kvs_it, &next)) { + while (kvstoreIteratorNext(kvs_it, &next, HASHTABLE_ITER_PREFETCH_VALUES)) { robj *o = next; int curr_slot = kvstoreIteratorGetCurrentHashtableIndex(kvs_it); /* Save slot info. */ diff --git a/src/server.c b/src/server.c index 8255b57e25..68aff159c2 100644 --- a/src/server.c +++ b/src/server.c @@ -576,6 +576,14 @@ const void *hashtableObjectGetKey(const void *entry) { return objectGetKey(entry); } +/* Prefetch the value if it's not embedded. */ +void hashtableObjectPrefetchValue(const void *entry) { + const robj *obj = entry; + if (obj->encoding != OBJ_ENCODING_EMBSTR) { + valkey_prefetch(obj->ptr); + } +} + int hashtableObjKeyCompare(const void *key1, const void *key2) { const robj *o1 = key1, *o2 = key2; return hashtableSdsKeyCompare(o1->ptr, o2->ptr); @@ -588,6 +596,7 @@ void hashtableObjectDestructor(void *val) { /* Kvstore->keys, keys are sds strings, vals are Objects. */ hashtableType kvstoreKeysHashtableType = { + .entryPrefetchValue = hashtableObjectPrefetchValue, .entryGetKey = hashtableObjectGetKey, .hashFunction = hashtableSdsHash, .keyCompare = hashtableSdsKeyCompare, @@ -601,6 +610,7 @@ hashtableType kvstoreKeysHashtableType = { /* Kvstore->expires */ hashtableType kvstoreExpiresHashtableType = { + .entryPrefetchValue = hashtableObjectPrefetchValue, .entryGetKey = hashtableObjectGetKey, .hashFunction = hashtableSdsHash, .keyCompare = hashtableSdsKeyCompare, @@ -630,12 +640,18 @@ const void *hashHashtableTypeGetKey(const void *entry) { return (const void *)hashTypeEntryGetField(hash_entry); } +void hashHashtableTypePrefetchValue(const void *entry) { + const hashTypeEntry *hash_entry = entry; + valkey_prefetch(hashTypeEntryGetValue(hash_entry)); +} + void hashHashtableTypeDestructor(void *entry) { hashTypeEntry *hash_entry = entry; freeHashTypeEntry(hash_entry); } hashtableType hashHashtableType = { + .entryPrefetchValue = hashHashtableTypePrefetchValue, .hashFunction = dictSdsHash, .entryGetKey = hashHashtableTypeGetKey, .keyCompare = hashtableSdsKeyCompare, @@ -3202,7 +3218,7 @@ void resetCommandTableStats(hashtable *commands) { hashtableIterator iter; void *next; hashtableInitSafeIterator(&iter, commands); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *c = next; c->microseconds = 0; c->calls = 0; @@ -4985,7 +5001,7 @@ void addReplyCommandSubCommands(client *c, void *next; hashtableIterator iter; hashtableInitSafeIterator(&iter, cmd->subcommands_ht); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *sub = next; if (use_map) addReplyBulkCBuffer(c, sub->fullname, sdslen(sub->fullname)); reply_function(c, sub); @@ -5147,7 +5163,7 @@ void commandCommand(client *c) { void *next; addReplyArrayLen(c, hashtableSize(server.commands)); hashtableInitIterator(&iter, server.commands); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *cmd = next; addReplyCommandInfo(c, cmd); } @@ -5206,7 +5222,7 @@ void commandListWithFilter(client *c, hashtable *commands, commandListFilter fil hashtableIterator iter; void *next; hashtableInitIterator(&iter, commands); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *cmd = next; if (!shouldFilterFromCommandList(cmd, &filter)) { addReplyBulkCBuffer(c, cmd->fullname, sdslen(cmd->fullname)); @@ -5225,7 +5241,7 @@ void commandListWithoutFilter(client *c, hashtable *commands, int *numcmds) { hashtableIterator iter; void *next; hashtableInitIterator(&iter, commands); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *cmd = next; addReplyBulkCBuffer(c, cmd->fullname, sdslen(cmd->fullname)); (*numcmds)++; @@ -5287,7 +5303,7 @@ void commandInfoCommand(client *c) { void *next; addReplyArrayLen(c, hashtableSize(server.commands)); hashtableInitIterator(&iter, server.commands); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *cmd = next; addReplyCommandInfo(c, cmd); } @@ -5309,7 +5325,7 @@ void commandDocsCommand(client *c) { void *next; addReplyMapLen(c, hashtableSize(server.commands)); hashtableInitIterator(&iter, server.commands); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *cmd = next; addReplyBulkCBuffer(c, cmd->fullname, sdslen(cmd->fullname)); addReplyCommandDocs(c, cmd); @@ -5438,7 +5454,7 @@ sds genValkeyInfoStringCommandStats(sds info, hashtable *commands) { hashtableIterator iter; void *next; hashtableInitSafeIterator(&iter, commands); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *c = next; char *tmpsafe; if (c->calls || c->failed_calls || c->rejected_calls) { @@ -5475,7 +5491,7 @@ sds genValkeyInfoStringLatencyStats(sds info, hashtable *commands) { hashtableIterator iter; void *next; hashtableInitSafeIterator(&iter, commands); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { struct serverCommand *c = next; char *tmpsafe; if (c->latency_histogram) { diff --git a/src/sort.c b/src/sort.c index 7af96141e8..a82f6b0bc2 100644 --- a/src/sort.c +++ b/src/sort.c @@ -449,7 +449,7 @@ void sortCommandGeneric(client *c, int readonly) { hashtableIterator iter; hashtableInitIterator(&iter, ht); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { zskiplistNode *node = next; vector[j].obj = createStringObject(node->ele, sdslen(node->ele)); vector[j].u.score = 0; diff --git a/src/t_hash.c b/src/t_hash.c index b6e6457bb6..94145961b6 100644 --- a/src/t_hash.c +++ b/src/t_hash.c @@ -422,7 +422,7 @@ int hashTypeNext(hashTypeIterator *hi) { hi->fptr = fptr; hi->vptr = vptr; } else if (hi->encoding == OBJ_ENCODING_HASHTABLE) { - if (!hashtableNext(&hi->iter, &hi->next)) return C_ERR; + if (!hashtableNext(&hi->iter, &hi->next, 0)) return C_ERR; } else { serverPanic("Unknown hash encoding"); } diff --git a/src/t_set.c b/src/t_set.c index 4279baf82f..d4cc0d044f 100644 --- a/src/t_set.c +++ b/src/t_set.c @@ -357,7 +357,7 @@ void setTypeReleaseIterator(setTypeIterator *si) { int setTypeNext(setTypeIterator *si, char **str, size_t *len, int64_t *llele) { if (si->encoding == OBJ_ENCODING_HASHTABLE) { void *next; - if (!hashtableNext(si->hashtable_iterator, &next)) return -1; + if (!hashtableNext(si->hashtable_iterator, &next, 0)) return -1; *str = next; *len = sdslen(*str); *llele = -123456789; /* Not needed. Defensive. */ @@ -1184,7 +1184,7 @@ void srandmemberWithCountCommand(client *c) { addReplyArrayLen(c, count); serverAssert(count == hashtableSize(ht)); void *element; - while (hashtableNext(&iter, &element)) addReplyBulkSds(c, (sds)element); + while (hashtableNext(&iter, &element, 0)) addReplyBulkSds(c, (sds)element); hashtableResetIterator(&iter); hashtableRelease(ht); } diff --git a/src/t_zset.c b/src/t_zset.c index 77c96613b7..f47a1f4e53 100644 --- a/src/t_zset.c +++ b/src/t_zset.c @@ -2200,7 +2200,7 @@ static int zuiNext(zsetopsrc *op, zsetopval *val) { it->is.ii++; } else if (op->encoding == OBJ_ENCODING_HASHTABLE) { void *next; - if (!hashtableNext(it->ht.iter, &next)) return 0; + if (!hashtableNext(it->ht.iter, &next, 0)) return 0; val->ele = next; val->score = 1.0; } else if (op->encoding == OBJ_ENCODING_LISTPACK) { @@ -2351,7 +2351,7 @@ static size_t zsetHashtableGetMaxElementLength(hashtable *ht, size_t *totallen) hashtableIterator iter; hashtableInitIterator(&iter, ht); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { zskiplistNode *node = next; size_t elelen = sdslen(node->ele); if (elelen > maxelelen) maxelelen = elelen; @@ -2752,7 +2752,7 @@ static void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIn hashtableInitIterator(&iter, dstzset->ht); void *next; - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { zskiplistNode *node = next; zslInsertNode(dstzset->zsl, node); } diff --git a/src/unit/test_hashtable.c b/src/unit/test_hashtable.c index 689440e43d..25f7f9e539 100644 --- a/src/unit/test_hashtable.c +++ b/src/unit/test_hashtable.c @@ -548,7 +548,7 @@ int test_iterator(int argc, char **argv, int flags) { hashtableIterator iter; void *next; hashtableInitIterator(&iter, ht); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { uint8_t *entry = next; num_returned++; TEST_ASSERT(entry >= entry_array && entry < entry_array + count); @@ -593,7 +593,7 @@ int test_safe_iterator(int argc, char **argv, int flags) { hashtableIterator iter; void *next; hashtableInitSafeIterator(&iter, ht); - while (hashtableNext(&iter, &next)) { + while (hashtableNext(&iter, &next, 0)) { uint8_t *entry = next; size_t index = entry - entry_counts; num_returned++; @@ -659,7 +659,7 @@ int test_compact_bucket_chain(int argc, char **argv, int flags) { hashtableIterator iter; hashtableInitSafeIterator(&iter, ht); void *entry; - while (hashtableNext(&iter, &entry)) { + while (hashtableNext(&iter, &entry, 0)) { /* As long as the iterator is still returning entries from the same * bucket chain, the bucket chain is not compacted, so it still has the * same number of buckets. */ diff --git a/src/unit/test_kvstore.c b/src/unit/test_kvstore.c index d4cc91d6d8..2298c5ec36 100644 --- a/src/unit/test_kvstore.c +++ b/src/unit/test_kvstore.c @@ -78,7 +78,7 @@ int test_kvstoreIteratorRemoveAllKeysNoDeleteEmptyHashtable(int argc, char **arg } kvs_it = kvstoreIteratorInit(kvs1); - while (kvstoreIteratorNext(kvs_it, &key)) { + while (kvstoreIteratorNext(kvs_it, &key, 0)) { curr_slot = kvstoreIteratorGetCurrentHashtableIndex(kvs_it); TEST_ASSERT(kvstoreHashtableDelete(kvs1, curr_slot, key)); } @@ -111,7 +111,7 @@ int test_kvstoreIteratorRemoveAllKeysDeleteEmptyHashtable(int argc, char **argv, } kvs_it = kvstoreIteratorInit(kvs2); - while (kvstoreIteratorNext(kvs_it, &key)) { + while (kvstoreIteratorNext(kvs_it, &key, 0)) { curr_slot = kvstoreIteratorGetCurrentHashtableIndex(kvs_it); TEST_ASSERT(kvstoreHashtableDelete(kvs2, curr_slot, key)); }