Skip to content

Commit 1687155

Browse files
committed
sql_cacher: Add support for dumping a given cache
1 parent 41aea5f commit 1687155

File tree

1 file changed

+243
-2
lines changed

1 file changed

+243
-2
lines changed

modules/sql_cacher/sql_cacher.c

Lines changed: 243 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "../../ipc.h"
3636
#include "../../status_report.h"
3737
#include "sql_cacher.h"
38+
#include "../../lib/csv.h"
3839

3940
static int mod_init(void);
4041
static void destroy(void);
@@ -44,7 +45,15 @@ int pv_parse_name(pv_spec_p sp, const str *in);
4445
int pv_init_param(pv_spec_p sp, int param);
4546
int pv_get_sql_cached_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
4647
static int parse_cache_entry(unsigned int type, void *val);
48+
static void optimize_cdb_decode(pv_name_fix_t *pv_name);
4749
static void free_c_entry(cache_entry_t *c);
50+
static int fixup_cache_dump_con(void **param);
51+
static int fixup_cache_dump_fields(void **param);
52+
static int fixup_cache_dump_fields_free(void **param);
53+
static int fixup_cache_dump_ret(void **param);
54+
static int fixup_cache_dump_ret_free(void **param);
55+
static int sql_cache_dump(struct sip_msg *msg, db_handlers_t *dbh,
56+
pv_name_fix_t *cols, pvname_list_t *dst_avps);
4857

4958
static mi_response_t *mi_reload_1(const mi_params_t *params,
5059
struct mi_handler *async_hdl);
@@ -69,6 +78,17 @@ gen_lock_t *queries_lock;
6978

7079
void *sql_srg = NULL;
7180

