文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

PostgreSQL的后台进程walsender分析

2024-04-02 19:55

关注

这篇文章主要介绍“PostgreSQL的后台进程walsender分析”,在日常操作中,相信很多人在PostgreSQL的后台进程walsender分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL的后台进程walsender分析”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

该进程实质上是streaming replication环境中master节点上普通的backend进程,在standby节点启动时,standby节点向master发送连接请求,master节点的postmaster进程接收到请求后,启动该进程与standby节点的walreceiver进程建立通讯连接,用于传输WAL Record.
walsender启动后,使用gdb跟踪此进程,其调用栈如下:

(gdb) bt
#0  0x00007fb6e6390903 in __epoll_wait_nocancel () from /lib64/libc.so.6
#1  0x000000000088e668 in WaitEventSetWaitBlock (set=0x10ac808, cur_timeout=29999, occurred_events=0x7ffd634441b0, 
    nevents=1) at latch.c:1048
#2  0x000000000088e543 in WaitEventSetWait (set=0x10ac808, timeout=29999, occurred_events=0x7ffd634441b0, nevents=1, 
    wait_event_info=83886092) at latch.c:1000
#3  0x000000000088dcec in WaitLatchOrSocket (latch=0x7fb6dcbfc4d4, wakeEvents=27, sock=10, timeout=29999, 
    wait_event_info=83886092) at latch.c:385
#4  0x000000000085405b in WalSndLoop (send_data=0x8547fe <XLogSendPhysical>) at walsender.c:2229
#5  0x0000000000851c93 in StartReplication (cmd=0x10ab750) at walsender.c:684
#6  0x00000000008532f0 in exec_replication_command (cmd_string=0x101dd78 "START_REPLICATION 0/5D000000 TIMELINE 16")
    at walsender.c:1539
#7  0x00000000008c0170 in PostgresMain (argc=1, argv=0x1049cb8, dbname=0x1049ba8 "", username=0x1049b80 "replicator")
    at postgres.c:4178
#8  0x000000000081e06c in BackendRun (port=0x103fb50) at postmaster.c:4361
#9  0x000000000081d7df in BackendStartup (port=0x103fb50) at postmaster.c:4033
#10 0x0000000000819bd9 in ServerLoop () at postmaster.c:1706
#11 0x000000000081948f in PostmasterMain (argc=1, argv=0x1018a50) at postmaster.c:1379
#12 0x0000000000742931 in main (argc=1, argv=0x1018a50) at main.c:228

本节首先介绍调用栈中PostgresMain函数.

一、数据结构

StringInfo
StringInfoData结构体保存关于扩展字符串的相关信息.


typedef struct StringInfoData
{
    char       *data;
    int         len;
    int         maxlen;
    int         cursor;
} StringInfoData;
typedef StringInfoData *StringInfo;

二、源码解读

PostgresMain
后台进程postgres的主循环入口 — 所有的交互式或其他形式的后台进程在这里启动.
其主要逻辑如下:
1.初始化相关变量
2.初始化进程信息,设置进程状态,初始化GUC参数
3.解析命令行参数并作相关校验
4.如为walsender进程,则调用WalSndSignals初始化,否则执行其他信号初始化
5.初始化BlockSig/UnBlockSig/StartupBlockSig
6.非Postmaster,则检查数据库路径/切换路径/创建锁定文件等操作
7.调用BaseInit执行基本的初始化
8.调用InitProcess/InitPostgres初始化进程
9.重置内存上下文,处理加载库和前后台消息交互等
10.初始化内存上下文
11.进入主循环
11.1切换至MessageContext上下文
11.2初始化输入的消息
11.3给客户端发送可以执行查询等消息
11.4读取命令
11.5根据命令类型执行相关操作



