这里主要是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;
- }