Chinaunix首页 | 论坛 | 博客
  • 博客访问: 550670
  • 博文数量: 469
  • 博客积分: 50
  • 博客等级: 民兵
  • 技术积分: 1495
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-15 21:04
文章分类

全部博文(469)

文章存档

2015年(81)

2014年(125)

2013年(261)

2012年(2)

分类: LINUX

2013-08-27 11:54:37

memcached-1.4.15 SLAB页转移过程分析

 

启动时指定参数 -o slab_reassign,slab_automove=12

         此时程序将启动两个线程:slab_maintenance_threadslab_rebalance_thread

 

一、      slab_maintenance_thread线程为SLAB主线程

代码如下

  1. static void *slab_maintenance_thread(void *arg) {
  2.     int src, dest;
  3.     while (do_run_slab_thread) {
  4.         if (settings.slab_automove == 1) {

  5.             //自动寻找符合条件的需要进行page页转移的两个slabclass id:src和dest
  6.             if (slab_automove_decision(&src, &dest) == 1) {

  7.                 //通过pthread_cond_signal唤醒 slab_rebalance_thread 线程进行page页的实际转移
  8.                 slabs_reassign(src, dest);
  9.             }
  10.             sleep(1);
  11.         } else {
  12.             /* Don't wake as often if we're not enabled.
  13.              * This is lazier than setting up a condition right now. */
  14.             sleep(5);
  15.         }
  16.     }
  17.     return NULL;
  18. }


(一)            slab_automove = 1

    由上边的代码显示出,线程将自动选择符合条件的src slabclassdest slabclass。选取规则如下:

   10秒检查一次{

1.        获取没给slabclass 发生LRU的次数(itemstats[id].evicted

2.        找出一个检查了3次(10秒检查一次)并且LRU次数没有增加的、page页数3页以上的class作为src slabclass

3.        如果本次检查中,LRU次数增加最多的slabclass为连续检查3次都是LRU增加最多的slabclass,则选取当前classdest slabclass

4.        src slabclass dest slabclass 都选到时,通过pthread_cond_signal唤醒 slab_rebalance_thread线程进行slab转移,否则继续轮询检查(10秒检查一次)。

    }

以上的LRU为没有指定-M选项,并且内存不足无法分配item时。

 

(二)            slab_automove = 2

当内存不足,无法分配新的item时,发生LRU后,进行slab页转移,转移到当前页。src slabclass选取规则为随机选取,选取规则如下:

1.        第一次LRU时,从slabclass1开始向后查找(查找范围为所有页数的上半部分)一个有2slab page以上的slabclass作为src slabclass

2.        第二次发生LRU后,会从上一次选取的class之后进行查找(查找范围为当前class到最大slabclass数量的上半部分)合适的class进作为src slabclass

 

代码如下:

  1. static int slabs_reassign_pick_any(int dst) { //从前往后获取一个slab page 至少有2个的class
  2.     static int cur = POWER_SMALLEST - 1;
  3.     int tries = power_largest - POWER_SMALLEST + 1;
  4.     for (; tries > 0; tries--) {
  5.         cur++;
  6.         if (cur > power_largest)
  7.             cur = POWER_SMALLEST;
  8.         if (cur == dst)
  9.             continue;
  10.         if (slabclass[cur].slabs > 1) {
  11.             return cur;
  12.         }
  13.     }
  14.     return -1;
  15. }


二、       slab_rebalance_thread线程为SLAB页移动线程。将src slabclass中的第一页移动到dest slabclass中,为最后一页。过程如下:

1.        slab_rebalance_start:赋值 slab_rebal全局变量,将page页的起止位置、结束位置、src slabclass iddest slabclass id赋值给全局变量 slab_rebal,用于后期处理;并检查dest slabclasspage页链表是否空间充足,如果空间不足则扩展空间为原来的两倍大小。

2.        slab_rebalance_move:将 slab_rebal指向的 page页中chunk存储的所有itemhashtable中删除,并将其从原slabclassheadtail链表中删除,并从回收链表中删除。

3.        slab_rebalance_finish:重置slab_rebal全局变量,并初始化page0,并将page分成chunk添加到dest slabclassslots链表中。

slab_rebalance结构体如下:

struct slab_rebalance {

    void *slab_start;  //待转移page的内存起始地址

    void *slab_end;  //page页的尾地址

    void *slab_pos;  //当前处理的item所在该page中的位置(从前向后处理)

    int s_clsid;      //src slabclass id

    int d_clsid;      //dest slabclass id

    int busy_items;  //busy item的数量(当前item被加锁,所以无法处理)

    uint8_t done;   //是否该页中chunk存储的item已经全部处理完毕(hashtable中删除、从原slabclass中的回收链表中删除)

};

 

代码如下:

  1. static void *slab_rebalance_thread(void *arg) {
  2.     int was_busy = 0;
  3.     /* So we first pass into cond_wait with the mutex held */
  4.     mutex_lock(&slabs_rebalance_lock);
  5.  
  6.     while (do_run_slab_rebalance_thread) {
  7.         if (slab_rebalance_signal == 1) {
  8.             //开始移动的准备工作,slab_rebal结构体赋值,dest slabclass page list是否空间足够等
  9.             if (slab_rebalance_start() < 0) {
  10.                 /* Handle errors with more specifity as required. */
  11.                 slab_rebalance_signal = 0;
  12.             }
  13.  
  14.             was_busy = 0;
  15.         } else if (slab_rebalance_signal && slab_rebal.slab_start != NULL) {
  16.             //准备工作完毕,将page页中的item从hashtable中删除,从class的head,tail链表体中删除,并将chunk从回收链表中删除
  17.             was_busy = slab_rebalance_move();
  18.         }
  19.  
  20.         if (slab_rebal.done) {
  21.             //将页移动到新的slabclass中,并将chunk添加到回收链表中,处理完毕
  22.             slab_rebalance_finish();
  23.         } else if (was_busy) {
  24.             /* Stuck waiting for some items to unlock, so slow down a bit
  25.              * to give them a chance to free up */
  26.             usleep(50);
  27.         }
  28.  
  29.         if (slab_rebalance_signal == 0) {
  30.             /* always hold this lock while we're running */
  31.             pthread_cond_wait(&slab_rebalance_cond, &slabs_rebalance_lock);
  32.         }
  33.     }
  34.     return NULL;
  35. }


未完待续,如有错误,请指正。


阅读(1074) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~