void
PostgresMain(int argc, char *argv[],
             const char *dbname,
             const char *username)
{
    int         firstchar;//临时变量,读取输入的Command
    StringInfoData input_message;//字符串增强结构体
    sigjmp_buf  local_sigjmp_buf;//系统变量
    volatile bool send_ready_for_query = true;//
    bool        disable_idle_in_transaction_timeout = false;
    
    //如需要,初始化启动进程环境
    if (!IsUnderPostmaster//未初始化?initialized for the bootstrap/standalone case
        InitStandaloneProcess(argv[0]);//初始化进程
    SetProcessingMode(InitProcessing);//设置进程状态为InitProcessing
    
    if (!IsUnderPostmaster)
        InitializeGUCOptions();//初始化GUC参数,GUC=Grand Unified Configuration
    
    process_postgres_switches(argc, argv, PGC_POSTMASTER, &dbname);//解析输入参数
    
    //必须包含数据库名称或者存在默认值
    if (dbname == NULL)//输入的dbname为空
    {
        dbname = username;//设置为用户名
        if (dbname == NULL)//如仍为空,报错
            ereport(FATAL,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("%s: no database nor user name specified",
                            progname)));
    }
    
    //请求配置参数,除非从postmaster中继承
    if (!IsUnderPostmaster)
    {
        if (!SelectConfigFiles(userDoption, progname))//读取配置文件conf/hba文件&定位数据目录
            proc_exit(1);
    }
    
    if (am_walsender)//wal sender进程?
        WalSndSignals();//如果是,则调用WalSndSignals
    else//不是wal sender进程
    {
        //设置标记,读取配置文件
        pqsignal(SIGHUP, PostgresSigHupHandler);    
        //中断信号处理器(中断当前查询)
        pqsignal(SIGINT, StatementCancelHandler);   
        //终止当前查询并退出
        pqsignal(SIGTERM, die); 
        
        //bool IsUnderPostmaster = false
        if (IsUnderPostmaster)
            //悲催时刻,执行quickdie()
            pqsignal(SIGQUIT, quickdie);    
        else
            //执行die()
            pqsignal(SIGQUIT, die); 
        //建立SIGALRM处理器
        InitializeTimeouts();   
        
        pqsignal(SIGPIPE, SIG_IGN);
        pqsignal(SIGUSR1, procsignal_sigusr1_handler);
        pqsignal(SIGUSR2, SIG_IGN);
        pqsignal(SIGFPE, FloatExceptionHandler);
        
        //在某些平台上,system()需要这个信号
        pqsignal(SIGCHLD, SIG_DFL); 
    }
    //初始化BlockSig/UnBlockSig/StartupBlockSig
    pqinitmask();//Initialize BlockSig, UnBlockSig, and StartupBlockSig.
    if (IsUnderPostmaster)
    {
        
        //放开SIGQUIT(quickdie)
        sigdelset(&BlockSig, SIGQUIT);
    }
    //除了SIGQUIT,阻塞其他
    PG_SETMASK(&BlockSig);      
    if (!IsUnderPostmaster)
    {
        
        checkDataDir();//确认数据库路径OK,使用stat命令
        
        //切换至数据库路径,使用chdir命令
        ChangeToDataDir();
        
        //创建锁定文件,CreateLockFile(DIRECTORY_LOCK_FILE, amPostmaster, "", true, DataDir);
        CreateDataDirLockFile(false);
        
        //读取控制文件(错误检查和包含配置)
        LocalProcessControlFile(false);//Read the control file, set respective GUCs.
        
        //从配置选项中初始化MaxBackends
        InitializeMaxBackends();//Initialize MaxBackends value from config options.
    }
    
    BaseInit();//执行基本的初始化
    
// initialize a per-process data structure for this backend
#ifdef EXEC_BACKEND
    if (!IsUnderPostmaster)
        InitProcess();
#else
    InitProcess();
#endif
    
    //在初始化事务期间需要允许SIGINT等等
    PG_SETMASK(&UnBlockSig);
    
    InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL, false);//Initialize POSTGRES
    
    if (PostmasterContext)
    {
        MemoryContextDelete(PostmasterContext);
        PostmasterContext = NULL;
    }
    //完成初始化后,设置进程模式为NormalProcessing
    SetProcessingMode(NormalProcessing);
    
    //Report GUC
    BeginReportingGUCOptions();
    
    //设置处理器,用于记录会话结束;
    //等待直至确保Log_disconnections最终有值存在
    if (IsUnderPostmaster && Log_disconnections)
        on_proc_exit(log_disconnections, 0);//this function adds a callback function to the list of functions invoked by proc_exit()
    
    //为WAL sender进程执行特别的初始化
    if (am_walsender)
        InitWalSender();//初始化 WAL sender process
    
    process_session_preload_libraries();//加载LIB
    
    if (whereToSendOutput == DestRemote)
    {
        StringInfoData buf;
        pq_beginmessage(&buf, 'K');
        pq_sendint32(&buf, (int32) MyProcPid);
        pq_sendint32(&buf, (int32) MyCancelKey);
        pq_endmessage(&buf);
        
        //不需要flush,因为ReadyForQuery会执行该操作
    }
    
    //standalone的欢迎信息
    if (whereToSendOutput == DestDebug)
        printf("\nPostgreSQL stand-alone backend %s\n", PG_VERSION);
    
    //初始化内存上下文:MessageContext
    MessageContext = AllocSetContextCreate(TopMemoryContext,
                                           "MessageContext",
                                           ALLOCSET_DEFAULT_SIZES);
    
    //TODO 传输RowDescription messages?
    row_description_context = AllocSetContextCreate(TopMemoryContext,
                                                    "RowDescriptionContext",
                                                    ALLOCSET_DEFAULT_SIZES);
    MemoryContextSwitchTo(row_description_context);
    initStringInfo(&row_description_buf);
    MemoryContextSwitchTo(TopMemoryContext);
    
    if (!IsUnderPostmaster)
        PgStartTime = GetCurrentTimestamp();//记录启动时间
    
    if (sigsetjmp(local_sigjmp_buf, 1) != 0)//
    {
        
        
        //不使用PG_TRY,必须重置错误栈
        error_context_stack = NULL;
        
        //清理时禁止中断
        HOLD_INTERRUPTS();
        
        disable_all_timeouts(false);
        QueryCancelPending = false; 
        stmt_timeout_active = false;
        
        //不再从客户端读取信息
        DoingCommandRead = false;
        
        //确保libq状态OK
        pq_comm_reset();
        
        //向客户端和/或服务器日志报告错误
        EmitErrorReport();
        
        debug_query_string = NULL;
        
        AbortCurrentTransaction();
        if (am_walsender)
            //如为walsender,则执行清理工作
            WalSndErrorCleanup();
        //错误清理
        PortalErrorCleanup();
        SPICleanup();
        
        if (MyReplicationSlot != NULL)
            ReplicationSlotRelease();
        
        //出现错误时,清理临时slots
        ReplicationSlotCleanup();
        //重置JIT
        jit_reset_after_error();
        
        MemoryContextSwitchTo(TopMemoryContext);
        FlushErrorState();
        
        if (doing_extended_query_message)
            ignore_till_sync = true;
        
        //不再有打开的事务命令
        xact_started = false;
        
        if (pq_is_reading_msg())
            ereport(FATAL,
                    (errcode(ERRCODE_PROTOCOL_VIOLATION),
                     errmsg("terminating connection because protocol synchronization was lost")));
        
        //允许中断
        RESUME_INTERRUPTS();
    }
    
    //现在可以处理ereport(ERROR)了
    PG_exception_stack = &local_sigjmp_buf;
    if (!ignore_till_sync)
        //错误恢复后重新初始化
        send_ready_for_query = true;    
    
    for (;;)//主循环
    {
        
        doing_extended_query_message = false;
        
        MemoryContextSwitchTo(MessageContext);//切换至MessageContext
        MemoryContextResetAndDeleteChildren(MessageContext);
        initStringInfo(&input_message);//初始化输入的信息
        
        InvalidateCatalogSnapshotConditionally();
        
        if (send_ready_for_query)//I am ready!
        {
            if (IsAbortedTransactionBlockState())
            {
                set_ps_display("idle in transaction (aborted)", false);
                pgstat_report_activity(STATE_IDLEINTRANSACTION_ABORTED, NULL);
                
                if (IdleInTransactionSessionTimeout > 0)
                {
                    disable_idle_in_transaction_timeout = true;
                    enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT,
                                         IdleInTransactionSessionTimeout);
                }
            }
            else if (IsTransactionOrTransactionBlock())
            {
                set_ps_display("idle in transaction", false);
                pgstat_report_activity(STATE_IDLEINTRANSACTION, NULL);
                
                if (IdleInTransactionSessionTimeout > 0)
                {
                    disable_idle_in_transaction_timeout = true;
                    enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT,
                                         IdleInTransactionSessionTimeout);
                }
            }
            else
            {
                ProcessCompletedNotifies();
                pgstat_report_stat(false);
                set_ps_display("idle", false);
                pgstat_report_activity(STATE_IDLE, NULL);
            }
            ReadyForQuery(whereToSendOutput);
            send_ready_for_query = false;
        }
        
        DoingCommandRead = true;
        
        firstchar = ReadCommand(&input_message);//读取命令
        
        CHECK_FOR_INTERRUPTS();
        DoingCommandRead = false;
        
        if (disable_idle_in_transaction_timeout)
        {
            disable_timeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, false);
            disable_idle_in_transaction_timeout = false;
        }
        
        if (ConfigReloadPending)
        {
            ConfigReloadPending = false;
            ProcessConfigFile(PGC_SIGHUP);
        }
        
        if (ignore_till_sync && firstchar != EOF)
            continue;
        switch (firstchar)
        {
            case 'Q':           
                {
                    //--------- 简单查询
                    const char *query_string;
                    
                    //设置时间戳
                    SetCurrentStatementStartTimestamp();
                    //SQL语句
                    query_string = pq_getmsgstring(&input_message);
                    pq_getmsgend(&input_message);
                    if (am_walsender)
                    {
                        //如为WAL sender,执行exec_replication_command
                        if (!exec_replication_command(query_string))
                            exec_simple_query(query_string);
                    }
                    else
                        //普通的后台进程
                        exec_simple_query(query_string);//执行SQL语句
                    send_ready_for_query = true;
                }
                break;
            case 'P':           
                {
                    //---------- 解析
                    const char *stmt_name;
                    const char *query_string;
                    int         numParams;
                    Oid        *paramTypes = NULL;
                    forbidden_in_wal_sender(firstchar);
                    
                    SetCurrentStatementStartTimestamp();
                    stmt_name = pq_getmsgstring(&input_message);
                    query_string = pq_getmsgstring(&input_message);
                    numParams = pq_getmsgint(&input_message, 2);
                    if (numParams > 0)
                    {
                        int         i;
                        paramTypes = (Oid *) palloc(numParams * sizeof(Oid));
                        for (i = 0; i < numParams; i++)
                            paramTypes[i] = pq_getmsgint(&input_message, 4);
                    }
                    pq_getmsgend(&input_message);
                    //执行解析
                    exec_parse_message(query_string, stmt_name,
                                       paramTypes, numParams);
                }
                break;
            case 'B':           
                //------------- 绑定
                forbidden_in_wal_sender(firstchar);
                
                SetCurrentStatementStartTimestamp();
                
                exec_bind_message(&input_message);
                break;
            case 'E':           
                {
                    //------------ 执行
                    const char *portal_name;
                    int         max_rows;
                    forbidden_in_wal_sender(firstchar);
                    
                    SetCurrentStatementStartTimestamp();
                    portal_name = pq_getmsgstring(&input_message);
                    max_rows = pq_getmsgint(&input_message, 4);
                    pq_getmsgend(&input_message);
                    exec_execute_message(portal_name, max_rows);
                }
                break;
            case 'F':           
                //----------- 函数调用
                forbidden_in_wal_sender(firstchar);
                
                SetCurrentStatementStartTimestamp();
                
                pgstat_report_activity(STATE_FASTPATH, NULL);
                set_ps_display("<FASTPATH>", false);
                
                start_xact_command();
                
                
                MemoryContextSwitchTo(MessageContext);
                HandleFunctionRequest(&input_message);
                
                finish_xact_command();
                send_ready_for_query = true;
                break;
            case 'C':           
                {
                    //---------- 关闭
                    int         close_type;
                    const char *close_target;
                    forbidden_in_wal_sender(firstchar);
                    close_type = pq_getmsgbyte(&input_message);
                    close_target = pq_getmsgstring(&input_message);
                    pq_getmsgend(&input_message);
                    switch (close_type)
                    {
                        case 'S':
                            if (close_target[0] != '\0')
                                DropPreparedStatement(close_target, false);
                            else
                            {
                                
                                drop_unnamed_stmt();
                            }
                            break;
                        case 'P':
                            {
                                Portal      portal;
                                portal = GetPortalByName(close_target);
                                if (PortalIsValid(portal))
                                    PortalDrop(portal, false);
                            }
                            break;
                        default:
                            ereport(ERROR,
                                    (errcode(ERRCODE_PROTOCOL_VIOLATION),
                                     errmsg("invalid CLOSE message subtype %d",
                                            close_type)));
                            break;
                    }
                    if (whereToSendOutput == DestRemote)
                        pq_putemptymessage('3');    
                }
                break;
            case 'D':           
                {
                    //------------- 描述比如\d等命令
                    int         describe_type;
                    const char *describe_target;
                    forbidden_in_wal_sender(firstchar);
                    
                    SetCurrentStatementStartTimestamp();
                    describe_type = pq_getmsgbyte(&input_message);
                    describe_target = pq_getmsgstring(&input_message);
                    pq_getmsgend(&input_message);
                    switch (describe_type)
                    {
                        case 'S':
                            exec_describe_statement_message(describe_target);
                            break;
                        case 'P':
                            exec_describe_portal_message(describe_target);
                            break;
                        default:
                            ereport(ERROR,
                                    (errcode(ERRCODE_PROTOCOL_VIOLATION),
                                     errmsg("invalid DESCRIBE message subtype %d",
                                            describe_type)));
                            break;
                    }
                }
                break;
            case 'H':           
                //--------- flush 刷新
                pq_getmsgend(&input_message);
                if (whereToSendOutput == DestRemote)
                    pq_flush();
                break;
            case 'S':           
                //---------- Sync 同步
                pq_getmsgend(&input_message);
                finish_xact_command();
                send_ready_for_query = true;
                break;
                
            case 'X':
            case EOF:
                
                if (whereToSendOutput == DestRemote)
                    whereToSendOutput = DestNone;
                
                proc_exit(0);
            case 'd':           
            case 'c':           
            case 'f':           
                
                break;
            default:
                ereport(FATAL,
                        (errcode(ERRCODE_PROTOCOL_VIOLATION),
                         errmsg("invalid frontend message type %d",
                                firstchar)));
        }
    }                           
}

