关键词搜索

源码搜索 ×
×

漫话Redis源码之六十七

发布2022-01-23浏览562次

详情内容

这里主要是摘要算法,我曾写过md5sum, sha, 虽然不懂数学原理。

  1. void xorStringObjectDigest(unsigned char *digest, robj *o) {
  2. o = getDecodedObject(o);
  3. xorDigest(digest,o->ptr,sdslen(o->ptr));
  4. decrRefCount(o);
  5. }
  6. /* This function instead of just computing the SHA1 and xoring it
  7. * against digest, also perform the digest of "digest" itself and
  8. * replace the old value with the new one.
  9. *
  10. * So the final digest will be:
  11. *
  12. * digest = SHA1(digest xor SHA1(data))
  13. *
  14. * This function is used every time we want to preserve the order so
  15. * that digest(a,b,c,d) will be different than digest(b,c,d,a)
  16. *
  17. * Also note that mixdigest("foo") followed by mixdigest("bar")
  18. * will lead to a different digest compared to "fo", "obar".
  19. */
  20. void mixDigest(unsigned char *digest, void *ptr, size_t len) {
  21. SHA1_CTX ctx;
  22. char *s = ptr;
  23. xorDigest(digest,s,len);
  24. SHA1Init(&ctx);
  25. SHA1Update(&ctx,digest,20);
  26. SHA1Final(digest,&ctx);
  27. }
  28. void mixStringObjectDigest(unsigned char *digest, robj *o) {
  29. o = getDecodedObject(o);
  30. mixDigest(digest,o->ptr,sdslen(o->ptr));
  31. decrRefCount(o);
  32. }
  33. /* This function computes the digest of a data structure stored in the
  34. * object 'o'. It is the core of the DEBUG DIGEST command: when taking the
  35. * digest of a whole dataset, we take the digest of the key and the value
  36. * pair, and xor all those together.
  37. *
  38. * Note that this function does not reset the initial 'digest' passed, it
  39. * will continue mixing this object digest to anything that was already
  40. * present. */
  41. void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o) {
  42. uint32_t aux = htonl(o->type);
  43. mixDigest(digest,&aux,sizeof(aux));
  44. long long expiretime = getExpire(db,keyobj);
  45. char buf[128];
  46. /* Save the key and associated value */
  47. if (o->type == OBJ_STRING) {
  48. mixStringObjectDigest(digest,o);
  49. } else if (o->type == OBJ_LIST) {
  50. listTypeIterator *li = listTypeInitIterator(o,0,LIST_TAIL);
  51. listTypeEntry entry;
  52. while(listTypeNext(li,&entry)) {
  53. robj *eleobj = listTypeGet(&entry);
  54. mixStringObjectDigest(digest,eleobj);
  55. decrRefCount(eleobj);
  56. }
  57. listTypeReleaseIterator(li);
  58. } else if (o->type == OBJ_SET) {
  59. setTypeIterator *si = setTypeInitIterator(o);
  60. sds sdsele;
  61. while((sdsele = setTypeNextObject(si)) != NULL) {
  62. xorDigest(digest,sdsele,sdslen(sdsele));
  63. sdsfree(sdsele);
  64. }
  65. setTypeReleaseIterator(si);
  66. } else if (o->type == OBJ_ZSET) {
  67. unsigned char eledigest[20];
  68. if (o->encoding == OBJ_ENCODING_ZIPLIST) {
  69. unsigned char *zl = o->ptr;
  70. unsigned char *eptr, *sptr;
  71. unsigned char *vstr;
  72. unsigned int vlen;
  73. long long vll;
  74. double score;
  75. eptr = ziplistIndex(zl,0);
  76. serverAssert(eptr != NULL);
  77. sptr = ziplistNext(zl,eptr);
  78. serverAssert(sptr != NULL);
  79. while (eptr != NULL) {
  80. serverAssert(ziplistGet(eptr,&vstr,&vlen,&vll));
  81. score = zzlGetScore(sptr);
  82. memset(eledigest,0,20);
  83. if (vstr != NULL) {
  84. mixDigest(eledigest,vstr,vlen);
  85. } else {
  86. ll2string(buf,sizeof(buf),vll);
  87. mixDigest(eledigest,buf,strlen(buf));
  88. }
  89. snprintf(buf,sizeof(buf),"%.17g",score);
  90. mixDigest(eledigest,buf,strlen(buf));
  91. xorDigest(digest,eledigest,20);
  92. zzlNext(zl,&eptr,&sptr);
  93. }
  94. } else if (o->encoding == OBJ_ENCODING_SKIPLIST) {
  95. zset *zs = o->ptr;
  96. dictIterator *di = dictGetIterator(zs->dict);
  97. dictEntry *de;
  98. while((de = dictNext(di)) != NULL) {
  99. sds sdsele = dictGetKey(de);
  100. double *score = dictGetVal(de);
  101. snprintf(buf,sizeof(buf),"%.17g",*score);
  102. memset(eledigest,0,20);
  103. mixDigest(eledigest,sdsele,sdslen(sdsele));
  104. mixDigest(eledigest,buf,strlen(buf));
  105. xorDigest(digest,eledigest,20);
  106. }
  107. dictReleaseIterator(di);
  108. } else {
  109. serverPanic("Unknown sorted set encoding");
  110. }
  111. } else if (o->type == OBJ_HASH) {
  112. hashTypeIterator *hi = hashTypeInitIterator(o);
  113. while (hashTypeNext(hi) != C_ERR) {
  114. unsigned char eledigest[20];
  115. sds sdsele;
  116. memset(eledigest,0,20);
  117. sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY);
  118. mixDigest(eledigest,sdsele,sdslen(sdsele));
  119. sdsfree(sdsele);
  120. sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE);
  121. mixDigest(eledigest,sdsele,sdslen(sdsele));
  122. sdsfree(sdsele);
  123. xorDigest(digest,eledigest,20);
  124. }
  125. hashTypeReleaseIterator(hi);
  126. } else if (o->type == OBJ_STREAM) {
  127. streamIterator si;
  128. streamIteratorStart(&si,o->ptr,NULL,NULL,0);
  129. streamID id;
  130. int64_t numfields;
  131. while(streamIteratorGetID(&si,&id,&numfields)) {
  132. sds itemid = sdscatfmt(sdsempty(),"%U.%U",id.ms,id.seq);
  133. mixDigest(digest,itemid,sdslen(itemid));
  134. sdsfree(itemid);
  135. while(numfields--) {
  136. unsigned char *field, *value;
  137. int64_t field_len, value_len;
  138. streamIteratorGetField(&si,&field,&value,
  139. &field_len,&value_len);
  140. mixDigest(digest,field,field_len);
  141. mixDigest(digest,value,value_len);
  142. }
  143. }
  144. streamIteratorStop(&si);
  145. } else if (o->type == OBJ_MODULE) {
  146. RedisModuleDigest md = {{0},{0}};
  147. moduleValue *mv = o->ptr;
  148. moduleType *mt = mv->type;
  149. moduleInitDigestContext(md);
  150. if (mt->digest) {
  151. mt->digest(&md,mv->value);
  152. xorDigest(digest,md.x,sizeof(md.x));
  153. }
  154. } else {
  155. serverPanic("Unknown object type");
  156. }
  157. /* If the key has an expire, add it to the mix */
  158. if (expiretime != -1) xorDigest(digest,"!!expire!!",10);
  159. }
  160. /* Compute the dataset digest. Since keys, sets elements, hashes elements
  161. * are not ordered, we use a trick: every aggregate digest is the xor
  162. * of the digests of their elements. This way the order will not change
  163. * the result. For list instead we use a feedback entering the output digest
  164. * as input in order to ensure that a different ordered list will result in
  165. * a different digest. */
  166. void computeDatasetDigest(unsigned char *final) {
  167. unsigned char digest[20];
  168. dictIterator *di = NULL;
  169. dictEntry *de;
  170. int j;
  171. uint32_t aux;
  172. memset(final,0,20); /* Start with a clean result */
  173. for (j = 0; j < server.dbnum; j++) {
  174. redisDb *db = server.db+j;
  175. if (dictSize(db->dict) == 0) continue;
  176. di = dictGetSafeIterator(db->dict);
  177. /* hash the DB id, so the same dataset moved in a different
  178. * DB will lead to a different digest */
  179. aux = htonl(j);
  180. mixDigest(final,&aux,sizeof(aux));
  181. /* Iterate this DB writing every entry */
  182. while((de = dictNext(di)) != NULL) {
  183. sds key;
  184. robj *keyobj, *o;
  185. memset(digest,0,20); /* This key-val digest */
  186. key = dictGetKey(de);
  187. keyobj = createStringObject(key,sdslen(key));
  188. mixDigest(digest,key,sdslen(key));
  189. o = dictGetVal(de);
  190. xorObjectDigest(db,keyobj,digest,o);
  191. /* We can finally xor the key-val digest to the final digest */
  192. xorDigest(final,digest,20);
  193. decrRefCount(keyobj);
  194. }
  195. dictReleaseIterator(di);
  196. }
  197. }

相关技术文章

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

提示信息

×

选择支付方式

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