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分析”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341