diff --git a/src/adlist.c b/src/adlist.c index 68a5d70f7c4..d7ca5fbcc89 100644 --- a/src/adlist.c +++ b/src/adlist.c @@ -196,22 +196,13 @@ void listUnlinkNode(list *list, listNode *node) { * call to listNext() will return the next element of the list. * * This function can't fail. */ -listIter *listGetIterator(list *list, int direction) +void listInitIterator(listIter *iter, list *list, int direction) { - listIter *iter; - - if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL; if (direction == AL_START_HEAD) iter->next = list->head; else iter->next = list->tail; iter->direction = direction; - return iter; -} - -/* Release the iterator memory */ -void listReleaseIterator(listIter *iter) { - zfree(iter); } /* Create an iterator in the list private iterator structure */ diff --git a/src/adlist.h b/src/adlist.h index 712c03fd71e..bb0eed1ea5f 100644 --- a/src/adlist.h +++ b/src/adlist.h @@ -58,9 +58,8 @@ list *listAddNodeHead(list *list, void *value); list *listAddNodeTail(list *list, void *value); list *listInsertNode(list *list, listNode *old_node, void *value, int after); void listDelNode(list *list, listNode *node); -listIter *listGetIterator(list *list, int direction); +void listInitIterator(listIter *iter, list *list, int direction); listNode *listNext(listIter *iter); -void listReleaseIterator(listIter *iter); list *listDup(list *orig); listNode *listSearchKey(list *list, void *key); listNode *listIndex(list *list, long index); diff --git a/src/aof.c b/src/aof.c index c56951dbcea..45b6ed52958 100644 --- a/src/aof.c +++ b/src/aof.c @@ -1920,9 +1920,10 @@ int rioWriteBulkObject(rio *r, robj *obj) { int rewriteListObject(rio *r, robj *key, robj *o) { long long count = 0, items = listTypeLength(o); - listTypeIterator *li = listTypeInitIterator(o,0,LIST_TAIL); + listTypeIterator li; listTypeEntry entry; - while (listTypeNext(li,&entry)) { + listTypeInitIterator(&li, o, 0, LIST_TAIL); + while (listTypeNext(&li, &entry)) { if (count == 0) { int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ? AOF_REWRITE_ITEMS_PER_CMD : items; @@ -1930,7 +1931,7 @@ int rewriteListObject(rio *r, robj *key, robj *o) { !rioWriteBulkString(r,"RPUSH",5) || !rioWriteBulkObject(r,key)) { - listTypeReleaseIterator(li); + listTypeResetIterator(&li); return 0; } } @@ -1941,19 +1942,19 @@ int rewriteListObject(rio *r, robj *key, robj *o) { vstr = listTypeGetValue(&entry,&vlen,&lval); if (vstr) { if (!rioWriteBulkString(r,(char*)vstr,vlen)) { - listTypeReleaseIterator(li); + listTypeResetIterator(&li); return 0; } } else { if (!rioWriteBulkLongLong(r,lval)) { - listTypeReleaseIterator(li); + listTypeResetIterator(&li); return 0; } } if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0; items--; } - listTypeReleaseIterator(li); + listTypeResetIterator(&li); return 1; } @@ -1961,11 +1962,12 @@ int rewriteListObject(rio *r, robj *key, robj *o) { * The function returns 0 on error, 1 on success. */ int rewriteSetObject(rio *r, robj *key, robj *o) { long long count = 0, items = setTypeSize(o); - setTypeIterator *si = setTypeInitIterator(o); + setTypeIterator si; char *str; size_t len; int64_t llval; - while (setTypeNext(si, &str, &len, &llval) != -1) { + setTypeInitIterator(&si, o); + while (setTypeNext(&si, &str, &len, &llval) != -1) { if (count == 0) { int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ? AOF_REWRITE_ITEMS_PER_CMD : items; @@ -1973,20 +1975,20 @@ int rewriteSetObject(rio *r, robj *key, robj *o) { !rioWriteBulkString(r,"SADD",4) || !rioWriteBulkObject(r,key)) { - setTypeReleaseIterator(si); + setTypeResetIterator(&si); return 0; } } size_t written = str ? rioWriteBulkString(r, str, len) : rioWriteBulkLongLong(r, llval); if (!written) { - setTypeReleaseIterator(si); + setTypeResetIterator(&si); return 0; } if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0; items--; } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); return 1; } @@ -2104,14 +2106,14 @@ static int rioWriteHashIteratorCursor(rio *r, hashTypeIterator *hi, int what) { int rewriteHashObject(rio *r, robj *key, robj *o) { int res = 0; /*fail*/ - hashTypeIterator *hi; + hashTypeIterator hi; long long count = 0, items = hashTypeLength(o, 0); int isHFE = hashTypeGetMinExpire(o, 0) != EB_EXPIRE_TIME_INVALID; - hi = hashTypeInitIterator(o); + hashTypeInitIterator(&hi, o); if (!isHFE) { - while (hashTypeNext(hi, 0) != C_ERR) { + while (hashTypeNext(&hi, 0) != C_ERR) { if (count == 0) { int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ? AOF_REWRITE_ITEMS_PER_CMD : items; @@ -2121,31 +2123,31 @@ int rewriteHashObject(rio *r, robj *key, robj *o) { goto reHashEnd; } - if (!rioWriteHashIteratorCursor(r, hi, OBJ_HASH_KEY) || - !rioWriteHashIteratorCursor(r, hi, OBJ_HASH_VALUE)) + if (!rioWriteHashIteratorCursor(r, &hi, OBJ_HASH_KEY) || + !rioWriteHashIteratorCursor(r, &hi, OBJ_HASH_VALUE)) goto reHashEnd; if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0; items--; } } else { - while (hashTypeNext(hi, 0) != C_ERR) { + while (hashTypeNext(&hi, 0) != C_ERR) { char hmsetCmd[] = "*4\r\n$5\r\nHMSET\r\n"; if ( (!rioWrite(r, hmsetCmd, sizeof(hmsetCmd) - 1)) || (!rioWriteBulkObject(r, key)) || - (!rioWriteHashIteratorCursor(r, hi, OBJ_HASH_KEY)) || - (!rioWriteHashIteratorCursor(r, hi, OBJ_HASH_VALUE)) ) + (!rioWriteHashIteratorCursor(r, &hi, OBJ_HASH_KEY)) || + (!rioWriteHashIteratorCursor(r, &hi, OBJ_HASH_VALUE)) ) goto reHashEnd; - if (hi->expire_time != EB_EXPIRE_TIME_INVALID) { + if (hi.expire_time != EB_EXPIRE_TIME_INVALID) { char cmd[] = "*6\r\n$10\r\nHPEXPIREAT\r\n"; if ( (!rioWrite(r, cmd, sizeof(cmd) - 1)) || (!rioWriteBulkObject(r, key)) || - (!rioWriteBulkLongLong(r, hi->expire_time)) || + (!rioWriteBulkLongLong(r, hi.expire_time)) || (!rioWriteBulkString(r, "FIELDS", 6)) || (!rioWriteBulkString(r, "1", 1)) || - (!rioWriteHashIteratorCursor(r, hi, OBJ_HASH_KEY)) ) + (!rioWriteHashIteratorCursor(r, &hi, OBJ_HASH_KEY)) ) goto reHashEnd; } } @@ -2154,7 +2156,7 @@ int rewriteHashObject(rio *r, robj *key, robj *o) { res = 1; /* success */ reHashEnd: - hashTypeReleaseIterator(hi); + hashTypeResetIterator(&hi); return res; } @@ -2428,7 +2430,7 @@ int rewriteAppendOnlyFileRio(rio *aof) { long key_count = 0; long long updated_time = 0; unsigned long long skipped = 0; - kvstoreIterator *kvs_it = NULL; + kvstoreIterator kvs_it; /* Record timestamp at the beginning of rewriting AOF. */ if (server.aof_timestamp_enabled) { @@ -2448,9 +2450,9 @@ int rewriteAppendOnlyFileRio(rio *aof) { if (rioWrite(aof,selectcmd,sizeof(selectcmd)-1) == 0) goto werr; if (rioWriteBulkLongLong(aof,j) == 0) goto werr; - kvs_it = kvstoreIteratorInit(db->keys); + kvstoreIteratorInit(&kvs_it, db->keys); /* Iterate this DB writing every entry */ - while((de = kvstoreIteratorNext(kvs_it)) != NULL) { + while((de = kvstoreIteratorNext(&kvs_it)) != NULL) { long long expiretime; size_t aof_bytes_before_key = aof->processed_bytes; @@ -2462,7 +2464,7 @@ int rewriteAppendOnlyFileRio(rio *aof) { /* Skip keys that are being trimmed */ if (server.cluster_enabled) { - int curr_slot = kvstoreIteratorGetCurrentDictIndex(kvs_it); + int curr_slot = kvstoreIteratorGetCurrentDictIndex(&kvs_it); if (isSlotInTrimJob(curr_slot)) { skipped++; continue; @@ -2473,7 +2475,7 @@ int rewriteAppendOnlyFileRio(rio *aof) { robj key; initStaticStringObject(key, kvobjGetKey(o)); - if (rewriteObject(aof, &key, o, j, expiretime) == C_ERR) goto werr; + if (rewriteObject(aof, &key, o, j, expiretime) == C_ERR) goto werr2; /* In fork child process, we can try to release memory back to the * OS and possibly avoid or decrease COW. We give the dismiss @@ -2496,13 +2498,14 @@ int rewriteAppendOnlyFileRio(rio *aof) { if (server.rdb_key_save_delay) debugDelay(server.rdb_key_save_delay); } - kvstoreIteratorRelease(kvs_it); + kvstoreIteratorReset(&kvs_it); } serverLog(LL_NOTICE, "AOF rewrite done, %ld keys saved, %llu keys skipped.", key_count, skipped); return C_OK; +werr2: + kvstoreIteratorReset(&kvs_it); werr: - if (kvs_it) kvstoreIteratorRelease(kvs_it); return C_ERR; } diff --git a/src/cluster.c b/src/cluster.c index 8a7bdade612..561ab8bdd80 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -1054,16 +1054,16 @@ void clusterCommand(client *c) { unsigned int keys_in_slot = countKeysInSlot(slot); unsigned int numkeys = maxkeys > keys_in_slot ? keys_in_slot : maxkeys; addReplyArrayLen(c,numkeys); - kvstoreDictIterator *kvs_di = NULL; + kvstoreDictIterator kvs_di; dictEntry *de = NULL; - kvs_di = kvstoreGetDictIterator(server.db->keys, slot); + kvstoreInitDictIterator(&kvs_di, server.db->keys, slot); for (unsigned int i = 0; i < numkeys; i++) { - de = kvstoreDictIteratorNext(kvs_di); + de = kvstoreDictIteratorNext(&kvs_di); serverAssert(de != NULL); sds sdskey = kvobjGetKey(dictGetKV(de)); addReplyBulkCBuffer(c, sdskey, sdslen(sdskey)); } - kvstoreReleaseDictIterator(kvs_di); + kvstoreResetDictIterator(&kvs_di); } else if ((!strcasecmp(c->argv[1]->ptr,"slaves") || !strcasecmp(c->argv[1]->ptr,"replicas")) && c->argc == 3) { /* CLUSTER SLAVES */ @@ -1670,10 +1670,10 @@ unsigned int clusterDelKeysInSlot(unsigned int hashslot, int by_command) { if (!kvstoreDictSize(server.db->keys, (int) hashslot)) return 0; - kvstoreDictIterator *kvs_di = NULL; + kvstoreDictIterator kvs_di; dictEntry *de = NULL; - kvs_di = kvstoreGetDictSafeIterator(server.db->keys, (int) hashslot); - while((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { + kvstoreInitDictSafeIterator(&kvs_di, server.db->keys, (int) hashslot); + while((de = kvstoreDictIteratorNext(&kvs_di)) != NULL) { enterExecutionUnit(1, 0); sds sdskey = kvobjGetKey(dictGetKV(de)); robj *key = createStringObject(sdskey, sdslen(sdskey)); @@ -1700,7 +1700,7 @@ unsigned int clusterDelKeysInSlot(unsigned int hashslot, int by_command) { j++; server.dirty++; } - kvstoreReleaseDictIterator(kvs_di); + kvstoreResetDictIterator(&kvs_di); return j; } diff --git a/src/cluster_asm.c b/src/cluster_asm.c index 172fc67eeac..bb65d4d95ed 100644 --- a/src/cluster_asm.c +++ b/src/cluster_asm.c @@ -2180,7 +2180,7 @@ int slotSnapshotSaveRio(int req, rio *rdb, int *error) { serverAssert(req & SLAVE_REQ_SLOTS_SNAPSHOT); dictEntry *de; - kvstoreDictIterator *kvs_di = NULL; + kvstoreDictIterator kvs_di; if (unlikely(asmDebugIsFailPointActive(ASM_MIGRATE_RDB_CHANNEL, ASM_SEND_BULK_AND_STREAM))) rioAbort(rdb); /* Simulate a failure */ @@ -2228,9 +2228,9 @@ int slotSnapshotSaveRio(int req, rio *rdb, int *error) { /* Iterate all keys in the slot range */ for (int k = sr->start; k <= sr->end; k++) { int send_slot_info = 0; - kvs_di = kvstoreGetDictIterator(server.db->keys, k); - while ((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { + kvstoreInitDictIterator(&kvs_di, server.db->keys, k); + while ((de = kvstoreDictIteratorNext(&kvs_di)) != NULL) { /* Send slot info before the first key in the slot */ if (!send_slot_info) { /* Format slot info */ @@ -2241,28 +2241,27 @@ int slotSnapshotSaveRio(int req, rio *rdb, int *error) { serverAssert(len > 0 && len < (int)sizeof(buf)); /* Send slot info */ - if (rioWriteBulkCount(rdb, '*', 5) == 0) goto werr; - if (rioWriteBulkString(rdb, "CLUSTER", 7) == 0) goto werr; - if (rioWriteBulkString(rdb, "SYNCSLOTS", 9) == 0) goto werr; - if (rioWriteBulkString(rdb, "CONF", 4) == 0) goto werr; - if (rioWriteBulkString(rdb, "SLOT-INFO", 9) == 0) goto werr; - if (rioWriteBulkString(rdb, buf, len) == 0) goto werr; + if (rioWriteBulkCount(rdb, '*', 5) == 0) goto werr2; + if (rioWriteBulkString(rdb, "CLUSTER", 7) == 0) goto werr2; + if (rioWriteBulkString(rdb, "SYNCSLOTS", 9) == 0) goto werr2; + if (rioWriteBulkString(rdb, "CONF", 4) == 0) goto werr2; + if (rioWriteBulkString(rdb, "SLOT-INFO", 9) == 0) goto werr2; + if (rioWriteBulkString(rdb, buf, len) == 0) goto werr2; send_slot_info = 1; } /* Save a key-value pair */ kvobj *o = dictGetKV(de); - if (slotSnapshotSaveKeyValuePair(rdb, o, db->id) == C_ERR) goto werr; + if (slotSnapshotSaveKeyValuePair(rdb, o, db->id) == C_ERR) goto werr2; /* Delay return if required (for testing) */ if (unlikely(server.rdb_key_save_delay)) { /* Send buffer to the destination ASAP. */ - if (rioFlush(rdb) == 0) goto werr; + if (rioFlush(rdb) == 0) goto werr2; debugDelay(server.rdb_key_save_delay); } } - kvstoreReleaseDictIterator(kvs_di); - kvs_di = NULL; + kvstoreResetDictIterator(&kvs_di); } } } @@ -2274,8 +2273,9 @@ int slotSnapshotSaveRio(int req, rio *rdb, int *error) { if (rioWriteBulkString(rdb, "SNAPSHOT-EOF", 12) == 0) goto werr; return C_OK; +werr2: + kvstoreResetDictIterator(&kvs_di); werr: - if (kvs_di) kvstoreReleaseDictIterator(kvs_di); if (error) *error = errno; return C_ERR; } @@ -3356,8 +3356,9 @@ void asmActiveTrimCycle(void) { while (!time_exceeded && slot != -1) { dictEntry *de; - kvstoreDictIterator *kvs_di = kvstoreGetDictSafeIterator(server.db[0].keys, slot); - while ((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { + kvstoreDictIterator kvs_di; + kvstoreInitDictSafeIterator(&kvs_di, server.db[0].keys, slot); + while ((de = kvstoreDictIteratorNext(&kvs_di)) != NULL) { kvobj *kv = dictGetKV(de); sds sdskey = kvobjGetKey(kv); @@ -3375,7 +3376,7 @@ void asmActiveTrimCycle(void) { break; } } - kvstoreReleaseDictIterator(kvs_di); + kvstoreResetDictIterator(&kvs_di); if (!time_exceeded) slot = slotRangeArrayNext(asmManager->active_trim_it); } diff --git a/src/db.c b/src/db.c index 3970432a38c..06e6c759fec 100644 --- a/src/db.c +++ b/src/db.c @@ -144,15 +144,16 @@ void dbgAssertKeysizesHist(redisDb *db) { /* Scan DB and build expected histogram by scanning all keys */ int64_t scanHist[MAX_KEYSIZES_TYPES][MAX_KEYSIZES_BINS] = {{0}}; dictEntry *de; - kvstoreIterator *kvs_it = kvstoreIteratorInit(db->keys); - while ((de = kvstoreIteratorNext(kvs_it)) != NULL) { + kvstoreIterator kvs_it; + kvstoreIteratorInit(&kvs_it, db->keys); + while ((de = kvstoreIteratorNext(&kvs_it)) != NULL) { kvobj *kv = dictGetKV(de); if (kv->type < OBJ_TYPE_BASIC_MAX) { int64_t len = getObjectLength(kv); scanHist[kv->type][(len == 0) ? 0 : log2ceil(len) + 1]++; } } - kvstoreIteratorRelease(kvs_it); + kvstoreIteratorReset(&kvs_it); for (int type = 0; type < OBJ_TYPE_BASIC_MAX; type++) { volatile int64_t *keysizesHist = kvstoreGetMetadata(db->keys)->keysizes_hist[type]; for (int i = 0; i < MAX_KEYSIZES_BINS; i++) { @@ -184,13 +185,14 @@ void dbgAssertAllocSizePerSlot(redisDb *db) { if (!server.memory_tracking_per_slot) return; size_t slot_sizes[CLUSTER_SLOTS] = {0}; dictEntry *de; - kvstoreIterator *kvs_it = kvstoreIteratorInit(db->keys); - while ((de = kvstoreIteratorNext(kvs_it)) != NULL) { - int slot = kvstoreIteratorGetCurrentDictIndex(kvs_it); + kvstoreIterator kvs_it; + kvstoreIteratorInit(&kvs_it, db->keys); + while ((de = kvstoreIteratorNext(&kvs_it)) != NULL) { + int slot = kvstoreIteratorGetCurrentDictIndex(&kvs_it); kvobj *kv = dictGetKV(de); slot_sizes[slot] += kvobjAllocSize(kv); } - kvstoreIteratorRelease(kvs_it); + kvstoreIteratorReset(&kvs_it); int num_slots = kvstoreNumDicts(db->keys); for (int slot = 0; slot < num_slots; slot++) { @@ -1424,21 +1426,24 @@ void keysCommand(client *c) { if (server.cluster_enabled && !allkeys) { pslot = patternHashSlot(pattern, plen); } - kvstoreDictIterator *kvs_di = NULL; - kvstoreIterator *kvs_it = NULL; - if (pslot != -1) { + int has_slot = pslot != -1; + union { + kvstoreDictIterator kvs_di; + kvstoreIterator kvs_it; + } it; + if (has_slot) { if (!kvstoreDictSize(c->db->keys, pslot) || accessKeysShouldSkipDictIndex(pslot)) { /* Requested slot is empty */ setDeferredArrayLen(c,replylen,0); return; } - kvs_di = kvstoreGetDictSafeIterator(c->db->keys, pslot); + kvstoreInitDictSafeIterator(&it.kvs_di, c->db->keys, pslot); } else { - kvs_it = kvstoreIteratorInit(c->db->keys); + kvstoreIteratorInit(&it.kvs_it, c->db->keys); } - while ((de = kvs_di ? kvstoreDictIteratorNext(kvs_di) : kvstoreIteratorNext(kvs_it)) != NULL) { - if (kvs_it && accessKeysShouldSkipDictIndex(kvstoreIteratorGetCurrentDictIndex(kvs_it))) { + while ((de = has_slot ? kvstoreDictIteratorNext(&it.kvs_di) : kvstoreIteratorNext(&it.kvs_it)) != NULL) { + if (!has_slot && accessKeysShouldSkipDictIndex(kvstoreIteratorGetCurrentDictIndex(&it.kvs_it))) { continue; } @@ -1454,10 +1459,10 @@ void keysCommand(client *c) { if (c->flags & CLIENT_CLOSE_ASAP) break; } - if (kvs_di) - kvstoreReleaseDictIterator(kvs_di); - if (kvs_it) - kvstoreIteratorRelease(kvs_it); + if (!has_slot) + kvstoreResetDictIterator(&it.kvs_di); + else + kvstoreIteratorReset(&it.kvs_it); setDeferredArrayLen(c,replylen,numkeys); } @@ -1796,9 +1801,10 @@ void scanGenericCommand(client *c, robj *o, unsigned long long cursor) { addReplyArrayLen(c, array_reply_len); } - setTypeIterator *si = setTypeInitIterator(o); + setTypeIterator si; unsigned long cur_length = 0; - while (setTypeNext(si, &str, &len, &llele) != -1) { + setTypeInitIterator(&si, o); + while (setTypeNext(&si, &str, &len, &llele) != -1) { if (str == NULL) { len = ll2string(buf, sizeof(buf), llele); } @@ -1809,7 +1815,7 @@ void scanGenericCommand(client *c, robj *o, unsigned long long cursor) { addReplyBulkCBuffer(c, key, len); cur_length++; } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); if (use_pattern) setDeferredArrayLen(c,replylen,cur_length); else diff --git a/src/debug.c b/src/debug.c index c1f9ea1869c..cc4a7e45c78 100644 --- a/src/debug.c +++ b/src/debug.c @@ -141,22 +141,24 @@ void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o) if (o->type == OBJ_STRING) { mixStringObjectDigest(digest,o); } else if (o->type == OBJ_LIST) { - listTypeIterator *li = listTypeInitIterator(o,0,LIST_TAIL); + listTypeIterator li; listTypeEntry entry; - while(listTypeNext(li,&entry)) { + listTypeInitIterator(&li, o, 0, LIST_TAIL); + while(listTypeNext(&li, &entry)) { robj *eleobj = listTypeGet(&entry); mixStringObjectDigest(digest,eleobj); decrRefCount(eleobj); } - listTypeReleaseIterator(li); + listTypeResetIterator(&li); } else if (o->type == OBJ_SET) { - setTypeIterator *si = setTypeInitIterator(o); + setTypeIterator si; sds sdsele; - while((sdsele = setTypeNextObject(si)) != NULL) { + setTypeInitIterator(&si, o); + while((sdsele = setTypeNextObject(&si)) != NULL) { xorDigest(digest,sdsele,sdslen(sdsele)); sdsfree(sdsele); } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); } else if (o->type == OBJ_ZSET) { unsigned char eledigest[20]; @@ -211,26 +213,27 @@ void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o) serverPanic("Unknown sorted set encoding"); } } else if (o->type == OBJ_HASH) { - hashTypeIterator *hi = hashTypeInitIterator(o); - while (hashTypeNext(hi, 0) != C_ERR) { + hashTypeIterator hi; + hashTypeInitIterator(&hi, o); + while (hashTypeNext(&hi, 0) != C_ERR) { unsigned char eledigest[20]; sds sdsele; /* field */ memset(eledigest,0,20); - sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY); + sdsele = hashTypeCurrentObjectNewSds(&hi,OBJ_HASH_KEY); mixDigest(eledigest,sdsele,sdslen(sdsele)); sdsfree(sdsele); /* val */ - sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE); + sdsele = hashTypeCurrentObjectNewSds(&hi,OBJ_HASH_VALUE); mixDigest(eledigest,sdsele,sdslen(sdsele)); sdsfree(sdsele); /* hash-field expiration (HFE) */ - if (hi->expire_time != EB_EXPIRE_TIME_INVALID) + if (hi.expire_time != EB_EXPIRE_TIME_INVALID) xorDigest(eledigest,"!!hexpire!!",11); xorDigest(digest,eledigest,20); } - hashTypeReleaseIterator(hi); + hashTypeResetIterator(&hi); } else if (o->type == OBJ_STREAM) { streamIterator si; streamIteratorStart(&si,o->ptr,NULL,NULL,0); @@ -286,14 +289,15 @@ void computeDatasetDigest(unsigned char *final) { redisDb *db = server.db+j; if (kvstoreSize(db->keys) == 0) continue; - kvstoreIterator *kvs_it = kvstoreIteratorInit(db->keys); /* hash the DB id, so the same dataset moved in a different DB will lead to a different digest */ aux = htonl(j); mixDigest(final,&aux,sizeof(aux)); /* Iterate this DB writing every entry */ - while((de = kvstoreIteratorNext(kvs_it)) != NULL) { + kvstoreIterator kvs_it; + kvstoreIteratorInit(&kvs_it, db->keys); + while((de = kvstoreIteratorNext(&kvs_it)) != NULL) { robj *keyobj; memset(digest,0,20); /* This key-val digest */ @@ -309,7 +313,7 @@ void computeDatasetDigest(unsigned char *final) { xorDigest(final,digest,20); decrRefCount(keyobj); } - kvstoreIteratorRelease(kvs_it); + kvstoreIteratorReset(&kvs_it); } } diff --git a/src/kvstore.c b/src/kvstore.c index c6878bc0b30..a0c988d6d96 100644 --- a/src/kvstore.c +++ b/src/kvstore.c @@ -44,21 +44,6 @@ struct _kvstore { void *metadata[]; /* conditionally allocated based on "flags" */ }; -/* Structure for kvstore iterator that allows iterating across multiple dicts. */ -struct _kvstoreIterator { - kvstore *kvs; - long long didx; - long long next_didx; - dictIterator di; -}; - -/* Structure for kvstore dict iterator that allows iterating the corresponding dict. */ -struct _kvstoreDictIterator { - kvstore *kvs; - long long didx; - dictIterator di; -}; - /* Basic metadata allocated per dict */ typedef struct { listNode *rehashing_node; /* list node in rehashing list */ @@ -514,8 +499,10 @@ void kvstoreGetStats(kvstore *kvs, char *buf, size_t bufsize, int full) { dictStats *mainHtStats = NULL; dictStats *rehashHtStats = NULL; dict *d; - kvstoreIterator *kvs_it = kvstoreIteratorInit(kvs); - while ((d = kvstoreIteratorNextDict(kvs_it))) { + kvstoreIterator kvs_it; + + kvstoreIteratorInit(&kvs_it, kvs); + while ((d = kvstoreIteratorNextDict(&kvs_it))) { dictStats *stats = dictGetStatsHt(d, 0, full); if (!mainHtStats) { mainHtStats = stats; @@ -533,7 +520,7 @@ void kvstoreGetStats(kvstore *kvs, char *buf, size_t bufsize, int full) { } } } - kvstoreIteratorRelease(kvs_it); + kvstoreIteratorReset(&kvs_it); if (mainHtStats && bufsize > 0) { l = dictGetStatsMsg(buf, bufsize, mainHtStats, full); @@ -638,26 +625,22 @@ void kvstoreMoveDict(kvstore *kvs, kvstore *dst, int didx) { /* Returns kvstore iterator that can be used to iterate through sub-dictionaries. * - * The caller should free the resulting kvs_it with kvstoreIteratorRelease. */ -kvstoreIterator *kvstoreIteratorInit(kvstore *kvs) { - kvstoreIterator *kvs_it = zmalloc(sizeof(*kvs_it)); + * The caller should reset kvs_it with kvstoreIteratorReset. */ +void kvstoreIteratorInit(kvstoreIterator *kvs_it, kvstore *kvs) { kvs_it->kvs = kvs; kvs_it->didx = -1; kvs_it->next_didx = kvstoreGetFirstNonEmptyDictIndex(kvs_it->kvs); /* Finds first non-empty dict index. */ dictInitSafeIterator(&kvs_it->di, NULL); - return kvs_it; } /* Free the kvs_it returned by kvstoreIteratorInit. */ -void kvstoreIteratorRelease(kvstoreIterator *kvs_it) { +void kvstoreIteratorReset(kvstoreIterator *kvs_it) { dictIterator *iter = &kvs_it->di; dictResetIterator(iter); /* In the safe iterator context, we may delete entries. */ freeDictIfNeeded(kvs_it->kvs, kvs_it->didx); - zfree(kvs_it); } - /* Returns next dictionary from the iterator, or NULL if iteration is complete. * * - Takes care to reset the iter of the previous dict before moved to the next dict. @@ -774,26 +757,22 @@ size_t kvstoreDictAllocSize(kvstore *kvs, int didx) return dictMeta->alloc_size; } -kvstoreDictIterator *kvstoreGetDictIterator(kvstore *kvs, int didx) +void kvstoreInitDictIterator(kvstoreDictIterator *kvs_di, kvstore *kvs, int didx) { - kvstoreDictIterator *kvs_di = zmalloc(sizeof(*kvs_di)); kvs_di->kvs = kvs; kvs_di->didx = didx; dictInitIterator(&kvs_di->di, kvstoreGetDict(kvs, didx)); - return kvs_di; } -kvstoreDictIterator *kvstoreGetDictSafeIterator(kvstore *kvs, int didx) +void kvstoreInitDictSafeIterator(kvstoreDictIterator *kvs_di, kvstore *kvs, int didx) { - kvstoreDictIterator *kvs_di = zmalloc(sizeof(*kvs_di)); kvs_di->kvs = kvs; kvs_di->didx = didx; dictInitSafeIterator(&kvs_di->di, kvstoreGetDict(kvs, didx)); - return kvs_di; } /* Free the kvs_di returned by kvstoreGetDictIterator and kvstoreGetDictSafeIterator. */ -void kvstoreReleaseDictIterator(kvstoreDictIterator *kvs_di) +void kvstoreResetDictIterator(kvstoreDictIterator *kvs_di) { /* The dict may be deleted during the iteration process, so here need to check for NULL. */ if (kvstoreGetDict(kvs_di->kvs, kvs_di->didx)) { @@ -801,8 +780,6 @@ void kvstoreReleaseDictIterator(kvstoreDictIterator *kvs_di) /* In the safe iterator context, we may delete entries. */ freeDictIfNeeded(kvs_di->kvs, kvs_di->didx); } - - zfree(kvs_di); } /* Get the next element of the dict through kvstoreDictIterator and dictNext. */ @@ -1081,8 +1058,8 @@ int kvstoreTest(int argc, char **argv, int flags) { int i; void *key; dictEntry *de; - kvstoreIterator *kvs_it; - kvstoreDictIterator *kvs_di; + kvstoreIterator kvs_it; + kvstoreDictIterator kvs_di; /* Test also dictType with no_value=1 */ dictType KvstoreDictNovalTestType = KvstoreDictTestType; @@ -1107,13 +1084,13 @@ int kvstoreTest(int argc, char **argv, int flags) { } TEST("kvstoreIterator case 1: removing all keys does not delete the empty dict") { - kvs_it = kvstoreIteratorInit(kvs1); - while((de = kvstoreIteratorNext(kvs_it)) != NULL) { - curr_slot = kvstoreIteratorGetCurrentDictIndex(kvs_it); + kvstoreIteratorInit(&kvs_it, kvs1); + while((de = kvstoreIteratorNext(&kvs_it)) != NULL) { + curr_slot = kvstoreIteratorGetCurrentDictIndex(&kvs_it); key = dictGetKey(de); assert(kvstoreDictDelete(kvs1, curr_slot, key) == DICT_OK); } - kvstoreIteratorRelease(kvs_it); + kvstoreIteratorReset(&kvs_it); dict *d = kvstoreGetDict(kvs1, didx); assert(d != NULL); @@ -1122,13 +1099,13 @@ int kvstoreTest(int argc, char **argv, int flags) { } TEST("kvstoreIterator case 2: removing all keys will delete the empty dict") { - kvs_it = kvstoreIteratorInit(kvs2); - while((de = kvstoreIteratorNext(kvs_it)) != NULL) { - curr_slot = kvstoreIteratorGetCurrentDictIndex(kvs_it); + kvstoreIteratorInit(&kvs_it, kvs2); + while((de = kvstoreIteratorNext(&kvs_it)) != NULL) { + curr_slot = kvstoreIteratorGetCurrentDictIndex(&kvs_it); key = dictGetKey(de); assert(kvstoreDictDelete(kvs2, curr_slot, key) == DICT_OK); } - kvstoreIteratorRelease(kvs_it); + kvstoreIteratorReset(&kvs_it); /* Make sure the dict was removed from the rehashing list. */ while (kvstoreIncrementallyRehash(kvs2, 1000)) {} @@ -1153,12 +1130,12 @@ int kvstoreTest(int argc, char **argv, int flags) { } TEST("kvstoreDictIterator case 1: removing all keys does not delete the empty dict") { - kvs_di = kvstoreGetDictSafeIterator(kvs1, didx); - while((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { + kvstoreInitDictSafeIterator(&kvs_di, kvs1, didx); + while((de = kvstoreDictIteratorNext(&kvs_di)) != NULL) { key = dictGetKey(de); assert(kvstoreDictDelete(kvs1, didx, key) == DICT_OK); } - kvstoreReleaseDictIterator(kvs_di); + kvstoreResetDictIterator(&kvs_di); dict *d = kvstoreGetDict(kvs1, didx); assert(d != NULL); @@ -1167,12 +1144,12 @@ int kvstoreTest(int argc, char **argv, int flags) { } TEST("kvstoreDictIterator case 2: removing all keys will delete the empty dict") { - kvs_di = kvstoreGetDictSafeIterator(kvs2, didx); - while((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { + kvstoreInitDictSafeIterator(&kvs_di, kvs2, didx); + while((de = kvstoreDictIteratorNext(&kvs_di)) != NULL) { key = dictGetKey(de); assert(kvstoreDictDelete(kvs2, didx, key) == DICT_OK); } - kvstoreReleaseDictIterator(kvs_di); + kvstoreResetDictIterator(&kvs_di); dict *d = kvstoreGetDict(kvs2, didx); assert(d == NULL); @@ -1207,14 +1184,14 @@ int kvstoreTest(int argc, char **argv, int flags) { /* Step by step, clear all dictionaries and ensure non-empty dict count is updated */ for (int idx = 0; idx < 4; idx++) { - kvs_di = kvstoreGetDictSafeIterator(kvs, idx); - while((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { + kvstoreInitDictSafeIterator(&kvs_di, kvs, idx); + while((de = kvstoreDictIteratorNext(&kvs_di)) != NULL) { key = dictGetKey(de); assert(kvstoreDictDelete(kvs, idx, key) == DICT_OK); /* When the dictionary is emptied, the number of non-empty dictionaries is reduced by 1. */ if (kvstoreDictSize(kvs, idx) == 0) assert(kvstoreNumNonEmptyDicts(kvs) == 3 - idx); } - kvstoreReleaseDictIterator(kvs_di); + kvstoreResetDictIterator(&kvs_di); } kvstoreRelease(kvs); } diff --git a/src/kvstore.h b/src/kvstore.h index d685fab1f11..a5ba3593d86 100644 --- a/src/kvstore.h +++ b/src/kvstore.h @@ -46,8 +46,21 @@ typedef struct { } kvstoreDictMetadata; typedef struct _kvstore kvstore; -typedef struct _kvstoreIterator kvstoreIterator; -typedef struct _kvstoreDictIterator kvstoreDictIterator; + +/* Structure for kvstore iterator that allows iterating across multiple dicts. */ +typedef struct _kvstoreIterator { + kvstore *kvs; + long long didx; + long long next_didx; + dictIterator di; +} kvstoreIterator; + +/* Structure for kvstore dict iterator that allows iterating the corresponding dict. */ +typedef struct _kvstoreDictIterator { + kvstore *kvs; + long long didx; + dictIterator di; +} kvstoreDictIterator; typedef int (kvstoreScanShouldSkipDict)(dict *d, int didx); typedef int (kvstoreExpandShouldSkipDictIndex)(int didx); @@ -80,8 +93,8 @@ int kvstoreNumDicts(kvstore *kvs); void kvstoreMoveDict(kvstore *kvs, kvstore *dst, int didx); /* kvstore iterator specific functions */ -kvstoreIterator *kvstoreIteratorInit(kvstore *kvs); -void kvstoreIteratorRelease(kvstoreIterator *kvs_it); +void kvstoreIteratorInit(kvstoreIterator *kvs_it, kvstore *kvs); +void kvstoreIteratorReset(kvstoreIterator *kvs_it); dict *kvstoreIteratorNextDict(kvstoreIterator *kvs_it); int kvstoreIteratorGetCurrentDictIndex(kvstoreIterator *kvs_it); dictEntry *kvstoreIteratorNext(kvstoreIterator *kvs_it); @@ -96,9 +109,9 @@ unsigned long kvstoreDictRehashingCount(kvstore *kvs); /* Specific dict access by dict-index */ unsigned long kvstoreDictSize(kvstore *kvs, int didx); size_t kvstoreDictAllocSize(kvstore *kvs, int didx); -kvstoreDictIterator *kvstoreGetDictIterator(kvstore *kvs, int didx); -kvstoreDictIterator *kvstoreGetDictSafeIterator(kvstore *kvs, int didx); -void kvstoreReleaseDictIterator(kvstoreDictIterator *kvs_id); +void kvstoreInitDictIterator(kvstoreDictIterator *kvs_di, kvstore *kvs, int didx); +void kvstoreInitDictSafeIterator(kvstoreDictIterator *kvs_di, kvstore *kvs, int didx); +void kvstoreResetDictIterator(kvstoreDictIterator *kvs_di); dictEntry *kvstoreDictIteratorNext(kvstoreDictIterator *kvs_di); dictEntry *kvstoreDictGetRandomKey(kvstore *kvs, int didx); dictEntry *kvstoreDictGetFairRandomKey(kvstore *kvs, int didx); diff --git a/src/module.c b/src/module.c index 9371b415064..6b6f9a3c382 100644 --- a/src/module.c +++ b/src/module.c @@ -736,7 +736,10 @@ int moduleCreateEmptyKey(RedisModuleKey *key, int type) { static void moduleFreeKeyIterator(RedisModuleKey *key) { serverAssert(key->iter != NULL); switch (key->kv->type) { - case OBJ_LIST: listTypeReleaseIterator(key->iter); break; + case OBJ_LIST: + listTypeResetIterator(key->iter); + zfree(key->iter); + break; case OBJ_STREAM: streamIteratorStop(key->iter); zfree(key->iter); @@ -4530,8 +4533,8 @@ int moduleListIteratorSeek(RedisModuleKey *key, long index, int mode) { if (key->iter == NULL) { /* No existing iterator. Create one. */ - key->iter = listTypeInitIterator(key->kv, index, LIST_TAIL); - serverAssert(key->iter != NULL); + key->iter = zmalloc(sizeof(listTypeIterator)); + listTypeInitIterator(key->iter, key->kv, index, LIST_HEAD); serverAssert(listTypeNext(key->iter, &key->u.list.entry)); key->u.list.index = index; return 1; @@ -11645,14 +11648,15 @@ int RM_ScanKey(RedisModuleKey *key, RedisModuleScanCursor *cursor, RedisModuleSc ret = 0; } } else if (kv->type == OBJ_SET) { - setTypeIterator *si = setTypeInitIterator(kv); + setTypeIterator si; sds sdsele; - while ((sdsele = setTypeNextObject(si)) != NULL) { + setTypeInitIterator(&si, kv); + while ((sdsele = setTypeNextObject(&si)) != NULL) { robj *field = createObject(OBJ_STRING, sdsele); fn(key, field, NULL, privdata); decrRefCount(field); } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); cursor->cursor = 1; cursor->done = 1; ret = 0; diff --git a/src/pubsub.c b/src/pubsub.c index 9d61e093b60..6a4c4011ae0 100644 --- a/src/pubsub.c +++ b/src/pubsub.c @@ -319,9 +319,10 @@ void pubsubShardUnsubscribeAllChannelsInSlot(unsigned int slot) { if (!kvstoreDictSize(server.pubsubshard_channels, slot)) return; - kvstoreDictIterator *kvs_di = kvstoreGetDictSafeIterator(server.pubsubshard_channels, slot); dictEntry *de; - while ((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { + kvstoreDictIterator kvs_di; + kvstoreInitDictSafeIterator(&kvs_di, server.pubsubshard_channels, slot); + while ((de = kvstoreDictIteratorNext(&kvs_di)) != NULL) { robj *channel = dictGetKey(de); dict *clients = dictGetVal(de); /* For each client subscribed to the channel, unsubscribe it. */ @@ -343,7 +344,7 @@ void pubsubShardUnsubscribeAllChannelsInSlot(unsigned int slot) { dictResetIterator(&iter); kvstoreDictDelete(server.pubsubshard_channels, slot, channel); } - kvstoreReleaseDictIterator(kvs_di); + kvstoreResetDictIterator(&kvs_di); } /* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the client was already subscribed to that pattern. */ @@ -694,9 +695,10 @@ void channelList(client *c, sds pat, kvstore *pubsub_channels) { for (unsigned int i = 0; i < slot_cnt; i++) { if (!kvstoreDictSize(pubsub_channels, i)) continue; - kvstoreDictIterator *kvs_di = kvstoreGetDictIterator(pubsub_channels, i); dictEntry *de; - while((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { + kvstoreDictIterator kvs_di; + kvstoreInitDictIterator(&kvs_di, pubsub_channels, i); + while((de = kvstoreDictIteratorNext(&kvs_di)) != NULL) { robj *cobj = dictGetKey(de); sds channel = cobj->ptr; @@ -707,7 +709,7 @@ void channelList(client *c, sds pat, kvstore *pubsub_channels) { mblen++; } } - kvstoreReleaseDictIterator(kvs_di); + kvstoreResetDictIterator(&kvs_di); } setDeferredArrayLen(c,replylen,mblen); } diff --git a/src/rdb.c b/src/rdb.c index 5f6d8e57d73..0d1481624cb 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -1393,7 +1393,7 @@ ssize_t rdbSaveDb(rio *rdb, int dbid, int rdbflags, long *key_counter, unsigned ssize_t written = 0; ssize_t res; size_t oldsize = 0; - kvstoreIterator *kvs_it = NULL; + kvstoreIterator kvs_it; static long long info_updated_time = 0; char *pname = (rdbflags & RDBFLAGS_AOF_PREAMBLE) ? "AOF rewrite" : "RDB"; @@ -1416,20 +1416,20 @@ ssize_t rdbSaveDb(rio *rdb, int dbid, int rdbflags, long *key_counter, unsigned if ((res = rdbSaveLen(rdb,expires_size)) < 0) goto werr; written += res; - kvs_it = kvstoreIteratorInit(db->keys); + kvstoreIteratorInit(&kvs_it, db->keys); int last_slot = -1; /* Iterate this DB writing every entry */ - while ((de = kvstoreIteratorNext(kvs_it)) != NULL) { - int curr_slot = kvstoreIteratorGetCurrentDictIndex(kvs_it); + while ((de = kvstoreIteratorNext(&kvs_it)) != NULL) { + int curr_slot = kvstoreIteratorGetCurrentDictIndex(&kvs_it); /* Save slot info. */ if (server.cluster_enabled && curr_slot != last_slot) { - if ((res = rdbSaveType(rdb, RDB_OPCODE_SLOT_INFO)) < 0) goto werr; + if ((res = rdbSaveType(rdb, RDB_OPCODE_SLOT_INFO)) < 0) goto werr2; written += res; - if ((res = rdbSaveLen(rdb, curr_slot)) < 0) goto werr; + if ((res = rdbSaveLen(rdb, curr_slot)) < 0) goto werr2; written += res; - if ((res = rdbSaveLen(rdb, kvstoreDictSize(db->keys, curr_slot))) < 0) goto werr; + if ((res = rdbSaveLen(rdb, kvstoreDictSize(db->keys, curr_slot))) < 0) goto werr2; written += res; - if ((res = rdbSaveLen(rdb, kvstoreDictSize(db->expires, curr_slot))) < 0) goto werr; + if ((res = rdbSaveLen(rdb, kvstoreDictSize(db->expires, curr_slot))) < 0) goto werr2; written += res; last_slot = curr_slot; } @@ -1451,7 +1451,7 @@ ssize_t rdbSaveDb(rio *rdb, int dbid, int rdbflags, long *key_counter, unsigned res = rdbSaveKeyValuePair(rdb, &key, kv, expire, dbid); if (server.memory_tracking_per_slot) updateSlotAllocSize(db, curr_slot, oldsize, kvobjAllocSize(kv)); - if (res < 0) goto werr; + if (res < 0) goto werr2; written += res; /* In fork child process, we can try to release memory back to the @@ -1471,11 +1471,12 @@ ssize_t rdbSaveDb(rio *rdb, int dbid, int rdbflags, long *key_counter, unsigned } } } - kvstoreIteratorRelease(kvs_it); + kvstoreIteratorReset(&kvs_it); return written; +werr2: + kvstoreIteratorReset(&kvs_it); werr: - if (kvs_it) kvstoreIteratorRelease(kvs_it); return -1; } diff --git a/src/server.h b/src/server.h index 1e537e2a7ef..b5d8e53fbc2 100644 --- a/src/server.h +++ b/src/server.h @@ -2770,7 +2770,7 @@ typedef struct { robj *subject; int encoding; int ii; /* intset iterator */ - dictIterator *di; + dictIterator di; unsigned char *lpi; /* listpack iterator */ } setTypeIterator; @@ -2785,7 +2785,7 @@ typedef struct { unsigned char *fptr, *vptr, *tptr; uint64_t expire_time; /* Only used with OBJ_ENCODING_LISTPACK_EX */ - dictIterator *di; + dictIterator di; dictEntry *de; } hashTypeIterator; @@ -3103,8 +3103,8 @@ void listTypePush(robj *subject, robj *value, int where); robj *listTypePop(robj *subject, int where); unsigned long listTypeLength(const robj *subject); size_t listTypeAllocSize(const robj *o); -listTypeIterator *listTypeInitIterator(robj *subject, long index, unsigned char direction); -void listTypeReleaseIterator(listTypeIterator *li); +void listTypeInitIterator(listTypeIterator *li, robj *subject, long index, unsigned char direction); +void listTypeResetIterator(listTypeIterator *li); void listTypeSetIteratorDirection(listTypeIterator *li, listTypeEntry *entry, unsigned char direction); int listTypeNext(listTypeIterator *li, listTypeEntry *entry); robj *listTypeGet(listTypeEntry *entry); @@ -3558,8 +3558,8 @@ int setTypeRemove(robj *subject, sds value); int setTypeRemoveAux(robj *set, char *str, size_t len, int64_t llval, int str_is_sds); int setTypeIsMember(robj *subject, sds value); int setTypeIsMemberAux(robj *set, char *str, size_t len, int64_t llval, int str_is_sds); -setTypeIterator *setTypeInitIterator(robj *subject); -void setTypeReleaseIterator(setTypeIterator *si); +void setTypeInitIterator(setTypeIterator *si, robj *subject); +void setTypeResetIterator(setTypeIterator *si); int setTypeNext(setTypeIterator *si, char **str, size_t *len, int64_t *llele); sds setTypeNextObject(setTypeIterator *si); int setTypeRandomElement(robj *setobj, char **str, size_t *len, int64_t *llele); @@ -3626,8 +3626,8 @@ int hashTypeExists(redisDb *db, kvobj *kv, sds field, int hfeFlags, int *isHashD int hashTypeDelete(robj *o, void *key, int isSdsField); unsigned long hashTypeLength(const robj *o, int subtractExpiredFields); size_t hashTypeAllocSize(const robj *o); -hashTypeIterator *hashTypeInitIterator(robj *subject); -void hashTypeReleaseIterator(hashTypeIterator *hi); +void hashTypeInitIterator(hashTypeIterator *hi, robj *subject); +void hashTypeResetIterator(hashTypeIterator *hi); int hashTypeNext(hashTypeIterator *hi, int skipExpiredFields); void hashTypeCurrentFromListpack(hashTypeIterator *hi, int what, unsigned char **vstr, diff --git a/src/sort.c b/src/sort.c index 6f55085d500..774dcd7833f 100644 --- a/src/sort.c +++ b/src/sort.c @@ -395,45 +395,47 @@ void sortCommandGeneric(client *c, int readonly) { * Note that in this case we also handle LIMIT here in a direct * way, just getting the required range, as an optimization. */ if (end >= start) { - listTypeIterator *li; + listTypeIterator li; listTypeEntry entry; - li = listTypeInitIterator(sortval, + listTypeInitIterator(&li, sortval, desc ? (long)(listTypeLength(sortval) - start - 1) : start, desc ? LIST_HEAD : LIST_TAIL); - while(j < vectorlen && listTypeNext(li,&entry)) { + while(j < vectorlen && listTypeNext(&li, &entry)) { vector[j].obj = listTypeGet(&entry); vector[j].u.score = 0; vector[j].u.cmpobj = NULL; j++; } - listTypeReleaseIterator(li); + listTypeResetIterator(&li); /* Fix start/end: output code is not aware of this optimization. */ end -= start; start = 0; } } else if (sortval->type == OBJ_LIST) { - listTypeIterator *li = listTypeInitIterator(sortval,0,LIST_TAIL); + listTypeIterator li; listTypeEntry entry; - while(listTypeNext(li,&entry)) { + listTypeInitIterator(&li, sortval, 0, LIST_TAIL); + while(listTypeNext(&li, &entry)) { vector[j].obj = listTypeGet(&entry); vector[j].u.score = 0; vector[j].u.cmpobj = NULL; j++; } - listTypeReleaseIterator(li); + listTypeResetIterator(&li); } else if (sortval->type == OBJ_SET) { if (server.memory_tracking_per_slot) oldsize = setTypeAllocSize(sortval); - setTypeIterator *si = setTypeInitIterator(sortval); + setTypeIterator si; sds sdsele; - while((sdsele = setTypeNextObject(si)) != NULL) { + setTypeInitIterator(&si, sortval); + while((sdsele = setTypeNextObject(&si)) != NULL) { vector[j].obj = createObject(OBJ_STRING,sdsele); vector[j].u.score = 0; vector[j].u.cmpobj = NULL; j++; } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); if (server.memory_tracking_per_slot) updateSlotAllocSize(c->db, getKeySlot(c->argv[1]->ptr), oldsize, setTypeAllocSize(sortval)); } else if (sortval->type == OBJ_ZSET && dontsort) { diff --git a/src/t_hash.c b/src/t_hash.c index bed6f482f6c..ac76410978f 100644 --- a/src/t_hash.c +++ b/src/t_hash.c @@ -1357,8 +1357,7 @@ size_t hashTypeAllocSize(const robj *o) { return size; } -hashTypeIterator *hashTypeInitIterator(robj *subject) { - hashTypeIterator *hi = zmalloc(sizeof(hashTypeIterator)); +void hashTypeInitIterator(hashTypeIterator *hi, robj *subject) { hi->subject = subject; hi->encoding = subject->encoding; @@ -1370,17 +1369,15 @@ hashTypeIterator *hashTypeInitIterator(robj *subject) { hi->tptr = NULL; hi->expire_time = EB_EXPIRE_TIME_INVALID; } else if (hi->encoding == OBJ_ENCODING_HT) { - hi->di = dictGetIterator(subject->ptr); + dictInitIterator(&hi->di, subject->ptr); } else { serverPanic("Unknown hash encoding"); } - return hi; } -void hashTypeReleaseIterator(hashTypeIterator *hi) { - if (hi->encoding == OBJ_ENCODING_HT) - dictReleaseIterator(hi->di); - zfree(hi); +void hashTypeResetIterator(hashTypeIterator *hi) { + if (hi->encoding == OBJ_ENCODING_LISTPACK) + dictResetIterator(&hi->di); } /* Move to the next entry in the hash. Return C_OK when the next entry @@ -1459,7 +1456,7 @@ int hashTypeNext(hashTypeIterator *hi, int skipExpiredFields) { hi->expire_time = (expire_time != HASH_LP_NO_TTL) ? (uint64_t) expire_time : EB_EXPIRE_TIME_INVALID; } else if (hi->encoding == OBJ_ENCODING_HT) { - while ((hi->de = dictNext(hi->di)) != NULL) { + while ((hi->de = dictNext(&hi->di)) != NULL) { hi->expire_time = hfieldGetExpireTime(dictGetKey(hi->de)); /* this condition still valid if expire_time equals EB_EXPIRE_TIME_INVALID */ if (skipExpiredFields && ((mstime_t)hi->expire_time < commandTimeSnapshot())) @@ -1621,34 +1618,34 @@ void hashTypeConvertListpack(robj *o, int enc) { o->encoding = OBJ_ENCODING_LISTPACK_EX; o->ptr = lpt; } else if (enc == OBJ_ENCODING_HT) { - hashTypeIterator *hi; + hashTypeIterator hi; dict *dict; int ret; - hi = hashTypeInitIterator(o); + hashTypeInitIterator(&hi, o); dict = dictCreate(&mstrHashDictType); /* Presize the dict to avoid rehashing */ dictExpand(dict,hashTypeLength(o, 0)); size_t usable, *alloc_size = htGetMetadataSize(dict); - while (hashTypeNext(hi, 0) != C_ERR) { + while (hashTypeNext(&hi, 0) != C_ERR) { - hfield key = hashTypeCurrentObjectNewHfield(hi, &usable); - sds value = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE); + hfield key = hashTypeCurrentObjectNewHfield(&hi, &usable); + sds value = hashTypeCurrentObjectNewSds(&hi,OBJ_HASH_VALUE); dictUseStoredKeyApi(dict, 1); ret = dictAdd(dict, key, value); dictUseStoredKeyApi(dict, 0); if (ret != DICT_OK) { hfieldFree(key, NULL); sdsfree(value); /* Needed for gcc ASAN */ - hashTypeReleaseIterator(hi); /* Needed for gcc ASAN */ + hashTypeResetIterator(&hi); /* Needed for gcc ASAN */ serverLogHexDump(LL_WARNING,"listpack with dup elements dump", o->ptr,lpBytes(o->ptr)); serverPanic("Listpack corruption detected"); } *alloc_size += usable + sdsAllocSize(value); } - hashTypeReleaseIterator(hi); + hashTypeResetIterator(&hi); zfree(o->ptr); o->encoding = OBJ_ENCODING_HT; o->ptr = dict; @@ -1666,7 +1663,7 @@ void hashTypeConvertListpackEx(redisDb *db, robj *o, int enc) { } else if (enc == OBJ_ENCODING_HT) { uint64_t minExpire = EB_EXPIRE_TIME_INVALID; int ret, slot = -1; - hashTypeIterator *hi; + hashTypeIterator hi; dict *dict; htMetadataEx *dictExpireMeta; listpackEx *lpt = o->ptr; @@ -1685,28 +1682,28 @@ void hashTypeConvertListpackEx(redisDb *db, robj *o, int enc) { dictExpireMeta->hfe = ebCreate(); /* Allocate HFE DS */ dictExpireMeta->expireMeta.trash = 1; /* mark as trash (as long it wasn't ebAdd()) */ - hi = hashTypeInitIterator(o); + hashTypeInitIterator(&hi, o); size_t usable, *alloc_size = &dictExpireMeta->alloc_size; - while (hashTypeNext(hi, 0) != C_ERR) { - hfield key = hashTypeCurrentObjectNewHfield(hi, &usable); - sds value = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE); + while (hashTypeNext(&hi, 0) != C_ERR) { + hfield key = hashTypeCurrentObjectNewHfield(&hi, &usable); + sds value = hashTypeCurrentObjectNewSds(&hi,OBJ_HASH_VALUE); dictUseStoredKeyApi(dict, 1); ret = dictAdd(dict, key, value); dictUseStoredKeyApi(dict, 0); if (ret != DICT_OK) { hfieldFree(key, NULL); sdsfree(value); /* Needed for gcc ASAN */ - hashTypeReleaseIterator(hi); /* Needed for gcc ASAN */ + hashTypeResetIterator(&hi); /* Needed for gcc ASAN */ serverLogHexDump(LL_WARNING,"listpack with dup elements dump", lpt->lp,lpBytes(lpt->lp)); serverPanic("Listpack corruption detected"); } *alloc_size += usable + sdsAllocSize(value); - if (hi->expire_time != EB_EXPIRE_TIME_INVALID) - ebAdd(&dictExpireMeta->hfe, &hashFieldExpireBucketsType, key, hi->expire_time); + if (hi.expire_time != EB_EXPIRE_TIME_INVALID) + ebAdd(&dictExpireMeta->hfe, &hashFieldExpireBucketsType, key, hi.expire_time); } - hashTypeReleaseIterator(hi); + hashTypeResetIterator(&hi); listpackExFree(lpt); o->encoding = OBJ_ENCODING_HT; @@ -1739,7 +1736,7 @@ void hashTypeConvert(redisDb *db, robj *o, int enc) { * The resulting object always has refcount set to 1 */ robj *hashTypeDup(kvobj *o, uint64_t *minHashExpire) { robj *hobj; - hashTypeIterator *hi; + hashTypeIterator hi; serverAssert(o->type == OBJ_HASH); @@ -1787,14 +1784,14 @@ robj *hashTypeDup(kvobj *o, uint64_t *minHashExpire) { dictExpand(d, dictSize((const dict*)o->ptr)); size_t usable, *alloc_size = htGetMetadataSize(d); - hi = hashTypeInitIterator(o); - while (hashTypeNext(hi, 0) != C_ERR) { + hashTypeInitIterator(&hi, o); + while (hashTypeNext(&hi, 0) != C_ERR) { uint64_t expireTime; sds newfield, newvalue; /* Extract a field-value pair from an original hash object.*/ char *field, *value; size_t fieldLen, valueLen; - hashTypeCurrentFromHashTable(hi, OBJ_HASH_KEY, &field, &fieldLen, &expireTime); + hashTypeCurrentFromHashTable(&hi, OBJ_HASH_KEY, &field, &fieldLen, &expireTime); if (expireTime == EB_EXPIRE_TIME_INVALID) { newfield = hfieldNew(field, fieldLen, 0, &usable); } else { @@ -1802,7 +1799,7 @@ robj *hashTypeDup(kvobj *o, uint64_t *minHashExpire) { ebAdd(&dictExpireMetaDst->hfe, &hashFieldExpireBucketsType, newfield, expireTime); } - hashTypeCurrentFromHashTable(hi, OBJ_HASH_VALUE, &value, &valueLen, NULL); + hashTypeCurrentFromHashTable(&hi, OBJ_HASH_VALUE, &value, &valueLen, NULL); newvalue = sdsnewlen(value, valueLen); /* Add a field-value pair to a new hash object. */ @@ -1811,7 +1808,7 @@ robj *hashTypeDup(kvobj *o, uint64_t *minHashExpire) { dictUseStoredKeyApi(d, 0); *alloc_size += usable + sdsAllocSize(newvalue); } - hashTypeReleaseIterator(hi); + hashTypeResetIterator(&hi); hobj = createObject(OBJ_HASH, d); hobj->encoding = OBJ_ENCODING_HT; @@ -3006,7 +3003,7 @@ static void addHashIteratorCursorToReply(client *c, hashTypeIterator *hi, int wh void genericHgetallCommand(client *c, int flags) { kvobj *o; - hashTypeIterator *hi; + hashTypeIterator hi; int length, count = 0; size_t oldsize = 0; @@ -3030,20 +3027,20 @@ void genericHgetallCommand(client *c, int flags) { if (server.memory_tracking_per_slot) oldsize = hashTypeAllocSize(o); - hi = hashTypeInitIterator(o); + hashTypeInitIterator(&hi, o); - while (hashTypeNext(hi, 1 /*skipExpiredFields*/) != C_ERR) { + while (hashTypeNext(&hi, 1 /*skipExpiredFields*/) != C_ERR) { if (flags & OBJ_HASH_KEY) { - addHashIteratorCursorToReply(c, hi, OBJ_HASH_KEY); + addHashIteratorCursorToReply(c, &hi, OBJ_HASH_KEY); count++; } if (flags & OBJ_HASH_VALUE) { - addHashIteratorCursorToReply(c, hi, OBJ_HASH_VALUE); + addHashIteratorCursorToReply(c, &hi, OBJ_HASH_VALUE); count++; } } - hashTypeReleaseIterator(hi); + hashTypeResetIterator(&hi); if (server.memory_tracking_per_slot) updateSlotAllocSize(c->db, getKeySlot(c->argv[1]->ptr), oldsize, hashTypeAllocSize(o)); @@ -3210,15 +3207,16 @@ void hrandfieldWithCountCommand(client *c, long l, int withvalues) { * The number of requested elements is greater than the number of * elements inside the hash: simply return the whole hash. */ if(count >= size) { - hashTypeIterator *hi = hashTypeInitIterator(hash); - while (hashTypeNext(hi, 0) != C_ERR) { + hashTypeIterator hi; + hashTypeInitIterator(&hi, hash); + while (hashTypeNext(&hi, 0) != C_ERR) { if (withvalues && c->resp > 2) addReplyArrayLen(c,2); - addHashIteratorCursorToReply(c, hi, OBJ_HASH_KEY); + addHashIteratorCursorToReply(c, &hi, OBJ_HASH_KEY); if (withvalues) - addHashIteratorCursorToReply(c, hi, OBJ_HASH_VALUE); + addHashIteratorCursorToReply(c, &hi, OBJ_HASH_VALUE); } - hashTypeReleaseIterator(hi); + hashTypeResetIterator(&hi); goto out; } diff --git a/src/t_list.c b/src/t_list.c index 69d1882cbea..56d1816f408 100644 --- a/src/t_list.c +++ b/src/t_list.c @@ -226,9 +226,8 @@ size_t listTypeAllocSize(const robj *o) { } /* Initialize an iterator at the specified index. */ -listTypeIterator *listTypeInitIterator(robj *subject, long index, - unsigned char direction) { - listTypeIterator *li = zmalloc(sizeof(listTypeIterator)); +void listTypeInitIterator(listTypeIterator *li, robj *subject, + long index, unsigned char direction) { li->subject = subject; li->encoding = subject->encoding; li->direction = direction; @@ -244,7 +243,6 @@ listTypeIterator *listTypeInitIterator(robj *subject, long index, } else { serverPanic("Unknown list encoding"); } - return li; } /* Sets the direction of an iterator. */ @@ -266,10 +264,9 @@ void listTypeSetIteratorDirection(listTypeIterator *li, listTypeEntry *entry, un } /* Clean up the iterator. */ -void listTypeReleaseIterator(listTypeIterator *li) { - if (li->encoding == OBJ_ENCODING_QUICKLIST) +void listTypeResetIterator(listTypeIterator *li) { + if (li->encoding == OBJ_ENCODING_LISTPACK) quicklistReleaseIterator(li->iter); - zfree(li); } /* Stores pointer to current the entry in the provided entry structure @@ -547,7 +544,7 @@ void rpushxCommand(client *c) { void linsertCommand(client *c) { int where; kvobj *subject; - listTypeIterator *iter; + listTypeIterator iter; listTypeEntry entry; int inserted = 0; size_t oldsize = 0; @@ -574,18 +571,18 @@ void linsertCommand(client *c) { listTypeTryConversionAppend(subject,c->argv,4,4,NULL,NULL); /* Seek pivot from head to tail */ - iter = listTypeInitIterator(subject,0,LIST_TAIL); + listTypeInitIterator(&iter, subject, 0, LIST_TAIL); const size_t object_len = sdslen(c->argv[3]->ptr); long long cached_longval = 0; int cached_valid = 0; - while (listTypeNext(iter,&entry)) { + while (listTypeNext(&iter, &entry)) { if (listTypeEqual(&entry,c->argv[3],object_len,&cached_longval,&cached_valid)) { listTypeInsert(&entry,c->argv[4],where); inserted = 1; break; } } - listTypeReleaseIterator(iter); + listTypeResetIterator(&iter); if (server.memory_tracking_per_slot) updateSlotAllocSize(c->db, getKeySlot(c->argv[1]->ptr), oldsize, listTypeAllocSize(subject)); @@ -621,13 +618,14 @@ void lindexCommand(client *c) { if ((getLongFromObjectOrReply(c, c->argv[2], &index, NULL) != C_OK)) return; - listTypeIterator *iter = listTypeInitIterator(o,index,LIST_TAIL); + listTypeIterator iter; listTypeEntry entry; unsigned char *vstr; size_t vlen; long long lval; - if (listTypeNext(iter,&entry)) { + listTypeInitIterator(&iter, o, index, LIST_TAIL); + if (listTypeNext(&iter, &entry)) { vstr = listTypeGetValue(&entry,&vlen,&lval); if (vstr) { addReplyBulkCBuffer(c, vstr, vlen); @@ -638,7 +636,7 @@ void lindexCommand(client *c) { addReplyNull(c); } - listTypeReleaseIterator(iter); + listTypeResetIterator(&iter); } /* LSET */ @@ -1062,15 +1060,15 @@ void lposCommand(client *c) { if (count != -1) arraylenptr = addReplyDeferredLen(c); /* Seek the element. */ - listTypeIterator *li; - li = listTypeInitIterator(o,direction == LIST_HEAD ? -1 : 0,direction); + listTypeIterator li; listTypeEntry entry; + listTypeInitIterator(&li, o, direction == LIST_HEAD ? -1 : 0, direction); long llen = listTypeLength(o); long index = 0, matches = 0, matchindex = -1, arraylen = 0; const size_t ele_len = sdslen(ele->ptr); long long cached_longval = 0; int cached_valid = 0; - while (listTypeNext(li,&entry) && (maxlen == 0 || index < maxlen)) { + while (listTypeNext(&li, &entry) && (maxlen == 0 || index < maxlen)) { if (listTypeEqual(&entry,ele,ele_len,&cached_longval,&cached_valid)) { matches++; matchindex = (direction == LIST_TAIL) ? index : llen - index - 1; @@ -1087,7 +1085,7 @@ void lposCommand(client *c) { index++; matchindex = -1; /* Remember if we exit the loop without a match. */ } - listTypeReleaseIterator(li); + listTypeResetIterator(&li); /* Reply to the client. Note that arraylenptr is not NULL only if * the COUNT option was selected. */ @@ -1114,12 +1112,12 @@ void lremCommand(client *c) { kvobj *subject = lookupKeyWriteOrReply(c, c->argv[1], shared.czero); if (subject == NULL || checkType(c,subject,OBJ_LIST)) return; - listTypeIterator *li; + listTypeIterator li; if (toremove < 0) { toremove = -toremove; - li = listTypeInitIterator(subject,-1,LIST_HEAD); + listTypeInitIterator(&li, subject, -1, LIST_HEAD); } else { - li = listTypeInitIterator(subject,0,LIST_TAIL); + listTypeInitIterator(&li, subject, 0, LIST_TAIL); } listTypeEntry entry; @@ -1129,15 +1127,15 @@ void lremCommand(client *c) { size_t oldsize = 0; if (server.memory_tracking_per_slot) oldsize = listTypeAllocSize(subject); - while (listTypeNext(li,&entry)) { + while (listTypeNext(&li, &entry)) { if (listTypeEqual(&entry,obj,object_len,&cached_longval,&cached_valid)) { - listTypeDelete(li, &entry); + listTypeDelete(&li, &entry); server.dirty++; removed++; if (toremove && removed == toremove) break; } } - listTypeReleaseIterator(li); + listTypeResetIterator(&li); if (removed) { long ll = listTypeLength(subject); diff --git a/src/t_set.c b/src/t_set.c index dd23e69c7db..bddafa12656 100644 --- a/src/t_set.c +++ b/src/t_set.c @@ -76,8 +76,9 @@ static void maybeConvertToIntset(robj *set) { char *str; size_t len = 0; int64_t llval = 0; - setTypeIterator *si = setTypeInitIterator(set); - while (setTypeNext(si, &str, &len, &llval) != -1) { + setTypeIterator si; + setTypeInitIterator(&si, set); + while (setTypeNext(&si, &str, &len, &llval) != -1) { if (str) { /* If the element is returned as a string, we may be able to convert * it to integer. This happens for OBJ_ENCODING_HT. */ @@ -87,7 +88,7 @@ static void maybeConvertToIntset(robj *set) { is = intsetAdd(is, llval, &success); serverAssert(success); } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); freeSetObject(set); /* frees the internals but not robj itself */ set->ptr = is; set->encoding = OBJ_ENCODING_INTSET; @@ -313,12 +314,11 @@ int setTypeIsMemberAux(robj *set, char *str, size_t len, int64_t llval, int str_ } } -setTypeIterator *setTypeInitIterator(robj *subject) { - setTypeIterator *si = zmalloc(sizeof(setTypeIterator)); +void setTypeInitIterator(setTypeIterator *si, robj *subject) { si->subject = subject; si->encoding = subject->encoding; if (si->encoding == OBJ_ENCODING_HT) { - si->di = dictGetIterator(subject->ptr); + dictInitIterator(&si->di, subject->ptr); } else if (si->encoding == OBJ_ENCODING_INTSET) { si->ii = 0; } else if (si->encoding == OBJ_ENCODING_LISTPACK) { @@ -326,13 +326,11 @@ setTypeIterator *setTypeInitIterator(robj *subject) { } else { serverPanic("Unknown set encoding"); } - return si; } -void setTypeReleaseIterator(setTypeIterator *si) { +void setTypeResetIterator(setTypeIterator *si) { if (si->encoding == OBJ_ENCODING_HT) - dictReleaseIterator(si->di); - zfree(si); + dictResetIterator(&si->di); } /* Move to the next entry in the set. Returns the object at the current @@ -358,7 +356,7 @@ void setTypeReleaseIterator(setTypeIterator *si) { * When there are no more elements -1 is returned. */ int setTypeNext(setTypeIterator *si, char **str, size_t *len, int64_t *llele) { if (si->encoding == OBJ_ENCODING_HT) { - dictEntry *de = dictNext(si->di); + dictEntry *de = dictNext(&si->di); if (de == NULL) return -1; *str = dictGetKey(de); *len = sdslen(*str); @@ -507,7 +505,7 @@ void setTypeConvert(robj *setobj, int enc) { * C_ERR on OOM (panic=0). If panic=1 is given, this function always returns * C_OK. */ int setTypeConvertAndExpand(robj *setobj, int enc, unsigned long cap, int panic) { - setTypeIterator *si; + setTypeIterator si; serverAssertWithInfo(NULL,setobj,setobj->type == OBJ_SET && setobj->encoding != enc); @@ -525,12 +523,12 @@ int setTypeConvertAndExpand(robj *setobj, int enc, unsigned long cap, int panic) /* To add the elements we extract integers and create redis objects */ size_t *alloc_size = htGetMetadataSize(d); - si = setTypeInitIterator(setobj); - while ((element = setTypeNextObject(si)) != NULL) { + setTypeInitIterator(&si, setobj); + while ((element = setTypeNextObject(&si)) != NULL) { serverAssert(dictAdd(d,element,NULL) == DICT_OK); *alloc_size += sdsAllocSize(element); } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); freeSetObject(setobj); /* frees the internals but not setobj itself */ setobj->encoding = OBJ_ENCODING_HT; @@ -548,14 +546,14 @@ int setTypeConvertAndExpand(robj *setobj, int enc, unsigned long cap, int panic) char *str; size_t len = 0; int64_t llele = 0; - si = setTypeInitIterator(setobj); - while (setTypeNext(si, &str, &len, &llele) != -1) { + setTypeInitIterator(&si, setobj); + while (setTypeNext(&si, &str, &len, &llele) != -1) { if (str != NULL) lp = lpAppend(lp, (unsigned char *)str, len); else lp = lpAppendInteger(lp, llele); } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); freeSetObject(setobj); /* frees the internals but not setobj itself */ setobj->encoding = OBJ_ENCODING_LISTPACK; @@ -573,7 +571,6 @@ int setTypeConvertAndExpand(robj *setobj, int enc, unsigned long cap, int panic) * The resulting object always has refcount set to 1 */ robj *setTypeDup(robj *o) { robj *set; - setTypeIterator *si; serverAssert(o->type == OBJ_SET); @@ -596,14 +593,15 @@ robj *setTypeDup(robj *o) { set = createSetObject(); dict *d = o->ptr; dictExpand(set->ptr, dictSize(d)); - si = setTypeInitIterator(o); + setTypeIterator si; + setTypeInitIterator(&si, o); char *str; size_t len = 0; int64_t intobj = 0; - while (setTypeNext(si, &str, &len, &intobj) != -1) { + while (setTypeNext(&si, &str, &len, &intobj) != -1) { setTypeAdd(set, (sds)str); } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); } else { serverPanic("Unknown set encoding"); } @@ -993,9 +991,9 @@ void spopWithCountCommand(client *c) { } /* Transfer the old set to the client. */ - setTypeIterator *si; - si = setTypeInitIterator(set); - while (setTypeNext(si, &str, &len, &llele) != -1) { + setTypeIterator si; + setTypeInitIterator(&si, set); + while (setTypeNext(&si, &str, &len, &llele) != -1) { if (str == NULL) { addReplyBulkLongLong(c,llele); propargv[propindex++] = createStringObjectFromLongLong(llele); @@ -1012,7 +1010,7 @@ void spopWithCountCommand(client *c) { propindex = 2; } } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); /* Update key size histogram "explicitly" and not indirectly by dbReplaceValue() * since function dbReplaceValue() assumes the entire set is being replaced, @@ -1183,10 +1181,10 @@ void srandmemberWithCountCommand(client *c) { * The number of requested elements is greater than the number of * elements inside the set: simply return the whole set. */ if (count >= size) { - setTypeIterator *si; + setTypeIterator si; addReplyArrayLen(c,size); - si = setTypeInitIterator(set); - while (setTypeNext(si, &str, &len, &llele) != -1) { + setTypeInitIterator(&si, set); + while (setTypeNext(&si, &str, &len, &llele) != -1) { if (str == NULL) { addReplyBulkLongLong(c,llele); } else { @@ -1194,7 +1192,7 @@ void srandmemberWithCountCommand(client *c) { } size--; } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); serverAssert(size==0); return; } @@ -1240,12 +1238,12 @@ void srandmemberWithCountCommand(client *c) { * a bit less than the number of elements in the set, the natural approach * used into CASE 4 is highly inefficient. */ if (count*SRANDMEMBER_SUB_STRATEGY_MUL > size) { - setTypeIterator *si; + setTypeIterator si; /* Add all the elements into the temporary dictionary. */ - si = setTypeInitIterator(set); + setTypeInitIterator(&si, set); dictExpand(d, size); - while (setTypeNext(si, &str, &len, &llele) != -1) { + while (setTypeNext(&si, &str, &len, &llele) != -1) { int retval = DICT_ERR; if (str == NULL) { @@ -1255,7 +1253,7 @@ void srandmemberWithCountCommand(client *c) { } serverAssert(retval == DICT_OK); } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); serverAssert(dictSize(d) == size); /* Remove random elements to reach the right count. */ @@ -1377,7 +1375,7 @@ void sinterGenericCommand(client *c, robj **setkeys, unsigned long setnum, robj *dstkey, int cardinality_only, unsigned long limit) { setopsrc *sets = zmalloc(sizeof(setopsrc)*setnum); - setTypeIterator *si; + setTypeIterator si; robj *dstset = NULL; char *str; size_t len = 0; @@ -1461,8 +1459,8 @@ void sinterGenericCommand(client *c, robj **setkeys, * the element against all the other sets, if at least one set does * not include the element it is discarded */ int only_integers = 1; - si = setTypeInitIterator(sets[0].set); - while((encoding = setTypeNext(si, &str, &len, &intobj)) != -1) { + setTypeInitIterator(&si, sets[0].set); + while((encoding = setTypeNext(&si, &str, &len, &intobj)) != -1) { for (j = 1; j < setnum; j++) { if (sets[j].set == sets[0].set) continue; if (!setTypeIsMemberAux(sets[j].set, str, len, intobj, @@ -1505,7 +1503,7 @@ void sinterGenericCommand(client *c, robj **setkeys, } } } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); if (server.memory_tracking_per_slot) { for (j = 0; j < setnum; j++) { @@ -1554,7 +1552,7 @@ void sinterCommand(client *c) { /* SMEMBERS key */ void smembersCommand(client *c) { - setTypeIterator *si; + setTypeIterator si; char *str; size_t len = 0; int64_t intobj = 0; @@ -1572,16 +1570,16 @@ void smembersCommand(client *c) { if (server.memory_tracking_per_slot) oldsize = setTypeAllocSize(setobj); /* Iterate through the elements of the set. */ - si = setTypeInitIterator(setobj); + setTypeInitIterator(&si, setobj); - while (setTypeNext(si, &str, &len, &intobj) != -1) { + while (setTypeNext(&si, &str, &len, &intobj) != -1) { if (str != NULL) addReplyBulkCBuffer(c, str, len); else addReplyBulkLongLong(c, intobj); length--; } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); if (server.memory_tracking_per_slot) updateSlotAllocSize(c->db, getKeySlot(c->argv[1]->ptr), oldsize, setTypeAllocSize(setobj)); serverAssert(length == 0); /* fail on corrupt data */ @@ -1627,7 +1625,7 @@ void sinterstoreCommand(client *c) { void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum, robj *dstkey, int op) { setopsrc *sets = zmalloc(sizeof(setopsrc)*setnum); - setTypeIterator *si; + setTypeIterator si; robj *dstset = NULL; int dstset_encoding = OBJ_ENCODING_INTSET; char *str; @@ -1722,11 +1720,11 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum, for (j = 0; j < setnum; j++) { if (!sets[j].set) continue; /* non existing keys are like empty sets */ - si = setTypeInitIterator(sets[j].set); - while ((encoding = setTypeNext(si, &str, &len, &llval)) != -1) { + setTypeInitIterator(&si, sets[j].set); + while ((encoding = setTypeNext(&si, &str, &len, &llval)) != -1) { cardinality += setTypeAddAux(dstset, str, len, llval, encoding == OBJ_ENCODING_HT); } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); } } else if (op == SET_OP_DIFF && sameset) { /* At least one of the sets is the same one (same key) as the first one, result must be empty. */ @@ -1739,8 +1737,8 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum, * * This way we perform at max N*M operations, where N is the size of * the first set, and M the number of sets. */ - si = setTypeInitIterator(sets[0].set); - while ((encoding = setTypeNext(si, &str, &len, &llval)) != -1) { + setTypeInitIterator(&si, sets[0].set); + while ((encoding = setTypeNext(&si, &str, &len, &llval)) != -1) { for (j = 1; j < setnum; j++) { if (!sets[j].set) continue; /* no key is an empty set. */ if (sets[j].set == sets[0].set) break; /* same set! */ @@ -1753,7 +1751,7 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum, cardinality += setTypeAddAux(dstset, str, len, llval, encoding == OBJ_ENCODING_HT); } } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); } else if (op == SET_OP_DIFF && sets[0].set && diff_algo == 2) { /* DIFF Algorithm 2: * @@ -1765,8 +1763,8 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum, for (j = 0; j < setnum; j++) { if (!sets[j].set) continue; /* non existing keys are like empty sets */ - si = setTypeInitIterator(sets[j].set); - while((encoding = setTypeNext(si, &str, &len, &llval)) != -1) { + setTypeInitIterator(&si, sets[j].set); + while((encoding = setTypeNext(&si, &str, &len, &llval)) != -1) { if (j == 0) { cardinality += setTypeAddAux(dstset, str, len, llval, encoding == OBJ_ENCODING_HT); @@ -1775,7 +1773,7 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum, encoding == OBJ_ENCODING_HT); } } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); /* Exit if result set is empty as any additional removal * of elements will have no effect. */ @@ -1793,14 +1791,14 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum, /* Output the content of the resulting set, if not in STORE mode */ if (!dstkey) { addReplySetLen(c,cardinality); - si = setTypeInitIterator(dstset); - while (setTypeNext(si, &str, &len, &llval) != -1) { + setTypeInitIterator(&si, dstset); + while (setTypeNext(&si, &str, &len, &llval) != -1) { if (str) addReplyBulkCBuffer(c, str, len); else addReplyBulkLongLong(c, llval); } - setTypeReleaseIterator(si); + setTypeResetIterator(&si); server.lazyfree_lazy_server_del ? freeObjAsync(NULL, dstset, -1) : decrRefCount(dstset); } else {