forked from memcached/memcached
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathproxy_ustats.c
103 lines (90 loc) · 3.16 KB
/
proxy_ustats.c
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
102
103
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "proxy.h"
// mcp.add_stat(index, name)
// creates a custom lua stats counter
int mcplib_add_stat(lua_State *L) {
int idx = luaL_checkinteger(L, -2);
const char *name = luaL_checkstring(L, -1);
proxy_ctx_t *ctx = PROXY_GET_CTX(L);
if (idx < 1) {
proxy_lua_error(L, "stat index must be 1 or higher");
return 0;
}
if (idx > ctx->tunables.max_ustats) {
proxy_lua_ferror(L, "stat index must be %d or less", ctx->tunables.max_ustats);
return 0;
}
// max name length? avoids errors if something huge gets thrown in.
if (strlen(name) > STAT_KEY_LEN - 6) {
// we prepend "user_" to the output. + null byte.
proxy_lua_ferror(L, "stat name too long: %s\n", name);
return 0;
}
// restrict characters, at least no spaces/newlines.
for (int x = 0; x < strlen(name); x++) {
if (isspace(name[x])) {
proxy_lua_error(L, "stat cannot contain spaces or newlines");
return 0;
}
}
STAT_L(ctx);
int stats_num = ctx->user_stats_num;
struct proxy_user_stats_entry *entries = ctx->user_stats;
// if num_stats is 0 we need to init sizes.
// TODO (v2): malloc fail checking. (should be rare/impossible)
if (stats_num < idx) {
struct proxy_user_stats_entry *nentries = calloc(idx, sizeof(*entries));
// funny realloc; start with zeroed memory and copy in original.
if (entries) {
memcpy(nentries, entries, sizeof(*entries) * stats_num);
free(entries);
}
ctx->user_stats = nentries;
ctx->user_stats_num = idx;
entries = nentries;
}
idx--; // real slot start as 0.
if (entries[idx].name != NULL) {
// If name changed, we have to reset the counter in the slot.
// Also only free/strdup the string if it's changed.
if (strcmp(name, entries[idx].name) != 0) {
entries[idx].reset = true;
free(entries[idx].name);
entries[idx].name = strdup(name);
}
// else the stat name didn't change, so don't do anything.
} else if (entries[idx].cname) {
char *oldname = ctx->user_stats_namebuf + entries[idx].cname;
if (strcmp(name, oldname) != 0) {
entries[idx].reset = true;
entries[idx].name = strdup(name);
}
} else {
entries[idx].name = strdup(name);
}
STAT_UL(ctx);
return 0;
}
int mcplib_stat(lua_State *L) {
LIBEVENT_THREAD *t = PROXY_GET_THR(L);
if (t == NULL) {
proxy_lua_error(L, "stat must be called from router handlers");
return 0;
}
struct proxy_user_stats *tus = t->proxy_user_stats;
if (tus == NULL) {
proxy_lua_error(L, "no stats counters initialized");
return 0;
}
int idx = luaL_checkinteger(L, -2);
int change = luaL_checkinteger(L, -1);
if (idx < 1 || idx > tus->num_stats) {
proxy_lua_error(L, "stat index out of range");
return 0;
}
idx--; // actual array is 0 indexed.
WSTAT_L(t);
tus->counters[idx] += change;
WSTAT_UL(t);
return 0;
}