关键词搜索

源码搜索 ×
×

漫话Redis源码之六十六

发布2022-01-23浏览547次

详情内容

这里主要是generic分配,功能比较直白。

  1. /* Defrag helper for generic allocations.
  2. *
  3. * returns NULL in case the allocation wasn't moved.
  4. * when it returns a non-null value, the old pointer was already released
  5. * and should NOT be accessed. */
  6. void* activeDefragAlloc(void *ptr) {
  7. size_t size;
  8. void *newptr;
  9. if(!je_get_defrag_hint(ptr)) {
  10. server.stat_active_defrag_misses++;
  11. return NULL;
  12. }
  13. /* move this allocation to a new allocation.
  14. * make sure not to use the thread cache. so that we don't get back the same
  15. * pointers we try to free */
  16. size = zmalloc_size(ptr);
  17. newptr = zmalloc_no_tcache(size);
  18. memcpy(newptr, ptr, size);
  19. zfree_no_tcache(ptr);
  20. return newptr;
  21. }
  22. /*Defrag helper for sds strings
  23. *
  24. * returns NULL in case the allocation wasn't moved.
  25. * when it returns a non-null value, the old pointer was already released
  26. * and should NOT be accessed. */
  27. sds activeDefragSds(sds sdsptr) {
  28. void* ptr = sdsAllocPtr(sdsptr);
  29. void* newptr = activeDefragAlloc(ptr);
  30. if (newptr) {
  31. size_t offset = sdsptr - (char*)ptr;
  32. sdsptr = (char*)newptr + offset;
  33. return sdsptr;
  34. }
  35. return NULL;
  36. }
  37. /* Defrag helper for robj and/or string objects
  38. *
  39. * returns NULL in case the allocation wasn't moved.
  40. * when it returns a non-null value, the old pointer was already released
  41. * and should NOT be accessed. */
  42. robj *activeDefragStringOb(robj* ob, long *defragged) {
  43. robj *ret = NULL;
  44. if (ob->refcount!=1)
  45. return NULL;
  46. /* try to defrag robj (only if not an EMBSTR type (handled below). */
  47. if (ob->type!=OBJ_STRING || ob->encoding!=OBJ_ENCODING_EMBSTR) {
  48. if ((ret = activeDefragAlloc(ob))) {
  49. ob = ret;
  50. (*defragged)++;
  51. }
  52. }
  53. /* try to defrag string object */
  54. if (ob->type == OBJ_STRING) {
  55. if(ob->encoding==OBJ_ENCODING_RAW) {
  56. sds newsds = activeDefragSds((sds)ob->ptr);
  57. if (newsds) {
  58. ob->ptr = newsds;
  59. (*defragged)++;
  60. }
  61. } else if (ob->encoding==OBJ_ENCODING_EMBSTR) {
  62. /* The sds is embedded in the object allocation, calculate the
  63. * offset and update the pointer in the new allocation. */
  64. long ofs = (intptr_t)ob->ptr - (intptr_t)ob;
  65. if ((ret = activeDefragAlloc(ob))) {
  66. ret->ptr = (void*)((intptr_t)ret + ofs);
  67. (*defragged)++;
  68. }
  69. } else if (ob->encoding!=OBJ_ENCODING_INT) {
  70. serverPanic("Unknown string encoding");
  71. }
  72. }
  73. return ret;
  74. }
  75. /* Defrag helper for dictEntries to be used during dict iteration (called on
  76. * each step). Returns a stat of how many pointers were moved. */
  77. long dictIterDefragEntry(dictIterator *iter) {
  78. /* This function is a little bit dirty since it messes with the internals
  79. * of the dict and it's iterator, but the benefit is that it is very easy
  80. * to use, and require no other changes in the dict. */
  81. long defragged = 0;
  82. dictht *ht;
  83. /* Handle the next entry (if there is one), and update the pointer in the
  84. * current entry. */
  85. if (iter->nextEntry) {
  86. dictEntry *newde = activeDefragAlloc(iter->nextEntry);
  87. if (newde) {
  88. defragged++;
  89. iter->nextEntry = newde;
  90. iter->entry->next = newde;
  91. }
  92. }
  93. /* handle the case of the first entry in the hash bucket. */
  94. ht = &iter->d->ht[iter->table];
  95. if (ht->table[iter->index] == iter->entry) {
  96. dictEntry *newde = activeDefragAlloc(iter->entry);
  97. if (newde) {
  98. iter->entry = newde;
  99. ht->table[iter->index] = newde;
  100. defragged++;
  101. }
  102. }
  103. return defragged;
  104. }
  105. /* Defrag helper for dict main allocations (dict struct, and hash tables).
  106. * receives a pointer to the dict* and implicitly updates it when the dict
  107. * struct itself was moved. Returns a stat of how many pointers were moved. */
  108. long dictDefragTables(dict* d) {
  109. dictEntry **newtable;
  110. long defragged = 0;
  111. /* handle the first hash table */
  112. newtable = activeDefragAlloc(d->ht[0].table);
  113. if (newtable)
  114. defragged++, d->ht[0].table = newtable;
  115. /* handle the second hash table */
  116. if (d->ht[1].table) {
  117. newtable = activeDefragAlloc(d->ht[1].table);
  118. if (newtable)
  119. defragged++, d->ht[1].table = newtable;
  120. }
  121. return defragged;
  122. }
  123. /* Internal function used by zslDefrag */
  124. void zslUpdateNode(zskiplist *zsl, zskiplistNode *oldnode, zskiplistNode *newnode, zskiplistNode **update) {
  125. int i;
  126. for (i = 0; i < zsl->level; i++) {
  127. if (update[i]->level[i].forward == oldnode)
  128. update[i]->level[i].forward = newnode;
  129. }
  130. serverAssert(zsl->header!=oldnode);
  131. if (newnode->level[0].forward) {
  132. serverAssert(newnode->level[0].forward->backward==oldnode);
  133. newnode->level[0].forward->backward = newnode;
  134. } else {
  135. serverAssert(zsl->tail==oldnode);
  136. zsl->tail = newnode;
  137. }
  138. }
  139. /* Defrag helper for sorted set.
  140. * Update the robj pointer, defrag the skiplist struct and return the new score
  141. * reference. We may not access oldele pointer (not even the pointer stored in
  142. * the skiplist), as it was already freed. Newele may be null, in which case we
  143. * only need to defrag the skiplist, but not update the obj pointer.
  144. * When return value is non-NULL, it is the score reference that must be updated
  145. * in the dict record. */
  146. double *zslDefrag(zskiplist *zsl, double score, sds oldele, sds newele) {
  147. zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x, *newx;
  148. int i;
  149. sds ele = newele? newele: oldele;
  150. /* find the skiplist node referring to the object that was moved,
  151. * and all pointers that need to be updated if we'll end up moving the skiplist node. */
  152. x = zsl->header;
  153. for (i = zsl->level-1; i >= 0; i--) {
  154. while (x->level[i].forward &&
  155. x->level[i].forward->ele != oldele && /* make sure not to access the
  156. ->obj pointer if it matches
  157. oldele */
  158. (x->level[i].forward->score < score ||
  159. (x->level[i].forward->score == score &&
  160. sdscmp(x->level[i].forward->ele,ele) < 0)))
  161. x = x->level[i].forward;
  162. update[i] = x;
  163. }
  164. /* update the robj pointer inside the skip list record. */
  165. x = x->level[0].forward;
  166. serverAssert(x && score == x->score && x->ele==oldele);
  167. if (newele)
  168. x->ele = newele;
  169. /* try to defrag the skiplist record itself */
  170. newx = activeDefragAlloc(x);
  171. if (newx) {
  172. zslUpdateNode(zsl, x, newx, update);
  173. return &newx->score;
  174. }
  175. return NULL;
  176. }
  177. /* Defrag helper for sorted set.
  178. * Defrag a single dict entry key name, and corresponding skiplist struct */
  179. long activeDefragZsetEntry(zset *zs, dictEntry *de) {
  180. sds newsds;
  181. double* newscore;
  182. long defragged = 0;
  183. sds sdsele = dictGetKey(de);
  184. if ((newsds = activeDefragSds(sdsele)))
  185. defragged++, de->key = newsds;
  186. newscore = zslDefrag(zs->zsl, *(double*)dictGetVal(de), sdsele, newsds);
  187. if (newscore) {
  188. dictSetVal(zs->dict, de, newscore);
  189. defragged++;
  190. }
  191. return defragged;
  192. }
  193. #define DEFRAG_SDS_DICT_NO_VAL 0
  194. #define DEFRAG_SDS_DICT_VAL_IS_SDS 1
  195. #define DEFRAG_SDS_DICT_VAL_IS_STROB 2
  196. #define DEFRAG_SDS_DICT_VAL_VOID_PTR 3
  197. /* Defrag a dict with sds key and optional value (either ptr, sds or robj string) */
  198. long activeDefragSdsDict(dict* d, int val_type) {
  199. dictIterator *di;
  200. dictEntry *de;
  201. long defragged = 0;
  202. di = dictGetIterator(d);
  203. while((de = dictNext(di)) != NULL) {
  204. sds sdsele = dictGetKey(de), newsds;
  205. if ((newsds = activeDefragSds(sdsele)))
  206. de->key = newsds, defragged++;
  207. /* defrag the value */
  208. if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
  209. sdsele = dictGetVal(de);
  210. if ((newsds = activeDefragSds(sdsele)))
  211. de->v.val = newsds, defragged++;
  212. } else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
  213. robj *newele, *ele = dictGetVal(de);
  214. if ((newele = activeDefragStringOb(ele, &defragged)))
  215. de->v.val = newele;
  216. } else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
  217. void *newptr, *ptr = dictGetVal(de);
  218. if ((newptr = activeDefragAlloc(ptr)))
  219. de->v.val = newptr, defragged++;
  220. }
  221. defragged += dictIterDefragEntry(di);
  222. }
  223. dictReleaseIterator(di);
  224. return defragged;
  225. }
  226. /* Defrag a list of ptr, sds or robj string values */
  227. long activeDefragList(list *l, int val_type) {
  228. long defragged = 0;
  229. listNode *ln, *newln;
  230. for (ln = l->head; ln; ln = ln->next) {
  231. if ((newln = activeDefragAlloc(ln))) {
  232. if (newln->prev)
  233. newln->prev->next = newln;
  234. else
  235. l->head = newln;
  236. if (newln->next)
  237. newln->next->prev = newln;
  238. else
  239. l->tail = newln;
  240. ln = newln;
  241. defragged++;
  242. }
  243. if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
  244. sds newsds, sdsele = ln->value;
  245. if ((newsds = activeDefragSds(sdsele)))
  246. ln->value = newsds, defragged++;
  247. } else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
  248. robj *newele, *ele = ln->value;
  249. if ((newele = activeDefragStringOb(ele, &defragged)))
  250. ln->value = newele;
  251. } else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
  252. void *newptr, *ptr = ln->value;
  253. if ((newptr = activeDefragAlloc(ptr)))
  254. ln->value = newptr, defragged++;
  255. }
  256. }
  257. return defragged;
  258. }

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载