三、跟踪分析

在主节点上用gdb跟踪postmaster,在PostgresMain上设置断点后启动standby节点,进入断点

[xdb@localhost ~]$ ps -ef|grep postgre
xdb       1263     1  0 14:20 pts/0    00:00:00 /appdb/xdb/pg11.2/bin/postgres
(gdb) b PostgresMain
Breakpoint 1 at 0x8bf9df: file postgres.c, line 3660.
(gdb) set follow-fork-mode child
(gdb) c
Continuing.
[New process 1332]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[Switching to Thread 0x7fb3885d98c0 (LWP 1332)]
Breakpoint 1, PostgresMain (argc=1, argv=0x1aa4c78, dbname=0x1aa4b68 "", username=0x1aa4b40 "replicator") at postgres.c:3660
3660        volatile bool send_ready_for_query = true;
(gdb)

1.初始化相关变量
注意变量IsUnderPostmaster,如为T则表示该进程为postmaster的子进程

(gdb) p *argv
$1 = 0xc27715 "postgres"
(gdb) n
3661        bool        disable_idle_in_transaction_timeout = false;
(gdb) 
3664        if (!IsUnderPostmaster)
(gdb) p IsUnderPostmaster
$2 = true

2.初始化进程信息,设置进程状态,初始化GUC参数

