WiredTiger의 Hazard Pointer

 

WiredTiger의 Hazard Pointer

WiredTiger에서 Hazard Pointer는 메모리 페이지가 퇴거 될 수 있는지 여부를 관리하는 데 사용됩니다. 이 포스팅에서는 Hazard Pointer의 구현 프로세스를 분석합니다.

Hazard Pointer

Hazard Pointer는 다중 스레드 환경에서 리소스에 대한 잠금없이 액세스 할 수 있는 방법입니다. space-time-changing 방식으로 구현되어 있습니다.

  • 각 리소스에 대해 Hazard Pointer 배열을 할당하고 배열의 크기는 스레드 수와 같으며 각 항목은 특정 리소스에 대한 포인터를 포함하거나 비어 있습니다.
  • 스레드가 리소스에 액세스하려고 할 때마다 스레드에 해당하는 Hazard Pointer를 수정합니다. Hazard Pointer에 포함 된 리소스 포인터에 리소스를 할당합니다.
  • 스레드가 액세스를 완료하면 스레드의 Hazard Pointer가 Null로 설정됩니다.
  • 자원을 삭제하려면 Hazard Pointer 배열을 탐색하여 여전히 자원을 가리키는 다른 스레드의 Hazard Pointer가 있는지 확인해야 합니다. Hazard Pointer가 가리키는 자원이 있다면 삭제할 수 없습니다.

 

WIREDTIGER에서 사용

MongoDB 4.4 버전에서는 WiredTiger 10.0.1 버전의 스토리지 엔진을 사용합니다. 자세한 내용은 wiredTiger의 레퍼런스 가이드를 참고 하시기 바랍니다.

WIREDTIGER에서 Hazard Pointer는 메모리 페이지를 메모리에서 디스크로 플러시 할 수 있는지 여부를 결정하는 데 사용됩니다.

세션은 임의의 수의 열린 커서를 가질 수 있고, 열린 커서는 한 번에 여러 페이지에 접근할 수 있으며, 커서는 페이지가 그 아래에서 제거되지 않도록 하기 위해 각각의 페이지에 Hazar Pointer가 필요합니다.

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 pointer의 크기. */
uint32_t nhazard;           /* 사용된 hazard pointer의 수 */
WT_HAZARD *hazard;          /* Hazard Pointer 정렬 */
};

여기에서 각 세션에서 WT_HAZARD 배열이 정의되고 크기는 hazard_size임을 알 수 있습니다. hazard_size가 생성되면 session_count가 할당을 확인하므로 각 스레드가 배열에 고유 한 인덱스를 가지고 있음을 의미합니다. 메모리 페이지를 운영하기 위해 메모리 페이지의 포인터를 해당 스레드에 해당하는 Hazard Pointer에 할당합니다. 스레드는 자신의 스레드 인덱스에 해당하는 Hazard Pointer 만 수정할 수 있으므로 다른 스레드로 수정되지 않습니다. 포인터 및 모든 스레드가 다른 모든 스레드의 Hazard Pointer 사용을 읽을 수 있으므로 잠금없이 세션 -> Hazard 배열을 수정하는 것이 안전합니다.

메모리 페이지를 디스크에 덤프 할 수 있는지 여부를 결정하고 싶을 때 세션 -> 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);
}

 

hazard.c (github)

https://github.com/wiredtiger/wiredtiger/blob/master/src/support/hazard.c

You may also like...

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다