Compute the dataset digest. Since keys, sets elements, hashes elements * are not ordered, we use a trick: every aggregate digest is the xor * of the digests of their elements. This way the order will not change * the result. For list instead we use a feedback entering the output digest * as input in order to ensure that a different ordered list will result in * a different digest. */
| 271 | * as input in order to ensure that a different ordered list will result in |
| 272 | * a different digest. */ |
| 273 | void computeDatasetDigest(unsigned char *final) { |
| 274 | unsigned char digest[20]; |
| 275 | dictIterator *di = NULL; |
| 276 | dictEntry *de; |
| 277 | int j; |
| 278 | uint32_t aux; |
| 279 | |
| 280 | memset(final,0,20); /* Start with a clean result */ |
| 281 | |
| 282 | for (j = 0; j < server.dbnum; j++) { |
| 283 | redisDb *db = server.db+j; |
| 284 | |
| 285 | if (dictSize(db->dict) == 0) continue; |
| 286 | di = dictGetSafeIterator(db->dict); |
| 287 | |
| 288 | /* hash the DB id, so the same dataset moved in a different |
| 289 | * DB will lead to a different digest */ |
| 290 | aux = htonl(j); |
| 291 | mixDigest(final,&aux,sizeof(aux)); |
| 292 | |
| 293 | /* Iterate this DB writing every entry */ |
| 294 | while((de = dictNext(di)) != NULL) { |
| 295 | sds key; |
| 296 | robj *keyobj, *o; |
| 297 | |
| 298 | memset(digest,0,20); /* This key-val digest */ |
| 299 | key = dictGetKey(de); |
| 300 | keyobj = createStringObject(key,sdslen(key)); |
| 301 | |
| 302 | mixDigest(digest,key,sdslen(key)); |
| 303 | |
| 304 | o = dictGetVal(de); |
| 305 | xorObjectDigest(db,keyobj,digest,o); |
| 306 | |
| 307 | /* We can finally xor the key-val digest to the final digest */ |
| 308 | xorDigest(final,digest,20); |
| 309 | decrRefCount(keyobj); |
| 310 | } |
| 311 | dictReleaseIterator(di); |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | #ifdef USE_JEMALLOC |
| 316 | void mallctl_int(client *c, robj **argv, int argc) { |
no test coverage detected