#include "redis.h"
#include "sha1.h" /* SHA1 is used for DEBUG DIGEST */
+#include <arpa/inet.h>
+
/* ================================= Debugging ============================== */
/* Compute the sha1 of string at 's' with 'len' bytes long.
mixDigest(digest,key,sdslen(key));
/* Make sure the key is loaded if VM is active */
- o = lookupKeyRead(db,keyobj);
+ o = dictGetEntryVal(de);
aux = htonl(o->type);
mixDigest(digest,&aux,sizeof(aux));
}
listTypeReleaseIterator(li);
} else if (o->type == REDIS_SET) {
- dict *set = o->ptr;
- dictIterator *di = dictGetIterator(set);
- dictEntry *de;
-
- while((de = dictNext(di)) != NULL) {
- robj *eleobj = dictGetEntryKey(de);
-
- xorObjectDigest(digest,eleobj);
+ setTypeIterator *si = setTypeInitIterator(o);
+ robj *ele;
+ while((ele = setTypeNextObject(si)) != NULL) {
+ xorObjectDigest(digest,ele);
+ decrRefCount(ele);
}
- dictReleaseIterator(di);
+ setTypeReleaseIterator(si);
} else if (o->type == REDIS_ZSET) {
- zset *zs = o->ptr;
- dictIterator *di = dictGetIterator(zs->dict);
- dictEntry *de;
-
- while((de = dictNext(di)) != NULL) {
- robj *eleobj = dictGetEntryKey(de);
- double *score = dictGetEntryVal(de);
- unsigned char eledigest[20];
-
- snprintf(buf,sizeof(buf),"%.17g",*score);
- memset(eledigest,0,20);
- mixObjectDigest(eledigest,eleobj);
- mixDigest(eledigest,buf,strlen(buf));
- xorDigest(digest,eledigest,20);
+ unsigned char eledigest[20];
+
+ if (o->encoding == REDIS_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);
+ redisAssert(eptr != NULL);
+ sptr = ziplistNext(zl,eptr);
+ redisAssert(sptr != NULL);
+
+ while (eptr != NULL) {
+ redisAssert(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 == REDIS_ENCODING_SKIPLIST) {
+ zset *zs = o->ptr;
+ dictIterator *di = dictGetIterator(zs->dict);
+ dictEntry *de;
+
+ while((de = dictNext(di)) != NULL) {
+ robj *eleobj = dictGetEntryKey(de);
+ double *score = dictGetEntryVal(de);
+
+ snprintf(buf,sizeof(buf),"%.17g",*score);
+ memset(eledigest,0,20);
+ mixObjectDigest(eledigest,eleobj);
+ mixDigest(eledigest,buf,strlen(buf));
+ xorDigest(digest,eledigest,20);
+ }
+ dictReleaseIterator(di);
+ } else {
+ redisPanic("Unknown sorted set encoding");
}
- dictReleaseIterator(di);
} else if (o->type == REDIS_HASH) {
hashTypeIterator *hi;
robj *obj;
unsigned char eledigest[20];
memset(eledigest,0,20);
- obj = hashTypeCurrent(hi,REDIS_HASH_KEY);
+ obj = hashTypeCurrentObject(hi,REDIS_HASH_KEY);
mixObjectDigest(eledigest,obj);
decrRefCount(obj);
- obj = hashTypeCurrent(hi,REDIS_HASH_VALUE);
+ obj = hashTypeCurrentObject(hi,REDIS_HASH_VALUE);
mixObjectDigest(eledigest,obj);
decrRefCount(obj);
xorDigest(digest,eledigest,20);
void debugCommand(redisClient *c) {
if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
*((char*)-1) = 'x';
+ } else if (!strcasecmp(c->argv[1]->ptr,"assert")) {
+ if (c->argc >= 3) c->argv[2] = tryObjectEncoding(c->argv[2]);
+ redisAssertWithInfo(c,c->argv[0],1 == 2);
} else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
if (rdbSave(server.dbfilename) != REDIS_OK) {
addReply(c,shared.err);
redisLog(REDIS_WARNING,"Append Only File loaded by DEBUG LOADAOF");
addReply(c,shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
- dictEntry *de = dictFind(c->db->dict,c->argv[2]->ptr);
+ dictEntry *de;
robj *val;
+ char *strenc;
- if (!de) {
- addReply(c,shared.nokeyerr);
- return;
- }
- val = dictGetEntryVal(de);
- if (!server.vm_enabled || (val->storage == REDIS_VM_MEMORY ||
- val->storage == REDIS_VM_SWAPPING)) {
- char *strenc;
-
- strenc = strEncoding(val->encoding);
- addReplySds(c,sdscatprintf(sdsempty(),
- "+Value at:%p refcount:%d "
- "encoding:%s serializedlength:%lld\r\n",
- (void*)val, val->refcount,
- strenc, (long long) rdbSavedObjectLen(val,NULL)));
- } else {
- vmpointer *vp = (vmpointer*) val;
- addReplySds(c,sdscatprintf(sdsempty(),
- "+Value swapped at: page %llu "
- "using %llu pages\r\n",
- (unsigned long long) vp->page,
- (unsigned long long) vp->usedpages));
- }
- } else if (!strcasecmp(c->argv[1]->ptr,"swapin") && c->argc == 3) {
- lookupKeyRead(c->db,c->argv[2]);
- addReply(c,shared.ok);
- } else if (!strcasecmp(c->argv[1]->ptr,"swapout") && c->argc == 3) {
- dictEntry *de = dictFind(c->db->dict,c->argv[2]->ptr);
- robj *val;
- vmpointer *vp;
-
- if (!server.vm_enabled) {
- addReplySds(c,sdsnew("-ERR Virtual Memory is disabled\r\n"));
- return;
- }
- if (!de) {
+ if ((de = dictFind(c->db->dict,c->argv[2]->ptr)) == NULL) {
addReply(c,shared.nokeyerr);
return;
}
val = dictGetEntryVal(de);
- /* Swap it */
- if (val->storage != REDIS_VM_MEMORY) {
- addReplySds(c,sdsnew("-ERR This key is not in memory\r\n"));
- } else if (val->refcount != 1) {
- addReplySds(c,sdsnew("-ERR Object is shared\r\n"));
- } else if ((vp = vmSwapObjectBlocking(val)) != NULL) {
- dictGetEntryVal(de) = vp;
- addReply(c,shared.ok);
- } else {
- addReply(c,shared.err);
- }
+ strenc = strEncoding(val->encoding);
+
+ addReplyStatusFormat(c,
+ "Value at:%p refcount:%d "
+ "encoding:%s serializedlength:%lld "
+ "lru:%d lru_seconds_idle:%lu",
+ (void*)val, val->refcount,
+ strenc, (long long) rdbSavedObjectLen(val),
+ val->lru, estimateObjectIdleTime(val));
} else if (!strcasecmp(c->argv[1]->ptr,"populate") && c->argc == 3) {
long keys, j;
robj *key, *val;
addReply(c,shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr,"digest") && c->argc == 2) {
unsigned char digest[20];
- sds d = sdsnew("+");
+ sds d = sdsempty();
int j;
computeDatasetDigest(digest);
for (j = 0; j < 20; j++)
d = sdscatprintf(d, "%02x",digest[j]);
+ addReplyStatus(c,d);
+ sdsfree(d);
+ } else if (!strcasecmp(c->argv[1]->ptr,"sleep") && c->argc == 3) {
+ double dtime = strtod(c->argv[2]->ptr,NULL);
+ long long utime = dtime*1000000;
- d = sdscatlen(d,"\r\n",2);
- addReplySds(c,d);
+ usleep(utime);
+ addReply(c,shared.ok);
} else {
- addReplySds(c,sdsnew(
- "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPIN <key>|SWAPOUT <key>|RELOAD]\r\n"));
+ addReplyError(c,
+ "Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPIN <key>|SWAPOUT <key>|RELOAD]");
}
}
#endif
}
+void _redisAssertPrintClientInfo(redisClient *c) {
+ int j;
+
+ redisLog(REDIS_WARNING,"=== ASSERTION FAILED CLIENT CONTEXT ===");
+ redisLog(REDIS_WARNING,"client->flags = %d", c->flags);
+ redisLog(REDIS_WARNING,"client->fd = %d", c->fd);
+ redisLog(REDIS_WARNING,"client->argc = %d", c->argc);
+ for (j=0; j < c->argc; j++) {
+ char buf[128];
+ char *arg;
+
+ if (c->argv[j]->type == REDIS_STRING &&
+ c->argv[j]->encoding == REDIS_ENCODING_RAW)
+ {
+ arg = (char*) c->argv[j]->ptr;
+ } else {
+ snprintf(buf,sizeof(buf),"Object type: %d, encoding: %d",
+ c->argv[j]->type, c->argv[j]->encoding);
+ arg = buf;
+ }
+ redisLog(REDIS_WARNING,"client->argv[%d] = \"%s\" (refcount: %d)",
+ j, arg, c->argv[j]->refcount);
+ }
+}
+
+void _redisAssertPrintObject(robj *o) {
+ redisLog(REDIS_WARNING,"=== ASSERTION FAILED OBJECT CONTEXT ===");
+ redisLog(REDIS_WARNING,"Object type: %d", o->type);
+ redisLog(REDIS_WARNING,"Object encoding: %d", o->encoding);
+ redisLog(REDIS_WARNING,"Object refcount: %d", o->refcount);
+ if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_RAW) {
+ redisLog(REDIS_WARNING,"Object raw string len: %d", sdslen(o->ptr));
+ if (sdslen(o->ptr) < 4096)
+ redisLog(REDIS_WARNING,"Object raw string content: \"%s\"", (char*)o->ptr);
+ }
+}
+
+void _redisAssertWithInfo(redisClient *c, robj *o, char *estr, char *file, int line) {
+ if (c) _redisAssertPrintClientInfo(c);
+ if (o) _redisAssertPrintObject(o);
+ _redisAssert(estr,file,line);
+}
+
void _redisPanic(char *msg, char *file, int line) {
+ redisLog(REDIS_WARNING,"------------------------------------------------");
redisLog(REDIS_WARNING,"!!! Software Failure. Press left mouse button to continue");
redisLog(REDIS_WARNING,"Guru Meditation: %s #%s:%d",msg,file,line);
#ifdef HAVE_BACKTRACE
redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
+ redisLog(REDIS_WARNING,"------------------------------------------------");
*((char*)-1) = 'x';
#endif
}