-
Notifications
You must be signed in to change notification settings - Fork 235
Expand file tree
/
Copy pathdebug.c
More file actions
102 lines (79 loc) · 2.6 KB
/
Copy pathdebug.c
File metadata and controls
102 lines (79 loc) · 2.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
* Copyright 2018-2020 Redis Labs Ltd. and Contributors
*
* This file is available under the Redis Labs Source Available License Agreement
*/
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include "RG.h"
#include "util/thpool/pools.h"
#include "commands/cmd_context.h"
extern CommandCtx **command_ctxs;
static struct sigaction old_act;
static void startCrashReport(void) {
RedisModule_Log(NULL, "warning", "=== REDISGRAPH BUG REPORT START: ===");
}
static void endCrashReport(void) {
RedisModule_Log(NULL, "warning", "=== REDISGRAPH BUG REPORT END. ===");
}
static void logCommands(void) {
// #readers + #writers + Redis main thread
int nthreads = ThreadPools_ThreadCount() + 1;
for(int i = 0; i < nthreads; i++) {
CommandCtx *cmd = command_ctxs[i];
if(cmd != NULL) {
RedisModule_Log(NULL, "warning", "%s %s", cmd->command_name,
cmd->query);
}
}
}
void InfoFunc(RedisModuleInfoCtx *ctx, int for_crash_report) {
// make sure information is requested for crash report
if(!for_crash_report) return;
// pause all working threads
// NOTE: pausing is not an atomic action;
// other threads can potentially change states before being interrupted.
ThreadPools_Pause();
char *command_desc = NULL;
// #readers + #writers + Redis main thread
int nthreads = ThreadPools_ThreadCount() + 1;
RedisModule_InfoAddSection(ctx, "executing commands");
for(int i = 0; i < nthreads; i++) {
CommandCtx *cmd = command_ctxs[i];
if(cmd != NULL) {
asprintf(&command_desc, "%s %s", cmd->command_name, cmd->query);
RedisModule_InfoAddFieldCString(ctx, "command", command_desc);
free(command_desc);
}
}
}
void crashHandler(int sig, siginfo_t *info, void *ucontext) {
// pause all working threads
// NOTE: pausing is an async operation
ThreadPools_Pause();
startCrashReport();
// log currently executing GRAPH commands
logCommands();
endCrashReport();
// call previous (Redis original) handler
(*old_act.sa_sigaction)(sig, info, ucontext);
}
void setupCrashHandlers(RedisModuleCtx *ctx) {
// if RedisModule_RegisterInfoFunc is available use it
// to report RedisGraph additional information in case of a crash
// otherwise overwrite Redis signal handler
if(RedisModule_RegisterInfoFunc) {
int registered = RedisModule_RegisterInfoFunc(ctx, InfoFunc);
ASSERT(registered == REDISMODULE_OK);
} else {
// RegisterInfoFunc is not available, replace redis
// SIGSEGV signal handler
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
act.sa_sigaction = crashHandler;
sigaction(SIGSEGV, &act, &old_act);
}
}