流老化入口函数FlowManger调用函数FlowTimeoutHash完成流老化处理,这个函数完成了大部分老化工作,把一个老化的流从flow_hash上移走,移入了回收队列,由回收线程取出来放入空闲全局flow内存池。
1. FlowTimeoutHash 函数
FlowManager-》FlowTimeoutHash
函数有两个参数表示flow bucket的范围值,const uint32_t hash_min, const uint32_t hash_max,先把老化的flow移入参数td->aside_queue队列,再从aside_queue队列移入回收线程的队列flow_recycle_q,如此玩法,flow必晕。
/**
* \brief time out flows from the hash
*
* \param ts timestamp
* \param hash_min min hash index to consider
* \param hash_max max hash index to consider
* \param counters ptr to FlowTimeoutCounters structure
*
* \retval cnt number of timed out flow
*/
//新版本的老化策略比旧版本复杂了很多,流分配那块修改应该是有效率提升,
//但是这个函数应该没有效率提升,
//这个函数总思路就是先设置一个位图,每1位表示一个bucket是否有需要老化的flow,
//还是和旧版一样判断每个bucket的next_ts与最新时间,先循环32或64次检查每个
//bucket是否有超时的flow,有超时的放入一个32或64位的整数,
//循环完成,再循环这个整数,检查每一位同时检查next_ts,都符合超时条件则进行老化,好复杂,没毛用
static uint32_t FlowTimeoutHash(FlowManagerTimeoutThread *td,
struct timeval *ts,
const uint32_t hash_min, const uint32_t hash_max,
FlowTimeoutCounters *counters)
{
uint32_t cnt = 0;
//获取紧急模式标志
const int emergency = ((SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY));
//计算检查的bucket数量
const uint32_t rows_checked = hash_max - hash_min;
uint32_t rows_skipped = 0;
uint32_t rows_empty = 0;
//那个一次取32还是64个bucket就是这个系统位数决定的,以下都认为64位吧
#if __WORDSIZE==64
#define BITS 64
#define TYPE uint64_t
#else
#define BITS 32
#define TYPE uint32_t
#endif
for (uint32_t idx = hash_min; idx < hash_max; idx+=BITS) {
TYPE check_bits = 0; //64位整数
//取最小的数,万一bucket数量不够64个呢
const uint32_t check = MIN(BITS, (hash_max - idx));
//循环64次,检查64个bucket是否有超时的flow,有则设置一位到check_bits
for (uint32_t i = 0; i < check; i++) {
FlowBucket *fb = &flow_hash[idx+i];
check_bits |= (TYPE)(SC_ATOMIC_LOAD_EXPLICIT(fb->next_ts, SC_ATOMIC_MEMORY_ORDER_RELAXED) <= (int32_t)ts->tv_sec) << (TYPE)i;
}
if (check_bits == 0) //没有一个超时的则继续下一轮64个bucket的超时判断
continue;
//多循环一次
for (uint32_t i = 0; i < check; i++) {
//有超时的,则循环检测这个64位数,然后老化之
FlowBucket *fb = &flow_hash[idx+i];
//多比较一次,何苦呢
if ((check_bits & ((TYPE)1 << (TYPE)i)) != 0 && SC_ATOMIC_GET(fb->next_ts) <= (int32_t)ts->tv_sec) {
FBLOCK_LOCK(fb);
Flow *evicted = NULL;
if (fb->evicted != NULL || fb->head != NULL) {
if (fb->evicted != NULL) {
//这个evicted队列