summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2018-12-07 16:30:33 +0100
committerantirez <antirez@gmail.com>2018-12-07 16:30:33 +0100
commite9400e8efdad01c93b80624805b7ddb2d7ec99ec (patch)
treeb34de9e27b0027e6212dbe4043e7e6ec8e383055
parent0006c989d2cde8475c7daa56a6e11d7ba72dbd91 (diff)
downloadredis-e9400e8efdad01c93b80624805b7ddb2d7ec99ec.tar.gz
DEBUG DIGEST refactoring: extract function to digest a value.
-rw-r--r--src/debug.c273
1 files changed, 142 insertions, 131 deletions
diff --git a/src/debug.c b/src/debug.c
index 3cb567520..3c2e7fd55 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -74,7 +74,7 @@ void xorDigest(unsigned char *digest, void *ptr, size_t len) {
digest[j] ^= hash[j];
}
-void xorObjectDigest(unsigned char *digest, robj *o) {
+void xorStringObjectDigest(unsigned char *digest, robj *o) {
o = getDecodedObject(o);
xorDigest(digest,o->ptr,sdslen(o->ptr));
decrRefCount(o);
@@ -104,12 +104,151 @@ void mixDigest(unsigned char *digest, void *ptr, size_t len) {
SHA1Final(digest,&ctx);
}
-void mixObjectDigest(unsigned char *digest, robj *o) {
+void mixStringObjectDigest(unsigned char *digest, robj *o) {
o = getDecodedObject(o);
mixDigest(digest,o->ptr,sdslen(o->ptr));
decrRefCount(o);
}
+/* This function computes the digest of a data structure stored in the
+ * object 'o'. It is the core of the DEBUG DIGEST command: when taking the
+ * digest of a whole dataset, we take the digest of the key and the value
+ * pair, and xor all those together.
+ *
+ * Note that this function does not reset the initial 'digest' passed, it
+ * will continue mixing this object digest to anything that was already
+ * present. */
+void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o) {
+ uint32_t aux = htonl(o->type);
+ mixDigest(digest,&aux,sizeof(aux));
+ long long expiretime = getExpire(db,keyobj);
+ char buf[128];
+
+ /* Save the key and associated value */
+ if (o->type == OBJ_STRING) {
+ mixStringObjectDigest(digest,o);
+ } else if (o->type == OBJ_LIST) {
+ listTypeIterator *li = listTypeInitIterator(o,0,LIST_TAIL);
+ listTypeEntry entry;
+ while(listTypeNext(li,&entry)) {
+ robj *eleobj = listTypeGet(&entry);
+ mixStringObjectDigest(digest,eleobj);
+ decrRefCount(eleobj);
+ }
+ listTypeReleaseIterator(li);
+ } else if (o->type == OBJ_SET) {
+ setTypeIterator *si = setTypeInitIterator(o);
+ sds sdsele;
+ while((sdsele = setTypeNextObject(si)) != NULL) {
+ xorDigest(digest,sdsele,sdslen(sdsele));
+ sdsfree(sdsele);
+ }
+ setTypeReleaseIterator(si);
+ } else if (o->type == OBJ_ZSET) {
+ unsigned char eledigest[20];
+
+ if (o->encoding == OBJ_ENCODING_ZIPLIST) {
+ unsigned char *zl = o->ptr;
+ unsigned char *eptr, *sptr;
+ unsigned char *vstr;
+ unsigned int vlen;
+ long long vll;
+ double score;
+
+ eptr = ziplistIndex(zl,0);
+ serverAssert(eptr != NULL);
+ sptr = ziplistNext(zl,eptr);
+ serverAssert(sptr != NULL);
+
+ while (eptr != NULL) {
+ serverAssert(ziplistGet(eptr,&vstr,&vlen,&vll));
+ score = zzlGetScore(sptr);
+
+ memset(eledigest,0,20);
+ if (vstr != NULL) {
+ mixDigest(eledigest,vstr,vlen);
+ } else {
+ ll2string(buf,sizeof(buf),vll);
+ mixDigest(eledigest,buf,strlen(buf));
+ }
+
+ snprintf(buf,sizeof(buf),"%.17g",score);
+ mixDigest(eledigest,buf,strlen(buf));
+ xorDigest(digest,eledigest,20);
+ zzlNext(zl,&eptr,&sptr);
+ }
+ } else if (o->encoding == OBJ_ENCODING_SKIPLIST) {
+ zset *zs = o->ptr;
+ dictIterator *di = dictGetIterator(zs->dict);
+ dictEntry *de;
+
+ while((de = dictNext(di)) != NULL) {
+ sds sdsele = dictGetKey(de);
+ double *score = dictGetVal(de);
+
+ snprintf(buf,sizeof(buf),"%.17g",*score);
+ memset(eledigest,0,20);
+ mixDigest(eledigest,sdsele,sdslen(sdsele));
+ mixDigest(eledigest,buf,strlen(buf));
+ xorDigest(digest,eledigest,20);
+ }
+ dictReleaseIterator(di);
+ } else {
+ serverPanic("Unknown sorted set encoding");
+ }
+ } else if (o->type == OBJ_HASH) {
+ hashTypeIterator *hi = hashTypeInitIterator(o);
+ while (hashTypeNext(hi) != C_ERR) {
+ unsigned char eledigest[20];
+ sds sdsele;
+
+ memset(eledigest,0,20);
+ sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY);
+ mixDigest(eledigest,sdsele,sdslen(sdsele));
+ sdsfree(sdsele);
+ sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE);
+ mixDigest(eledigest,sdsele,sdslen(sdsele));
+ sdsfree(sdsele);
+ xorDigest(digest,eledigest,20);
+ }
+ hashTypeReleaseIterator(hi);
+ } else if (o->type == OBJ_STREAM) {
+ streamIterator si;
+ streamIteratorStart(&si,o->ptr,NULL,NULL,0);
+ streamID id;
+ int64_t numfields;
+
+ while(streamIteratorGetID(&si,&id,&numfields)) {
+ sds itemid = sdscatfmt(sdsempty(),"%U.%U",id.ms,id.seq);
+ mixDigest(digest,itemid,sdslen(itemid));
+ sdsfree(itemid);
+
+ while(numfields--) {
+ unsigned char *field, *value;
+ int64_t field_len, value_len;
+ streamIteratorGetField(&si,&field,&value,
+ &field_len,&value_len);
+ mixDigest(digest,field,field_len);
+ mixDigest(digest,value,value_len);
+ }
+ }
+ streamIteratorStop(&si);
+ } else if (o->type == OBJ_MODULE) {
+ RedisModuleDigest md;
+ moduleValue *mv = o->ptr;
+ moduleType *mt = mv->type;
+ moduleInitDigestContext(md);
+ if (mt->digest) {
+ mt->digest(&md,mv->value);
+ xorDigest(digest,md.x,sizeof(md.x));
+ }
+ } else {
+ serverPanic("Unknown object type");
+ }
+ /* If the key has an expire, add it to the mix */
+ if (expiretime != -1) xorDigest(digest,"!!expire!!",10);
+}
+
/* 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
@@ -118,7 +257,6 @@ void mixObjectDigest(unsigned char *digest, robj *o) {
* a different digest. */
void computeDatasetDigest(unsigned char *final) {
unsigned char digest[20];
- char buf[128];
dictIterator *di = NULL;
dictEntry *de;
int j;
@@ -141,7 +279,6 @@ void computeDatasetDigest(unsigned char *final) {
while((de = dictNext(di)) != NULL) {
sds key;
robj *keyobj, *o;
- long long expiretime;
memset(digest,0,20); /* This key-val digest */
key = dictGetKey(de);
@@ -150,134 +287,8 @@ void computeDatasetDigest(unsigned char *final) {
mixDigest(digest,key,sdslen(key));
o = dictGetVal(de);
+ xorObjectDigest(db,keyobj,digest,o);
- aux = htonl(o->type);
- mixDigest(digest,&aux,sizeof(aux));
- expiretime = getExpire(db,keyobj);
-
- /* Save the key and associated value */
- if (o->type == OBJ_STRING) {
- mixObjectDigest(digest,o);
- } else if (o->type == OBJ_LIST) {
- listTypeIterator *li = listTypeInitIterator(o,0,LIST_TAIL);
- listTypeEntry entry;
- while(listTypeNext(li,&entry)) {
- robj *eleobj = listTypeGet(&entry);
- mixObjectDigest(digest,eleobj);
- decrRefCount(eleobj);
- }
- listTypeReleaseIterator(li);
- } else if (o->type == OBJ_SET) {
- setTypeIterator *si = setTypeInitIterator(o);
- sds sdsele;
- while((sdsele = setTypeNextObject(si)) != NULL) {
- xorDigest(digest,sdsele,sdslen(sdsele));
- sdsfree(sdsele);
- }
- setTypeReleaseIterator(si);
- } else if (o->type == OBJ_ZSET) {
- unsigned char eledigest[20];
-
- if (o->encoding == OBJ_ENCODING_ZIPLIST) {
- unsigned char *zl = o->ptr;
- unsigned char *eptr, *sptr;
- unsigned char *vstr;
- unsigned int vlen;
- long long vll;
- double score;
-
- eptr = ziplistIndex(zl,0);
- serverAssert(eptr != NULL);
- sptr = ziplistNext(zl,eptr);
- serverAssert(sptr != NULL);
-
- while (eptr != NULL) {
- serverAssert(ziplistGet(eptr,&vstr,&vlen,&vll));
- score = zzlGetScore(sptr);
-
- memset(eledigest,0,20);
- if (vstr != NULL) {
- mixDigest(eledigest,vstr,vlen);
- } else {
- ll2string(buf,sizeof(buf),vll);
- mixDigest(eledigest,buf,strlen(buf));
- }
-
- snprintf(buf,sizeof(buf),"%.17g",score);
- mixDigest(eledigest,buf,strlen(buf));
- xorDigest(digest,eledigest,20);
- zzlNext(zl,&eptr,&sptr);
- }
- } else if (o->encoding == OBJ_ENCODING_SKIPLIST) {
- zset *zs = o->ptr;
- dictIterator *di = dictGetIterator(zs->dict);
- dictEntry *de;
-
- while((de = dictNext(di)) != NULL) {
- sds sdsele = dictGetKey(de);
- double *score = dictGetVal(de);
-
- snprintf(buf,sizeof(buf),"%.17g",*score);
- memset(eledigest,0,20);
- mixDigest(eledigest,sdsele,sdslen(sdsele));
- mixDigest(eledigest,buf,strlen(buf));
- xorDigest(digest,eledigest,20);
- }
- dictReleaseIterator(di);
- } else {
- serverPanic("Unknown sorted set encoding");
- }
- } else if (o->type == OBJ_HASH) {
- hashTypeIterator *hi = hashTypeInitIterator(o);
- while (hashTypeNext(hi) != C_ERR) {
- unsigned char eledigest[20];
- sds sdsele;
-
- memset(eledigest,0,20);
- sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY);
- mixDigest(eledigest,sdsele,sdslen(sdsele));
- sdsfree(sdsele);
- sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE);
- mixDigest(eledigest,sdsele,sdslen(sdsele));
- sdsfree(sdsele);
- xorDigest(digest,eledigest,20);
- }
- hashTypeReleaseIterator(hi);
- } else if (o->type == OBJ_STREAM) {
- streamIterator si;
- streamIteratorStart(&si,o->ptr,NULL,NULL,0);
- streamID id;
- int64_t numfields;
-
- while(streamIteratorGetID(&si,&id,&numfields)) {
- sds itemid = sdscatfmt(sdsempty(),"%U.%U",id.ms,id.seq);
- mixDigest(digest,itemid,sdslen(itemid));
- sdsfree(itemid);
-
- while(numfields--) {
- unsigned char *field, *value;
- int64_t field_len, value_len;
- streamIteratorGetField(&si,&field,&value,
- &field_len,&value_len);
- mixDigest(digest,field,field_len);
- mixDigest(digest,value,value_len);
- }
- }
- streamIteratorStop(&si);
- } else if (o->type == OBJ_MODULE) {
- RedisModuleDigest md;
- moduleValue *mv = o->ptr;
- moduleType *mt = mv->type;
- moduleInitDigestContext(md);
- if (mt->digest) {
- mt->digest(&md,mv->value);
- xorDigest(digest,md.x,sizeof(md.x));
- }
- } else {
- serverPanic("Unknown object type");
- }
- /* If the key has an expire, add it to the mix */
- if (expiretime != -1) xorDigest(digest,"!!expire!!",10);
/* We can finally xor the key-val digest to the final digest */
xorDigest(final,digest,20);
decrRefCount(keyobj);