(gdb) n
3667        SetProcessingMode(InitProcessing);
(gdb) 
3672        if (!IsUnderPostmaster)
(gdb) p InitProcessing
$3 = InitProcessing

3.解析命令行参数并作相关校验

(gdb) n
3678        process_postgres_switches(argc, argv, PGC_POSTMASTER, &dbname);
(gdb) 
3681        if (dbname == NULL)
(gdb) p dbname
$4 = 0x1aa4b68 ""
(gdb) p username
$5 = 0x1aa4b40 "replicator"
(gdb) n
3692        if (!IsUnderPostmaster)
(gdb)

4.如为walsender进程,则调用WalSndSignals初始化,否则执行其他信号初始化

3712        if (am_walsender)
(gdb) 
3713            WalSndSignals();
(gdb)

5.初始化BlockSig/UnBlockSig/StartupBlockSig

(gdb) 
3751        pqinitmask();
(gdb) 
3753        if (IsUnderPostmaster)
(gdb) 
3756            sigdelset(&BlockSig, SIGQUIT);
(gdb) 
(gdb) 
3759        PG_SETMASK(&BlockSig);      
(gdb)

6.非子进程(仍为postmaster进程),则检查数据库路径/切换路径/创建锁定文件等操作

N/A

7.调用BaseInit执行基本的初始化

