PVFS2发布的某些类型的任务(job)设置了超时,需要任务时间管理器(job time manager)统一记录和管理这些任务。
- 数据结构
任务时间管理器维护一个时间散列,时间元(time bucket)由链表实现,按时刻由早到晚排列;每个时间元又维护一个任务描述符(job descriptor)链表,表示在该时刻应完成的任务,其中每个任务描述符对一个任务。这里的链表使用quicklist 。
时间元的结构体如下:
第3行expire_time_sec记录超时时间,由当日到该时间的秒数表示,是该时间元的时刻。
第4行bucket_link表示时间散列中的一个项。
第5行jd_queue表示该时间元维护的任务描述符链表,记录的是链表头。
qlist_head类型参见quicklist 。
还有重要声明就是时间散列:
时间元结构体的成员bucket_link就是链接在这个链表中。QLIST_HEAD定义参见quicklist 。
- 功能函数
带有“__”前缀的函数不是线程安全的,通常只被接口函数调用;接口函数供其他组件调用,且都是线程安全的。
- 初始化
初始化了时间散列,INIT_QLIST_HEAD定义参见quicklist 。 - 添加任务
接口函数是job_time_mgr_add,它只是以加锁的方式线程安全地调用了如下__job_time_mgr_add函数:
第12~13行计算任务超时的时刻,是由当前时刻加上任务等待时间(timeout)。
第16~27行遍历时间散列bucket_queue查找任务添加的合适时间元。如果当前时间元tmp_bucket的截止时刻已经大于或等于任务超时时刻,那么就终止遍历(第21~24行);此时,之前遍历过的时间元一定早于任务超时时刻,之后未遍历的时间元一定晚于任务超时时刻,或者说与任务超时时刻最接近的就是当前时间元。
如果当前时间元截止时间恰好是任务超时时间,那么会跳过第18~47行,直接将该任务描述符添加到当前时间元(第50行)。
但是,当前时间元的截止时间可能不是恰好等于任务超时时间,这就需要创建新的时间元(第31~33行),设置它的时刻为该任务超时时刻(第34行)和其他成员,并插入到时间散列bucket_queue中。 - 检查超时
检查有无已经超时的任务。第14行对应的外循环遍历时间散列,对于已经超时的时间元执行第24行对应的内循环。内循环中,主要就是处理该时间元记录的任务,它们已经超时。处理这些超时任务的办法根据任务类型不同而不同,这里只列出了JOB_BMI类型的代码(第31~33行),主要就是进行记录并取消任务。 - 撤销任务和清理时间管理器
可以通过函数job_time_mgr_rem取消对某个任务的超时监控;时间管理器的清理任务由job_time_mgr_expire负责。它们主要操作都是删除相关项并释放空间,此处从略。