PostgreSQL Latch 实现逻辑

源码版本: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 种:

<ul>
    <li>
        Latch
    </li>
    <li>
        Socket,socket 相关事件
    </li>
    <li>
        Timeout,等待超时事件
    </li>
</ul>

关键的数据结构:

struct WaitEventSet;

struct WaitEvent;


一个 WaitEventSet 只能设置一个 Latch,可以设置多个 WaitEvent。通过函数 AddWaitEventToSet() 将 Latch、socket 等事件放置到  WaitEventSet 中。AddWaitEventToSet() 函数根据系统支持的多路复用模型epoll/poll/win32 不同类型,调用下面 3 个函数中的 1 个完成。

<ul>
    <li>
        WaitEventAdjustEpoll()
    </li>
    <li>
        WaitEventAdjustPoll()
    </li>
    <li>
        WaitEventAdjustWin32()
    </li>
</ul>

调用函数 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() 来唤醒等待的进程。