Chinaunix首页 | 论坛 | 博客
  • 博客访问: 790161
  • 博文数量: 264
  • 博客积分: 592
  • 博客等级: 中士
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-24 22:02
文章分类

全部博文(264)

文章存档

2019年(2)

2018年(1)

2017年(1)

2016年(4)

2015年(14)

2014年(57)

2013年(88)

2012年(97)

分类: LINUX

2014-02-12 16:06:08

转:http://blog.csdn.net/nerdx/article/details/12884185
  1. //  同步回收机制  
  2. //  返回值:  
  3. //      0,达到回收目标  
  4. //      1,没有达到回收目标  
  5.   
  6. //  注:ip_rt_gc_min_interval = HZ/2  
  7. //      ip_rt_gc_timeout = RT_GC_TIMEOUT = 300HZ  
  8. //      ip_rt_gc_elasticity = 8*(rt_hash_mask+1)(正常情况下)  
  9. //      ip_rt_gc_elasticity = 1(当绑定缓存到邻居子系统失败时)  
  10.   
  11.   
  12. //  平衡点,gc目标数的动态调整:  
  13. //      1.当前缓存个数 < 安全阈值(安全范围,试图gc少缓存)  
  14. //          1.1 当前缓存个数 > 上次gc的平衡点(安全范围内允许缓存增多)  
  15. //              1.1.1 新平衡点+=min((当前缓存个数-上次平衡点)/2 , buckets)  
  16. //              1.2.1 gc目标数=当前缓存个数-新平衡点  
  17. //                  1.2.1.1 gc目标数 < 0  
  18. //                      1.2.1.1.1 新平衡点+=gc目标数  
  19.   
  20. //      2. 当前缓存个数 > 安全阈值(危险范围,试图gc多缓存)  
  21. //          2.1 gc目标数 = max((当前缓存个数-安全阈值)/2, buckets)(超过安全阈值的缓存一半将被gc)  
  22. //          2.2 新平衡点=当前缓存个数-gc目标数  
  23. //      3. gc目标数>0时,进行垃圾回收  
  24. //  注,安全阈值,每个bucket的冲突链中有8个bucket  
  25.   
  26.   
  27. //  回收过程:  
  28. //      1.令,遍历所有bucket = 一个回收单位  
  29. //      2.如果一个回收单位释放了gc目标数,调整expire  
  30. //          2.1 expire+=HZ/2,放宽到期时限  
  31. //      3.如果一个回收单位没有释放gc目标数  
  32. //          3.1 如果当前缓存个数 < 缓存允许的最小值,退出,下一次使用当前的expire作为时限  
  33. //          3.2 否则,只有在用户态,并且耗时<1 jiffes时,继续回收。  
  34.   
  35. //  回收时限确定:  
  36. //      1.expire, 回收单位的起始到期时限,每个bucket使用该时限作为起始时限  
  37. //          当前回收单位没有完成gc目标数,下一个回收单位折半expire。  
  38. //      5.tmo,每个冲突链起始设置tmo=expire,当冲突链的一个节点不能被删除时,  
  39. //          tmo折半。  
  40.   
  41. 1.1 static int rt_garbage_collect(void)  
  42. {  
  43.     //静态变量  
  44.     static unsigned long expire = RT_GC_TIMEOUT;  
  45.     static unsigned long last_gc;  
  46.     static int rover;  
  47.     static int equilibrium;  
  48.     struct rtable *rth, **rthp;  
  49.     unsigned long now = jiffies;  
  50.     int goal;  
  51.   
  52.     //回收速率限制  
  53.     //  在ip_rt_gc_min_interval时间范围内,如果缓存数量没有超过最大值,则放弃回收  
  54.     if (now - last_gc < ip_rt_gc_min_interval &&  
  55.         atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size) {  
  56.         RT_CACHE_STAT_INC(gc_ignored);  
  57.         goto out;  
  58.     }  
  59.   
  60.     //ipv4_dst_ops.entries保存当前缓存的个数  
  61.     goal = atomic_read(&ipv4_dst_ops.entries) -  
  62.         (ip_rt_gc_elasticity << rt_hash_log);//平均长度下,所有bucket的缓存个数  
  63.   
  64.     //当前缓存的个数没有达到平均缓存个数  
  65.     if (goal <= 0) {  
  66.         if (equilibrium < ipv4_dst_ops.gc_thresh)  
  67.             equilibrium = ipv4_dst_ops.gc_thresh;  
  68.         //当前缓存的个数相对于上次平衡点的增长个数  
  69.         goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;  
  70.         //缓存个数增加  
  71.         if (goal > 0) {  
  72.             //在平均水平下,平衡点随着缓存个数的增加而增加  
  73.             equilibrium += min_t(unsigned int, goal / 2, rt_hash_mask + 1);  
  74.             //新平衡点为剩余缓存个数  
  75.             goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;  
  76.         }  
  77.     //当前缓存个数超过平均缓存个数  
  78.     } else {  
  79.         //至少回收 number of buckets  
  80.         goal = max_t(unsigned int, goal / 2, rt_hash_mask + 1);  
  81.         //新平衡点为剩余缓存个数  
  82.         equilibrium = atomic_read(&ipv4_dst_ops.entries) - goal;  
  83.     }  
  84.   
  85.     if (now - last_gc >= ip_rt_gc_min_interval)  
  86.         last_gc = now;  
  87.     //当前缓存总数小于平均值时,并且小于上次的平衡点  
  88.     //  说明缓存个数开始递减,则降低平衡点,不进行回收  
  89.     if (goal <= 0) {  
  90.         equilibrium += goal;  
  91.         goto work_done;  
  92.     }  
  93.   
  94.     do {  
  95.         int i, k;  
  96.         //rover记录上次遍历的bucket  
  97.         for (i = rt_hash_mask, k = rover; i >= 0; i--) {  
  98.             //tmo,bucket冲突链表内部使用的起始到期时限  
  99.             //expire, bucket之间使用的起始到期时限  
  100.             unsigned long tmo = expire;  
  101.   
  102.             k = (k + 1) & rt_hash_mask;  
  103.             //这次应该遍历的bucket  
  104.             rthp = &rt_hash_table[k].chain;  
  105.             spin_lock_bh(&rt_hash_table[k].lock);  
  106.             while ((rth = *rthp) != NULL) {  
  107.                 //检查缓存到期  
  108.                 if (!rt_may_expire(rth, tmo, expire)) {  
  109.                     //到期时间折半,使回收更加严格  
  110.                     tmo >>= 1;  
  111.                     rthp = &rth->u.rt_next;  
  112.                     continue;  
  113.                 }  
  114.                 *rthp = rth->u.rt_next;  
  115.                 rt_free(rth);  
  116.                 goal--;  
  117.             }  
  118.             spin_unlock_bh(&rt_hash_table[k].lock);  
  119.             if (goal <= 0)  
  120.                 break;  
  121.         }  
  122.         rover = k;  
  123.   
  124.         if (goal <= 0)  
  125.             goto work_done;  
  126.         //到期时间已经足够严格,依然没有达到目标,放弃回收  
  127.         if (expire == 0)  
  128.             break;  
  129.         //下一轮遍历的到期时间折半,使到期时间更加严格  
  130.         expire >>= 1;  
  131.   
  132.   
  133.         if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)  
  134.             goto out;  
  135.     } while (!in_softirq() && time_before_eq(jiffies, now));  
  136.   
  137.     if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)  
  138.         goto out;  
  139.     return 1;  
  140.   
  141. work_done:  
  142.     expire += ip_rt_gc_min_interval;  
  143.     if (expire > ip_rt_gc_timeout ||  
  144.         atomic_read(&ipv4_dst_ops.entries) < ipv4_dst_ops.gc_thresh)  
  145.         expire = ip_rt_gc_timeout;  
  146.   
  147. out:    return 0;  
  148. }  
  149.   
  150.   
  151. //  异步垃圾回收  
  152. //      垃圾回收定时器函数  
  153.   
  154. //  函数主要任务:  
  155. //      1.计算此次gc处理的bucket数  
  156. //      2.从上次遍历到的下一个bucket开始  
  157. //          2.1 如果dst到期时间为0,可以被释放,从冲突链取下节点,释放  
  158. //          2.2 该dst没有到期,调整gc时限更加严格  
  159. //      3.重新激活gc定时器  
  160.   
  161.   
  162. //  注:ip_rt_gc_interval=60HZ  
  163.   
  164. //  注:ip_rt_gc_timeout,ip_rt_gc_interval的关系  
  165. //      1.一个bucket至少在ip_rt_gc_timeout间隔gc一次  
  166. //      2.两次异步gc的间隔为ip_rt_gc_interval(即定时器的到期间隔)  
  167. //      3.此次gc处理的bucket个数=(ip_rt_gc_interval*(rt_hash_mask+1))/ip_rt_gc_timeout  
  168.   
  169. //  使路由缓存到期的事件:  
  170. //      1.主机接收到 ICMP UNREACHABLE 或 ICMP FRAGMENTATION NEEDED,设置为一段时间后(10min)过期。  
  171. //      2.邻居项无法解析l3到l2的映射,目的ip不可达时,设置为立即过期。  
  172.   
  173. //  dst_entry->expires  
  174. //      默认情况下,路由缓存表项永远不会过期,因此dst_entry->expires设置为0,当发生使路由缓存过期的事件时  
  175. //      ,更新dst_entry->expires为缓存到期的时间戳。  
  176.   
  177. 2.1 static void rt_check_expire(unsigned long dummy)  
  178. {  
  179.     static int rover;  
  180.     int i = rover, t;  
  181.     struct rtable *rth, **rthp;  
  182.     unsigned long now = jiffies;  
  183.     //计算可gc的bucket个数  
  184.     for (t = ip_rt_gc_interval << rt_hash_log; t >= 0;  
  185.         //gc定时器到期时间ip_rt_gc_timeout  
  186.          t -= ip_rt_gc_timeout) {  
  187.         unsigned long tmo = ip_rt_gc_timeout;  
  188.         //rover记录上次gc的bucket  
  189.         i = (i + 1) & rt_hash_mask;  
  190.         rthp = &rt_hash_table[i].chain;  
  191.   
  192.         spin_lock(&rt_hash_table[i].lock);  
  193.         while ((rth = *rthp) != NULL) {  
  194.             //dst->expires该dst将过期的时间戳  
  195.             if (rth->u.dst.expires) {  
  196.                 //表示指定的过期还没到  
  197.                 if (time_before_eq(now, rth->u.dst.expires)) {  
  198.                     //过期时限折半  
  199.                     tmo >>= 1;  
  200.                     rthp = &rth->u.rt_next;  
  201.                     continue;  
  202.                 }  
  203.             //该dst还不能被释放  
  204.             } else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout)) {  
  205.                 tmo >>= 1;  
  206.                 rthp = &rth->u.rt_next;  
  207.                 continue;  
  208.             }  
  209.   
  210.             //从bucket的冲突链取下,释放  
  211.             *rthp = rth->u.rt_next;  
  212.             rt_free(rth);  
  213.         }  
  214.         spin_unlock(&rt_hash_table[i].lock);  
  215.         //一步回收不超过1 jiffies  
  216.         if (time_after(jiffies, now))  
  217.             break;  
  218.     }  
  219.     rover = i;  
  220.     //下次到期的时间  
  221.     mod_timer(&rt_periodic_timer, now + ip_rt_gc_interval);  
  222. }  
  223.   
  224. //  判断缓存是否可以释放  
  225. //  参数:  
  226. //      tmo1,可快速清理的缓存使用的到期时限  
  227. //      tmo2,高代价创建的缓存使用的到期时限  
  228. //      tmo2 > tmo1  
  229.   
  230. //  缓存释放的条件:  
  231. //      1.引用计数=0  
  232. //      2.如果,缓存指定了到期时间,并且达到了到期时间,可清理  
  233. //      3.否则,可以快速清理,并且清理代价较低  
  234.   
  235. //  可以快速清理的缓存项:  
  236. //      1.广播多播地址  
  237. //      2.入口路由  
  238. //      3.冲突链表中,其后有缓存项  
  239.   
  240. //  清理代价较高的缓存项:  
  241. //      1.重定向的的缓存项  
  242. 3.1 static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2)  
  243. {  
  244.     unsigned long age;  
  245.     int ret = 0;  
  246.   
  247.     if (atomic_read(&rth->u.dst.__refcnt))  
  248.         goto out;  
  249.   
  250.     ret = 1;  
  251.     if (rth->u.dst.expires &&  
  252.         time_after_eq(jiffies, rth->u.dst.expires))  
  253.         goto out;  
  254.   
  255.     age = jiffies - rth->u.dst.lastuse;  
  256.     ret = 0;  
  257.     if ((age <= tmo1 && !rt_fast_clean(rth)) ||  
  258.         (age <= tmo2 && rt_valuable(rth)))  
  259.         goto out;  
  260.     ret = 1;  
  261. out:    return ret;  
  262. }  
阅读(833) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~