WiredTiger hazard指针

在WiredTiger里面, 采用Hazard pointers来管理一个内存页是否可以被Evict, 本文分析下其实现过程。

Hazard pointers

Hazard pointers是在多线程环境下实现资源无锁访问的一种方法, 它采用空间换时间的方法:

  • 为每一个资源分配一个Hazard指针数组,数组大小等于线程个数, 每一项里面包含一个指针指向某个资源或者为空;
  • 每当线程要访问资源的时候, 将该线程对应的Hazard pointer修改: 资源的指针赋给Hazard指针包含的资源指针;
  • 当一个线程完成访问, 将该线程的Hazard指针设定为空;
  • 当要删除资源, 遍历Hazard 指针数组, 看是否有其他线程的Hazard指针还在指向该资源, 如果没有就删除, 否则就不能删除;

WIREDTIGER中的使用

在WIREDTIGER里面, 使用Hazard pointers来判断某个内存页能不能从内存刷到磁盘上面。

struct __wt_hazard {
    WT_PAGE *page;            /* 内存页对象 */
#ifdef HAVE_DIAGNOSTIC
    const char *file;        /* File/line where hazard acquired */
    int        line;
#endif
};

struct WT_COMPILER_TYPE_ALIGN(WT_CACHE_LINE_ALIGNMENT) __wt_session_impl {
    /*
     * Hazard pointers.
     *
     * session的hazard为空, 代表第一次使用
     */
#define    WT_SESSION_FIRST_USE(s)                        \
    ((s)->hazard == NULL)

    uint32_t   hazard_size;        /* 分配的hazard数组大小. */
    uint32_t   nhazard;        /* 已使用的hazard指针数目 */
    WT_HAZARD *hazard;        /* Hazard pointer 数组 */
};

这里, 可以看到在每个session里面, 定义了一个WT_HAZARD数组, 大小是hazard_size, hazard_size在创建的时候, 检查session_count来赋值, 就是说保证每一个线程, 都在数组里面有唯一的一个index, 每当某个线程要操作内存页, 就会将该内存页的指针赋予该线程对应的Hazard指针, 由于某个线程只能也只需要修改自己线程index对应的Hazard指针, 不会修改到别的线程的Hazard pointers, 而且任何线程都可以读到所有的其他线程Hazard指针的使用情况, 因此对于session->hazard数组的修改是安全的, 不需要加锁。

当我们要决定是否可以将某个内存页转存到磁盘, 可以遍历session->hazard数组, 如果有某个线程还在使用该内存页就无法刷盘。

/*
 * __wt_page_hazard_check --
 *	Return if there's a hazard pointer to the page in the system.
 */
static inline WT_HAZARD *
__wt_page_hazard_check(WT_SESSION_IMPL *session, WT_PAGE *page)
{
	WT_CONNECTION_IMPL *conn;
	WT_HAZARD *hp;
	WT_SESSION_IMPL *s;
	uint32_t i, j, hazard_size, max, session_cnt;

	conn = S2C(session);

	/*
	 * No lock is required because the session array is fixed size, but it
	 * may contain inactive entries.  We must review any active session
	 * that might contain a hazard pointer, so insert a barrier before
	 * reading the active session count.  That way, no matter what sessions
	 * come or go, we'll check the slots for all of the sessions that could
	 * have been active when we started our check.
	 */
	WT_STAT_FAST_CONN_INCR(session, cache_hazard_checks);
	WT_ORDERED_READ(session_cnt, conn->session_cnt);
	for (s = conn->sessions, i = 0, j = 0, max = 0;
	    i < session_cnt; ++s, ++i) {
		if (!s->active)
			continue;
		WT_ORDERED_READ(hazard_size, s->hazard_size);
		if (s->hazard_size > max) {
			max = s->hazard_size;
			WT_STAT_FAST_CONN_SET(session,
			    cache_hazard_max, max);
		}
		for (hp = s->hazard; hp < s->hazard + hazard_size; ++hp) {
			++j;
			if (hp->page == page) {
				WT_STAT_FAST_CONN_INCRV(session,
				    cache_hazard_walks, j);
				return (hp);
			}
		}
	}
	WT_STAT_FAST_CONN_INCRV(session, cache_hazard_walks, j);
	return (NULL);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值