iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >PostgreSQL的后台进程walsender分析
  • 459
分享到

PostgreSQL的后台进程walsender分析

2024-04-02 19:04:59 459人浏览 八月长安
摘要

这篇文章主要介绍“postgresql的后台进程walsender分析”,在日常操作中,相信很多人在Postgresql的后台进程walsender分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操

这篇文章主要介绍“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分析”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL的后台进程walsender分析

本文链接: https://www.lsjlt.com/news/64187.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • PostgreSQL的后台进程walsender分析
    这篇文章主要介绍“PostgreSQL的后台进程walsender分析”,在日常操作中,相信很多人在PostgreSQL的后台进程walsender分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操...
    99+
    2024-04-02
  • PostgreSQL的后台进程checkpointer分析
    本篇内容介绍了“PostgreSQL的后台进程checkpointer分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,...
    99+
    2024-04-02
  • PostgreSQL 源码解读(155)- 后台进程#7(walsender#3)
    本节继续介绍PostgreSQL...
    99+
    2024-04-02
  • PostgreSQL 源码解读(154)- 后台进程#6(walsender#2)
    本节继续介绍PostgreSQL...
    99+
    2024-04-02
  • 怎么理解PostgreSQL的后台进程autovacuum
    本篇内容介绍了“怎么理解PostgreSQL的后台进程autovacuum”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、数据结构Auto...
    99+
    2023-05-31
  • Oracle部分后台进程
            1.PMON:后台进程 负责在连接出现异常中止后进行清理工作 PMON会回滚未提交的工作,释放锁,并释...
    99+
    2024-04-02
  • vue element后台鉴权流程分析
    前言: 最近项目遇到一个管理系统,感觉权限配置挺有意思,记录一下流程实现的过程,便于自己学习以及整理思路,部分思路整合在代码的注释中: 路由拦截鉴权常用的两种方法 1:路由拦截:单纯...
    99+
    2024-04-02
  • 为什么PostgreSQL checkpointer后台进程使用这么多内存
    这篇文章主要讲解了“为什么PostgreSQL checkpointer后台进程使用这么多内存”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“为什么Postg...
    99+
    2024-04-02
  • PhpMyAdmin后台getshell的示例分析
    这篇文章主要介绍了PhpMyAdmin后台getshell的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。PhpMyAdmin简介P...
    99+
    2024-04-02
  • Oracle的后台进程是什么
    本篇内容介绍了“Oracle的后台进程是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1 SMON:常...
    99+
    2024-04-02
  • oracle后台进程是怎样的
    这篇文章将为大家详细讲解有关oracle后台进程是怎样的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。oracle后台进程伴随实例的启动而启动,他们主要是维...
    99+
    2024-04-02
  • PostgreSQL中vacuum过程分析
    本篇内容主要讲解“PostgreSQL中vacuum过程分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中vacuum过程分析”吧!一、数...
    99+
    2024-04-02
  • 微信小程序中后台登录的示例分析
    这篇文章主要介绍微信小程序中后台登录的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!微信小程序 后台登录实现效果图:最近写了一个工具类的小程序,按需求要求不要微信提供的微信账...
    99+
    2024-04-02
  • 分析一个Node进程的死亡与善后
    这篇文章主要讲解了“分析一个Node进程的死亡与善后”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“分析一个Node进程的死亡与善后”吧!Exit Code什...
    99+
    2024-04-02
  • Linux如何查看后台进程
    这篇文章给大家分享的是有关Linux如何查看后台进程的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。LINUX后台进程也叫守护进程(Daemon),是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任...
    99+
    2023-06-28
  • PostgreSQL中vacuum主流程分析
    本篇内容介绍了“PostgreSQL中vacuum主流程分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!...
    99+
    2024-04-02
  • jsp到servlet后台服务通信过程的示例分析
    这篇文章主要介绍了jsp到servlet后台服务通信过程的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。web.xml 文件对于任何一个web 运用来说,有,而且只能...
    99+
    2023-06-02
  • 分析PostgreSQL创建函数的过程
    本篇内容主要讲解“分析PostgreSQL创建函数的过程”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析PostgreSQL创建函数的过程”吧!一、数据结构F...
    99+
    2024-04-02
  • Linux前后台任务实例分析
    这篇文章主要讲解了“Linux前后台任务实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux前后台任务实例分析”吧!对于任务的管理,我们一般有如下几个需求:将进程切换到前台将进程...
    99+
    2023-06-28
  • Linux后台进程管理的常用命令
    这篇文章主要介绍“Linux后台进程管理的常用命令”,在日常操作中,相信很多人在Linux后台进程管理的常用命令问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux后台进程管理的常用命令”的疑惑有所帮助!...
    99+
    2023-06-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作