35
35
#include "../../ipc.h"
36
36
#include "../../status_report.h"
37
37
#include "sql_cacher.h"
38
+ #include "../../lib/csv.h"
38
39
39
40
static int mod_init (void );
40
41
static void destroy (void );
@@ -44,7 +45,15 @@ int pv_parse_name(pv_spec_p sp, const str *in);
44
45
int pv_init_param (pv_spec_p sp , int param );
45
46
int pv_get_sql_cached_value (struct sip_msg * msg , pv_param_t * param , pv_value_t * res );
46
47
static int parse_cache_entry (unsigned int type , void * val );
48
+ static void optimize_cdb_decode (pv_name_fix_t * pv_name );
47
49
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 );
48
57
49
58
static mi_response_t * mi_reload_1 (const mi_params_t * params ,
50
59
struct mi_handler * async_hdl );
@@ -69,6 +78,17 @@ gen_lock_t *queries_lock;
69
78
70
79
void * sql_srg = NULL ;
71
80
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
+
72
92
/* module parameters */
73
93
static const param_export_t mod_params [] = {
74
94
{"spec_delimiter" , STR_PARAM , & spec_delimiter .s },
@@ -118,7 +138,7 @@ struct module_exports exports = {
118
138
DEFAULT_DLFLAGS , /* dlopen flags */
119
139
0 , /* load function */
120
140
& deps , /* OpenSIPS module dependencies */
121
- 0 , /* exported functions */
141
+ cmds , /* exported functions */
122
142
0 , /* exported async functions */
123
143
mod_params , /* exported parameters */
124
144
0 , /* exported statistics */
@@ -1499,7 +1519,7 @@ static int cdb_fetch(pv_name_fix_t *pv_name, str *cdb_res, int *entry_rld_vers)
1499
1519
* 2 - error
1500
1520
* 3 - does not match reload version (old value)
1501
1521
*/
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 ,
1503
1523
str * str_res , int * int_res )
1504
1524
{
1505
1525
int int_val , next_str_off , i , rc ;
@@ -2126,3 +2146,224 @@ static void destroy(void)
2126
2146
lock_destroy (queries_lock );
2127
2147
lock_dealloc (queries_lock );
2128
2148
}
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