Move stat_active_defrag_hits increment to activeDefragAlloc

instead of passing it around to every defrag function
This commit is contained in:
Viktor Söderqvist 2022-11-21 15:34:38 +01:00
parent b60d33c91e
commit 2bbc89196a
3 changed files with 122 additions and 184 deletions

View File

@ -64,6 +64,7 @@ void* activeDefragAlloc(void *ptr) {
newptr = zmalloc_no_tcache(size); newptr = zmalloc_no_tcache(size);
memcpy(newptr, ptr, size); memcpy(newptr, ptr, size);
zfree_no_tcache(ptr); zfree_no_tcache(ptr);
server.stat_active_defrag_hits++;
return newptr; return newptr;
} }
@ -88,7 +89,7 @@ sds activeDefragSds(sds sdsptr) {
* returns NULL in case the allocation wasn't moved. * returns NULL in case the allocation wasn't moved.
* when it returns a non-null value, the old pointer was already released * when it returns a non-null value, the old pointer was already released
* and should NOT be accessed. */ * and should NOT be accessed. */
robj *activeDefragStringOb(robj* ob, long *defragged) { robj *activeDefragStringOb(robj* ob) {
robj *ret = NULL; robj *ret = NULL;
if (ob->refcount!=1) if (ob->refcount!=1)
return NULL; return NULL;
@ -97,7 +98,6 @@ robj *activeDefragStringOb(robj* ob, long *defragged) {
if (ob->type!=OBJ_STRING || ob->encoding!=OBJ_ENCODING_EMBSTR) { if (ob->type!=OBJ_STRING || ob->encoding!=OBJ_ENCODING_EMBSTR) {
if ((ret = activeDefragAlloc(ob))) { if ((ret = activeDefragAlloc(ob))) {
ob = ret; ob = ret;
(*defragged)++;
} }
} }
@ -107,7 +107,6 @@ robj *activeDefragStringOb(robj* ob, long *defragged) {
sds newsds = activeDefragSds((sds)ob->ptr); sds newsds = activeDefragSds((sds)ob->ptr);
if (newsds) { if (newsds) {
ob->ptr = newsds; ob->ptr = newsds;
(*defragged)++;
} }
} else if (ob->encoding==OBJ_ENCODING_EMBSTR) { } else if (ob->encoding==OBJ_ENCODING_EMBSTR) {
/* The sds is embedded in the object allocation, calculate the /* The sds is embedded in the object allocation, calculate the
@ -115,7 +114,6 @@ robj *activeDefragStringOb(robj* ob, long *defragged) {
long ofs = (intptr_t)ob->ptr - (intptr_t)ob; long ofs = (intptr_t)ob->ptr - (intptr_t)ob;
if ((ret = activeDefragAlloc(ob))) { if ((ret = activeDefragAlloc(ob))) {
ret->ptr = (void*)((intptr_t)ret + ofs); ret->ptr = (void*)((intptr_t)ret + ofs);
(*defragged)++;
} }
} else if (ob->encoding!=OBJ_ENCODING_INT) { } else if (ob->encoding!=OBJ_ENCODING_INT) {
serverPanic("Unknown string encoding"); serverPanic("Unknown string encoding");
@ -129,17 +127,16 @@ robj *activeDefragStringOb(robj* ob, long *defragged) {
* returns NULL in case the allocation wasn't moved. * returns NULL in case the allocation wasn't moved.
* when it returns a non-null value, the old pointer was already released * when it returns a non-null value, the old pointer was already released
* and should NOT be accessed. */ * and should NOT be accessed. */
luaScript *activeDefragLuaScript(luaScript *script, long *defragged) { luaScript *activeDefragLuaScript(luaScript *script) {
luaScript *ret = NULL; luaScript *ret = NULL;
/* try to defrag script struct */ /* try to defrag script struct */
if ((ret = activeDefragAlloc(script))) { if ((ret = activeDefragAlloc(script))) {
script = ret; script = ret;
(*defragged)++;
} }
/* try to defrag actual script object */ /* try to defrag actual script object */
robj *ob = activeDefragStringOb(script->body, defragged); robj *ob = activeDefragStringOb(script->body);
if (ob) script->body = ob; if (ob) script->body = ob;
return ret; return ret;
@ -148,20 +145,18 @@ luaScript *activeDefragLuaScript(luaScript *script, long *defragged) {
/* Defrag helper for dict main allocations (dict struct, and hash tables). /* Defrag helper for dict main allocations (dict struct, and hash tables).
* receives a pointer to the dict* and implicitly updates it when the dict * receives a pointer to the dict* and implicitly updates it when the dict
* struct itself was moved. Returns a stat of how many pointers were moved. */ * struct itself was moved. Returns a stat of how many pointers were moved. */
long dictDefragTables(dict* d) { void dictDefragTables(dict* d) {
dictEntry **newtable; dictEntry **newtable;
long defragged = 0;
/* handle the first hash table */ /* handle the first hash table */
newtable = activeDefragAlloc(d->ht_table[0]); newtable = activeDefragAlloc(d->ht_table[0]);
if (newtable) if (newtable)
defragged++, d->ht_table[0] = newtable; d->ht_table[0] = newtable;
/* handle the second hash table */ /* handle the second hash table */
if (d->ht_table[1]) { if (d->ht_table[1]) {
newtable = activeDefragAlloc(d->ht_table[1]); newtable = activeDefragAlloc(d->ht_table[1]);
if (newtable) if (newtable)
defragged++, d->ht_table[1] = newtable; d->ht_table[1] = newtable;
} }
return defragged;
} }
/* Internal function used by zslDefrag */ /* Internal function used by zslDefrag */
@ -225,19 +220,16 @@ double *zslDefrag(zskiplist *zsl, double score, sds oldele, sds newele) {
/* Defrag helper for sorted set. /* Defrag helper for sorted set.
* Defrag a single dict entry key name, and corresponding skiplist struct */ * Defrag a single dict entry key name, and corresponding skiplist struct */
long activeDefragZsetEntry(zset *zs, dictEntry *de) { void activeDefragZsetEntry(zset *zs, dictEntry *de) {
sds newsds; sds newsds;
double* newscore; double* newscore;
long defragged = 0;
sds sdsele = dictGetKey(de); sds sdsele = dictGetKey(de);
if ((newsds = activeDefragSds(sdsele))) if ((newsds = activeDefragSds(sdsele)))
defragged++, dictSetKey(zs->dict, de, newsds); dictSetKey(zs->dict, de, newsds);
newscore = zslDefrag(zs->zsl, *(double*)dictGetVal(de), sdsele, newsds); newscore = zslDefrag(zs->zsl, *(double*)dictGetVal(de), sdsele, newsds);
if (newscore) { if (newscore) {
dictSetVal(zs->dict, de, newscore); dictSetVal(zs->dict, de, newscore);
defragged++;
} }
return defragged;
} }
#define DEFRAG_SDS_DICT_NO_VAL 0 #define DEFRAG_SDS_DICT_NO_VAL 0
@ -249,7 +241,6 @@ long activeDefragZsetEntry(zset *zs, dictEntry *de) {
typedef struct { typedef struct {
dict *dict; dict *dict;
int val_type; int val_type;
long defragged;
} activeDefragSdsDictData; } activeDefragSdsDictData;
void activeDefragSdsDictCallback(void *privdata, const dictEntry *_de) { void activeDefragSdsDictCallback(void *privdata, const dictEntry *_de) {
@ -259,41 +250,39 @@ void activeDefragSdsDictCallback(void *privdata, const dictEntry *_de) {
int val_type = data->val_type; int val_type = data->val_type;
sds sdsele = dictGetKey(de), newsds; sds sdsele = dictGetKey(de), newsds;
if ((newsds = activeDefragSds(sdsele))) if ((newsds = activeDefragSds(sdsele)))
dictSetKey(d, de, newsds), data->defragged++; dictSetKey(d, de, newsds);
/* defrag the value */ /* defrag the value */
if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) { if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
sdsele = dictGetVal(de); sdsele = dictGetVal(de);
if ((newsds = activeDefragSds(sdsele))) if ((newsds = activeDefragSds(sdsele)))
dictSetVal(d, de, newsds), data->defragged++; dictSetVal(d, de, newsds);
} else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) { } else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
robj *newele, *ele = dictGetVal(de); robj *newele, *ele = dictGetVal(de);
if ((newele = activeDefragStringOb(ele, &data->defragged))) if ((newele = activeDefragStringOb(ele)))
dictSetVal(d, de, newele); dictSetVal(d, de, newele);
} else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) { } else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
void *newptr, *ptr = dictGetVal(de); void *newptr, *ptr = dictGetVal(de);
if ((newptr = activeDefragAlloc(ptr))) if ((newptr = activeDefragAlloc(ptr)))
dictSetVal(d, de, newptr), data->defragged++; dictSetVal(d, de, newptr);
} else if (val_type == DEFRAG_SDS_DICT_VAL_LUA_SCRIPT) { } else if (val_type == DEFRAG_SDS_DICT_VAL_LUA_SCRIPT) {
void *newptr, *ptr = dictGetVal(de); void *newptr, *ptr = dictGetVal(de);
if ((newptr = activeDefragLuaScript(ptr, &data->defragged))) if ((newptr = activeDefragLuaScript(ptr)))
dictSetVal(d, de, newptr); dictSetVal(d, de, newptr);
} }
} }
/* Defrag a dict with sds key and optional value (either ptr, sds or robj string) */ /* Defrag a dict with sds key and optional value (either ptr, sds or robj string) */
long activeDefragSdsDict(dict* d, int val_type) { void activeDefragSdsDict(dict* d, int val_type) {
activeDefragSdsDictData data = {d, val_type, 0}; activeDefragSdsDictData data = {d, val_type};
unsigned long cursor = 0; unsigned long cursor = 0;
do { do {
cursor = dictScanDefrag(d, cursor, activeDefragSdsDictCallback, cursor = dictScanDefrag(d, cursor, activeDefragSdsDictCallback,
activeDefragAlloc, &data); activeDefragAlloc, &data);
} while (cursor != 0); } while (cursor != 0);
return data.defragged;
} }
/* Defrag a list of ptr, sds or robj string values */ /* Defrag a list of ptr, sds or robj string values */
long activeDefragList(list *l, int val_type) { void activeDefragList(list *l, int val_type) {
long defragged = 0;
listNode *ln, *newln; listNode *ln, *newln;
for (ln = l->head; ln; ln = ln->next) { for (ln = l->head; ln; ln = ln->next) {
if ((newln = activeDefragAlloc(ln))) { if ((newln = activeDefragAlloc(ln))) {
@ -306,28 +295,25 @@ long activeDefragList(list *l, int val_type) {
else else
l->tail = newln; l->tail = newln;
ln = newln; ln = newln;
defragged++;
} }
if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) { if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
sds newsds, sdsele = ln->value; sds newsds, sdsele = ln->value;
if ((newsds = activeDefragSds(sdsele))) if ((newsds = activeDefragSds(sdsele)))
ln->value = newsds, defragged++; ln->value = newsds;
} else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) { } else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
robj *newele, *ele = ln->value; robj *newele, *ele = ln->value;
if ((newele = activeDefragStringOb(ele, &defragged))) if ((newele = activeDefragStringOb(ele)))
ln->value = newele; ln->value = newele;
} else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) { } else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
void *newptr, *ptr = ln->value; void *newptr, *ptr = ln->value;
if ((newptr = activeDefragAlloc(ptr))) if ((newptr = activeDefragAlloc(ptr)))
ln->value = newptr, defragged++; ln->value = newptr;
} }
} }
return defragged;
} }
long activeDefragQuickListNode(quicklist *ql, quicklistNode **node_ref) { void activeDefragQuickListNode(quicklist *ql, quicklistNode **node_ref) {
quicklistNode *newnode, *node = *node_ref; quicklistNode *newnode, *node = *node_ref;
long defragged = 0;
unsigned char *newzl; unsigned char *newzl;
if ((newnode = activeDefragAlloc(node))) { if ((newnode = activeDefragAlloc(node))) {
if (newnode->prev) if (newnode->prev)
@ -339,21 +325,17 @@ long activeDefragQuickListNode(quicklist *ql, quicklistNode **node_ref) {
else else
ql->tail = newnode; ql->tail = newnode;
*node_ref = node = newnode; *node_ref = node = newnode;
defragged++;
} }
if ((newzl = activeDefragAlloc(node->entry))) if ((newzl = activeDefragAlloc(node->entry)))
defragged++, node->entry = newzl; node->entry = newzl;
return defragged;
} }
long activeDefragQuickListNodes(quicklist *ql) { void activeDefragQuickListNodes(quicklist *ql) {
quicklistNode *node = ql->head; quicklistNode *node = ql->head;
long defragged = 0;
while (node) { while (node) {
defragged += activeDefragQuickListNode(ql, &node); activeDefragQuickListNode(ql, &node);
node = node->next; node = node->next;
} }
return defragged;
} }
/* when the value has lots of elements, we want to handle it later and not as /* when the value has lots of elements, we want to handle it later and not as
@ -365,7 +347,7 @@ void defragLater(redisDb *db, dictEntry *kde) {
} }
/* returns 0 if no more work needs to be been done, and 1 if time is up and more work is needed. */ /* returns 0 if no more work needs to be been done, and 1 if time is up and more work is needed. */
long scanLaterList(robj *ob, unsigned long *cursor, long long endtime, long long *defragged) { long scanLaterList(robj *ob, unsigned long *cursor, long long endtime) {
quicklist *ql = ob->ptr; quicklist *ql = ob->ptr;
quicklistNode *node; quicklistNode *node;
long iterations = 0; long iterations = 0;
@ -388,7 +370,7 @@ long scanLaterList(robj *ob, unsigned long *cursor, long long endtime, long long
(*cursor)++; (*cursor)++;
while (node) { while (node) {
(*defragged) += activeDefragQuickListNode(ql, &node); activeDefragQuickListNode(ql, &node);
server.stat_active_defrag_scanned++; server.stat_active_defrag_scanned++;
if (++iterations > 128 && !bookmark_failed) { if (++iterations > 128 && !bookmark_failed) {
if (ustime() > endtime) { if (ustime() > endtime) {
@ -410,29 +392,26 @@ long scanLaterList(robj *ob, unsigned long *cursor, long long endtime, long long
typedef struct { typedef struct {
zset *zs; zset *zs;
long defragged;
} scanLaterZsetData; } scanLaterZsetData;
void scanLaterZsetCallback(void *privdata, const dictEntry *_de) { void scanLaterZsetCallback(void *privdata, const dictEntry *_de) {
dictEntry *de = (dictEntry*)_de; dictEntry *de = (dictEntry*)_de;
scanLaterZsetData *data = privdata; scanLaterZsetData *data = privdata;
data->defragged += activeDefragZsetEntry(data->zs, de); activeDefragZsetEntry(data->zs, de);
server.stat_active_defrag_scanned++; server.stat_active_defrag_scanned++;
} }
long scanLaterZset(robj *ob, unsigned long *cursor) { void scanLaterZset(robj *ob, unsigned long *cursor) {
if (ob->type != OBJ_ZSET || ob->encoding != OBJ_ENCODING_SKIPLIST) if (ob->type != OBJ_ZSET || ob->encoding != OBJ_ENCODING_SKIPLIST)
return 0; return;
zset *zs = (zset*)ob->ptr; zset *zs = (zset*)ob->ptr;
dict *d = zs->dict; dict *d = zs->dict;
scanLaterZsetData data = {zs, 0}; scanLaterZsetData data = {zs};
*cursor = dictScanDefrag(d, *cursor, scanLaterZsetCallback, activeDefragAlloc, &data); *cursor = dictScanDefrag(d, *cursor, scanLaterZsetCallback, activeDefragAlloc, &data);
return data.defragged;
} }
typedef struct { typedef struct {
dict *dict; dict *dict;
long defragged;
} scanLaterDictData; } scanLaterDictData;
void scanLaterSetCallback(void *privdata, const dictEntry *_de) { void scanLaterSetCallback(void *privdata, const dictEntry *_de) {
@ -440,17 +419,16 @@ void scanLaterSetCallback(void *privdata, const dictEntry *_de) {
scanLaterDictData *data = privdata; scanLaterDictData *data = privdata;
sds sdsele = dictGetKey(de), newsds; sds sdsele = dictGetKey(de), newsds;
if ((newsds = activeDefragSds(sdsele))) if ((newsds = activeDefragSds(sdsele)))
data->defragged++, dictSetKey(data->dict, de, newsds); dictSetKey(data->dict, de, newsds);
server.stat_active_defrag_scanned++; server.stat_active_defrag_scanned++;
} }
long scanLaterSet(robj *ob, unsigned long *cursor) { void scanLaterSet(robj *ob, unsigned long *cursor) {
if (ob->type != OBJ_SET || ob->encoding != OBJ_ENCODING_HT) if (ob->type != OBJ_SET || ob->encoding != OBJ_ENCODING_HT)
return 0; return;
dict *d = ob->ptr; dict *d = ob->ptr;
scanLaterDictData data = {d, 0}; scanLaterDictData data = {d};
*cursor = dictScanDefrag(d, *cursor, scanLaterSetCallback, activeDefragAlloc, &data); *cursor = dictScanDefrag(d, *cursor, scanLaterSetCallback, activeDefragAlloc, &data);
return data.defragged;
} }
void scanLaterHashCallback(void *privdata, const dictEntry *_de) { void scanLaterHashCallback(void *privdata, const dictEntry *_de) {
@ -458,39 +436,35 @@ void scanLaterHashCallback(void *privdata, const dictEntry *_de) {
scanLaterDictData *data = privdata; scanLaterDictData *data = privdata;
sds sdsele = dictGetKey(de), newsds; sds sdsele = dictGetKey(de), newsds;
if ((newsds = activeDefragSds(sdsele))) if ((newsds = activeDefragSds(sdsele)))
data->defragged++, dictSetKey(data->dict, de, newsds); dictSetKey(data->dict, de, newsds);
sdsele = dictGetVal(de); sdsele = dictGetVal(de);
if ((newsds = activeDefragSds(sdsele))) if ((newsds = activeDefragSds(sdsele)))
data->defragged++, dictSetVal(data->dict, de, newsds); dictSetVal(data->dict, de, newsds);
server.stat_active_defrag_scanned++; server.stat_active_defrag_scanned++;
} }
long scanLaterHash(robj *ob, unsigned long *cursor) { void scanLaterHash(robj *ob, unsigned long *cursor) {
if (ob->type != OBJ_HASH || ob->encoding != OBJ_ENCODING_HT) if (ob->type != OBJ_HASH || ob->encoding != OBJ_ENCODING_HT)
return 0; return;
dict *d = ob->ptr; dict *d = ob->ptr;
scanLaterDictData data = {d, 0}; scanLaterDictData data = {d};
*cursor = dictScanDefrag(d, *cursor, scanLaterHashCallback, activeDefragAlloc, &data); *cursor = dictScanDefrag(d, *cursor, scanLaterHashCallback, activeDefragAlloc, &data);
return data.defragged;
} }
long defragQuicklist(redisDb *db, dictEntry *kde) { void defragQuicklist(redisDb *db, dictEntry *kde) {
robj *ob = dictGetVal(kde); robj *ob = dictGetVal(kde);
long defragged = 0;
quicklist *ql = ob->ptr, *newql; quicklist *ql = ob->ptr, *newql;
serverAssert(ob->type == OBJ_LIST && ob->encoding == OBJ_ENCODING_QUICKLIST); serverAssert(ob->type == OBJ_LIST && ob->encoding == OBJ_ENCODING_QUICKLIST);
if ((newql = activeDefragAlloc(ql))) if ((newql = activeDefragAlloc(ql)))
defragged++, ob->ptr = ql = newql; ob->ptr = ql = newql;
if (ql->len > server.active_defrag_max_scan_fields) if (ql->len > server.active_defrag_max_scan_fields)
defragLater(db, kde); defragLater(db, kde);
else else
defragged += activeDefragQuickListNodes(ql); activeDefragQuickListNodes(ql);
return defragged;
} }
long defragZsetSkiplist(redisDb *db, dictEntry *kde) { void defragZsetSkiplist(redisDb *db, dictEntry *kde) {
robj *ob = dictGetVal(kde); robj *ob = dictGetVal(kde);
long defragged = 0;
zset *zs = (zset*)ob->ptr; zset *zs = (zset*)ob->ptr;
zset *newzs; zset *newzs;
zskiplist *newzsl; zskiplist *newzsl;
@ -499,30 +473,28 @@ long defragZsetSkiplist(redisDb *db, dictEntry *kde) {
struct zskiplistNode *newheader; struct zskiplistNode *newheader;
serverAssert(ob->type == OBJ_ZSET && ob->encoding == OBJ_ENCODING_SKIPLIST); serverAssert(ob->type == OBJ_ZSET && ob->encoding == OBJ_ENCODING_SKIPLIST);
if ((newzs = activeDefragAlloc(zs))) if ((newzs = activeDefragAlloc(zs)))
defragged++, ob->ptr = zs = newzs; ob->ptr = zs = newzs;
if ((newzsl = activeDefragAlloc(zs->zsl))) if ((newzsl = activeDefragAlloc(zs->zsl)))
defragged++, zs->zsl = newzsl; zs->zsl = newzsl;
if ((newheader = activeDefragAlloc(zs->zsl->header))) if ((newheader = activeDefragAlloc(zs->zsl->header)))
defragged++, zs->zsl->header = newheader; zs->zsl->header = newheader;
if (dictSize(zs->dict) > server.active_defrag_max_scan_fields) if (dictSize(zs->dict) > server.active_defrag_max_scan_fields)
defragLater(db, kde); defragLater(db, kde);
else { else {
dictIterator *di = dictGetIterator(zs->dict); dictIterator *di = dictGetIterator(zs->dict);
while((de = dictNext(di)) != NULL) { while((de = dictNext(di)) != NULL) {
defragged += activeDefragZsetEntry(zs, de); activeDefragZsetEntry(zs, de);
} }
dictReleaseIterator(di); dictReleaseIterator(di);
} }
/* handle the dict struct */ /* handle the dict struct */
if ((newdict = activeDefragAlloc(zs->dict))) if ((newdict = activeDefragAlloc(zs->dict)))
defragged++, zs->dict = newdict; zs->dict = newdict;
/* defrag the dict tables */ /* defrag the dict tables */
defragged += dictDefragTables(zs->dict); dictDefragTables(zs->dict);
return defragged;
} }
long defragHash(redisDb *db, dictEntry *kde) { void defragHash(redisDb *db, dictEntry *kde) {
long defragged = 0;
robj *ob = dictGetVal(kde); robj *ob = dictGetVal(kde);
dict *d, *newd; dict *d, *newd;
serverAssert(ob->type == OBJ_HASH && ob->encoding == OBJ_ENCODING_HT); serverAssert(ob->type == OBJ_HASH && ob->encoding == OBJ_ENCODING_HT);
@ -530,17 +502,15 @@ long defragHash(redisDb *db, dictEntry *kde) {
if (dictSize(d) > server.active_defrag_max_scan_fields) if (dictSize(d) > server.active_defrag_max_scan_fields)
defragLater(db, kde); defragLater(db, kde);
else else
defragged += activeDefragSdsDict(d, DEFRAG_SDS_DICT_VAL_IS_SDS); activeDefragSdsDict(d, DEFRAG_SDS_DICT_VAL_IS_SDS);
/* handle the dict struct */ /* handle the dict struct */
if ((newd = activeDefragAlloc(ob->ptr))) if ((newd = activeDefragAlloc(ob->ptr)))
defragged++, ob->ptr = newd; ob->ptr = newd;
/* defrag the dict tables */ /* defrag the dict tables */
defragged += dictDefragTables(ob->ptr); dictDefragTables(ob->ptr);
return defragged;
} }
long defragSet(redisDb *db, dictEntry *kde) { void defragSet(redisDb *db, dictEntry *kde) {
long defragged = 0;
robj *ob = dictGetVal(kde); robj *ob = dictGetVal(kde);
dict *d, *newd; dict *d, *newd;
serverAssert(ob->type == OBJ_SET && ob->encoding == OBJ_ENCODING_HT); serverAssert(ob->type == OBJ_SET && ob->encoding == OBJ_ENCODING_HT);
@ -548,13 +518,12 @@ long defragSet(redisDb *db, dictEntry *kde) {
if (dictSize(d) > server.active_defrag_max_scan_fields) if (dictSize(d) > server.active_defrag_max_scan_fields)
defragLater(db, kde); defragLater(db, kde);
else else
defragged += activeDefragSdsDict(d, DEFRAG_SDS_DICT_NO_VAL); activeDefragSdsDict(d, DEFRAG_SDS_DICT_NO_VAL);
/* handle the dict struct */ /* handle the dict struct */
if ((newd = activeDefragAlloc(ob->ptr))) if ((newd = activeDefragAlloc(ob->ptr)))
defragged++, ob->ptr = newd; ob->ptr = newd;
/* defrag the dict tables */ /* defrag the dict tables */
defragged += dictDefragTables(ob->ptr); dictDefragTables(ob->ptr);
return defragged;
} }
/* Defrag callback for radix tree iterator, called for each node, /* Defrag callback for radix tree iterator, called for each node,
@ -569,7 +538,7 @@ int defragRaxNode(raxNode **noderef) {
} }
/* returns 0 if no more work needs to be been done, and 1 if time is up and more work is needed. */ /* returns 0 if no more work needs to be been done, and 1 if time is up and more work is needed. */
int scanLaterStreamListpacks(robj *ob, unsigned long *cursor, long long endtime, long long *defragged) { int scanLaterStreamListpacks(robj *ob, unsigned long *cursor, long long endtime) {
static unsigned char last[sizeof(streamID)]; static unsigned char last[sizeof(streamID)];
raxIterator ri; raxIterator ri;
long iterations = 0; long iterations = 0;
@ -603,7 +572,7 @@ int scanLaterStreamListpacks(robj *ob, unsigned long *cursor, long long endtime,
while (raxNext(&ri)) { while (raxNext(&ri)) {
void *newdata = activeDefragAlloc(ri.data); void *newdata = activeDefragAlloc(ri.data);
if (newdata) if (newdata)
raxSetData(ri.node, ri.data=newdata), (*defragged)++; raxSetData(ri.node, ri.data=newdata);
server.stat_active_defrag_scanned++; server.stat_active_defrag_scanned++;
if (++iterations > 128) { if (++iterations > 128) {
if (ustime() > endtime) { if (ustime() > endtime) {
@ -621,19 +590,18 @@ int scanLaterStreamListpacks(robj *ob, unsigned long *cursor, long long endtime,
} }
/* optional callback used defrag each rax element (not including the element pointer itself) */ /* optional callback used defrag each rax element (not including the element pointer itself) */
typedef void *(raxDefragFunction)(raxIterator *ri, void *privdata, long *defragged); typedef void *(raxDefragFunction)(raxIterator *ri, void *privdata);
/* defrag radix tree including: /* defrag radix tree including:
* 1) rax struct * 1) rax struct
* 2) rax nodes * 2) rax nodes
* 3) rax entry data (only if defrag_data is specified) * 3) rax entry data (only if defrag_data is specified)
* 4) call a callback per element, and allow the callback to return a new pointer for the element */ * 4) call a callback per element, and allow the callback to return a new pointer for the element */
long defragRadixTree(rax **raxref, int defrag_data, raxDefragFunction *element_cb, void *element_cb_data) { void defragRadixTree(rax **raxref, int defrag_data, raxDefragFunction *element_cb, void *element_cb_data) {
long defragged = 0;
raxIterator ri; raxIterator ri;
rax* rax; rax* rax;
if ((rax = activeDefragAlloc(*raxref))) if ((rax = activeDefragAlloc(*raxref)))
defragged++, *raxref = rax; *raxref = rax;
rax = *raxref; rax = *raxref;
raxStart(&ri,rax); raxStart(&ri,rax);
ri.node_cb = defragRaxNode; ri.node_cb = defragRaxNode;
@ -642,14 +610,13 @@ long defragRadixTree(rax **raxref, int defrag_data, raxDefragFunction *element_c
while (raxNext(&ri)) { while (raxNext(&ri)) {
void *newdata = NULL; void *newdata = NULL;
if (element_cb) if (element_cb)
newdata = element_cb(&ri, element_cb_data, &defragged); newdata = element_cb(&ri, element_cb_data);
if (defrag_data && !newdata) if (defrag_data && !newdata)
newdata = activeDefragAlloc(ri.data); newdata = activeDefragAlloc(ri.data);
if (newdata) if (newdata)
raxSetData(ri.node, ri.data=newdata), defragged++; raxSetData(ri.node, ri.data=newdata);
} }
raxStop(&ri); raxStop(&ri);
return defragged;
} }
typedef struct { typedef struct {
@ -657,8 +624,7 @@ typedef struct {
streamConsumer *c; streamConsumer *c;
} PendingEntryContext; } PendingEntryContext;
void* defragStreamConsumerPendingEntry(raxIterator *ri, void *privdata, long *defragged) { void* defragStreamConsumerPendingEntry(raxIterator *ri, void *privdata) {
UNUSED(defragged);
PendingEntryContext *ctx = privdata; PendingEntryContext *ctx = privdata;
streamNACK *nack = ri->data, *newnack; streamNACK *nack = ri->data, *newnack;
nack->consumer = ctx->c; /* update nack pointer to consumer */ nack->consumer = ctx->c; /* update nack pointer to consumer */
@ -668,90 +634,81 @@ void* defragStreamConsumerPendingEntry(raxIterator *ri, void *privdata, long *de
void *prev; void *prev;
raxInsert(ctx->cg->pel, ri->key, ri->key_len, newnack, &prev); raxInsert(ctx->cg->pel, ri->key, ri->key_len, newnack, &prev);
serverAssert(prev==nack); serverAssert(prev==nack);
/* note: we don't increment 'defragged' that's done by the caller */
} }
return newnack; return newnack;
} }
void* defragStreamConsumer(raxIterator *ri, void *privdata, long *defragged) { void* defragStreamConsumer(raxIterator *ri, void *privdata) {
streamConsumer *c = ri->data; streamConsumer *c = ri->data;
streamCG *cg = privdata; streamCG *cg = privdata;
void *newc = activeDefragAlloc(c); void *newc = activeDefragAlloc(c);
if (newc) { if (newc) {
/* note: we don't increment 'defragged' that's done by the caller */
c = newc; c = newc;
} }
sds newsds = activeDefragSds(c->name); sds newsds = activeDefragSds(c->name);
if (newsds) if (newsds)
(*defragged)++, c->name = newsds; c->name = newsds;
if (c->pel) { if (c->pel) {
PendingEntryContext pel_ctx = {cg, c}; PendingEntryContext pel_ctx = {cg, c};
*defragged += defragRadixTree(&c->pel, 0, defragStreamConsumerPendingEntry, &pel_ctx); defragRadixTree(&c->pel, 0, defragStreamConsumerPendingEntry, &pel_ctx);
} }
return newc; /* returns NULL if c was not defragged */ return newc; /* returns NULL if c was not defragged */
} }
void* defragStreamConsumerGroup(raxIterator *ri, void *privdata, long *defragged) { void* defragStreamConsumerGroup(raxIterator *ri, void *privdata) {
streamCG *cg = ri->data; streamCG *cg = ri->data;
UNUSED(privdata); UNUSED(privdata);
if (cg->consumers) if (cg->consumers)
*defragged += defragRadixTree(&cg->consumers, 0, defragStreamConsumer, cg); defragRadixTree(&cg->consumers, 0, defragStreamConsumer, cg);
if (cg->pel) if (cg->pel)
*defragged += defragRadixTree(&cg->pel, 0, NULL, NULL); defragRadixTree(&cg->pel, 0, NULL, NULL);
return NULL; return NULL;
} }
long defragStream(redisDb *db, dictEntry *kde) { void defragStream(redisDb *db, dictEntry *kde) {
long defragged = 0;
robj *ob = dictGetVal(kde); robj *ob = dictGetVal(kde);
serverAssert(ob->type == OBJ_STREAM && ob->encoding == OBJ_ENCODING_STREAM); serverAssert(ob->type == OBJ_STREAM && ob->encoding == OBJ_ENCODING_STREAM);
stream *s = ob->ptr, *news; stream *s = ob->ptr, *news;
/* handle the main struct */ /* handle the main struct */
if ((news = activeDefragAlloc(s))) if ((news = activeDefragAlloc(s)))
defragged++, ob->ptr = s = news; ob->ptr = s = news;
if (raxSize(s->rax) > server.active_defrag_max_scan_fields) { if (raxSize(s->rax) > server.active_defrag_max_scan_fields) {
rax *newrax = activeDefragAlloc(s->rax); rax *newrax = activeDefragAlloc(s->rax);
if (newrax) if (newrax)
defragged++, s->rax = newrax; s->rax = newrax;
defragLater(db, kde); defragLater(db, kde);
} else } else
defragged += defragRadixTree(&s->rax, 1, NULL, NULL); defragRadixTree(&s->rax, 1, NULL, NULL);
if (s->cgroups) if (s->cgroups)
defragged += defragRadixTree(&s->cgroups, 1, defragStreamConsumerGroup, NULL); defragRadixTree(&s->cgroups, 1, defragStreamConsumerGroup, NULL);
return defragged;
} }
/* Defrag a module key. This is either done immediately or scheduled /* Defrag a module key. This is either done immediately or scheduled
* for later. Returns then number of pointers defragged. * for later. Returns then number of pointers defragged.
*/ */
long defragModule(redisDb *db, dictEntry *kde) { void defragModule(redisDb *db, dictEntry *kde) {
robj *obj = dictGetVal(kde); robj *obj = dictGetVal(kde);
serverAssert(obj->type == OBJ_MODULE); serverAssert(obj->type == OBJ_MODULE);
long defragged = 0;
if (!moduleDefragValue(dictGetKey(kde), obj, &defragged, db->id)) if (!moduleDefragValue(dictGetKey(kde), obj, db->id))
defragLater(db, kde); defragLater(db, kde);
return defragged;
} }
/* for each key we scan in the main dict, this function will attempt to defrag /* for each key we scan in the main dict, this function will attempt to defrag
* all the various pointers it has. Returns a stat of how many pointers were * all the various pointers it has. Returns a stat of how many pointers were
* moved. */ * moved. */
long defragKey(redisDb *db, dictEntry *de) { void defragKey(redisDb *db, dictEntry *de) {
sds keysds = dictGetKey(de); sds keysds = dictGetKey(de);
robj *newob, *ob; robj *newob, *ob;
unsigned char *newzl; unsigned char *newzl;
long defragged = 0;
sds newsds; sds newsds;
/* Try to defrag the key name. */ /* Try to defrag the key name. */
newsds = activeDefragSds(keysds); newsds = activeDefragSds(keysds);
if (newsds) { if (newsds) {
defragged++;
dictSetKey(db->dict, de, newsds); dictSetKey(db->dict, de, newsds);
if (dictSize(db->expires)) { if (dictSize(db->expires)) {
/* We can't search in db->expires for that key after we've released /* We can't search in db->expires for that key after we've released
@ -765,7 +722,7 @@ long defragKey(redisDb *db, dictEntry *de) {
/* Try to defrag robj and / or string value. */ /* Try to defrag robj and / or string value. */
ob = dictGetVal(de); ob = dictGetVal(de);
if ((newob = activeDefragStringOb(ob, &defragged))) { if ((newob = activeDefragStringOb(ob))) {
dictSetVal(db->dict, de, newob); dictSetVal(db->dict, de, newob);
ob = newob; ob = newob;
} }
@ -774,58 +731,57 @@ long defragKey(redisDb *db, dictEntry *de) {
/* Already handled in activeDefragStringOb. */ /* Already handled in activeDefragStringOb. */
} else if (ob->type == OBJ_LIST) { } else if (ob->type == OBJ_LIST) {
if (ob->encoding == OBJ_ENCODING_QUICKLIST) { if (ob->encoding == OBJ_ENCODING_QUICKLIST) {
defragged += defragQuicklist(db, de); defragQuicklist(db, de);
} else if (ob->encoding == OBJ_ENCODING_LISTPACK) { } else if (ob->encoding == OBJ_ENCODING_LISTPACK) {
if ((newzl = activeDefragAlloc(ob->ptr))) if ((newzl = activeDefragAlloc(ob->ptr)))
defragged++, ob->ptr = newzl; ob->ptr = newzl;
} else { } else {
serverPanic("Unknown list encoding"); serverPanic("Unknown list encoding");
} }
} else if (ob->type == OBJ_SET) { } else if (ob->type == OBJ_SET) {
if (ob->encoding == OBJ_ENCODING_HT) { if (ob->encoding == OBJ_ENCODING_HT) {
defragged += defragSet(db, de); defragSet(db, de);
} else if (ob->encoding == OBJ_ENCODING_INTSET || } else if (ob->encoding == OBJ_ENCODING_INTSET ||
ob->encoding == OBJ_ENCODING_LISTPACK) ob->encoding == OBJ_ENCODING_LISTPACK)
{ {
void *newptr, *ptr = ob->ptr; void *newptr, *ptr = ob->ptr;
if ((newptr = activeDefragAlloc(ptr))) if ((newptr = activeDefragAlloc(ptr)))
defragged++, ob->ptr = newptr; ob->ptr = newptr;
} else { } else {
serverPanic("Unknown set encoding"); serverPanic("Unknown set encoding");
} }
} else if (ob->type == OBJ_ZSET) { } else if (ob->type == OBJ_ZSET) {
if (ob->encoding == OBJ_ENCODING_LISTPACK) { if (ob->encoding == OBJ_ENCODING_LISTPACK) {
if ((newzl = activeDefragAlloc(ob->ptr))) if ((newzl = activeDefragAlloc(ob->ptr)))
defragged++, ob->ptr = newzl; ob->ptr = newzl;
} else if (ob->encoding == OBJ_ENCODING_SKIPLIST) { } else if (ob->encoding == OBJ_ENCODING_SKIPLIST) {
defragged += defragZsetSkiplist(db, de); defragZsetSkiplist(db, de);
} else { } else {
serverPanic("Unknown sorted set encoding"); serverPanic("Unknown sorted set encoding");
} }
} else if (ob->type == OBJ_HASH) { } else if (ob->type == OBJ_HASH) {
if (ob->encoding == OBJ_ENCODING_LISTPACK) { if (ob->encoding == OBJ_ENCODING_LISTPACK) {
if ((newzl = activeDefragAlloc(ob->ptr))) if ((newzl = activeDefragAlloc(ob->ptr)))
defragged++, ob->ptr = newzl; ob->ptr = newzl;
} else if (ob->encoding == OBJ_ENCODING_HT) { } else if (ob->encoding == OBJ_ENCODING_HT) {
defragged += defragHash(db, de); defragHash(db, de);
} else { } else {
serverPanic("Unknown hash encoding"); serverPanic("Unknown hash encoding");
} }
} else if (ob->type == OBJ_STREAM) { } else if (ob->type == OBJ_STREAM) {
defragged += defragStream(db, de); defragStream(db, de);
} else if (ob->type == OBJ_MODULE) { } else if (ob->type == OBJ_MODULE) {
defragged += defragModule(db, de); defragModule(db, de);
} else { } else {
serverPanic("Unknown object type"); serverPanic("Unknown object type");
} }
return defragged;
} }
/* Defrag scan callback for the main db dictionary. */ /* Defrag scan callback for the main db dictionary. */
void defragScanCallback(void *privdata, const dictEntry *de) { void defragScanCallback(void *privdata, const dictEntry *de) {
long defragged = defragKey((redisDb*)privdata, (dictEntry*)de); long long hits_before = server.stat_active_defrag_hits;
server.stat_active_defrag_hits += defragged; defragKey((redisDb*)privdata, (dictEntry*)de);
if(defragged) if (server.stat_active_defrag_hits != hits_before)
server.stat_active_defrag_key_hits++; server.stat_active_defrag_key_hits++;
else else
server.stat_active_defrag_key_misses++; server.stat_active_defrag_key_misses++;
@ -863,15 +819,13 @@ float getAllocatorFragmentation(size_t *out_frag_bytes) {
/* We may need to defrag other globals, one small allocation can hold a full allocator run. /* We may need to defrag other globals, one small allocation can hold a full allocator run.
* so although small, it is still important to defrag these */ * so although small, it is still important to defrag these */
long defragOtherGlobals() { void defragOtherGlobals() {
long defragged = 0;
/* there are many more pointers to defrag (e.g. client argv, output / aof buffers, etc. /* there are many more pointers to defrag (e.g. client argv, output / aof buffers, etc.
* but we assume most of these are short lived, we only need to defrag allocations * but we assume most of these are short lived, we only need to defrag allocations
* that remain static for a long time */ * that remain static for a long time */
defragged += activeDefragSdsDict(evalScriptsDict(), DEFRAG_SDS_DICT_VAL_LUA_SCRIPT); activeDefragSdsDict(evalScriptsDict(), DEFRAG_SDS_DICT_VAL_LUA_SCRIPT);
defragged += moduleDefragGlobals(); moduleDefragGlobals();
return defragged;
} }
/* returns 0 more work may or may not be needed (see non-zero cursor), /* returns 0 more work may or may not be needed (see non-zero cursor),
@ -880,17 +834,17 @@ int defragLaterItem(dictEntry *de, unsigned long *cursor, long long endtime, int
if (de) { if (de) {
robj *ob = dictGetVal(de); robj *ob = dictGetVal(de);
if (ob->type == OBJ_LIST) { if (ob->type == OBJ_LIST) {
return scanLaterList(ob, cursor, endtime, &server.stat_active_defrag_hits); return scanLaterList(ob, cursor, endtime);
} else if (ob->type == OBJ_SET) { } else if (ob->type == OBJ_SET) {
server.stat_active_defrag_hits += scanLaterSet(ob, cursor); scanLaterSet(ob, cursor);
} else if (ob->type == OBJ_ZSET) { } else if (ob->type == OBJ_ZSET) {
server.stat_active_defrag_hits += scanLaterZset(ob, cursor); scanLaterZset(ob, cursor);
} else if (ob->type == OBJ_HASH) { } else if (ob->type == OBJ_HASH) {
server.stat_active_defrag_hits += scanLaterHash(ob, cursor); scanLaterHash(ob, cursor);
} else if (ob->type == OBJ_STREAM) { } else if (ob->type == OBJ_STREAM) {
return scanLaterStreamListpacks(ob, cursor, endtime, &server.stat_active_defrag_hits); return scanLaterStreamListpacks(ob, cursor, endtime);
} else if (ob->type == OBJ_MODULE) { } else if (ob->type == OBJ_MODULE) {
return moduleLateDefrag(dictGetKey(de), ob, cursor, endtime, &server.stat_active_defrag_hits, dbid); return moduleLateDefrag(dictGetKey(de), ob, cursor, endtime, dbid);
} else { } else {
*cursor = 0; /* object type may have changed since we schedule it for later */ *cursor = 0; /* object type may have changed since we schedule it for later */
} }
@ -1061,7 +1015,7 @@ void activeDefragCycle(void) {
/* Move on to next database, and stop if we reached the last one. */ /* Move on to next database, and stop if we reached the last one. */
if (++current_db >= server.dbnum) { if (++current_db >= server.dbnum) {
/* defrag other items not part of the db / keys */ /* defrag other items not part of the db / keys */
server.stat_active_defrag_hits += defragOtherGlobals(); defragOtherGlobals();
long long now = ustime(); long long now = ustime();
size_t frag_bytes; size_t frag_bytes;
@ -1100,19 +1054,14 @@ void activeDefragCycle(void) {
/* Scan the keyspace dict unless we're scanning the expire dict. */ /* Scan the keyspace dict unless we're scanning the expire dict. */
if (!expires_cursor) if (!expires_cursor)
cursor = dictScanDefrag(db->dict, cursor = dictScanDefrag(db->dict, cursor, defragScanCallback,
cursor, activeDefragAlloc, db);
defragScanCallback,
activeDefragAlloc,
db);
/* When done scanning the keyspace dict, we scan the expire dict. */ /* When done scanning the keyspace dict, we scan the expire dict. */
if (!cursor) if (!cursor)
expires_cursor = dictScanDefrag(db->expires, expires_cursor = dictScanDefrag(db->expires, expires_cursor,
expires_cursor,
defragExpireScanCallback, defragExpireScanCallback,
activeDefragAlloc, activeDefragAlloc, NULL);
NULL);
/* Once in 16 scan iterations, 512 pointer reallocations. or 64 keys /* Once in 16 scan iterations, 512 pointer reallocations. or 64 keys
* (if we have a lot of pointers in one hash bucket or rehashing), * (if we have a lot of pointers in one hash bucket or rehashing),
@ -1159,9 +1108,8 @@ void *activeDefragAlloc(void *ptr) {
return NULL; return NULL;
} }
robj *activeDefragStringOb(robj *ob, long *defragged) { robj *activeDefragStringOb(robj *ob) {
UNUSED(ob); UNUSED(ob);
UNUSED(defragged);
return NULL; return NULL;
} }

View File

@ -12562,7 +12562,6 @@ const char *RM_GetCurrentCommandName(RedisModuleCtx *ctx) {
* defrag callback. * defrag callback.
*/ */
struct RedisModuleDefragCtx { struct RedisModuleDefragCtx {
long defragged;
long long int endtime; long long int endtime;
unsigned long *cursor; unsigned long *cursor;
struct redisObject *key; /* Optional name of key processed, NULL when unknown. */ struct redisObject *key; /* Optional name of key processed, NULL when unknown. */
@ -12651,11 +12650,8 @@ int RM_DefragCursorGet(RedisModuleDefragCtx *ctx, unsigned long *cursor) {
* be used again. * be used again.
*/ */
void *RM_DefragAlloc(RedisModuleDefragCtx *ctx, void *ptr) { void *RM_DefragAlloc(RedisModuleDefragCtx *ctx, void *ptr) {
void *newptr = activeDefragAlloc(ptr); UNUSED(ctx);
if (newptr) return activeDefragAlloc(ptr);
ctx->defragged++;
return newptr;
} }
/* Defrag a RedisModuleString previously allocated by RM_Alloc, RM_Calloc, etc. /* Defrag a RedisModuleString previously allocated by RM_Alloc, RM_Calloc, etc.
@ -12669,7 +12665,8 @@ void *RM_DefragAlloc(RedisModuleDefragCtx *ctx, void *ptr) {
* on the Redis side is dropped as soon as the command callback returns). * on the Redis side is dropped as soon as the command callback returns).
*/ */
RedisModuleString *RM_DefragRedisModuleString(RedisModuleDefragCtx *ctx, RedisModuleString *str) { RedisModuleString *RM_DefragRedisModuleString(RedisModuleDefragCtx *ctx, RedisModuleString *str) {
return activeDefragStringOb(str, &ctx->defragged); UNUSED(ctx);
return activeDefragStringOb(str);
} }
@ -12678,11 +12675,11 @@ RedisModuleString *RM_DefragRedisModuleString(RedisModuleDefragCtx *ctx, RedisMo
* Returns a zero value (and initializes the cursor) if no more needs to be done, * Returns a zero value (and initializes the cursor) if no more needs to be done,
* or a non-zero value otherwise. * or a non-zero value otherwise.
*/ */
int moduleLateDefrag(robj *key, robj *value, unsigned long *cursor, long long endtime, long long *defragged, int dbid) { int moduleLateDefrag(robj *key, robj *value, unsigned long *cursor, long long endtime, int dbid) {
moduleValue *mv = value->ptr; moduleValue *mv = value->ptr;
moduleType *mt = mv->type; moduleType *mt = mv->type;
RedisModuleDefragCtx defrag_ctx = { 0, endtime, cursor, key, dbid}; RedisModuleDefragCtx defrag_ctx = { endtime, cursor, key, dbid};
/* Invoke callback. Note that the callback may be missing if the key has been /* Invoke callback. Note that the callback may be missing if the key has been
* replaced with a different type since our last visit. * replaced with a different type since our last visit.
@ -12691,7 +12688,6 @@ int moduleLateDefrag(robj *key, robj *value, unsigned long *cursor, long long en
if (mt->defrag) if (mt->defrag)
ret = mt->defrag(&defrag_ctx, key, &mv->value); ret = mt->defrag(&defrag_ctx, key, &mv->value);
*defragged += defrag_ctx.defragged;
if (!ret) { if (!ret) {
*cursor = 0; /* No more work to do */ *cursor = 0; /* No more work to do */
return 0; return 0;
@ -12706,7 +12702,7 @@ int moduleLateDefrag(robj *key, robj *value, unsigned long *cursor, long long en
* Returns 1 if the operation has been completed or 0 if it needs to * Returns 1 if the operation has been completed or 0 if it needs to
* be scheduled for late defrag. * be scheduled for late defrag.
*/ */
int moduleDefragValue(robj *key, robj *value, long *defragged, int dbid) { int moduleDefragValue(robj *key, robj *value, int dbid) {
moduleValue *mv = value->ptr; moduleValue *mv = value->ptr;
moduleType *mt = mv->type; moduleType *mt = mv->type;
@ -12715,7 +12711,6 @@ int moduleDefragValue(robj *key, robj *value, long *defragged, int dbid) {
*/ */
moduleValue *newmv = activeDefragAlloc(mv); moduleValue *newmv = activeDefragAlloc(mv);
if (newmv) { if (newmv) {
(*defragged)++;
value->ptr = mv = newmv; value->ptr = mv = newmv;
} }
@ -12733,29 +12728,24 @@ int moduleDefragValue(robj *key, robj *value, long *defragged, int dbid) {
return 0; /* Defrag later */ return 0; /* Defrag later */
} }
RedisModuleDefragCtx defrag_ctx = { 0, 0, NULL, key, dbid}; RedisModuleDefragCtx defrag_ctx = { 0, NULL, key, dbid };
mt->defrag(&defrag_ctx, key, &mv->value); mt->defrag(&defrag_ctx, key, &mv->value);
(*defragged) += defrag_ctx.defragged;
return 1; return 1;
} }
/* Call registered module API defrag functions */ /* Call registered module API defrag functions */
long moduleDefragGlobals(void) { void moduleDefragGlobals(void) {
dictIterator *di = dictGetIterator(modules); dictIterator *di = dictGetIterator(modules);
dictEntry *de; dictEntry *de;
long defragged = 0;
while ((de = dictNext(di)) != NULL) { while ((de = dictNext(di)) != NULL) {
struct RedisModule *module = dictGetVal(de); struct RedisModule *module = dictGetVal(de);
if (!module->defrag_cb) if (!module->defrag_cb)
continue; continue;
RedisModuleDefragCtx defrag_ctx = { 0, 0, NULL, NULL, -1}; RedisModuleDefragCtx defrag_ctx = { 0, NULL, NULL, -1};
module->defrag_cb(&defrag_ctx); module->defrag_cb(&defrag_ctx);
defragged += defrag_ctx.defragged;
} }
dictReleaseIterator(di); dictReleaseIterator(di);
return defragged;
} }
/* Returns the name of the key currently being processed. /* Returns the name of the key currently being processed.

View File

@ -2442,9 +2442,9 @@ void moduleNotifyKeyUnlink(robj *key, robj *val, int dbid, int flags);
size_t moduleGetFreeEffort(robj *key, robj *val, int dbid); size_t moduleGetFreeEffort(robj *key, robj *val, int dbid);
size_t moduleGetMemUsage(robj *key, robj *val, size_t sample_size, int dbid); size_t moduleGetMemUsage(robj *key, robj *val, size_t sample_size, int dbid);
robj *moduleTypeDupOrReply(client *c, robj *fromkey, robj *tokey, int todb, robj *value); robj *moduleTypeDupOrReply(client *c, robj *fromkey, robj *tokey, int todb, robj *value);
int moduleDefragValue(robj *key, robj *obj, long *defragged, int dbid); int moduleDefragValue(robj *key, robj *obj, int dbid);
int moduleLateDefrag(robj *key, robj *value, unsigned long *cursor, long long endtime, long long *defragged, int dbid); int moduleLateDefrag(robj *key, robj *value, unsigned long *cursor, long long endtime, int dbid);
long moduleDefragGlobals(void); void moduleDefragGlobals(void);
void *moduleGetHandleByName(char *modulename); void *moduleGetHandleByName(char *modulename);
int moduleIsModuleCommand(void *module_handle, struct redisCommand *cmd); int moduleIsModuleCommand(void *module_handle, struct redisCommand *cmd);
@ -2988,7 +2988,7 @@ void checkChildrenDone(void);
int setOOMScoreAdj(int process_class); int setOOMScoreAdj(int process_class);
void rejectCommandFormat(client *c, const char *fmt, ...); void rejectCommandFormat(client *c, const char *fmt, ...);
void *activeDefragAlloc(void *ptr); void *activeDefragAlloc(void *ptr);
robj *activeDefragStringOb(robj* ob, long *defragged); robj *activeDefragStringOb(robj* ob);
void dismissSds(sds s); void dismissSds(sds s);
void dismissMemory(void* ptr, size_t size_hint); void dismissMemory(void* ptr, size_t size_hint);
void dismissMemoryInChild(void); void dismissMemoryInChild(void);