PostgreSQL数据库复制——后台一等公民进程WalReceiver获知连接

网友投稿 272 2022-12-02

PostgreSQL数据库复制——后台一等公民进程WalReceiver获知连接

备机在启动时会调用RequestXLogStreaming函数(这一步在哪里调用在前面的博客中已经描述过),这个函数会将GUC参数中的primary_conninfo信息保存在WalRcvData中(WalRcvData是由WalRcvShmemInit函数在共享内存中初始化的),也会保存WAL日志的复制起始LSN及时间线信息,然后通过SendPostmasterSignal(PMSIGNAL_START_WALRECEIVER)通知Postmaster进程启动WalReceiver进程,WalReciver进程负责和主机建立连接关系。(摘抄自张树杰 PostgreSQL技术内幕 事务处理深度探索)

首先我们看一下WAL 接收器的六个状态字段,RequestXLogStreaming函数只有在WALRCV_STOPPED状态下,RequestXLogStreaming函数才会去发送PMSIGNAL_START_WALRECEIVER通知Postmaster进程启动WalReceiver进程,只有在WALRCV_WAITING状态下,才能直接调用SetLatch来唤醒wal reciver的latch。

typedef enum { WALRCV_STOPPED, /* stopped and mustn't start up again */ WALRCV_STARTING, /* launched, but the process hasn't initialized yet */ WALRCV_STREAMING, /* walreceiver is streaming */ WALRCV_WAITING, /* stopped streaming, waiting for orders */ WALRCV_RESTARTING, /* asked to restart streaming */ WALRCV_STOPPING /* requested to stop, but still running */} WalRcvState;

​​void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo, const char *slotname, bool create_temp_slot)​​函数的参数“recptr”表示流应该开始的位置; “conninfo”是要使用的 libpq 连接字符串; “slotname”是可选的,要获取的复制槽的名称;“create_temp_slot”表示在没有给出“slotname”时创建一个临时槽。WAL 接收器不直接加载用于连接到主节点的 GUC 参数,而是依赖此例程的调用者向下传递的值。 因此,任何新参数的添加都应通过此代码路径进行。

*walrcv = WalRcv; bool launch = false; pg_time_t now = (pg_time_t) time(NULL); Latch *latch; /* We always start at the beginning of the segment. That prevents a broken segment (i.e., with no records in the first half of a segment) from being created by XLOG streaming, which might cause trouble later on if the segment is e.g archived. 我们总是从段的开头开始。 这可以防止 XLOG 流创建损坏的段(即,段的前半部分没有记录),如果段被存档,这可能会在以后造成麻烦。 */ if (XLogSegmentOffset(recptr, wal_segment_size) != 0) recptr -= XLogSegmentOffset(recptr, wal_segment_size); SpinLockAcquire(&walrcv->mutex); // 获取锁 /* It better be stopped if we try to restart it 只有在停止状态和等待状态才能调用 */ Assert(walrcv->walRcvState == WALRCV_STOPPED || walrcv->walRcvState == WALRCV_WAITING); if (conninfo != NULL) strlcpy((char *) walrcv->conninfo, conninfo, MAXCONNINFO); else walrcv->conninfo[0] = '\0'; /* Use configured replication slot if present, and ignore the value of create_temp_slot as the slot name should be persistent. Otherwise, use create_temp_slot to determine whether this WAL receiver should create a temporary slot by itself and use it, or not. 如果存在,请使用配置的复制槽,并忽略 create_temp_slot 的值,因为槽名称应该是持久的。 否则,使用 create_temp_slot 来确定这个 WAL 接收器是否应该自己创建一个临时槽并使用它,或者不 */ if (slotname != NULL && slotname[0] != '\0'){ strlcpy((char *) walrcv->slotname, slotname, NAMEDATALEN); walrcv->is_temp_slot = false; }else{ walrcv->slotname[0] = '\0'; walrcv->is_temp_slot = create_temp_slot; } if (walrcv->walRcvState == WALRCV_STOPPED) { launch = true; walrcv->walRcvState = WALRCV_STARTING; } else walrcv->walRcvState = WALRCV_RESTARTING; walrcv->startTime = now; /* If this is the first startup of walreceiver (on this timeline), initialize flushedUpto and latestChunkStart to the starting point. 如果这是 walreceiver 的第一次启动(在此时间轴上),请将 flushedUpto 和 latestChunkStart 初始化为起点。 */ if (walrcv->receiveStart == 0 || walrcv->receivedTLI != tli) { walrcv->flushedUpto = recptr; walrcv->receivedTLI = tli; walrcv->latestChunkStart = recptr; } walrcv->receiveStart = recptr; walrcv->receiveStartTLI = tli; latch = walrcv->latch; SpinLockRelease(&walrcv->mutex); if (launch) SendPostmasterSignal(PMSIGNAL_START_WALRECEIVER); else if (latch) SetLatch(latch);}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java秒杀系统:web层详解
下一篇:PostgreSQL数据库网络层——libpq 查询协议PGQueryClass
相关文章

 发表评论

暂时没有评论,来抢沙发吧~