源码版本:pg 11.9
源码文件:src/backend/storage/ipc/latch.c
Latch 是 pg 中使用较多的一种数据结构,用于等待某个事件的发生或者超时,常见的 Latch 相关函数如下:
- InitLatch(),初始化一个非共享型 Latch
- InitSharedLatch(),初始化一个共享型 Latch
- WaitLatch(),等待 Latch
- ResetLatch(),重置 Latch
- SetLatch(),设置 Latch 标记,唤醒等待 Latch 的进程
- OwnLatch(),设置 Latch 的拥有者为当前进程
- DisownLatch(),当前进程不再拥有该 Latch
Latch 结构体
typedef struct Latch
{
sig_atomic_t is_set;
bool is_shared;
int owner_pid;
#ifdef WIN32
HANDLE event;
#endif
} Latch;
共享型、独占型 Latch
Latch 可分为共享型和独占型,共享型 Latch 的 owner_pid 可变,即拥有该 Latch 的进程 pid 可变。
内部实现:
WaitLatch() 内部调用 WaitLatchOrSocket() 实现等待事件,可等待的事件类型包括 3 种:
- Latch
- Socket,socket 相关事件
- Timeout,等待超时事件
关键的数据结构:
struct WaitEventSet;
struct WaitEvent;
一个 WaitEventSet 只能设置一个 Latch,可以设置多个 WaitEvent。通过函数 AddWaitEventToSet() 将 Latch、socket 等事件放置到 WaitEventSet 中。AddWaitEventToSet() 函数根据系统支持的多路复用模型epoll/poll/win32 不同类型,调用下面 3 个函数中的 1 个完成。
- WaitEventAdjustEpoll()
- WaitEventAdjustPoll()
- WaitEventAdjustWin32()
调用函数 WaitEventSetWait() 等待事件的发生或者超时,内部调用 WaitEventSetWaitBlock() 函数,该函数根据 epoll/poll/win32 有不同的实现,最终调用的是如下 3 个函数中的 1 个。
- epoll:epoll_wait()
- poll:poll()
- win32:WaitForMultipleObjects()
selfpipe管道
static int selfpipe_readfd = -1;
static int selfpipe_writefd = -1;
selfpipi 提供了 fd 用于监视,当 Latch 在等待过程中,进程可以接收信号,比如接收到 SIGUSR1 信号,通过函数 sendSelfPipeByte() 往 selfpipi 管道写入数据,唤醒等待 Latch 的进程。
SetLatch()函数的实现也是通过直接调用 sendSelfPipeByte() 往管道里写数据或者向指定进程发送 SIGUSR1 信号间接调用 sendSelfPipeByte() 来唤醒等待的进程。