81+
/* module functions */
82+
static const cmd_export_t cmds[] = {
83+
{"sql_cache_dump", (cmd_function)sql_cache_dump, {
84+
{CMD_PARAM_STR, fixup_cache_dump_con, 0},
85+
{CMD_PARAM_STR, fixup_cache_dump_fields, fixup_cache_dump_fields_free},
86+
{CMD_PARAM_STR|CMD_PARAM_NO_EXPAND, fixup_cache_dump_ret, fixup_cache_dump_ret_free},
87+
{0, 0, 0}},
88+
ALL_ROUTES},
89+
{0, 0, {{0, 0, 0}}, 0}
90+
};
91+
7292
/* module parameters */
7393
static const param_export_t mod_params[] = {
7494
{"spec_delimiter", STR_PARAM, &spec_delimiter.s},
@@ -118,7 +138,7 @@ struct module_exports exports = {
118138
DEFAULT_DLFLAGS, /* dlopen flags */
119139
0, /* load function */
120140
&deps, /* OpenSIPS module dependencies */
121-
0, /* exported functions */
141+
cmds, /* exported functions */
122142
0, /* exported async functions */
123143
mod_params, /* exported parameters */
124144
0, /* exported statistics */
@@ -1499,7 +1519,7 @@ static int cdb_fetch(pv_name_fix_t *pv_name, str *cdb_res, int *entry_rld_vers)
14991519
* 2 - error
15001520
* 3 - does not match reload version (old value)
15011521
*/
1502-
static int cdb_val_decode(pv_name_fix_t *pv_name, str *cdb_val, int reload_version,
1522+
static int cdb_val_decode(const pv_name_fix_t *pv_name, const str *cdb_val, int reload_version,
15031523
str *str_res, int *int_res)
15041524
{
15051525
int int_val, next_str_off, i, rc;
@@ -2126,3 +2146,224 @@ static void destroy(void)
21262146
lock_destroy(queries_lock);
21272147
lock_dealloc(queries_lock);
21282148
}
2149+
2150+
/* make the param con @c_entry available during param fields processing */
2151+
static cache_entry_t *c_entry;
2152+
static int fixup_cache_dump_con(void **param)
2153+
{
2154+
db_handlers_t *it;
2155+
str s = *(str *)*param;
2156+
2157+
for (it = db_hdls_list; it; it = it->next) {
2158+
if (str_match(&it->c_entry->id, &s)) {
2159+
*param = it;
2160+
c_entry = it->c_entry;
2161+
2162+
if (!CACHEDB_CAPABILITY(&it->cdbf, CACHEDB_CAP_ITER_KEYS)) {
2163+
LM_ERR("cacheDB id '%.*s' has no support "
2164+
"for key iteration\n", s.len, s.s);
2165+
return -1;
2166+
}
2167+
2168+
return 0;
2169+
}
2170+
}
2171+
LM_ERR("caching id not found: '%.*s'\n", s.len, s.s);
2172+
return E_UNSPEC;
2173+
}
2174+
2175+
/* make the param 2 size available during param 3 processing */
2176+
static int ncols;
2177+
2178+
static int fixup_cache_dump_fields(void **param)
2179+
{
2180+
pv_name_fix_t *fixed_cols;
2181+
csv_record *cols, *col;
2182+
int i, len;
2183+
char *p;
2184+
str s = *(str *)*param;
2185+
2186+
cols = parse_csv_record(&s);
2187+
if (!cols) {
2188+
LM_ERR("oom\n");
2189+
return -1;
2190+
}
2191+
2192+
len = 0;
2193+
for (col = cols; col; col = col->next, ncols++) {
2194+
if (col->s.len == 0) {
2195+
LM_ERR("empty-string column in cache: '%.*s'\n", s.len, s.s);
2196+
return -1;
2197+
}
2198+
len += col->s.len;
2199+
}
2200+
2201+
fixed_cols = pkg_malloc((ncols + 1) * sizeof *fixed_cols + len);
2202+
if (!fixed_cols) {
2203+
LM_ERR("oom\n");
2204+
return -1;
2205+
}
2206+
memset(fixed_cols, 0, (ncols + 1) * sizeof *fixed_cols);
2207+
p = (char *)fixed_cols + (ncols + 1) * sizeof *fixed_cols;
2208+
2209+
for (i = 0, col = cols; col; col = col->next, i++) {
2210+
memcpy(p, col->s.s, col->s.len);
2211+
fixed_cols[i].id.len = -1; /* hack: signifies 'reload-version' */
2212+
fixed_cols[i].col.s = p;
2213+
fixed_cols[i].col.len = col->s.len;
2214+
fixed_cols[i].c_entry = c_entry;
2215+
p += col->s.len;
2216+
}
2217+
free_csv_record(cols);
2218+
c_entry = NULL;
2219+
2220+
*param = (void *)fixed_cols;
2221+
return 0;
2222+
}
2223+
static int fixup_cache_dump_fields_free(void **param)
2224+
{
2225+
pkg_free(*param);
2226+
*param = NULL;
2227+
return 0;
2228+
}
2229+
static int fixup_cache_dump_ret(void **param)
2230+
{
2231+
int i;
2232+
pvname_list_t *avp_list, *avp;
2233+
str s = *(str *)*param;
2234+
2235+
avp_list = parse_pvname_list(&s, PVT_AVP);
2236+
if (!avp_list) {
2237+
LM_ERR("failed to parse AVP list: %s\n", s.s);
2238+
return E_UNSPEC;
2239+
}
2240+
2241+
for (i = 0, avp = avp_list; avp; i++, avp = avp->next)
2242+
;
2243+
2244+
if (i != ncols) {
2245+
LM_ERR("number of columns (%d) differs from number of AVPs (%d)\n",
2246+
ncols, i);
2247+
return E_UNSPEC;
2248+
}
2249+
2250+
ncols = 0;
2251+
*param = (void *)avp_list;
2252+
return 0;
2253+
}
2254+
2255+
static int fixup_cache_dump_ret_free(void **param)
2256+
{
2257+
pvname_list_t *l = (pvname_list_t *)*param, *next;
2258+
2259+
while (l) {
2260+
next = l->next;
2261+
pkg_free(l);
2262+
l = next;
2263+
}
2264+
2265+
*param = NULL;
2266+
return 0;
2267+
}
2268+
2269+
static const pv_name_fix_t *_selected_cols;
2270+
static pvname_list_t *_out_avps;
2271+
static int _rld_ver;
2272+
static struct sip_msg *_sip_msg;
2273+
static int decode_kv2avps(const str *key, const str *value)
2274+
{
2275+
static pv_value_t val_null = {str_init("<null>"), 0, PV_VAL_STR};
2276+
const pv_name_fix_t *col;
2277+
pvname_list_t *avp;
2278+
pv_value_t val;
2279+
str str_res;
2280+
int rc, int_res;
2281+
2282+
LM_DBG("called for key %.*s, val: %.*s\n", key->len, key->s, value->len, value->s);
2283+
2284+
/* skip internal keys (not part of the SQL table dataset) */
2285+
if (key->s[_selected_cols->c_entry->id.len] == '_')
2286+
return -1;
2287+
2288+
/* each column offset is pre-computed; fill in the AVPs ASAP! */
2289+
for (col = _selected_cols, avp = _out_avps; col->c_entry;
2290+
col++, avp = avp->next) {
2291+
2292+
str_res = STR_NULL;
2293+
int_res = 0;
2294+
rc = cdb_val_decode(col, value, _rld_ver, &str_res, &int_res);
2295+
switch (rc) {
2296+
case 0:
2297+
if (is_str_column(col)) {
2298+
val.rs = str_res;
2299+
val.flags = PV_VAL_STR;
2300+
} else {
2301+
val.ri = int_res;
2302+
val.flags = PV_VAL_INT|PV_TYPE_INT;
2303+
}
2304+
break;
2305+
2306+
case 1:
2307+
val = val_null;
2308+
break;
2309+
2310+
default:
2311+
LM_ERR("failed to decode key: '%.*s', val: '%.*s' (%d)\n",
2312+
key->len, key->s, value->len, value->s, rc);
2313+
return -1;
2314+
}
2315+
2316+
if (avp->sname.setf(_sip_msg, &avp->sname.pvp, 0, &val) != 0) {
2317+
LM_ERR("failed to set AVP\n");
2318+
return -1;
2319+
}
2320+
}
2321+
2322+
return 0;
2323+
}
2324+
2325+
static int sql_cache_dump(struct sip_msg *msg, db_handlers_t *dbh,
2326+
pv_name_fix_t *cols, pvname_list_t *dst_avps)
2327+
{
2328+
cache_entry_t *cache = dbh->c_entry;
2329+
int i, n, ver;
2330+
2331+
LM_DBG("dumping data from cache: %.*s\n", cache->id.len, cache->id.s);
2332+
2333+
lock_start_read(cache->ref_lock);
2334+
2335+
ver = get_rld_vers_from_cache(cache, dbh);
2336+
if (ver < 0) {
2337+
lock_stop_read(cache->ref_lock);
2338+
LM_ERR("failed to get reload version\n");
2339+
return -1;
2340+
}
2341+
2342+
if (cols[0].id.len != ver) {
2343+
for (i = 0; cols[i].c_entry; i++) {
2344+
optimize_cdb_decode(&cols[i]);
2345+
LM_DBG("optimized fields for col '%.*s': %d/%d/%d\n",
2346+
cols[i].col.len, cols[i].col.s, cols[i].col_offset,
2347+
cols[i].col_nr, cols[i].last_str);
2348+
}
2349+
2350+
cols[0].id.len = ver;
2351+
}
2352+
2353+
_selected_cols = cols;
2354+
_out_avps = dst_avps;
2355+
_rld_ver = ver;
2356+
_sip_msg = msg;
2357+
2358+
n = dbh->cdbf.iter_keys(dbh->cdbcon, decode_kv2avps);
2359+
if (n < 0) {
2360+
lock_stop_read(cache->ref_lock);
2361+
LM_ERR("failed to fully iterate through cache '%.*s'\n",
2362+
cache->id.len, cache->id.s);
2363+
return -1;
2364+
}
2365+
2366+
lock_stop_read(cache->ref_lock);
2367+
2368+
return n == 0 ? -2 : n;
2369+
}

0 commit comments

Comments
 (0)