3785        BaseInit();
(gdb)

8.调用InitProcess/InitPostgres初始化进程

3797        InitProcess();
(gdb) 
3801        PG_SETMASK(&UnBlockSig);
(gdb) 
3810        InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL, false);
(gdb)

9.重置内存上下文,处理加载库和前后台消息交互等

(gdb) 
3819        if (PostmasterContext)
(gdb) 
3821            MemoryContextDelete(PostmasterContext);
(gdb) P PostmasterContext
$6 = (MemoryContext) 0x1a78c60
(gdb) P *PostmasterContext
$7 = {type = T_AllocSetContext, isReset = false, allowInCritSection = false, methods = 0xc93260 <AllocSetMethods>, 
  parent = 0x1a73aa0, firstchild = 0x1a9a700, prevchild = 0x1a7ac70, nextchild = 0x1a75ab0, name = 0xc2622a "Postmaster", 
  ident = 0x0, reset_cbs = 0x0}
(gdb) n
3822            PostmasterContext = NULL;
(gdb) 
3825        SetProcessingMode(NormalProcessing);
(gdb) 
3831        BeginReportingGUCOptions();
(gdb) 
3837        if (IsUnderPostmaster && Log_disconnections)
(gdb) p Log_disconnections
$8 = false
(gdb) p
$9 = false
(gdb) n
3841        if (am_walsender)
(gdb) 
3842            InitWalSender();
(gdb) 
3848        process_session_preload_libraries();
(gdb) 
3853        if (whereToSendOutput == DestRemote)
(gdb) 
3857            pq_beginmessage(&buf, 'K');
(gdb) 
3858            pq_sendint32(&buf, (int32) MyProcPid);
(gdb) 
3859            pq_sendint32(&buf, (int32) MyCancelKey);
(gdb) 
3860            pq_endmessage(&buf);
(gdb) 
3865        if (whereToSendOutput == DestDebug)
(gdb)

