]>
git.saurik.com Git - redis.git/blob - src/debug.c
2 #include "sha1.h" /* SHA1 is used for DEBUG DIGEST */
10 #endif /* HAVE_BACKTRACE */
12 /* ================================= Debugging ============================== */
14 /* Compute the sha1 of string at 's' with 'len' bytes long.
15 * The SHA1 is then xored againt the string pointed by digest.
16 * Since xor is commutative, this operation is used in order to
17 * "add" digests relative to unordered elements.
19 * So digest(a,b,c,d) will be the same of digest(b,a,c,d) */
20 void xorDigest(unsigned char *digest
, void *ptr
, size_t len
) {
22 unsigned char hash
[20], *s
= ptr
;
26 SHA1Update(&ctx
,s
,len
);
29 for (j
= 0; j
< 20; j
++)
33 void xorObjectDigest(unsigned char *digest
, robj
*o
) {
34 o
= getDecodedObject(o
);
35 xorDigest(digest
,o
->ptr
,sdslen(o
->ptr
));
39 /* This function instead of just computing the SHA1 and xoring it
40 * against diget, also perform the digest of "digest" itself and
41 * replace the old value with the new one.
43 * So the final digest will be:
45 * digest = SHA1(digest xor SHA1(data))
47 * This function is used every time we want to preserve the order so
48 * that digest(a,b,c,d) will be different than digest(b,c,d,a)
50 * Also note that mixdigest("foo") followed by mixdigest("bar")
51 * will lead to a different digest compared to "fo", "obar".
53 void mixDigest(unsigned char *digest
, void *ptr
, size_t len
) {
57 xorDigest(digest
,s
,len
);
59 SHA1Update(&ctx
,digest
,20);
60 SHA1Final(digest
,&ctx
);
63 void mixObjectDigest(unsigned char *digest
, robj
*o
) {
64 o
= getDecodedObject(o
);
65 mixDigest(digest
,o
->ptr
,sdslen(o
->ptr
));
69 /* Compute the dataset digest. Since keys, sets elements, hashes elements
70 * are not ordered, we use a trick: every aggregate digest is the xor
71 * of the digests of their elements. This way the order will not change
72 * the result. For list instead we use a feedback entering the output digest
73 * as input in order to ensure that a different ordered list will result in
74 * a different digest. */
75 void computeDatasetDigest(unsigned char *final
) {
76 unsigned char digest
[20];
78 dictIterator
*di
= NULL
;
83 memset(final
,0,20); /* Start with a clean result */
85 for (j
= 0; j
< server
.dbnum
; j
++) {
86 redisDb
*db
= server
.db
+j
;
88 if (dictSize(db
->dict
) == 0) continue;
89 di
= dictGetIterator(db
->dict
);
91 /* hash the DB id, so the same dataset moved in a different
92 * DB will lead to a different digest */
94 mixDigest(final
,&aux
,sizeof(aux
));
96 /* Iterate this DB writing every entry */
97 while((de
= dictNext(di
)) != NULL
) {
100 long long expiretime
;
102 memset(digest
,0,20); /* This key-val digest */
103 key
= dictGetKey(de
);
104 keyobj
= createStringObject(key
,sdslen(key
));
106 mixDigest(digest
,key
,sdslen(key
));
108 /* Make sure the key is loaded if VM is active */
111 aux
= htonl(o
->type
);
112 mixDigest(digest
,&aux
,sizeof(aux
));
113 expiretime
= getExpire(db
,keyobj
);
115 /* Save the key and associated value */
116 if (o
->type
== REDIS_STRING
) {
117 mixObjectDigest(digest
,o
);
118 } else if (o
->type
== REDIS_LIST
) {
119 listTypeIterator
*li
= listTypeInitIterator(o
,0,REDIS_TAIL
);
121 while(listTypeNext(li
,&entry
)) {
122 robj
*eleobj
= listTypeGet(&entry
);
123 mixObjectDigest(digest
,eleobj
);
124 decrRefCount(eleobj
);
126 listTypeReleaseIterator(li
);
127 } else if (o
->type
== REDIS_SET
) {
128 setTypeIterator
*si
= setTypeInitIterator(o
);
130 while((ele
= setTypeNextObject(si
)) != NULL
) {
131 xorObjectDigest(digest
,ele
);
134 setTypeReleaseIterator(si
);
135 } else if (o
->type
== REDIS_ZSET
) {
136 unsigned char eledigest
[20];
138 if (o
->encoding
== REDIS_ENCODING_ZIPLIST
) {
139 unsigned char *zl
= o
->ptr
;
140 unsigned char *eptr
, *sptr
;
146 eptr
= ziplistIndex(zl
,0);
147 redisAssert(eptr
!= NULL
);
148 sptr
= ziplistNext(zl
,eptr
);
149 redisAssert(sptr
!= NULL
);
151 while (eptr
!= NULL
) {
152 redisAssert(ziplistGet(eptr
,&vstr
,&vlen
,&vll
));
153 score
= zzlGetScore(sptr
);
155 memset(eledigest
,0,20);
157 mixDigest(eledigest
,vstr
,vlen
);
159 ll2string(buf
,sizeof(buf
),vll
);
160 mixDigest(eledigest
,buf
,strlen(buf
));
163 snprintf(buf
,sizeof(buf
),"%.17g",score
);
164 mixDigest(eledigest
,buf
,strlen(buf
));
165 xorDigest(digest
,eledigest
,20);
166 zzlNext(zl
,&eptr
,&sptr
);
168 } else if (o
->encoding
== REDIS_ENCODING_SKIPLIST
) {
170 dictIterator
*di
= dictGetIterator(zs
->dict
);
173 while((de
= dictNext(di
)) != NULL
) {
174 robj
*eleobj
= dictGetKey(de
);
175 double *score
= dictGetVal(de
);
177 snprintf(buf
,sizeof(buf
),"%.17g",*score
);
178 memset(eledigest
,0,20);
179 mixObjectDigest(eledigest
,eleobj
);
180 mixDigest(eledigest
,buf
,strlen(buf
));
181 xorDigest(digest
,eledigest
,20);
183 dictReleaseIterator(di
);
185 redisPanic("Unknown sorted set encoding");
187 } else if (o
->type
== REDIS_HASH
) {
188 hashTypeIterator
*hi
;
191 hi
= hashTypeInitIterator(o
);
192 while (hashTypeNext(hi
) != REDIS_ERR
) {
193 unsigned char eledigest
[20];
195 memset(eledigest
,0,20);
196 obj
= hashTypeCurrentObject(hi
,REDIS_HASH_KEY
);
197 mixObjectDigest(eledigest
,obj
);
199 obj
= hashTypeCurrentObject(hi
,REDIS_HASH_VALUE
);
200 mixObjectDigest(eledigest
,obj
);
202 xorDigest(digest
,eledigest
,20);
204 hashTypeReleaseIterator(hi
);
206 redisPanic("Unknown object type");
208 /* If the key has an expire, add it to the mix */
209 if (expiretime
!= -1) xorDigest(digest
,"!!expire!!",10);
210 /* We can finally xor the key-val digest to the final digest */
211 xorDigest(final
,digest
,20);
212 decrRefCount(keyobj
);
214 dictReleaseIterator(di
);
218 void debugCommand(redisClient
*c
) {
219 if (!strcasecmp(c
->argv
[1]->ptr
,"segfault")) {
221 } else if (!strcasecmp(c
->argv
[1]->ptr
,"assert")) {
222 if (c
->argc
>= 3) c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
223 redisAssertWithInfo(c
,c
->argv
[0],1 == 2);
224 } else if (!strcasecmp(c
->argv
[1]->ptr
,"reload")) {
225 if (rdbSave(server
.rdb_filename
) != REDIS_OK
) {
226 addReply(c
,shared
.err
);
230 if (rdbLoad(server
.rdb_filename
) != REDIS_OK
) {
231 addReplyError(c
,"Error trying to load the RDB dump");
234 redisLog(REDIS_WARNING
,"DB reloaded by DEBUG RELOAD");
235 addReply(c
,shared
.ok
);
236 } else if (!strcasecmp(c
->argv
[1]->ptr
,"loadaof")) {
238 if (loadAppendOnlyFile(server
.aof_filename
) != REDIS_OK
) {
239 addReply(c
,shared
.err
);
242 server
.dirty
= 0; /* Prevent AOF / replication */
243 redisLog(REDIS_WARNING
,"Append Only File loaded by DEBUG LOADAOF");
244 addReply(c
,shared
.ok
);
245 } else if (!strcasecmp(c
->argv
[1]->ptr
,"object") && c
->argc
== 3) {
250 if ((de
= dictFind(c
->db
->dict
,c
->argv
[2]->ptr
)) == NULL
) {
251 addReply(c
,shared
.nokeyerr
);
254 val
= dictGetVal(de
);
255 strenc
= strEncoding(val
->encoding
);
257 addReplyStatusFormat(c
,
258 "Value at:%p refcount:%d "
259 "encoding:%s serializedlength:%lld "
260 "lru:%d lru_seconds_idle:%lu",
261 (void*)val
, val
->refcount
,
262 strenc
, (long long) rdbSavedObjectLen(val
),
263 val
->lru
, estimateObjectIdleTime(val
));
264 } else if (!strcasecmp(c
->argv
[1]->ptr
,"populate") && c
->argc
== 3) {
269 if (getLongFromObjectOrReply(c
, c
->argv
[2], &keys
, NULL
) != REDIS_OK
)
271 for (j
= 0; j
< keys
; j
++) {
272 snprintf(buf
,sizeof(buf
),"key:%lu",j
);
273 key
= createStringObject(buf
,strlen(buf
));
274 if (lookupKeyRead(c
->db
,key
) != NULL
) {
278 snprintf(buf
,sizeof(buf
),"value:%lu",j
);
279 val
= createStringObject(buf
,strlen(buf
));
280 dbAdd(c
->db
,key
,val
);
283 addReply(c
,shared
.ok
);
284 } else if (!strcasecmp(c
->argv
[1]->ptr
,"digest") && c
->argc
== 2) {
285 unsigned char digest
[20];
289 computeDatasetDigest(digest
);
290 for (j
= 0; j
< 20; j
++)
291 d
= sdscatprintf(d
, "%02x",digest
[j
]);
294 } else if (!strcasecmp(c
->argv
[1]->ptr
,"sleep") && c
->argc
== 3) {
295 double dtime
= strtod(c
->argv
[2]->ptr
,NULL
);
296 long long utime
= dtime
*1000000;
299 addReply(c
,shared
.ok
);
302 "Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPIN <key>|SWAPOUT <key>|RELOAD]");
306 /* =========================== Crash handling ============================== */
308 void _redisAssert(char *estr
, char *file
, int line
) {
310 redisLog(REDIS_WARNING
,"=== ASSERTION FAILED ===");
311 redisLog(REDIS_WARNING
,"==> %s:%d '%s' is not true",file
,line
,estr
);
312 #ifdef HAVE_BACKTRACE
313 server
.assert_failed
= estr
;
314 server
.assert_file
= file
;
315 server
.assert_line
= line
;
316 redisLog(REDIS_WARNING
,"(forcing SIGSEGV to print the bug report.)");
321 void _redisAssertPrintClientInfo(redisClient
*c
) {
325 redisLog(REDIS_WARNING
,"=== ASSERTION FAILED CLIENT CONTEXT ===");
326 redisLog(REDIS_WARNING
,"client->flags = %d", c
->flags
);
327 redisLog(REDIS_WARNING
,"client->fd = %d", c
->fd
);
328 redisLog(REDIS_WARNING
,"client->argc = %d", c
->argc
);
329 for (j
=0; j
< c
->argc
; j
++) {
333 if (c
->argv
[j
]->type
== REDIS_STRING
&&
334 c
->argv
[j
]->encoding
== REDIS_ENCODING_RAW
)
336 arg
= (char*) c
->argv
[j
]->ptr
;
338 snprintf(buf
,sizeof(buf
),"Object type: %d, encoding: %d",
339 c
->argv
[j
]->type
, c
->argv
[j
]->encoding
);
342 redisLog(REDIS_WARNING
,"client->argv[%d] = \"%s\" (refcount: %d)",
343 j
, arg
, c
->argv
[j
]->refcount
);
347 void redisLogObjectDebugInfo(robj
*o
) {
348 redisLog(REDIS_WARNING
,"Object type: %d", o
->type
);
349 redisLog(REDIS_WARNING
,"Object encoding: %d", o
->encoding
);
350 redisLog(REDIS_WARNING
,"Object refcount: %d", o
->refcount
);
351 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_RAW
) {
352 redisLog(REDIS_WARNING
,"Object raw string len: %d", sdslen(o
->ptr
));
353 if (sdslen(o
->ptr
) < 4096)
354 redisLog(REDIS_WARNING
,"Object raw string content: \"%s\"", (char*)o
->ptr
);
355 } else if (o
->type
== REDIS_LIST
) {
356 redisLog(REDIS_WARNING
,"List length: %d", (int) listTypeLength(o
));
357 } else if (o
->type
== REDIS_SET
) {
358 redisLog(REDIS_WARNING
,"Set size: %d", (int) setTypeSize(o
));
359 } else if (o
->type
== REDIS_HASH
) {
360 redisLog(REDIS_WARNING
,"Hash size: %d", (int) hashTypeLength(o
));
361 } else if (o
->type
== REDIS_ZSET
) {
362 redisLog(REDIS_WARNING
,"Sorted set size: %d", (int) zsetLength(o
));
363 if (o
->encoding
== REDIS_ENCODING_SKIPLIST
)
364 redisLog(REDIS_WARNING
,"Skiplist level: %d", (int) ((zset
*)o
->ptr
)->zsl
->level
);
368 void _redisAssertPrintObject(robj
*o
) {
370 redisLog(REDIS_WARNING
,"=== ASSERTION FAILED OBJECT CONTEXT ===");
371 redisLogObjectDebugInfo(o
);
374 void _redisAssertWithInfo(redisClient
*c
, robj
*o
, char *estr
, char *file
, int line
) {
375 if (c
) _redisAssertPrintClientInfo(c
);
376 if (o
) _redisAssertPrintObject(o
);
377 _redisAssert(estr
,file
,line
);
380 void _redisPanic(char *msg
, char *file
, int line
) {
382 redisLog(REDIS_WARNING
,"------------------------------------------------");
383 redisLog(REDIS_WARNING
,"!!! Software Failure. Press left mouse button to continue");
384 redisLog(REDIS_WARNING
,"Guru Meditation: %s #%s:%d",msg
,file
,line
);
385 #ifdef HAVE_BACKTRACE
386 redisLog(REDIS_WARNING
,"(forcing SIGSEGV in order to print the stack trace)");
388 redisLog(REDIS_WARNING
,"------------------------------------------------");
392 void bugReportStart(void) {
393 if (server
.bug_report_start
== 0) {
394 redisLog(REDIS_WARNING
,
395 "\n\n=== REDIS BUG REPORT START: Cut & paste starting from here ===");
396 server
.bug_report_start
= 1;
400 #ifdef HAVE_BACKTRACE
401 static void *getMcontextEip(ucontext_t
*uc
) {
402 #if defined(__FreeBSD__)
403 return (void*) uc
->uc_mcontext
.mc_eip
;
404 #elif defined(__dietlibc__)
405 return (void*) uc
->uc_mcontext
.eip
;
406 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
408 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
410 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
412 return (void*) uc
->uc_mcontext
->__ss
.__srr0
;
414 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
415 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
416 return (void*) uc
->uc_mcontext
->__ss
.__rip
;
418 return (void*) uc
->uc_mcontext
->__ss
.__eip
;
420 #elif defined(__i386__)
421 return (void*) uc
->uc_mcontext
.gregs
[14]; /* Linux 32 */
422 #elif defined(__X86_64__) || defined(__x86_64__)
423 return (void*) uc
->uc_mcontext
.gregs
[16]; /* Linux 64 */
424 #elif defined(__ia64__) /* Linux IA64 */
425 return (void*) uc
->uc_mcontext
.sc_ip
;
431 void logStackContent(void **sp
) {
433 for (i
= 15; i
>= 0; i
--) {
434 if (sizeof(long) == 4)
435 redisLog(REDIS_WARNING
, "(%08lx) -> %08lx", sp
+i
, sp
[i
]);
437 redisLog(REDIS_WARNING
, "(%016lx) -> %016lx", sp
+i
, sp
[i
]);
441 void logRegisters(ucontext_t
*uc
) {
442 redisLog(REDIS_WARNING
, "--- REGISTERS");
443 #if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
444 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
445 redisLog(REDIS_WARNING
,
447 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
448 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
449 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
450 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
451 "RIP:%016lx EFL:%016lx\nCS :%016lx FS:%016lx GS:%016lx",
452 uc
->uc_mcontext
->__ss
.__rax
,
453 uc
->uc_mcontext
->__ss
.__rbx
,
454 uc
->uc_mcontext
->__ss
.__rcx
,
455 uc
->uc_mcontext
->__ss
.__rdx
,
456 uc
->uc_mcontext
->__ss
.__rdi
,
457 uc
->uc_mcontext
->__ss
.__rsi
,
458 uc
->uc_mcontext
->__ss
.__rbp
,
459 uc
->uc_mcontext
->__ss
.__rsp
,
460 uc
->uc_mcontext
->__ss
.__r8
,
461 uc
->uc_mcontext
->__ss
.__r9
,
462 uc
->uc_mcontext
->__ss
.__r10
,
463 uc
->uc_mcontext
->__ss
.__r11
,
464 uc
->uc_mcontext
->__ss
.__r12
,
465 uc
->uc_mcontext
->__ss
.__r13
,
466 uc
->uc_mcontext
->__ss
.__r14
,
467 uc
->uc_mcontext
->__ss
.__r15
,
468 uc
->uc_mcontext
->__ss
.__rip
,
469 uc
->uc_mcontext
->__ss
.__rflags
,
470 uc
->uc_mcontext
->__ss
.__cs
,
471 uc
->uc_mcontext
->__ss
.__fs
,
472 uc
->uc_mcontext
->__ss
.__gs
474 logStackContent((void**)uc
->uc_mcontext
->__ss
.__rsp
);
476 redisLog(REDIS_WARNING
,
478 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
479 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
480 "SS:%08lx EFL:%08lx EIP:%08lx CS :%08lx\n"
481 "DS:%08lx ES:%08lx FS :%08lx GS :%08lx",
482 uc
->uc_mcontext
->__ss
.__eax
,
483 uc
->uc_mcontext
->__ss
.__ebx
,
484 uc
->uc_mcontext
->__ss
.__ecx
,
485 uc
->uc_mcontext
->__ss
.__edx
,
486 uc
->uc_mcontext
->__ss
.__edi
,
487 uc
->uc_mcontext
->__ss
.__esi
,
488 uc
->uc_mcontext
->__ss
.__ebp
,
489 uc
->uc_mcontext
->__ss
.__esp
,
490 uc
->uc_mcontext
->__ss
.__ss
,
491 uc
->uc_mcontext
->__ss
.__eflags
,
492 uc
->uc_mcontext
->__ss
.__eip
,
493 uc
->uc_mcontext
->__ss
.__cs
,
494 uc
->uc_mcontext
->__ss
.__ds
,
495 uc
->uc_mcontext
->__ss
.__es
,
496 uc
->uc_mcontext
->__ss
.__fs
,
497 uc
->uc_mcontext
->__ss
.__gs
499 logStackContent((void**)uc
->uc_mcontext
->__ss
.__esp
);
501 #elif defined(__i386__)
502 redisLog(REDIS_WARNING
,
504 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
505 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
506 "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
507 "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
508 uc
->uc_mcontext
.gregs
[11],
509 uc
->uc_mcontext
.gregs
[8],
510 uc
->uc_mcontext
.gregs
[10],
511 uc
->uc_mcontext
.gregs
[9],
512 uc
->uc_mcontext
.gregs
[4],
513 uc
->uc_mcontext
.gregs
[5],
514 uc
->uc_mcontext
.gregs
[6],
515 uc
->uc_mcontext
.gregs
[7],
516 uc
->uc_mcontext
.gregs
[18],
517 uc
->uc_mcontext
.gregs
[17],
518 uc
->uc_mcontext
.gregs
[14],
519 uc
->uc_mcontext
.gregs
[15],
520 uc
->uc_mcontext
.gregs
[3],
521 uc
->uc_mcontext
.gregs
[2],
522 uc
->uc_mcontext
.gregs
[1],
523 uc
->uc_mcontext
.gregs
[0]
525 logStackContent((void**)uc
->uc_mcontext
.gregs
[7]);
526 #elif defined(__X86_64__) || defined(__x86_64__)
527 redisLog(REDIS_WARNING
,
529 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
530 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
531 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
532 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
533 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
534 uc
->uc_mcontext
.gregs
[13],
535 uc
->uc_mcontext
.gregs
[11],
536 uc
->uc_mcontext
.gregs
[14],
537 uc
->uc_mcontext
.gregs
[12],
538 uc
->uc_mcontext
.gregs
[8],
539 uc
->uc_mcontext
.gregs
[9],
540 uc
->uc_mcontext
.gregs
[10],
541 uc
->uc_mcontext
.gregs
[15],
542 uc
->uc_mcontext
.gregs
[0],
543 uc
->uc_mcontext
.gregs
[1],
544 uc
->uc_mcontext
.gregs
[2],
545 uc
->uc_mcontext
.gregs
[3],
546 uc
->uc_mcontext
.gregs
[4],
547 uc
->uc_mcontext
.gregs
[5],
548 uc
->uc_mcontext
.gregs
[6],
549 uc
->uc_mcontext
.gregs
[7],
550 uc
->uc_mcontext
.gregs
[16],
551 uc
->uc_mcontext
.gregs
[17],
552 uc
->uc_mcontext
.gregs
[18]
554 logStackContent((void**)uc
->uc_mcontext
.gregs
[15]);
556 redisLog(REDIS_WARNING
,
557 " Dumping of registers not supported for this OS/arch");
561 /* Logs the stack trace using the backtrace() call. */
562 sds
getStackTrace(ucontext_t
*uc
) {
564 int i
, trace_size
= 0;
565 char **messages
= NULL
;
568 /* Generate the stack trace */
569 trace_size
= backtrace(trace
, 100);
571 /* overwrite sigaction with caller's address */
572 if (getMcontextEip(uc
) != NULL
) {
573 trace
[1] = getMcontextEip(uc
);
575 messages
= backtrace_symbols(trace
, trace_size
);
576 for (i
=1; i
<trace_size
; ++i
) {
577 st
= sdscat(st
,messages
[i
]);
578 st
= sdscatlen(st
,"\n",1);
580 zlibc_free(messages
);
584 /* Log information about the "current" client, that is, the client that is
585 * currently being served by Redis. May be NULL if Redis is not serving a
586 * client right now. */
587 void logCurrentClient(void) {
588 if (server
.current_client
== NULL
) return;
590 redisClient
*cc
= server
.current_client
;
594 redisLog(REDIS_WARNING
, "--- CURRENT CLIENT INFO");
595 client
= getClientInfoString(cc
);
596 redisLog(REDIS_WARNING
,"client: %s", client
);
598 for (j
= 0; j
< cc
->argc
; j
++) {
601 decoded
= getDecodedObject(cc
->argv
[j
]);
602 redisLog(REDIS_WARNING
,"argv[%d]: '%s'", j
, (char*)decoded
->ptr
);
603 decrRefCount(decoded
);
605 /* Check if the first argument, usually a key, is found inside the
606 * selected DB, and if so print info about the associated object. */
611 key
= getDecodedObject(cc
->argv
[1]);
612 de
= dictFind(cc
->db
->dict
, key
->ptr
);
614 val
= dictGetVal(de
);
615 redisLog(REDIS_WARNING
,"key '%s' found in DB containing the following object:", key
->ptr
);
616 redisLogObjectDebugInfo(val
);
622 void sigsegvHandler(int sig
, siginfo_t
*info
, void *secret
) {
623 ucontext_t
*uc
= (ucontext_t
*) secret
;
624 sds infostring
, clients
, st
;
625 struct sigaction act
;
629 redisLog(REDIS_WARNING
,
630 " Redis %s crashed by signal: %d", REDIS_VERSION
, sig
);
631 redisLog(REDIS_WARNING
,
632 " Failed assertion: %s (%s:%d)", server
.assert_failed
,
633 server
.assert_file
, server
.assert_line
);
635 /* Log the stack trace */
636 st
= getStackTrace(uc
);
637 redisLog(REDIS_WARNING
, "--- STACK TRACE\n%s", st
);
640 /* Log INFO and CLIENT LIST */
641 redisLog(REDIS_WARNING
, "--- INFO OUTPUT");
642 infostring
= genRedisInfoString("all");
643 infostring
= sdscatprintf(infostring
, "hash_init_value: %u\n",
644 dictGetHashFunctionSeed());
645 redisLogRaw(REDIS_WARNING
, infostring
);
646 redisLog(REDIS_WARNING
, "--- CLIENT LIST OUTPUT");
647 clients
= getAllClientsInfoString();
648 redisLogRaw(REDIS_WARNING
, clients
);
652 /* Log the current client */
655 /* Log dump of processor registers */
658 redisLog(REDIS_WARNING
,
659 "\n=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
660 " Please report the crash opening an issue on github:\n\n"
661 " http://github.com/antirez/redis/issues\n\n"
662 " Suspect RAM error? Use redis-server --test-memory to veryfy it.\n\n"
664 /* free(messages); Don't call free() with possibly corrupted memory. */
665 if (server
.daemonize
) unlink(server
.pidfile
);
667 /* Make sure we exit with the right signal at the end. So for instance
668 * the core will be dumped if enabled. */
669 sigemptyset (&act
.sa_mask
);
670 act
.sa_flags
= SA_NODEFER
| SA_ONSTACK
| SA_RESETHAND
;
671 act
.sa_handler
= SIG_DFL
;
672 sigaction (sig
, &act
, NULL
);
675 #endif /* HAVE_BACKTRACE */
677 /* =========================== Software Watchdog ============================ */
678 #include <sys/time.h>
680 void watchdogSignalHandler(int sig
, siginfo_t
*info
, void *secret
) {
681 ucontext_t
*uc
= (ucontext_t
*) secret
;
686 log
= sdsnew("\n--- WATCHDOG TIMER EXPIRED ---\n");
687 #ifdef HAVE_BACKTRACE
688 st
= getStackTrace(uc
);
690 st
= sdsnew("Sorry: no support for backtrace().\n");
692 log
= sdscatsds(log
,st
);
693 log
= sdscat(log
,"------\n");
694 redisLogFromHandler(REDIS_WARNING
,log
);
699 /* Schedule a SIGALRM delivery after the specified period in milliseconds.
700 * If a timer is already scheduled, this function will re-schedule it to the
701 * specified time. If period is 0 the current timer is disabled. */
702 void watchdogScheduleSignal(int period
) {
705 /* Will stop the timer if period is 0. */
706 it
.it_value
.tv_sec
= period
/1000;
707 it
.it_value
.tv_usec
= (period%1000
)*1000;
708 /* Don't automatically restart. */
709 it
.it_interval
.tv_sec
= 0;
710 it
.it_interval
.tv_usec
= 0;
711 setitimer(ITIMER_REAL
, &it
, NULL
);
714 /* Enable the software watchdong with the specified period in milliseconds. */
715 void enableWatchdog(int period
) {
716 if (server
.watchdog_period
== 0) {
717 struct sigaction act
;
719 /* Watchdog was actually disabled, so we have to setup the signal
721 sigemptyset(&act
.sa_mask
);
722 act
.sa_flags
= SA_NODEFER
| SA_ONSTACK
| SA_SIGINFO
;
723 act
.sa_sigaction
= watchdogSignalHandler
;
724 sigaction(SIGALRM
, &act
, NULL
);
726 if (period
< 200) period
= 200; /* We don't accept periods < 200 ms. */
727 watchdogScheduleSignal(period
); /* Adjust the current timer. */
728 server
.watchdog_period
= period
;
731 /* Disable the software watchdog. */
732 void disableWatchdog(void) {
733 struct sigaction act
;
734 if (server
.watchdog_period
== 0) return; /* Already disabled. */
735 watchdogScheduleSignal(0); /* Stop the current timer. */
737 /* Set the signal handler to SIG_IGN, this will also remove pending
738 * signals from the queue. */
739 sigemptyset(&act
.sa_mask
);
741 act
.sa_handler
= SIG_IGN
;
742 sigaction(SIGALRM
, &act
, NULL
);
743 server
.watchdog_period
= 0;