1 #define MODULE_LOG_PREFIX "cache"
4 #include "module-cacheex.h"
5 #include "module-cw-cycle-check.h"
6 #include "oscam-cache.h"
8 #include "oscam-client.h"
10 #include "oscam-garbage.h"
11 #include "oscam-lock.h"
12 #include "oscam-net.h"
13 #include "oscam-string.h"
14 #include "oscam-time.h"
15 #include "oscam-hashtable.h"
17 #include "oscam-log.h"
21 // CACHE functions **************************************************************+
25 struct s_pushclient
*next_push
;
31 uint8_t odd_even
; // odd/even byte (0x80 0x81)
32 uint8_t cwc_cycletime
;
33 uint8_t cwc_next_cw_cycle
;
34 uint8_t got_bad_cwc
; // used by cycle check
35 uint16_t caid
; // first caid received
36 uint32_t prid
; // first prid received
37 uint16_t srvid
; // first srvid received
38 struct s_reader
*selected_reader
; // first answering: reader
39 struct s_client
*cacheex_src
; // first answering: cacheex client
40 uint64_t grp
; // updated grp
41 uint8_t csp
; // updated if answer from csp
42 uint8_t cacheex
; // updated if answer from cacheex
43 uint8_t localcards
; // updated if answer from local cards (or proxy using localcards option)
44 uint8_t proxy
; // updated if answer from local reader
45 uint32_t count
; // count of same cws receved
47 uint8_t localgenerated
; // flag for local generated CWs
50 pthread_rwlock_t pushout_client_lock
;
51 struct s_pushclient
*pushout_client
; // list of clients that pushing cw
53 node ht_node
; // node for hash table
54 node ll_node
; // node for linked list
57 typedef struct cache_t
61 struct timeb upd_time
; // updated time. Update time at each cw got
62 struct timeb first_recv_time
; // time of first cw received
64 node ht_node
; // node for hash table
65 node ll_node
; // node for linked list
69 typedef struct cw_cache_t
75 struct timeb first_recv_time
; // time of first cw received
76 struct timeb upd_time
; // updated time. Update time at each cw got
81 typedef struct cw_cache_setting_t
84 uint16_t timediff_old_cw
;
88 static pthread_rwlock_t cache_lock
;
90 static pthread_rwlock_t cw_cache_lock
;
92 static hash_table ht_cache
;
94 static hash_table ht_cw_cache
;
98 static list ll_cw_cache
;
100 static int8_t cache_init_done
= 0;
102 #ifdef CS_CACHEEX_AIO
103 static int8_t cw_cache_init_done
= 0;
104 static uint32_t lg_cache_size
= 0;
106 void init_cw_cache(void)
109 if(cfg
.cw_cache_size
> 0 || cfg
.cw_cache_memory
> 0)
111 init_hash_table(&ht_cw_cache
, &ll_cw_cache
);
112 if (pthread_rwlock_init(&cw_cache_lock
,NULL
) != 0)
113 { cs_log("Error creating lock cw_cache_lock!"); }
115 { cw_cache_init_done
= 1; }
121 void init_cache(void)
123 init_hash_table(&ht_cache
, &ll_cache
);
124 if (pthread_rwlock_init(&cache_lock
,NULL
) != 0)
125 { cs_log("Error creating lock cache_lock!"); }
127 { cache_init_done
= 1; }
130 void free_cache(void)
133 #ifdef CS_CACHEEX_AIO
134 cw_cache_cleanup(true);
135 ecm_cache_cleanup(true);
136 cw_cache_init_done
= 0;
137 deinitialize_hash_table(&ht_cw_cache
);
138 pthread_rwlock_destroy(&cw_cache_lock
);
141 deinitialize_hash_table(&ht_cache
);
142 pthread_rwlock_destroy(&cache_lock
);
145 #ifdef CS_CACHEEX_AIO
146 uint32_t cache_size_lg(void)
151 return lg_cache_size
;
155 uint32_t cache_size(void)
160 return count_hash_table(&ht_cache
);
163 static uint8_t count_sort(CW
*a
, CW
*b
)
165 if (a
->count
== b
->count
) return 0;
166 return (a
->count
> b
->count
) ? -1 : 1; // DESC order by count
169 #ifdef CS_CACHEEX_AIO
170 static uint8_t time_sort(CW_CACHE
*a
, CW_CACHE
*b
)
172 if (((int64_t)(a
->upd_time
.time
) * 1000ull + (int64_t) a
->upd_time
.millitm
) == ((int64_t)(b
->upd_time
.time
) * 1000ull + (int64_t) b
->upd_time
.millitm
)) return 0;
173 return (((int64_t)(a
->upd_time
.time
) * 1000ull + (int64_t) a
->upd_time
.millitm
) > ((int64_t)(b
->upd_time
.time
) * 1000ull + (int64_t) b
->upd_time
.millitm
)) ? -1 : 1;
177 uint8_t check_is_pushed(void *cwp
, struct s_client
*cl
)
179 struct s_pushclient
*cl_tmp
;
183 SAFE_RWLOCK_RDLOCK(&cw
->pushout_client_lock
);
184 for (cl_tmp
= cw
->pushout_client
; cl_tmp
; cl_tmp
= cl_tmp
->next_push
)
195 SAFE_RWLOCK_UNLOCK(&cw
->pushout_client_lock
);
196 SAFE_RWLOCK_WRLOCK(&cw
->pushout_client_lock
);
198 struct s_pushclient
*new_push_client
;
199 if(cs_malloc(&new_push_client
, sizeof(struct s_pushclient
)))
201 new_push_client
->cl
=cl
;
203 new_push_client
->next_push
=cw
->pushout_client
;
204 cw
->pushout_client
=new_push_client
;
207 SAFE_RWLOCK_UNLOCK(&cw
->pushout_client_lock
);
212 SAFE_RWLOCK_UNLOCK(&cw
->pushout_client_lock
);
217 uint8_t get_odd_even(ECM_REQUEST
*er
)
219 return (er
->ecm
[0] != 0x80 && er
->ecm
[0] != 0x81 ? 0 : er
->ecm
[0]);
223 CW
*get_first_cw(ECMHASH
*ecmhash
, ECM_REQUEST
*er
)
225 if(!ecmhash
) return NULL
;
230 j
= get_first_node_list(&ecmhash
->ll_cw
);
232 cw
= get_data_from_node(j
);
234 if(cw
&& cw
->odd_even
== get_odd_even(er
) && !cw
->got_bad_cwc
)
243 int compare_csp_hash(const void *arg
, const void *obj
)
245 uint32_t h
= ((const ECMHASH
*)obj
)->csp_hash
;
246 return memcmp(arg
, &h
, 4);
249 static int compare_cw(const void *arg
, const void *obj
)
251 return memcmp(arg
, ((const CW
*)obj
)->cw
, 16);
254 #ifdef CS_CACHEEX_AIO
255 static int compare_cw_cache(const void *arg
, const void *obj
)
257 return memcmp(arg
, ((const CW_CACHE
*)obj
)->cw
, 16);
261 static bool cwcycle_check_cache(struct s_client
*cl
, ECM_REQUEST
*er
, CW
*cw
)
263 (void)cl
; (void)er
; (void)cw
;
265 #ifdef CW_CYCLE_CHECK
269 uint8_t cwc_ct
= cw
->cwc_cycletime
> 0 ? cw
->cwc_cycletime
: 0;
270 uint8_t cwc_ncwc
= cw
->cwc_next_cw_cycle
< 2 ? cw
->cwc_next_cw_cycle
: 2;
271 if(checkcwcycle(cl
, er
, NULL
, cw
->cw
, 0, cwc_ct
, cwc_ncwc
) != 0)
273 cs_log_dbg(D_CWC
| D_LB
, "{client %s, caid %04X, srvid %04X} [check_cache] cyclecheck passed ecm in INT. cache.", (cl
? cl
->account
->usr
: "-"), er
->caid
, er
->srvid
);
277 #ifdef CS_CACHEEX_AIO
278 if(!er
->localgenerated
)
281 cs_log_dbg(D_CWC
, "cyclecheck [BAD CW Cycle] from Int. Cache detected.. {client %s, caid %04X, srvid %04X} [check_cache] -> skip cache answer", (cl
? cl
->account
->usr
: "-"), er
->caid
, er
->srvid
);
282 cw
->got_bad_cwc
= 1; // no need to check it again
284 #ifdef CS_CACHEEX_AIO
288 cs_log_dbg(D_CWC
, "cyclecheck [BAD CW Cycle] from Int. Cache detected.. {client %s, caid %04X, srvid %04X} [check_cache] -> lg-flagged CW -> do nothing", (cl
? cl
->account
->usr
: "-"), er
->caid
, er
->srvid
);
297 * This function returns cw (mostly received) in cache for er, or NULL if not found.
299 * - If found, DON'T forget to free returned ecm, because it is a copy useful to get data
300 * - If found, and cacheex_src client of returned ecm is not NULL, and we want to access it,
301 * remember to check for its validity (client structure is still existent)
302 * E.g.: if(ecm->cacheex_src && is_valid_client(ecm->cacheex_src) && !ecm->cacheex_src->kill)
303 * We don't want make this stuff here to avoid useless cpu time if outside function we would not access to it.
305 struct ecm_request_t
*check_cache(ECM_REQUEST
*er
, struct s_client
*cl
)
307 if(!cache_init_done
|| !er
->csp_hash
) return NULL
;
309 ECM_REQUEST
*ecm
= NULL
;
312 uint64_t grp
= cl
?cl
->grp
:0;
314 SAFE_RWLOCK_RDLOCK(&cache_lock
);
316 result
= find_hash_table(&ht_cache
, &er
->csp_hash
, sizeof(uint32_t),&compare_csp_hash
);
317 cw
= get_first_cw(result
, er
);
321 if(cw
->csp
// csp have no grp!
322 || !grp
// csp client(no grp) searching for cache
323 || (grp
&& cw
->grp
// ecm group --> only when readers/ex-clients answer (e_found) it
327 //if preferlocalcards=2 for this ecm request, we can server ONLY cw from localcards readers until stage<3
328 if(er
->preferlocalcards
==2 && !cw
->localcards
&& er
->stage
<3){
332 CWCHECK check_cw
= get_cwcheck(er
);
334 if((!cw
->proxy
&& !cw
->localcards
) // cw received from ONLY cacheex/csp peers
335 && check_cw
.counter
>1
336 && cw
->count
< check_cw
.counter
337 && (check_cw
.mode
== 1 || !er
->cacheex_wait_time_expired
))
342 #ifdef CS_CACHEEX_AIO
344 if( cl
&& !cw
->localgenerated
345 && !(chk_srvid_localgenerated_only_exception(er
)) // service-based exception
346 && (cl
->account
->cacheex
.localgenerated_only
347 || (chk_lg_only(er
, &cl
->account
->cacheex
.lg_only_tab
))
348 ) // only lg-flagged CWs
356 if (!cwcycle_check_cache(cl
, er
, cw
))
359 if (cs_malloc(&ecm
, sizeof(ECM_REQUEST
)))
363 memcpy(ecm
->cw
, cw
->cw
, 16);
365 ecm
->selected_reader
= cw
->selected_reader
;
366 ecm
->cwc_cycletime
= cw
->cwc_cycletime
;
367 ecm
->cwc_next_cw_cycle
= cw
->cwc_next_cw_cycle
;
368 ecm
->cacheex_src
= cw
->cacheex_src
;
369 #ifdef CS_CACHEEX_AIO
370 ecm
->localgenerated
= (cw
->localgenerated
) ? 1:0;
372 ecm
->cw_count
= cw
->count
;
377 SAFE_RWLOCK_UNLOCK(&cache_lock
);
381 #ifdef CS_CACHEEX_AIO
382 uint16_t get_cacheex_nopushafter(ECM_REQUEST
*er
)
384 return caidvaluetab_get_value(&cfg
.cacheex_nopushafter_tab
, er
->caid
, 0);
388 static void cacheex_cache_add(ECM_REQUEST
*er
, ECMHASH
*result
, CW
*cw
, bool add_new_cw
)
390 (void)er
; (void)result
; (void)cw
; (void)add_new_cw
;
393 cacheex_cache_push(er
);
395 // cacheex debug log lines and cw diff stuff
396 if(!check_client(er
->cacheex_src
))
399 #ifdef CS_CACHEEX_AIO
400 if (D_CACHEEX
& cs_dblevel
)
402 uint8_t remotenodeid
[8];
403 cacheex_get_srcnodeid(er
, remotenodeid
);
407 debug_ecm(D_CACHEEX
| D_CSP
, "got duplicate pushed ECM %s from %s - hop %i %s, src-nodeid %" PRIu64
"X", buf
, er
->from_csp
? "csp" : username(er
->cacheex_src
), ll_count(er
->csp_lastnodes
), er
->localgenerated
? "(lg)" : "", cacheex_node_id(remotenodeid
));
411 debug_ecm(D_CACHEEX
|D_CSP
, "got pushed ECM %s from %s - hop %i %s, src-nodeid %" PRIu64
"X", buf
, er
->from_csp
? "csp" : username(er
->cacheex_src
), ll_count(er
->csp_lastnodes
), er
->localgenerated
? "(lg)" : "", cacheex_node_id(remotenodeid
));
418 #ifdef CS_CACHEEX_AIO
419 debug_ecm(D_CACHEEX
| D_CSP
, "got duplicate pushed ECM %s from %s - hop %i %s", buf
, er
->from_csp
? "csp" : username(er
->cacheex_src
), ll_count(er
->csp_lastnodes
), er
->localgenerated
? "(lg)" : "");
421 debug_ecm(D_CACHEEX
| D_CSP
, "got duplicate pushed ECM %s from %s", buf
, er
->from_csp
? "csp" : username(er
->cacheex_src
));
426 #ifdef CS_CACHEEX_AIO
427 debug_ecm(D_CACHEEX
|D_CSP
, "got pushed ECM %s from %s - hop %i %s", buf
, er
->from_csp
? "csp" : username(er
->cacheex_src
), ll_count(er
->csp_lastnodes
), er
->localgenerated
? "(lg)" : "");
429 debug_ecm(D_CACHEEX
|D_CSP
, "got pushed ECM %s from %s", buf
, er
->from_csp
? "csp" : username(er
->cacheex_src
));
432 #ifdef CS_CACHEEX_AIO
436 CW
*cw_first
= get_first_cw(result
, er
);
440 // compare er cw with mostly counted cached cw
441 if(memcmp(er
->cw
, cw_first
->cw
, sizeof(er
->cw
)) != 0)
443 er
->cacheex_src
->cwcacheexerrcw
++;
444 if (er
->cacheex_src
->account
)
445 er
->cacheex_src
->account
->cwcacheexerrcw
++;
447 if (((0x0200| 0x0800) & cs_dblevel
)) // avoid useless operations if debug is not enabled
449 char cw1
[16*3+2], cw2
[16*3+2];
450 cs_hexdump(0, er
->cw
, 16, cw1
, sizeof(cw1
));
451 cs_hexdump(0, cw_first
->cw
, 16, cw2
, sizeof(cw2
));
453 char ip1
[20]="", ip2
[20]="";
454 if (check_client(er
->cacheex_src
))
455 cs_strncpy(ip1
, cs_inet_ntoa(er
->cacheex_src
->ip
), sizeof(ip1
));
456 if (check_client(cw_first
->cacheex_src
))
457 cs_strncpy(ip2
, cs_inet_ntoa(cw_first
->cacheex_src
->ip
), sizeof(ip2
));
458 else if (cw_first
->selected_reader
&& check_client(cw_first
->selected_reader
->client
))
459 cs_strncpy(ip2
, cs_inet_ntoa(cw_first
->selected_reader
->client
->ip
), sizeof(ip2
));
461 #ifdef CS_CACHEEX_AIO
462 uint8_t remotenodeid
[8];
463 cacheex_get_srcnodeid(er
, remotenodeid
);
465 uint8_t fakeF0
= 0, offset
= 0;
467 if(get_odd_even(er
) == 0x81)
471 (cw_first
->cw
[7+offset
] != 0x00 && er
->cw
[7+offset
] != 0x00)
472 && (cw_first
->cw
[7+offset
] ^ 0xF0) == er
->cw
[7+offset
]
478 debug_ecm(D_CACHEEX
| D_CSP
, "WARNING: Different CWs %s from %s(%s)<>%s(%s): %s<>%s lg: %i<>%i, hop:%02i, src-nodeid: %" PRIu64
"X%s", buf
,
480 debug_ecm(D_CACHEEX
| D_CSP
, "WARNING: Different CWs %s from %s(%s)<>%s(%s): %s<>%s ", buf
,
482 er
->from_csp
? "csp" : username(er
->cacheex_src
), ip1
,
483 check_client(cw_first
->cacheex_src
)?username(cw_first
->cacheex_src
):(cw_first
->selected_reader
?cw_first
->selected_reader
->label
:"unknown/csp"), ip2
,
484 #ifdef CS_CACHEEX_AIO
485 cw1
, cw2
, er
->localgenerated
, cw_first
->localgenerated
, er
->csp_lastnodes
? ll_count(er
->csp_lastnodes
) : 0, er
->csp_lastnodes
? cacheex_node_id(remotenodeid
): 0, fakeF0
? " [last byte xor 0xF0]" : "");
490 if(cs_dblevel
& D_CACHEEX
)
492 LL_LOCKITER
*li
= ll_li_create(er
->csp_lastnodes
, 0);
495 while((nodeid
= ll_li_next(li
)))
497 cs_log_dbg(D_CACHEEX
, "Different CW-nodelist hop%02u: %" PRIu64
"X", ++hops
, cacheex_node_id(nodeid
));
507 #ifdef CS_CACHEEX_AIO
508 CW_CACHE_SETTING
get_cw_cache(ECM_REQUEST
*er
)
510 int32_t i
, timediff_old_cw
= 0;
513 for(i
= 0; i
< cfg
.cw_cache_settings
.cwchecknum
; i
++)
515 CWCHECKTAB_DATA
*d
= &cfg
.cw_cache_settings
.cwcheckdata
[i
];
517 if(i
== 0 && d
->caid
<= 0)
520 timediff_old_cw
= d
->counter
;
521 continue; //check other, only valid for unset
524 if(d
->caid
== er
->caid
|| d
->caid
== er
->caid
>> 8 || ((d
->cmask
>= 0 && (er
->caid
& d
->cmask
) == d
->caid
) || d
->caid
== -1))
526 if((d
->prid
>= 0 && d
->prid
== (int32_t)er
->prid
) || d
->prid
== -1)
528 if((d
->srvid
>= 0 && d
->srvid
== er
->srvid
) || d
->srvid
== -1)
531 timediff_old_cw
= d
->counter
;
538 //check for correct values
539 if(mode
>3 || mode
<0) mode
=0;
540 if(timediff_old_cw
<1) timediff_old_cw
=0;
542 CW_CACHE_SETTING cw_cache_setting
;
543 memset(&cw_cache_setting
, 0, sizeof(CW_CACHE_SETTING
));
544 cw_cache_setting
.mode
= mode
;
545 cw_cache_setting
.timediff_old_cw
= timediff_old_cw
;
547 return cw_cache_setting
;
550 static bool cw_cache_check(ECM_REQUEST
*er
)
552 if(cw_cache_init_done
)
554 CW_CACHE_SETTING cw_cache_setting
= get_cw_cache(er
);
555 if(cw_cache_setting
.mode
> 0)
557 CW_CACHE
*cw_cache
= NULL
;
558 SAFE_RWLOCK_WRLOCK(&cw_cache_lock
);
559 cw_cache
= find_hash_table(&ht_cw_cache
, &er
->cw
, sizeof(er
->cw
), &compare_cw_cache
);
560 // add cw to ht_cw_cache if < cw_cache_size
563 // cw_cache-size(count/memory) pre-check
565 (cfg
.cw_cache_size
&& (cfg
.cw_cache_size
> tommy_hashlin_count(&ht_cw_cache
)))
566 || (cfg
.cw_cache_memory
&& (cfg
.cw_cache_memory
*1024*1024 > (2 * tommy_hashlin_memory_usage(&ht_cw_cache
))))
569 if(cs_malloc(&cw_cache
, sizeof(CW_CACHE
)))
571 memcpy(cw_cache
->cw
, er
->cw
, sizeof(er
->cw
));
572 cw_cache
->caid
= er
->caid
;
573 cw_cache
->prid
= er
->prid
;
574 cw_cache
->srvid
= er
->srvid
;
575 cs_ftime(&cw_cache
->first_recv_time
);
576 cs_ftime(&cw_cache
->upd_time
);
578 tommy_hashlin_insert(&ht_cw_cache
, &cw_cache
->ht_node
, cw_cache
, tommy_hash_u32(0, &er
->cw
, sizeof(er
->cw
)));
579 tommy_list_insert_tail(&ll_cw_cache
, &cw_cache
->ll_node
, cw_cache
);
581 SAFE_RWLOCK_UNLOCK(&cw_cache_lock
);
586 SAFE_RWLOCK_UNLOCK(&cw_cache_lock
);
587 cs_log("[cw_cache] ERROR: NO added HASH to cw_cache!!");
594 SAFE_RWLOCK_UNLOCK(&cw_cache_lock
);
595 cw_cache_cleanup(false);
605 int64_t gone_diff
= 0;
607 gone_diff
= comp_timeb(&er
->tps
, &cw_cache
->first_recv_time
);
609 if(D_CW_CACHE
& cs_dblevel
)
611 cs_hexdump(0, cw_cache
->cw
, 16, cw1
, sizeof(cw1
));
612 cs_hexdump(0, er
->cw
, 16, cw2
, sizeof(cw2
));
615 if(cw_cache_setting
.timediff_old_cw
> 0 && gone_diff
> cw_cache_setting
.timediff_old_cw
) // late (>cw_cache_setting.timediff_old_cw) cw incoming
618 if(cs_dblevel
& D_CW_CACHE
)
620 uint8_t remotenodeid
[8];
621 cacheex_get_srcnodeid(er
, remotenodeid
);
622 cs_log_dbg(D_CW_CACHE
,"[dupe CW] cache: %04X:%06X:%04X:%s | in: %04X:%06X:%04X:%s | diff(now): %"PRIi64
" ms > %"PRIu16
" - %s - hop %i%s, src-nodeid %" PRIu64
"X", cw_cache
->caid
, cw_cache
->prid
, cw_cache
->srvid
, cw1
, er
->caid
, er
->prid
, er
->srvid
, cw2
, gone_diff
, cw_cache_setting
.timediff_old_cw
, (er
->selected_reader
&& cs_strlen(er
->selected_reader
->label
)) ? er
->selected_reader
->label
: username(er
->cacheex_src
), ll_count(er
->csp_lastnodes
), (er
->localgenerated
) ? " (lg)" : "", er
->csp_lastnodes
? cacheex_node_id(remotenodeid
): 0);
625 if(cw_cache
->srvid
== er
->srvid
&& cw_cache
->caid
== er
->caid
) // same cw for same caid&srvid
627 cs_ftime(&cw_cache
->upd_time
);
628 cs_log_dbg(D_CW_CACHE
,"[late CW] cache: %04X:%06X:%04X:%s | in: %04X:%06X:%04X:%s | diff(now): %"PRIi64
" ms > %"PRIu16
" - %s - hop %i%s", cw_cache
->caid
, cw_cache
->prid
, cw_cache
->srvid
, cw1
, er
->caid
, er
->prid
, er
->srvid
, cw2
, gone_diff
, cw_cache_setting
.timediff_old_cw
, (er
->selected_reader
&& cs_strlen(er
->selected_reader
->label
)) ? er
->selected_reader
->label
: username(er
->cacheex_src
), ll_count(er
->csp_lastnodes
), (er
->localgenerated
) ? " (lg)" : "");
632 else if(cw_cache
->srvid
!= er
->srvid
) // same cw for different srvid & late
634 cs_ftime(&cw_cache
->upd_time
);
635 cs_log_dbg(D_CW_CACHE
,"[dupe&late CW] cache: %04X:%06X:%04X:%s | in: %04X:%06X:%04X:%s| diff(now): %"PRIi64
" ms - %s - hop %i%s", cw_cache
->caid
, cw_cache
->prid
, cw_cache
->srvid
, cw1
, er
->caid
, er
->prid
, er
->srvid
, cw2
, gone_diff
, (er
->selected_reader
&& cs_strlen(er
->selected_reader
->label
)) ? er
->selected_reader
->label
: username(er
->cacheex_src
), ll_count(er
->csp_lastnodes
), (er
->localgenerated
) ? " (lg)" : "");
638 else if(gone_diff
> 15000) // same cw later as 15 secs
641 if(cs_dblevel
& D_CW_CACHE
)
643 uint8_t remotenodeid
[8];
644 cacheex_get_srcnodeid(er
, remotenodeid
);
645 cs_log_dbg(D_CW_CACHE
,"[late-15sec+ CW] cache: %04X:%06X:%04X:%s | in: %04X:%06X:%04X:%s | diff(now): %"PRIi64
" ms > %"PRIu16
" - %s - hop %i%s, src-nodeid %" PRIu64
"X", cw_cache
->caid
, cw_cache
->prid
, cw_cache
->srvid
, cw1
, er
->caid
, er
->prid
, er
->srvid
, cw2
, gone_diff
, cw_cache_setting
.timediff_old_cw
, (er
->selected_reader
&& cs_strlen(er
->selected_reader
->label
)) ? er
->selected_reader
->label
: username(er
->cacheex_src
), ll_count(er
->csp_lastnodes
), (er
->localgenerated
) ? " (lg)" : "", er
->csp_lastnodes
? cacheex_node_id(remotenodeid
): 0);
651 if(cw_cache_setting
.mode
> 1 && drop_cw
)
653 // cw_cache->drop_count++;
654 cs_log_dbg(D_CW_CACHE
,"incoming CW dropped - current cw_cache_size: %i - cw_cache-mem-size: %iMiB", count_hash_table(&ht_cw_cache
), 2*(int)tommy_hashlin_memory_usage(&ht_cw_cache
)/1024/1024);
655 SAFE_RWLOCK_UNLOCK(&cw_cache_lock
);
661 SAFE_RWLOCK_UNLOCK(&cw_cache_lock
);
667 cs_log_dbg(D_CW_CACHE
,"[cw_cache] cw_cache_init_done %i cfg.cw_cache_size: %u cfg.cw_cache_memory %u", cw_cache_init_done
, cfg
.cw_cache_size
, cfg
.cw_cache_memory
);
674 void add_cache(ECM_REQUEST
*er
)
676 if(!cache_init_done
|| !er
->csp_hash
) return;
677 #ifdef CS_CACHEEX_AIO
679 if(!cw_cache_check(er
))
684 ECMHASH
*result
= NULL
;
686 bool add_new_cw
=false;
688 SAFE_RWLOCK_WRLOCK(&cache_lock
);
690 // add csp_hash to cache
691 result
= find_hash_table(&ht_cache
, &er
->csp_hash
, sizeof(uint32_t), &compare_csp_hash
);
694 if(cs_malloc(&result
, sizeof(ECMHASH
)))
696 result
->csp_hash
= er
->csp_hash
;
697 init_hash_table(&result
->ht_cw
, &result
->ll_cw
);
698 cs_ftime(&result
->first_recv_time
);
699 add_hash_table(&ht_cache
, &result
->ht_node
, &ll_cache
, &result
->ll_node
, result
, &result
->csp_hash
, sizeof(uint32_t));
703 SAFE_RWLOCK_UNLOCK(&cache_lock
);
704 cs_log("ERROR: NO added HASH to cache!!");
709 cs_ftime(&result
->upd_time
); // need to be updated at each cw! We use it for deleting this hash when no more cws arrive inside max_cache_time!
711 //add cw to this csp hash
712 cw
= find_hash_table(&result
->ht_cw
, er
->cw
, sizeof(er
->cw
), &compare_cw
);
716 if(count_hash_table(&result
->ht_cw
) >= 10) // max 10 different cws stored
718 SAFE_RWLOCK_UNLOCK(&cache_lock
);
724 if(cs_malloc(&cw
, sizeof(CW
)))
726 memcpy(cw
->cw
, er
->cw
, sizeof(er
->cw
));
727 cw
->odd_even
= get_odd_even(er
);
728 cw
->cwc_cycletime
= er
->cwc_cycletime
;
729 cw
->cwc_next_cw_cycle
= er
->cwc_next_cw_cycle
;
738 cw
->srvid
= er
->srvid
;
739 cw
->selected_reader
=er
->selected_reader
;
740 cw
->cacheex_src
=er
->cacheex_src
;
741 cw
->pushout_client
= NULL
;
745 if (pthread_rwlock_init(&cw
->pushout_client_lock
, NULL
) == 0)
748 cs_log("Error creating lock pushout_client_lock!");
752 add_hash_table(&result
->ht_cw
, &cw
->ht_node
, &result
->ll_cw
, &cw
->ll_node
, cw
, cw
->cw
, sizeof(er
->cw
));
757 cs_log("ERROR: NO added CW to cache!! Re-trying...");
762 // update if answered from csp/cacheex/local_proxy
763 if(er
->from_cacheex
) cw
->cacheex
= 1;
764 if(er
->from_csp
) cw
->csp
= 1;
767 if(is_localreader(er
->selected_reader
, er
)) cw
->localcards
=1;
771 #ifdef CS_CACHEEX_AIO
772 // copy flag for local generated CW
773 if(er
->localgenerated
|| (er
->selected_reader
&& !is_network_reader(er
->selected_reader
)))
775 cw
->localgenerated
= 1;
776 er
->localgenerated
= 1;
777 // to favorite CWs with this flag while sorting
778 if(cw
->count
< 0x0F000000)
780 cw
->count
|= 0x0F000000;
786 cw
->localgenerated
= 0;
790 // always update group and counter
794 #ifdef CS_CACHEEX_AIO
795 // add count to er for checking @ cacheex_push
796 er
->cw_count
+= cw
->count
;
798 // sort cw_list by counter (DESC order)
800 sort_list(&result
->ll_cw
, count_sort
);
802 #ifdef CS_CACHEEX_AIO
803 // dont push not flagged CWs - global
804 if(!er
->localgenerated
&&
806 !chk_srvid_localgenerated_only_exception(er
)
807 && (cfg
.cacheex_localgenerated_only
|| chk_lg_only(er
, &cfg
.cacheex_lg_only_tab
))
810 cs_log_dbg(D_CACHEEX
, "cacheex: push denied, cacheex_localgenerated_only->global");
811 SAFE_RWLOCK_UNLOCK(&cache_lock
);
815 // dont push CW if time for caid > x && from local reader | proxy
816 if(er
->rc
< 3 && er
->ecm_time
&& get_cacheex_nopushafter(er
) != 0 &&(get_cacheex_nopushafter(er
) < er
->ecm_time
))
818 cs_log_dbg(D_CACHEEX
, "cacheex: push denied, cacheex_nopushafter %04X:%u < %i, reader: %s", er
->caid
, get_cacheex_nopushafter(er
), er
->ecm_time
, er
->selected_reader
->label
);
819 SAFE_RWLOCK_UNLOCK(&cache_lock
);
823 // no cacheex-push on diff-cw's if no localgenerated flag exist
824 if(cfg
.cacheex_dropdiffs
&& (count_hash_table(&result
->ht_cw
) > 1) && !er
->localgenerated
)
826 cs_log_dbg(D_CACHEEX
,"cacheex: diff CW - cacheex push denied src: %s", er
->selected_reader
->label
);
827 SAFE_RWLOCK_UNLOCK(&cache_lock
);
832 SAFE_RWLOCK_UNLOCK(&cache_lock
);
834 cacheex_cache_add(er
, result
, cw
, add_new_cw
);
837 #ifdef CS_CACHEEX_AIO
838 void cw_cache_cleanup(bool force
)
840 if(!cw_cache_init_done
)
843 SAFE_RWLOCK_WRLOCK(&cw_cache_lock
);
849 uint32_t ll_ten_percent
= (uint
)tommy_list_count(&ll_cw_cache
)*0.1; // 10 percent of cache
852 sort_list(&ll_cw_cache
, time_sort
);
854 i
= get_first_node_list(&ll_cw_cache
);
859 cw_cache
= get_data_from_node(i
);
870 if(ll_c
< ll_ten_percent
)
872 remove_elem_list(&ll_cw_cache
, &cw_cache
->ll_node
);
873 remove_elem_hash_table(&ht_cw_cache
, &cw_cache
->ht_node
);
882 remove_elem_list(&ll_cw_cache
, &cw_cache
->ll_node
);
883 remove_elem_hash_table(&ht_cw_cache
, &cw_cache
->ht_node
);
890 SAFE_RWLOCK_UNLOCK(&cw_cache_lock
);
894 void cleanup_cache(bool force
)
898 struct s_pushclient
*pc
, *nxt
;
899 node
*i
,*i_next
,*j
,*j_next
;
902 int64_t gone_first
, gone_upd
;
907 SAFE_RWLOCK_WRLOCK(&cache_lock
);
909 i
= get_first_node_list(&ll_cache
);
913 ecmhash
= get_data_from_node(i
);
922 gone_first
= comp_timeb(&now
, &ecmhash
->first_recv_time
);
923 gone_upd
= comp_timeb(&now
, &ecmhash
->upd_time
);
925 if(!force
&& gone_first
<=(cfg
.max_cache_time
*1000)) // not continue, useless check for nexts one!
930 if(force
|| gone_upd
>(cfg
.max_cache_time
*1000))
932 j
= get_first_node_list(&ecmhash
->ll_cw
);
936 cw
= get_data_from_node(j
);
939 pthread_rwlock_destroy(&cw
->pushout_client_lock
);
940 pc
= cw
->pushout_client
;
941 cw
->pushout_client
=NULL
;
948 #ifdef CS_CACHEEX_AIO
949 if(cw
->count
>= 0x0F000000)
954 remove_elem_list(&ecmhash
->ll_cw
, &cw
->ll_node
);
955 remove_elem_hash_table(&ecmhash
->ht_cw
, &cw
->ht_node
);
961 deinitialize_hash_table(&ecmhash
->ht_cw
);
962 remove_elem_list(&ll_cache
, &ecmhash
->ll_node
);
963 remove_elem_hash_table(&ht_cache
, &ecmhash
->ht_node
);
968 SAFE_RWLOCK_UNLOCK(&cache_lock
);
971 #ifdef CS_CACHEEX_AIO
972 void cacheex_get_srcnodeid(ECM_REQUEST
*er
, uint8_t *remotenodeid
)
975 data
= ll_last_element(er
->csp_lastnodes
);
978 memcpy(remotenodeid
, data
, 8);
982 memset(remotenodeid
, 0 , 8);