溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PostgreSQL在響應(yīng)客戶端發(fā)出備份命令pg_basebackup時(shí)做了什么

發(fā)布時(shí)間:2021-11-09 14:55:22 來源:億速云 閱讀:169 作者:iii 欄目:關(guān)系型數(shù)據(jù)庫(kù)

這篇文章主要介紹“PostgreSQL在響應(yīng)客戶端發(fā)出備份命令pg_basebackup時(shí)做了什么”,在日常操作中,相信很多人在PostgreSQL在響應(yīng)客戶端發(fā)出備份命令pg_basebackup時(shí)做了什么問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”PostgreSQL在響應(yīng)客戶端發(fā)出備份命令pg_basebackup時(shí)做了什么”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

一、數(shù)據(jù)結(jié)構(gòu)

basebackup_options
pg_basebackup的選項(xiàng),在數(shù)據(jù)庫(kù)服務(wù)器解析為該數(shù)據(jù)結(jié)構(gòu).

typedef struct
{
  //備份的標(biāo)簽
    const char *label;
    //是否顯示進(jìn)度
    bool        progress;
    //是否執(zhí)行快速fast checkpoint?
    bool        fastcheckpoint;
    //nowait?
    bool        nowait;
    //是否包含wal data
    bool        includewal;
    //
    uint32      maxrate;
    //是否包含表空間映射文件?
    bool        sendtblspcmapfile;
} basebackup_options;

二、源碼解讀

數(shù)據(jù)庫(kù)服務(wù)器接收到請(qǐng)求,postmaster啟動(dòng)新的postgres進(jìn)程響應(yīng)此請(qǐng)求,此進(jìn)程被視為walsender,標(biāo)記am_walsender設(shè)置為T,在PostgresMain函數(shù)中,將執(zhí)行以下邏輯:

