Loading

postgres pg_receivewal代码分析

src\bin\pg_basebackup\pg_receivewal.c
main 468
    初始化,参数解析,获取连接681,检查wal size 714
    StreamLog(); src\bin\pg_basebackup\pg_receivewal.c 760
        stream分配内存,获得数据库连接,检查版本,检查系统
        FindStreamingStart(&stream.timeline); 406---》200  //根据目的文件夹中最大id的文件
                                                                ,找最后的xlog segment,决定本次的起点。
            获取目的目录src\port\dirent.c
            得到文件
            看是否是partical,是否压缩
        XLogSegmentOffset(stream.startpos, WalSegSz);    //找到在segment开始的地方复制下一个
        设置stream
        ReceiveXlogStream(conn, &stream);   //从特定的position开始复制log stream
                                                                src\bin\pg_basebackup\receivelog.c 437
            while(1){
                if(!existsTimeLineHistoryFile){     //查看本地是否存在wal,如果是从上次结束的地方在开始
                    res = PQexec(conn, "TIMELINE_HISTORY %u");    //538
                    //参考http://www.postgres.cn/docs/14/protocol-replication.html
                }  
                res = PQexec(conn, START_REPLICATION %s%X/%X TIMELINE %u"); 
                //执行语句,指示服务器开始启动流WAL,从 WAL 位置XXX/XXX开始。如果TIMELINE选项被指定,流传送会在时间线tli上开始,否则会选择服务器的当前时间线。完成这个操作后,后面只需要从本地buffer中读取和处理。参考http://www.postgres.cn/docs/14/protocol-replication.html
                    PQexecStart(conn)
                    PQsendQuery(conn, query)
                        PQsendQueryInternal(conn, query, true);
                            pqPutMsgStart('Q', conn)
                            pqPuts(query, conn)
                                pqPutMsgBytes(s, strlen(s) + 1, conn)
                                    memcpy(conn->outBuffer + conn->outMsgEnd, buf, len);//这里放到了socket发送buffer中就可以自动完成发送的任务。
                            pqPutMsgEnd(conn)
                    PQexecFinish(conn)

                HandleCopyStream(conn, stream, &stoppos); //处理query返回的stream包
                    CopyStreamReceive()
                        rawlen = PQgetCopyData //从socket buffer中copy到用户态
                            pqGetCopyData3
                                getCopyDataMessage
                                    pqGetc //获取一个char,表示类型
                                    pqGetInt //int 表示这个包的size length
                            malloc //如果rawlen!=0, 根据获得的长度,分配内存,并从socketbuf中拷贝到用户态
                            memcpy
                        if(rawlen == 0)
                            CopyStreamPoll
                                select //使用linux select等待数据到达,直到超时
                            pqReadData //select拿到通知,数据已经到达
                                pqReadData
                                    pqsecure_read
                                        pqsecure_raw_read
                                            recv //linux socket api 从socket中收数据
                    while(1) { 
                        r = CopyStreamReceive(conn, sleeptime, stream->stop_socket, &copybuf);
                            rawlen = PQgetCopyData(conn, &copybuf, 1);
                                return pqGetCopyData3(conn, buffer, async);
                                    for;;{
                                        msgLength = getCopyDataMessage(conn); //获取一行的message数据,message是stream的控制信息,后面的keep live,或者是wal data等信息。
                                            pqGetc(&id, conn) //从socket连接中获取
                                            pqGetInt //int 表示这个包的size length
                                        malloc //根据获得的长度,分配内存,并从socketbuf中拷贝到用户态
                                        memcpy
                                    }
                        while (r != 0)//一次query持续在这个循环中接收和处理服务器发送来的package,除非超时退出此循环
		        {
                              根据获取到的服务器massage,不同操作
                              if (copybuf[0] == 'k')
                              {
                                  ProcessKeepaliveMsg(conn, stream, copybuf, r, blockpos,
                                                          &last_status)
                              }
                              else if (copybuf[0] == 'w')
                              {
                                  ProcessXLogDataMsg(conn, stream, copybuf, r, &blockpos)
                                      write(walfile, copybuf + hdr_len + bytes_written,bytes_to_write) //这里完成写本地文件,完成备份。
                              }
                              CopyStreamReceive //同上
                        }
                    }
            }
posted @ 2022-06-26 21:48  skpupil  阅读(144)  评论(0编辑  收藏  举报