10.初始化内存上下文

(gdb) 
3874        MessageContext = AllocSetContextCreate(TopMemoryContext,
(gdb) 
3884        row_description_context = AllocSetContextCreate(TopMemoryContext,
(gdb) 
3887        MemoryContextSwitchTo(row_description_context);
(gdb) 
3888        initStringInfo(&row_description_buf);
(gdb) 
3889        MemoryContextSwitchTo(TopMemoryContext);
(gdb) 
3894        if (!IsUnderPostmaster)
(gdb) 
3919        if (sigsetjmp(local_sigjmp_buf, 1) != 0)
(gdb) 
4027        PG_exception_stack = &local_sigjmp_buf;
(gdb) 
4029        if (!ignore_till_sync)
(gdb) 
4030            send_ready_for_query = true;    
(gdb)

11.进入主循环
11.1切换至MessageContext上下文

(gdb) 
4042            doing_extended_query_message = false;
(gdb) 
4048            MemoryContextSwitchTo(MessageContext);
(gdb) 
4049            MemoryContextResetAndDeleteChildren(MessageContext);

11.2初始化输入的消息

(gdb) 
4051            initStringInfo(&input_message);
(gdb) 
4057            InvalidateCatalogSnapshotConditionally();
(gdb) p input_message
$10 = {data = 0x1a78d78 "", len = 0, maxlen = 1024, cursor = 0}
(gdb)

11.3给客户端发送可以执行查询等消息

(gdb) n
4072            if (send_ready_for_query)
(gdb) p send_ready_for_query
$12 = true
(gdb) n
4074                if (IsAbortedTransactionBlockState())
(gdb) 
4087                else if (IsTransactionOrTransactionBlock())
(gdb) 
4102                    ProcessCompletedNotifies();
(gdb) 
4103                    pgstat_report_stat(false);
(gdb) 
4105                    set_ps_display("idle", false);
(gdb) 
4106                    pgstat_report_activity(STATE_IDLE, NULL);
(gdb) 
4109                ReadyForQuery(whereToSendOutput);
(gdb) 
4110                send_ready_for_query = false;
(gdb)

11.4读取命令
命令是IDENTIFY_SYSTEM,判断系统标识是否OK
firstchar -> ASCII 81 —> 字母’Q’

(gdb) 
4119            DoingCommandRead = true;
(gdb) 
4124            firstchar = ReadCommand(&input_message);
(gdb) 
4135            CHECK_FOR_INTERRUPTS();
(gdb) p input_message
$13 = {data = 0x1a78d78 "IDENTIFY_SYSTEM", len = 16, maxlen = 1024, cursor = 0}
(gdb) p firstchar
$14 = 81
(gdb) 
$15 = 81
(gdb) n
4136            DoingCommandRead = false;
(gdb) 
4141            if (disable_idle_in_transaction_timeout)
(gdb) 
4151            if (ConfigReloadPending)
(gdb) 
4161            if (ignore_till_sync && firstchar != EOF)
(gdb)

11.5根据命令类型执行相关操作
walsender —> 执行exec_replication_command命令

(gdb) 
4164            switch (firstchar)
(gdb) 
4171                        SetCurrentStatementStartTimestamp();
(gdb) 
4173                        query_string = pq_getmsgstring(&input_message);
(gdb) 
4174                        pq_getmsgend(&input_message);
(gdb) p query_string
$16 = 0x1a78d78 "IDENTIFY_SYSTEM"
(gdb) n
4176                        if (am_walsender)
(gdb) 
4178                            if (!exec_replication_command(query_string))
(gdb) 
4184                        send_ready_for_query = true;
(gdb) 
4186                    break;
(gdb) 
4411        }                           
(gdb)

继续循环,接收命令,第二个命令是START_REPLICATION

...
(gdb) 
4124            firstchar = ReadCommand(&input_message);
(gdb) 
4135            CHECK_FOR_INTERRUPTS();
(gdb) p input_message
$18 = {data = 0x1a78d78 "START_REPLICATION 0/5D000000 TIMELINE 16", len = 41, maxlen = 1024, cursor = 0}
(gdb) p firstchar
$19 = 81
...
4164            switch (firstchar)
(gdb) n
4171                        SetCurrentStatementStartTimestamp();
(gdb) 
4173                        query_string = pq_getmsgstring(&input_message);
(gdb) 
4174                        pq_getmsgend(&input_message);
(gdb) 
4176                        if (am_walsender)
(gdb) p query_string
$20 = 0x1a78d78 "START_REPLICATION 0/5D000000 TIMELINE 16"
(gdb) p input_message
$21 = {data = 0x1a78d78 "START_REPLICATION 0/5D000000 TIMELINE 16", len = 41, maxlen = 1024, cursor = 41}
(gdb) n
4178                            if (!exec_replication_command(query_string))
(gdb)

开始执行复制,master节点使用psql连接数据库,执行sql语句,子进程会接收到相关信号,执行相关处理
执行脚本

[xdb@localhost ~]$ psql -d testdb
psql (11.2)
Type "help" for help.
testdb=# drop table t1;

子进程输出

(gdb) 
Program received signal SIGUSR1, User defined signal 1.
0x00007fb38696c903 in __epoll_wait_nocancel () from /lib64/libc.so.6
(gdb) 
Single stepping until exit from function __epoll_wait_nocancel,
which has no line number information.
procsignal_sigusr1_handler (postgres_signal_arg=32766) at procsignal.c:262
262 {
(gdb) n
263     int         save_errno = errno;
(gdb) 
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00007fb3881eecd0 in __errno_location () from /lib64/libpthread.so.0
(gdb) 
Single stepping until exit from function __errno_location,
which has no line number information.
procsignal_sigusr1_handler (postgres_signal_arg=10) at procsignal.c:265
265     if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
(gdb)

DONE!

DEBUG退出gdb后,psql会话crash:(

[xdb@localhost ~]$ psql -d testdb
psql (11.2)
Type "help" for help.
testdb=# drop table t1;
WARNING:  terminating connection because of crash of another server process
DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
HINT:  In a moment you should be able to reconnect to the database and repeat your command.
server closed the connection unexpectedly
    This probably means the server terminated abnormally
    before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.
!>

到此,关于“PostgreSQL的后台进程walsender分析”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