zfs当中的事务处理研究与探索

来源:互联网 发布:js cookie 代码 编辑:程序博客网 时间:2024/05/20 14:19
对于zfs而言,每一层都会有事务处理的痕迹。
zio,metaslab,spa,dmu 每层基本上都少不了transaction group。transaction group的更新主要是在txg的两个线程中完成的,使用最多的是spa 和dmu 层。
transaction group 总共分三组:
open 刚开始的写的请求分配一个open txg。
quiesce  等待同步的写请求 分配一个 quiesce txg。
sync    正在同步的写请求属于sync txg。

一个线程为tx_quiesce_thread,另一个为tx_sync_thread。

点击(此处)折叠或打开

  1. tx->tx_quiesce_thread = thread_create(NULL, 0, txg_quiesce_thread,
  2.      dp, 0, &p0, TS_RUN, minclsyspri);

  3.     /*
  4.      * The sync thread can need a larger-than-default stack size on
  5.      * 32-bit x86. This is due in part to nested pools and
  6.      * scrub_visitbp() recursion.
  7.      */
  8.     tx->tx_sync_thread = thread_create(NULL, 32<<10, txg_sync_thread,
  9.      dp, 0, &p0, TS_RUN, minclsyspri);




对于一个dsl_pool而言,会创建有两个线程,txg_sync_thread,和txg_quiesce_thread.

而这两个线程维护了所有的txg。
当zfs发生一个写请求的时候,会找到该请求的dsl_pool,然后通过dsl_pool找到相应的tx_state,从中找到当前的open transaction的ID(在zfs的transaction group的状态池当中更新引用该txg的计数,count++),然后封装成一个dmu_tx_t的数据结构给dmu buffer层。 当数据从req当中拷贝到dmu buffer之后返回,系统会调用dmu_tx_commit操作,做事务处理的最后的收回工作,并从zfs的transaction group的状态池当中减少对该txg的引用计数。当txg的引用计数为0的时候,通知该tc->tc_cv[g]条件满足。
 
下面的这个函数正好是quiesce thread 线程所要做的事情,该线程会等待所有的写操作返回,等该txg 为0。
txg_quiesce的部分代码。

点击(此处)折叠或打开

  1. for (c = 0; c < max_ncpus; c++) {
  2.         tx_cpu_t *tc = &tx->tx_cpu[c];
  3.         mutex_enter(&tc->tc_lock);
  4.         while (tc->tc_count[g] != 0)
  5.             cv_wait(&tc->tc_cv[g], &tc->tc_lock);
  6.         mutex_exit(&tc->tc_lock);
  7.     }
 

点击(此处)折叠或打开

  1.         mutex_exit(&tx->tx_sync_lock);
  2.         txg_quiesce(dp, txg);
  3.         mutex_enter(&tx->tx_sync_lock);

  4.         /*
  5.          * Hand this txg off to the sync thread.
  6.          */
  7.         dprintf("quiesce done, handing off txg %llu\n", txg);
  8.         tx->tx_quiesced_txg = txg;
  9.         cv_broadcast(&tx->tx_sync_more_cv);
  10.         cv_broadcast(&tx->tx_quiesce_done_cv);

可以从上面的代码看到,这个所谓的等待,实际上等待的是异步写,也就是写buffer,而不是写磁盘的操作。当该txg的写请求结束之后,标志该txg的已经静默完的。然后发广播说:异步写结束啦,快来同步我们吧,我们已经完成静默啦。
 

 
当系统要进行同步的时候,也就是txg_sync_thread会调用spa_sync(spa,txg)。spa_sync(spa,txg)会设置spa ->spa_syncing_txg = txg;
 

    最后的路径可以追溯到dbuf_sync_leaf这个函数,他负责同步dbuf叶子节点,也是dbuf同步的最后一步。他会设置db->db_data_pending = dr; 然后调用dbuf_write 产生一个写请求。通过zio_nowait(zio)执行这个请求。
    在dbuf_write 函数之中,会在其中传入回调函数指针,在dbuf_write_done函数调用中,也就是写操作结束后,会将db->db_data_pending 指针设置为NULL。标志着写操作的结束。
 
 
阅读(256) | 评论(0) | 转发(0) |
0

上一篇:对zfs脏记录的一些疑问

下一篇:linux打印当前函数调用栈backtrace

相关热门文章
  • 致力于将奥的斯的先进技术本土...
  • crtmpserver实现防盗流和流推...
  • Flash文件系统TFFS简介
  • 主流Linux/Unix文件系统架构简...
  • 内核调试之kprobes
  • 双机热备Oracle数据库服务器操...
  • 双机热备Oracle数据库服务器操...
  • 双机热备Oracle数据库服务器操...
  • 缘聚湘西南 武冈深圳同乡会 欢...
  • 虚拟磁带库 变革数据保护流程(...
  • 这样配置的服务器能够承受8k并...
  • vm里的系统能够ping到nfs,但...
  • bind是否随机从两台master中读...
  • 在win7下用cygwin搭建hadoop,...
  • Mysql的binglog日志能否分库备...
给主人留下些什么吧!~~