这里主要是generic分配,功能比较直白。
/* Defrag helper for generic allocations. * * returns NULL in case the allocation wasn't moved. * when it returns a non-null value, the old pointer was already released * and should NOT be accessed. */ void* activeDefragAlloc(void *ptr) { size_t size; void *newptr; if(!je_get_defrag_hint(ptr)) { server.stat_active_defrag_misses++; return NULL; } /* move this allocation to a new allocation. * make sure not to use the thread cache. so that we don't get back the same * pointers we try to free */ size = zmalloc_size(ptr); newptr = zmalloc_no_tcache(size); memcpy(newptr, ptr, size); zfree_no_tcache(ptr); return newptr; } /*Defrag helper for sds strings * * returns NULL in case the allocation wasn't moved. * when it returns a non-null value, the old pointer was already released * and should NOT be accessed. */ sds activeDefragSds(sds sdsptr) { void* ptr = sdsAllocPtr(sdsptr); void* newptr = activeDefragAlloc(ptr); if (newptr) { size_t offset = sdsptr - (char*)ptr; sdsptr = (char*)newptr + offset; return sdsptr; } return NULL; } /* Defrag helper for robj and/or string objects * * returns NULL in case the allocation wasn't moved. * when it returns a non-null value, the old pointer was already released * and should NOT be accessed. */ robj *activeDefragStringOb(robj* ob, long *defragged) { robj *ret = NULL; if (ob->refcount!=1) return NULL; /* try to defrag robj (only if not an EMBSTR type (handled below). */ if (ob->type!=OBJ_STRING || ob->encoding!=OBJ_ENCODING_EMBSTR) { if ((ret = activeDefragAlloc(ob))) { ob = ret; (*defragged)++; } } /* try to defrag string object */ if (ob->type == OBJ_STRING) { if(ob->encoding==OBJ_ENCODING_RAW) { sds newsds = activeDefragSds((sds)ob->ptr); if (newsds) { ob->ptr = newsds; (*defragged)++; } } else if (ob->encoding==OBJ_ENCODING_EMBSTR) { /* The sds is embedded in the object allocation, calculate the * offset and update the pointer in the new allocation. */ long ofs = (intptr_t)ob->ptr - (intptr_t)ob; if ((ret = activeDefragAlloc(ob))) { ret->ptr = (void*)((intptr_t)ret + ofs); (*defragged)++; } } else if (ob->encoding!=OBJ_ENCODING_INT) { serverPanic("Unknown string encoding"); } } return ret; } /* Defrag helper for dictEntries to be used during dict iteration (called on * each step). Returns a stat of how many pointers were moved. */ long dictIterDefragEntry(dictIterator *iter) { /* This function is a little bit dirty since it messes with the internals * of the dict and it's iterator, but the benefit is that it is very easy * to use, and require no other changes in the dict. */ long defragged = 0; dictht *ht; /* Handle the next entry (if there is one), and update the pointer in the * current entry. */ if (iter->nextEntry) { dictEntry *newde = activeDefragAlloc(iter->nextEntry); if (newde) { defragged++; iter->nextEntry = newde; iter->entry->next = newde; } } /* handle the case of the first entry in the hash bucket. */ ht = &iter->d->ht[iter->table]; if (ht->table[iter->index] == iter->entry) { dictEntry *newde = activeDefragAlloc(iter->entry); if (newde) { iter->entry = newde; ht->table[iter->index] = newde; defragged++; } } return defragged; } /* Defrag helper for dict main allocations (dict struct, and hash tables). * 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. */ long dictDefragTables(dict* d) { dictEntry **newtable; long defragged = 0; /* handle the first hash table */ newtable = activeDefragAlloc(d->ht[0].table); if (newtable) defragged++, d->ht[0].table = newtable; /* handle the second hash table */ if (d->ht[1].table) { newtable = activeDefragAlloc(d->ht[1].table); if (newtable) defragged++, d->ht[1].table = newtable; } return defragged; } /* Internal function used by zslDefrag */ void zslUpdateNode(zskiplist *zsl, zskiplistNode *oldnode, zskiplistNode *newnode, zskiplistNode **update) { int i; for (i = 0; i < zsl->level; i++) { if (update[i]->level[i].forward == oldnode) update[i]->level[i].forward = newnode; } serverAssert(zsl->header!=oldnode); if (newnode->level[0].forward) { serverAssert(newnode->level[0].forward->backward==oldnode); newnode->level[0].forward->backward = newnode; } else { serverAssert(zsl->tail==oldnode); zsl->tail = newnode; } } /* Defrag helper for sorted set. * Update the robj pointer, defrag the skiplist struct and return the new score * reference. We may not access oldele pointer (not even the pointer stored in * the skiplist), as it was already freed. Newele may be null, in which case we * only need to defrag the skiplist, but not update the obj pointer. * When return value is non-NULL, it is the score reference that must be updated * in the dict record. */ double *zslDefrag(zskiplist *zsl, double score, sds oldele, sds newele) { zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x, *newx; int i; sds ele = newele? newele: oldele; /* find the skiplist node referring to the object that was moved, * and all pointers that need to be updated if we'll end up moving the skiplist node. */ x = zsl->header; for (i = zsl->level-1; i >= 0; i--) { while (x->level[i].forward && x->level[i].forward->ele != oldele && /* make sure not to access the ->obj pointer if it matches oldele */ (x->level[i].forward->score < score || (x->level[i].forward->score == score && sdscmp(x->level[i].forward->ele,ele) < 0))) x = x->level[i].forward; update[i] = x; } /* update the robj pointer inside the skip list record. */ x = x->level[0].forward; serverAssert(x && score == x->score && x->ele==oldele); if (newele) x->ele = newele; /* try to defrag the skiplist record itself */ newx = activeDefragAlloc(x); if (newx) { zslUpdateNode(zsl, x, newx, update); return &newx->score; } return NULL; } /* Defrag helper for sorted set. * Defrag a single dict entry key name, and corresponding skiplist struct */ long activeDefragZsetEntry(zset *zs, dictEntry *de) { sds newsds; double* newscore; long defragged = 0; sds sdsele = dictGetKey(de); if ((newsds = activeDefragSds(sdsele))) defragged++, de->key = newsds; newscore = zslDefrag(zs->zsl, *(double*)dictGetVal(de), sdsele, newsds); if (newscore) { dictSetVal(zs->dict, de, newscore); defragged++; } return defragged; } #define DEFRAG_SDS_DICT_NO_VAL 0 #define DEFRAG_SDS_DICT_VAL_IS_SDS 1 #define DEFRAG_SDS_DICT_VAL_IS_STROB 2 #define DEFRAG_SDS_DICT_VAL_VOID_PTR 3 /* Defrag a dict with sds key and optional value (either ptr, sds or robj string) */ long activeDefragSdsDict(dict* d, int val_type) { dictIterator *di; dictEntry *de; long defragged = 0; di = dictGetIterator(d); while((de = dictNext(di)) != NULL) { sds sdsele = dictGetKey(de), newsds; if ((newsds = activeDefragSds(sdsele))) de->key = newsds, defragged++; /* defrag the value */ if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) { sdsele = dictGetVal(de); if ((newsds = activeDefragSds(sdsele))) de->v.val = newsds, defragged++; } else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) { robj *newele, *ele = dictGetVal(de); if ((newele = activeDefragStringOb(ele, &defragged))) de->v.val = newele; } else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) { void *newptr, *ptr = dictGetVal(de); if ((newptr = activeDefragAlloc(ptr))) de->v.val = newptr, defragged++; } defragged += dictIterDefragEntry(di); } dictReleaseIterator(di); return defragged; } /* Defrag a list of ptr, sds or robj string values */ long activeDefragList(list *l, int val_type) { long defragged = 0; listNode *ln, *newln; for (ln = l->head; ln; ln = ln->next) { if ((newln = activeDefragAlloc(ln))) { if (newln->prev) newln->prev->next = newln; else l->head = newln; if (newln->next) newln->next->prev = newln; else l->tail = newln; ln = newln; defragged++; } if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) { sds newsds, sdsele = ln->value; if ((newsds = activeDefragSds(sdsele))) ln->value = newsds, defragged++; } else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) { robj *newele, *ele = ln->value; if ((newele = activeDefragStringOb(ele, &defragged))) ln->value = newele; } else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) { void *newptr, *ptr = ln->value; if ((newptr = activeDefragAlloc(ptr))) ln->value = newptr, defragged++; } } return defragged; }