...
  for (;;)//主循環(huán)
  {
    ...
    switch (firstchar)
    {
      case 'Q':     /* simple query */
        {
          if (am_walsender)
          {
            //如為WAL sender,執(zhí)行exec_replication_command
            if (!exec_replication_command(query_string))
              exec_simple_query(query_string);
            ...
...

調(diào)用exec_replication_command函數(shù),執(zhí)行相關(guān)命令.該函數(shù)會(huì)調(diào)用SendBaseBackup函數(shù)執(zhí)行具體的實(shí)現(xiàn)邏輯,其中重點(diǎn)的實(shí)現(xiàn)函數(shù)是sendFileWithContent/sendDir.
1.sendFileWithContent函數(shù)用于發(fā)送backup_label等文件到客戶端
pq_putmessage發(fā)送消息,’d’的消息類型表示CopyData.

static void
sendFileWithContent(const char *filename, const char *content)
{
    struct stat statbuf;
    int         pad,
                len;
    len = strlen(content);
    /*
     * Construct a stat struct for the backup_label file we're injecting in
     * the tar.
     */
    /* Windows doesn't have the concept of uid and gid */
#ifdef WIN32
    statbuf.st_uid = 0;
    statbuf.st_gid = 0;
#else
    statbuf.st_uid = geteuid();
    statbuf.st_gid = getegid();
#endif
    statbuf.st_mtime = time(NULL);
    statbuf.st_mode = pg_file_create_mode;
    statbuf.st_size = len;
    _tarWriteHeader(filename, NULL, &statbuf, false);
    /* Send the contents as a CopyData message */
    pq_putmessage('d', content, len);
    /* Pad to 512 byte boundary, per tar format requirements */
    pad = ((len + 511) & ~511) - len;
    if (pad > 0)
    {
        char        buf[512];
        MemSet(buf, 0, pad);
        pq_putmessage('d', buf, pad);
    }
}

2.sendDir遍歷文件目錄,調(diào)用sendFile發(fā)送到客戶端
遞歸遍歷數(shù)據(jù)庫(kù)目錄,調(diào)用sendFile發(fā)送文件

...
            if (!sizeonly)
                sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
                                true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
            if (sent || sizeonly)
            {
                /* Add size, rounded up to 512byte block */
                size += ((statbuf.st_size + 511) & ~511);
                size += 512;    /* Size of the header of the file */
            }
...

sendFile發(fā)送相應(yīng)的文件內(nèi)容到客戶端

...
    while ((cnt = fread(buf, 1, Min(sizeof(buf), statbuf->st_size - len), fp)) > 0)
    {
      ...
       /* Send the chunk as a CopyData message */
        if (pq_putmessage('d', buf, cnt))
            ereport(ERROR,
                    (errmsg("base backup could not send data, aborting backup")));
        ...
    }

三、跟蹤分析

客戶端啟動(dòng)pg_basebackup

[xdb@localhost ~]$ pg_basebackup -h 192.168.26.25 -U replicator -p 5432 -D /data/backup -P -Xs -R
Password:

跟蹤postmaster,設(shè)置跟蹤子進(jìn)程

(gdb) set follow-fork-mode child
(gdb) b PostgresMain

客戶端輸入密碼后,進(jìn)入斷點(diǎn),在執(zhí)行BASE_BACKUP命令前,首先會(huì)執(zhí)行SHOW data_directory_mode/SHOW wal_segment_size/IDENTIFY_SYSTEM三個(gè)命令,然后再執(zhí)行BASE_BACKUP命令

...
(gdb) p input_message
$2 = {data = 0x20a1d78 "SHOW data_directory_mode", len = 25, maxlen = 1024, cursor = 0}
...
(gdb) p input_message
$4 = {data = 0x20a1d78 "SHOW wal_segment_size", len = 22, maxlen = 1024, cursor = 0}
...
(gdb) p input_message
$5 = {data = 0x20a1d78 "IDENTIFY_SYSTEM", len = 16, maxlen = 1024, cursor = 0}
...
(gdb) p input_message
$7 = {data = 0x20a1d78 "BASE_BACKUP LABEL 'pg_basebackup base backup' PROGRESS   NOWAIT   ", len = 67, maxlen = 1024, 
  cursor = 0}
...

跟蹤SendBaseBackup

(gdb) b SendBaseBackup
...
4178              if (!exec_replication_command(query_string))
(gdb) step
exec_replication_command (cmd_string=0x20a1d78 "BASE_BACKUP LABEL 'pg_basebackup base backup' PROGRESS   NOWAIT   ")
    at walsender.c:1438
1438    if (got_STOPPING)
1521        SendBaseBackup((BaseBackupCmd *) cmd_node);
...

進(jìn)入SendBaseBackup

(gdb) c
Continuing.
[New process 1811]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[Switching to Thread 0x7f46389b58c0 (LWP 1811)]
Breakpoint 1, SendBaseBackup (cmd=0x2137da8) at basebackup.c:762
762   parse_basebackup_options(cmd->options, &opt);
(gdb) n
764   WalSndSetState(WALSNDSTATE_BACKUP);
(gdb) p opt
$1 = {label = 0x2137760 "pg_basebackup base backup", progress = true, fastcheckpoint = false, nowait = true, 
  includewal = false, maxrate = 0, sendtblspcmapfile = false}

實(shí)際執(zhí)行backup的是函數(shù)perform_base_backup

...
(gdb) 
775   perform_base_backup(&opt);
(gdb) step
perform_base_backup (opt=0x7ffc96573180) at basebackup.c:232

執(zhí)行sendXXX

320       if (ti->path == NULL)
(gdb) 
325         sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
(gdb) p *labelfile
$4 = {
  data = 0x2138a50 "START WAL LOCATION: 0/66000028 (file 0000001", '0' <repeats 15 times>, "66)\nCHECKPOINT LOCATION: 0/66000060\nBACKUP METHOD: streamed\nBACKUP FROM: master\nSTART TIME: 2019-03-26 17:05:45 CST\nLABEL: pg_basebackup base"..., 
  len = 227, maxlen = 1024, cursor = 0}
(gdb) n
331         if (tblspc_map_file && opt->sendtblspcmapfile)
(gdb) 
337           sendDir(".", 1, false, tablespaces, true);
(gdb) 
340         if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
(gdb) 
345         sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false);
(gdb) 
356       if (opt->includewal && ti->path == NULL)
(gdb) 
361         pq_putemptymessage('c');  /* CopyDone */
(gdb) 
309     foreach(lc, tablespaces)
(gdb) 
364     endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
(gdb) 
366   PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
(gdb) 
369   if (opt->includewal)
(gdb) 
605   SendXlogRecPtrResult(endptr, endtli);
(gdb) 
607   if (total_checksum_failures)
(gdb) 
623 }
(gdb) 
SendBaseBackup (cmd=0x2137da8) at basebackup.c:776
776 }
(gdb) 
exec_replication_command (cmd_string=0x20a1d78 "BASE_BACKUP LABEL 'pg_basebackup base backup' PROGRESS   NOWAIT   ")
    at walsender.c:1522
1522        break;
(gdb) c
Continuing.
[Inferior 2 (process 1811) exited normally]
(gdb)

到此,關(guān)于“PostgreSQL在響應(yīng)客戶端發(fā)出備份命令pg_basebackup時(shí)做了什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI