PostgreSQL 소스 코드 판독 (110) - WAL \ # 6 (Insert & WAL - XLogRe...

33233 단어
이 절 은 XLogRecordAssemble 함수 의 실현 논 리 를 간단하게 소개 합 니 다. 이 함 수 는 등 록 된 데이터 와 버퍼 에서 XLOG record 를 XLogRecData 체인 에 조립 하여 XLOG Record 의 삽입 을 준비 합 니 다.
데이터 구조
전역 정적 변수 XLogRecordAssemble 에서 사용 하 는 전역 변 수 는 hdr 를 포함 합 니 다.rdt/hdr_scratch / rdatas 등.

/* flags for the in-progress insertion */
//            
static uint8 curinsert_flags = 0;

/*
 * These are used to hold the record header while constructing a record.
 * 'hdr_scratch' is not a plain variable, but is palloc'd at initialization,
 * because we want it to be MAXALIGNed and padding bytes zeroed.
 *    XLOG Record             .
 * 'hdr_scratch'       (plain)  ,         palloc   ,
 *               MAXALIGNed    0x00  .
 *
 * For simplicity, it's allocated large enough to hold the headers for any
 * WAL record.
 *     ,                    WAL Record     .
 */
static XLogRecData hdr_rdt;
static char *hdr_scratch = NULL;

#define SizeOfXlogOrigin    (sizeof(RepOriginId) + sizeof(char))

#define HEADER_SCRATCH_SIZE \
    (SizeOfXLogRecord + \
     MaxSizeOfXLogRecordBlockHeader * (XLR_MAX_BLOCK_ID + 1) + \
     SizeOfXLogRecordDataHeaderLong + SizeOfXlogOrigin)
/*
 * An array of XLogRecData structs, to hold registered data.
 * XLogRecData     ,        .
 */
static XLogRecData *rdatas;
static int  num_rdatas;         /* entries currently used */
//        
static int  max_rdatas;         /* allocated size */
//    XLogBeginInsert  
static bool begininsert_called = false;

static XLogCtlData *XLogCtl = NULL;

/* flags for the in-progress insertion */
static uint8 curinsert_flags = 0;

/*
 * A chain of XLogRecDatas to hold the "main data" of a WAL record, registered
 * with XLogRegisterData(...).
 *   WAL Record "main data" XLogRecDatas   
 */
static XLogRecData *mainrdata_head;
static XLogRecData *mainrdata_last = (XLogRecData *) &mainrdata_head;
//       mainrdata  
static uint32 mainrdata_len; /* total # of bytes in chain */

/*
 * ProcLastRecPtr points to the start of the last XLOG record inserted by the
 * current backend.  It is updated for all inserts.  XactLastRecEnd points to
 * end+1 of the last record, and is reset when we end a top-level transaction,
 * or start a new one; so it can be used to tell if the current transaction has
 * created any XLOG records.
 * ProcLastRecPtr             XLOG     。
 *            。
 * XactLastRecEnd              + 1,
 *                    ;
 *     ,                  XLOG  。
 *
 * While in parallel mode, this may not be fully up to date.  When committing,
 * a transaction can assume this covers all xlog records written either by the
 * user backend or by any parallel worker which was present at any point during
 * the transaction.  But when aborting, or when still in parallel mode, other
 * parallel backends may have written WAL records at later LSNs than the value
 * stored here.  The parallel leader advances its own copy, when necessary,
 * in WaitForParallelWorkersToFinish.
 *       ,           。
 *     ,                          worker     xlog  。
 *   ,    ,           ,              LSNs    WAL  ,
 *             。
 *     ,       leader WaitForParallelWorkersToFinish         。
 */
XLogRecPtr  ProcLastRecPtr = InvalidXLogRecPtr;
XLogRecPtr  XactLastRecEnd = InvalidXLogRecPtr;
XLogRecPtr XactLastCommitEnd = InvalidXLogRecPtr;

/* For WALInsertLockAcquire/Release functions */
//  WALInsertLockAcquire/Release  
static int  MyLockNo = 0;
static bool holdingAllLocks = false;


매크로 정의 XLogRegisterBuffer 함수 에 사용 할 flags
/* flags for XLogRegisterBuffer */
//XLogRegisterBuffer     flags
#define REGBUF_FORCE_IMAGE  0x01    /*     full-page-write;force a full-page image */
#define REGBUF_NO_IMAGE     0x02    /*    FPI;don't take a full-page image */
#define REGBUF_WILL_INIT    (0x04 | 0x02)   /*          page(  NO_IMAGE);
                                             * page will be re-initialized at
                                             * replay (implies NO_IMAGE) */
#define REGBUF_STANDARD     0x08    /*    page layout(   pd_lower pd_upper         )
                                     * page follows "standard" page layout,
                                     * (data between pd_lower and pd_upper
                                     * will be skipped) */
#define REGBUF_KEEP_DATA    0x10    /* include data even if a full-page image
                                      * is taken */
/*
 * Flag bits for the record being inserted, set using XLogSetRecordFlags().
 */
#define XLOG_INCLUDE_ORIGIN     0x01    /* include the replication origin */
#define XLOG_MARK_UNIMPORTANT   0x02    /* record not important for durability */    


XLogRecData xloginsert. c 의 함수 구조 XLogRecData 구조 체 체인 은 마지막 WAL 기록 을 표시 하 는 데 사 용 됩 니 다.
/*
 * The functions in xloginsert.c construct a chain of XLogRecData structs
 * to represent the final WAL record.
 * xloginsert.c        XLogRecData           WAL  
 */
typedef struct XLogRecData
{
    //         ,    NULL
    struct XLogRecData *next;   /* next struct in chain, or NULL */
    //rmgr       
    char       *data;           /* start of rmgr data to include */
    //rmgr    
    uint32      len;            /* length of rmgr data to include */
} XLogRecData;


registered_buffer 는 XLogRegisterBuffer 로 등 록 된 모든 데이터 블록 을 registered 에 채 웁 니 다.buffer 구조 체 중

/*
 * For each block reference registered with XLogRegisterBuffer, we fill in
 * a registered_buffer struct.
 *        XLogRegisterBuffer        ,
 *      registered_buffer    
 */
typedef struct
{
    //slot     ?
    bool        in_use;         /* is this slot in use? */
    //REGBUF_*     
    uint8       flags;          /* REGBUF_* flags */
    //            
    RelFileNode rnode;          /* identifies the relation and block */
    //fork    
    ForkNumber  forkno;
    //   
    BlockNumber block;
    //   
    Page        page;           /* page content */
    //rdata        
    uint32      rdata_len;      /* total length of data in rdata chain */
    //             
    XLogRecData *rdata_head;    /* head of the chain of data registered with
                                 * this block */
    //             
    XLogRecData *rdata_tail;    /* last entry in the chain, or &rdata_head if
                                 * empty */
    //  rdatas    ,    XLogRecordAssemble()         
    XLogRecData bkp_rdatas[2];  /* temporary rdatas used to hold references to
                                 * backup block data in XLogRecordAssemble() */

    /* buffer to store a compressed version of backup block image */
    //                 
    char        compressed_page[PGLZ_MAX_BLCKSZ];
} registered_buffer;
//registered_buffer  (    )
static registered_buffer *registered_buffers;
//      
static int  max_registered_buffers; /* allocated size */
//     + 1(     )
static int  max_registered_block_id = 0;    /* highest block_id + 1 currently
                                             * registered */

2. 소스 코드 해독
XLogRecordAssemble 함 수 는 등 록 된 데이터 와 버퍼 에서 XLOG record 를 XLogRecData 체인 에 조립 하고 조립 이 완료 되면 XLogInsertRecord () 함 수 를 WAL buffer 에 삽입 할 수 있 습 니 다.
 /*
  * Assemble a WAL record from the registered data and buffers into an
  * XLogRecData chain, ready for insertion with XLogInsertRecord().
  *               XLOG record XLogRecData  ,
  *          XLogInsertRecord()    .
  * 
  * The record header fields are filled in, except for the xl_prev field. The
  * calculated CRC does not include the record header yet.
  *   xl_prev ,XLOG Record header      .
  *    CRC     header  .
  *
  * If there are any registered buffers, and a full-page image was not taken
  * of all of them, *fpw_lsn is set to the lowest LSN among such pages. This
  * signals that the assembled record is only good for insertion on the
  * assumption that the RedoRecPtr and doPageWrites values were up-to-date.
  *           ,  full-page-image          ,
  *   *fpw_lsn           LSN.
  *   RedoRecPtr doPageWrites         ,
  *       XLOG Record          OK .
  */
 static XLogRecData *
 XLogRecordAssemble(RmgrId rmid, uint8 info,
                    XLogRecPtr RedoRecPtr, bool doPageWrites,
                    XLogRecPtr *fpw_lsn)
{
     XLogRecData *rdt;//XLogRecData  
     uint32      total_len = 0;//XLOG Record  
     int         block_id;// ID
     pg_crc32c   rdata_crc;//CRC
     registered_buffer *prev_regbuf = NULL;//    buffer  
     XLogRecData *rdt_datas_last;//
     XLogRecord *rechdr;//    
     char       *scratch = hdr_scratch;

     /*
      * Note: this function can be called multiple times for the same record.
      * All the modifications we do to the rdata chains below must handle that.
      *      XLOG Record,          .
      *      rdata                .
      */

     /* The record begins with the fixed-size header */
     //XLOG Record         .
     rechdr = (XLogRecord *) scratch;
     scratch += SizeOfXLogRecord;//    

     hdr_rdt.next = NULL;//hdr_rdt --> static XLogRecData hdr_rdt;
     rdt_datas_last = &hdr_rdt;//
     hdr_rdt.data = hdr_scratch;//rmgr       

     /*
      * Enforce consistency checks for this record if user is looking for it.
      * Do this before at the beginning of this routine to give the possibility
      * for callers of XLogInsert() to pass XLR_CHECK_CONSISTENCY directly for
      * a record.
      *         ,            .
      *                ,  XLogInsert()    
      *         XLR_CHECK_CONSISTENCY XLOG Record.
      */
     if (wal_consistency_checking[rmid])
         info |= XLR_CHECK_CONSISTENCY;

     /*
      * Make an rdata chain containing all the data portions of all block
      * references. This includes the data for full-page images. Also append
      * the headers for the block references in the scratch buffer.
      *                rdata .   FPI   .
      *   , scratch                 .
      */
     *fpw_lsn = InvalidXLogRecPtr;//     
     for (block_id = 0; block_id < max_registered_block_id; block_id++)//      block
     {
         registered_buffer *regbuf = &registered_buffers[block_id];//    block_id     
         bool        needs_backup;//    backup block
         bool        needs_data;//    data
         XLogRecordBlockHeader bkpb;//XLogRecordBlockHeader
         XLogRecordBlockImageHeader bimg;//XLogRecordBlockImageHeader
         XLogRecordBlockCompressHeader cbimg = {0};//       
         bool        samerel;//     rel?
         bool        is_compressed = false;//    
         bool        include_image;//    FPI

         if (!regbuf->in_use)//    ,     
             continue;

         /* Determine if this block needs to be backed up */
         //   block    backup
         if (regbuf->flags & REGBUF_FORCE_IMAGE)
             needs_backup = true;//    FPI
         else if (regbuf->flags & REGBUF_NO_IMAGE)
             needs_backup = false;//      IMAGE
         else if (!doPageWrites)
             needs_backup = false;//doPageWrites     F
         else//doPageWrites = T
         {
             /*
              * We assume page LSN is first data on *every* page that can be
              * passed to XLogInsert, whether it has the standard page layout
              * or not.
              *    page    page layout,
              *           page        page LSN,
              *   
              */
             XLogRecPtr  page_lsn = PageGetLSN(regbuf->page);//  LSN

             needs_backup = (page_lsn <= RedoRecPtr);//    backup
             if (!needs_backup)//   
             {
                 if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn)
                     *fpw_lsn = page_lsn;//  LSN
             }
         }

         /* Determine if the buffer data needs to included */
         //  buffer  data         
         if (regbuf->rdata_len == 0)//    
             needs_data = false;
         else if ((regbuf->flags & REGBUF_KEEP_DATA) != 0)//    data
             needs_data = true;
         else
             needs_data = !needs_backup;//needs_backup  
         //BlockHeader   
         bkpb.id = block_id;// ID
         bkpb.fork_flags = regbuf->forkno;//forkno
         bkpb.data_length = 0;//    

         if ((regbuf->flags & REGBUF_WILL_INIT) == REGBUF_WILL_INIT)
             bkpb.fork_flags |= BKPBLOCK_WILL_INIT;//    

         /*
          * If needs_backup is true or WAL checking is enabled for current
          * resource manager, log a full-page write for the current block.
          *  needs_backup T,    RM WAL     ,
          *      block  full-page-write
          */
         //  backup             
         include_image = needs_backup || (info & XLR_CHECK_CONSISTENCY) != 0;

         if (include_image)
         {
             //     
             Page        page = regbuf->page;//     page
             uint16      compressed_len = 0;//      

             /*
              * The page needs to be backed up, so calculate its hole length
              * and offset.
              * page    ,           
              */
             if (regbuf->flags & REGBUF_STANDARD)
             {
                 //     REGBUF
                 /* Assume we can omit data between pd_lower and pd_upper */
                 //        pd_lower pd_upper     
                 uint16      lower = ((PageHeader) page)->pd_lower;//  lower
                 uint16      upper = ((PageHeader) page)->pd_upper;//  upper

                 if (lower >= SizeOfPageHeaderData &&
                     upper > lower &&
                     upper <= BLCKSZ)
                 {
                     //lower  Page    && upper  lower && upper     
                     bimg.hole_offset = lower;
                     cbimg.hole_length = upper - lower;
                 }
                 else
                 {
                     /* No "hole" to remove */
                     //          
                     bimg.hole_offset = 0;
                     cbimg.hole_length = 0;
                 }
             }
             else
             {
                 //     REGBUF
                 /* Not a standard page header, don't try to eliminate "hole" */
                 //     page header,      "hole"
                 bimg.hole_offset = 0;
                 cbimg.hole_length = 0;
             }

             /*
              * Try to compress a block image if wal_compression is enabled
              *   wal_compression  ,     
              */
             if (wal_compression)
             {
                 is_compressed =
                     XLogCompressBackupBlock(page, bimg.hole_offset,
                                             cbimg.hole_length,
                                             regbuf->compressed_page,
                                             &compressed_len);//  XLogCompressBackupBlock  
             }

             /*
              * Fill in the remaining fields in the XLogRecordBlockHeader
              * struct
              *   XLogRecordBlockHeader         
              */
             bkpb.fork_flags |= BKPBLOCK_HAS_IMAGE;

             /*
              * Construct XLogRecData entries for the page content.
              *  page    XLogRecData  
              */
             rdt_datas_last->next = &regbuf->bkp_rdatas[0];
             rdt_datas_last = rdt_datas_last->next;
             //    
             bimg.bimg_info = (cbimg.hole_length == 0) ? 0 : BKPIMAGE_HAS_HOLE;

             /*
              * If WAL consistency checking is enabled for the resource manager
              * of this WAL record, a full-page image is included in the record
              * for the block modified. During redo, the full-page is replayed
              * only if BKPIMAGE_APPLY is set.
              *  WAL        ,    block  XLOG Record    FPI.
              *  redo  ,    BKPIMAGE_APPLY      full-page    .
              */
             if (needs_backup)
                 bimg.bimg_info |= BKPIMAGE_APPLY;//    

             if (is_compressed)//    ?
             {
                 bimg.length = compressed_len;//      
                 bimg.bimg_info |= BKPIMAGE_IS_COMPRESSED;//    

                 rdt_datas_last->data = regbuf->compressed_page;//  registered_buffer 
                 rdt_datas_last->len = compressed_len;//  
             }
             else
             {
                 //    
                 //image   
                 bimg.length = BLCKSZ - cbimg.hole_length;

                 if (cbimg.hole_length == 0)
                 {
                     rdt_datas_last->data = page;//        page
                     rdt_datas_last->len = BLCKSZ;//   block size
                 }
                 else
                 {
                     /* must skip the hole */
                     //  hole
                     rdt_datas_last->data = page;//    
                     rdt_datas_last->len = bimg.hole_offset;//  hole   

                     rdt_datas_last->next = &regbuf->bkp_rdatas[1];// 2  
                     rdt_datas_last = rdt_datas_last->next;//

                     rdt_datas_last->data =
                         page + (bimg.hole_offset + cbimg.hole_length);//        
                     rdt_datas_last->len =
                         BLCKSZ - (bimg.hole_offset + cbimg.hole_length);//    
                 }
             }

             total_len += bimg.length;//     
         }

         if (needs_data)//      
         {
             /*
              * Link the caller-supplied rdata chain for this buffer to the
              * overall list.
              *               rdata           
              */
             bkpb.fork_flags |= BKPBLOCK_HAS_DATA;//    
             bkpb.data_length = regbuf->rdata_len;//  
             total_len += regbuf->rdata_len;//   

             rdt_datas_last->next = regbuf->rdata_head;//    
             rdt_datas_last = regbuf->rdata_tail;
         }

         //     regbuf       RefFileNode(    /     /block  )
         if (prev_regbuf && RelFileNodeEquals(regbuf->rnode, prev_regbuf->rnode))
         {
             samerel = true;//    
             bkpb.fork_flags |= BKPBLOCK_SAME_REL;//   REL
         }
         else
             samerel = false;
         prev_regbuf = regbuf;//      regbuf

         /* Ok, copy the header to the scratch buffer */
         // OK,       scratch    
         memcpy(scratch, &bkpb, SizeOfXLogRecordBlockHeader);
         scratch += SizeOfXLogRecordBlockHeader;//    
         if (include_image)
         {
             //  FPI,  SizeOfXLogRecordBlockImageHeader
             memcpy(scratch, &bimg, SizeOfXLogRecordBlockImageHeader);
             scratch += SizeOfXLogRecordBlockImageHeader;//    
             if (cbimg.hole_length != 0 && is_compressed)
             {
                 //    ,  SizeOfXLogRecordBlockCompressHeader
                 memcpy(scratch, &cbimg,
                        SizeOfXLogRecordBlockCompressHeader);
                 scratch += SizeOfXLogRecordBlockCompressHeader;//    
             }
         }
         if (!samerel)
         {
             //     REL,  RelFileNode
             memcpy(scratch, &regbuf->rnode, sizeof(RelFileNode));
             scratch += sizeof(RelFileNode);//    
         }
         //  BlockNumber
         memcpy(scratch, &regbuf->block, sizeof(BlockNumber));
         scratch += sizeof(BlockNumber);//    
     }

     /* followed by the record's origin, if any */
     //   , XLOG Record origin
     if ((curinsert_flags & XLOG_INCLUDE_ORIGIN) &&
         replorigin_session_origin != InvalidRepOriginId)
     {
         //
         *(scratch++) = (char) XLR_BLOCK_ID_ORIGIN;
         memcpy(scratch, &replorigin_session_origin, sizeof(replorigin_session_origin));
         scratch += sizeof(replorigin_session_origin);
     }

     /* followed by main data, if any */
     //    main data
     if (mainrdata_len > 0)//main data   > 0
     {
         if (mainrdata_len > 255)//  255,   Long  
         {
             *(scratch++) = (char) XLR_BLOCK_ID_DATA_LONG;
             memcpy(scratch, &mainrdata_len, sizeof(uint32));
             scratch += sizeof(uint32);
         }
         else//    Short  
         {
             *(scratch++) = (char) XLR_BLOCK_ID_DATA_SHORT;
             *(scratch++) = (uint8) mainrdata_len;
         }
         rdt_datas_last->next = mainrdata_head;
         rdt_datas_last = mainrdata_last;
         total_len += mainrdata_len;
     }
     rdt_datas_last->next = NULL;

     hdr_rdt.len = (scratch - hdr_scratch);//    
     total_len += hdr_rdt.len;//   

     /*
      * Calculate CRC of the data
      *      CRC
      *
      * Note that the record header isn't added into the CRC initially since we
      * don't know the prev-link yet.  Thus, the CRC will represent the CRC of
      * the whole record in the order: rdata, then backup blocks, then record
      * header.
      *         prev-link   ,         CRC .
      *   ,CRC              CRC: rdata,   backup blocks,   record header。
      */
     INIT_CRC32C(rdata_crc);
     COMP_CRC32C(rdata_crc, hdr_scratch + SizeOfXLogRecord, hdr_rdt.len - SizeOfXLogRecord);
     for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
         COMP_CRC32C(rdata_crc, rdt->data, rdt->len);

     /*
      * Fill in the fields in the record header. Prev-link is filled in later,
      * once we know where in the WAL the record will be inserted. The CRC does
      * not include the record header yet.
      *               .
      * Prev-link                .
      * CRC           .
      */
     rechdr->xl_xid = GetCurrentTransactionIdIfAny();
     rechdr->xl_tot_len = total_len;
     rechdr->xl_info = info;
     rechdr->xl_rmid = rmid;
     rechdr->xl_prev = InvalidXLogRecPtr;
     rechdr->xl_crc = rdata_crc;

     return &hdr_rdt;
}


3. 추적 분석
장면 1: 데 이 터 를 제거 한 후 checkpoint 를 실행 한 후 첫 번 째 테스트 스 크 립 트 를 다음 과 같이 삽입 합 니 다.
testdb=# truncate table t_wal_partition;
TRUNCATE TABLE
testdb=# checkpoint;
CHECKPOINT
testdb=# insert into t_wal_partition(c1,c2,c3) VALUES(1,'checkpoint','checkpoint');


정지점 설정, XLogRecordAssemble 진입
(gdb) b XLogRecordAssemble
Breakpoint 1 at 0x565411: file xloginsert.c, line 488.
(gdb) c
Continuing.

Breakpoint 1, XLogRecordAssemble (rmid=10 '
', info=128 '\200', RedoRecPtr=5507633240, doPageWrites=true, fpw_lsn=0x7fff05cfe378) at xloginsert.c:488 488 uint32 total_len = 0;

입력 매개 변수: rmid = 10 즉 0x0A -- > Heap RedoRecPtr = 5507633240 doPageWrites = true, full - page - write fpw 필요lsn = 0x7fff05cfe 378 다음은 변수 할당 입 니 다. 그 중에서 hdrscratch 의 정의: static char * hdrscratch = NULL; hdr_rdt 의 정의: static XLogRecData hdrrdt;
(gdb) n
491     registered_buffer *prev_regbuf = NULL;
(gdb) 
494     char       *scratch = hdr_scratch;
(gdb) 
502     rechdr = (XLogRecord *) scratch;
(gdb) 
503     scratch += SizeOfXLogRecord;
(gdb) 

XLOG Record 의 머리 정보
(gdb) p *(XLogRecord *)rechdr
$11 = {xl_tot_len = 114, xl_xid = 1997, xl_prev = 5507669824, xl_info = 128 '\200', xl_rmid = 1 '\001', xl_crc = 3794462175}

scratch 포인터 가 Header 다음 주 소 를 가리 키 고 있 습 니 다.
(gdb) p hdr_scratch
$12 = 0x18a24c0 "r"

전역 변수 hdrrdt 할당
505     hdr_rdt.next = NULL;
(gdb) 
506     rdt_datas_last = &hdr_rdt;
(gdb) 
507     hdr_rdt.data = hdr_scratch;
(gdb) p hdr_rdt
$5 = {next = 0x0, data = 0x18a24c0 "r", len = 26}
(gdb) p *(XLogRecord *)hdr_rdt.data
$7 = {xl_tot_len = 114, xl_xid = 1997, xl_prev = 5507669824, xl_info = 128 '\200', xl_rmid = 1 '\001', xl_crc = 3794462175}

일치 성 검 사 를 실행 하지 않 음
(gdb) n
515     if (wal_consistency_checking[rmid])
(gdb) 
523     *fpw_lsn = InvalidXLogRecPtr;
(gdb) 

fpw 초기 화lsn, 순환 을 시작 합 니 다. 등 록 된 block id 는 1 개 입 니 다.
(gdb) n
524     for (block_id = 0; block_id < max_registered_block_id; block_id++)
(gdb) p max_registered_block_id
$13 = 1

등 록 된 buffer 를 가 져 옵 니 다. 그 중: rnode - > RelFilenode 구조 체, spcNode - > 표 공간 / dbNode - > 데이터베이스 / relNode - > 관계 Block - > 블록 ID page - > 데이터 페이지 포인터 (char *) rdatalen - > rdata 체인 의 데이터 총 크기 rdatahead - > 이 데이터 블록 으로 등 록 된 데이터 체인 헤드 rdatatail - > 이 데이터 블록 으로 등 록 된 데이터 체인 꼬리 bkprdatas - > 임시 rdatas 데이터 인용, XLogRecordAssemble () 에서 사용 하 는 백업 블록 데 이 터 를 저장 하 는 데 사 용 됩 니 다. bkprdatas 는 block image, bkp 를 조립 하 는 데 사 용 됩 니 다.rdatas [0] 남 은 공간 (hole) 전 데이터 저장, bkprdatas [1] 남 은 공간 후의 데 이 터 를 저장 합 니 다.
(gdb) n
526         registered_buffer *regbuf = &registered_buffers[block_id];
(gdb) 
531         XLogRecordBlockCompressHeader cbimg = {0};
(gdb) p *regbuf
$14 = {in_use = true, flags = 14 '\016', rnode = {spcNode = 1663, dbNode = 16402, relNode = 25258}, forkno = MAIN_FORKNUM, 
  block = 0, page = 0x7fb8539e7380 "", rdata_len = 32, rdata_head = 0x18a22c0, rdata_tail = 0x18a22d8, bkp_rdatas = {{
      next = 0x18a4230, data = 0x7fb85390f380 "\001", len = 252}, {next = 0x18a22a8, data = 0x7fb85390fe28 "\315\a", 
      len = 5464}}, compressed_page = '\000' }

메모: 메모리 에 main data 는 함수 XLogRegisterData 에 등록 되 어 있 으 며, mainradahead 와 mainradalast 포인터 유지 보수, 이 예 에서 xl 를 채 웠 습 니 다.heap_insert 구조 체. block data 는 XLogRegisterBuffer 에서 초기 화 되 었 고 XLogRegisterBufData 로 데 이 터 를 채 웠 습 니 다. 이 예 에서 XLogRegisterBufData 를 통 해 두 번 의 데 이 터 를 등 록 했 습 니 다. 첫 번 째 는 xl 입 니 다.heap_header 구조 체, 두 번 째 는 실제 데이터 (실질 적 으로 데이터 포인터 일 뿐 최종 적 으로 어떤 데이터 가 필요 한 지 조립 기 에서 확인) 입 니 다.
(gdb) p *mainrdata_head
$18 = {next = 0x18a22c0, data = 0x7fff05cfe3f0 "\001", len = 3}
(gdb) p *(xl_heap_insert *)mainrdata_head->data
$20 = {offnum = 1, flags = 0 '\000'}
(gdb) p *regbuf->rdata_head
$32 = {next = 0x18a22d8, data = 0x7fff05cfe3e0 "\003", len = 5}
(gdb) p *(xl_heap_header *)regbuf->rdata_head->data
$28 = {t_infomask2 = 3, t_infomask = 2050, t_hoff = 24 '\030'}
(gdb) p *regbuf->rdata_head->next
$34 = {next = 0x18a22f0, data = 0x18edaef "", len = 27}

주소 0x18edaef 이후 27 개의 바이트 (tuple data) 를 문자 형식 으로 표시 합 니 다.
(gdb) x/27bc 0x18edaef
0x18edaef:  0 '\000'    1 '\001'    0 '\000'    0 '\000'    0 '\000'    23 '\027'   99 'c'  104 'h'
0x18edaf7:  101 'e' 99 'c'  107 'k' 112 'p' 111 'o' 105 'i' 110 'n' 116 't'
0x18edaff:  23 '\027'   99 'c'  104 'h' 101 'e' 99 'c'  107 'k' 112 'p' 111 'o'
0x18edb07:  105 'i' 110 'n' 116 't'

이 기록 은 첫 번 째 기록 이기 때문에 full - page - image 를 실행 할 필요 가 없습니다.
(gdb) n
533         bool        is_compressed = false;
(gdb) 
536         if (!regbuf->in_use)
(gdb) 
540         if (regbuf->flags & REGBUF_FORCE_IMAGE)
(gdb) p regbuf->flags
$36 = 14 '\016'
(gdb) n
542         else if (regbuf->flags & REGBUF_NO_IMAGE)
(gdb) 
543             needs_backup = false;

needs_data 는 T 이 며, 트 랜 잭 션 로그 에 tuple data 만 기록 합 니 다.
(gdb) n
564         if (regbuf->rdata_len == 0)
(gdb) p regbuf->rdata_len
$37 = 32
(gdb) n
566         else if ((regbuf->flags & REGBUF_KEEP_DATA) != 0)
(gdb) 
569             needs_data = !needs_backup;
(gdb) 
571         bkpb.id = block_id;
(gdb) p needs_data
$38 = true

XLogRecordBlockHeader 필드 값 을 설정 합 니 다. page 의 첫 번 째 tuple 은 BKPBLOCK 로 표 시 됩 니 다.WILL_INIT
(gdb) n
572         bkpb.fork_flags = regbuf->forkno;
(gdb) 
573         bkpb.data_length = 0;
(gdb) 
575         if ((regbuf->flags & REGBUF_WILL_INIT) == REGBUF_WILL_INIT)
(gdb) n
576             bkpb.fork_flags |= BKPBLOCK_WILL_INIT;
(gdb) 
582         include_image = needs_backup || (info & XLR_CHECK_CONSISTENCY) != 0;
(gdb) p bkpb
$40 = {id = 0 '\000', fork_flags = 64 '@', data_length = 0}
(gdb) 

FPI 를 실행 할 필요 가 없습니다.
(gdb) p info
$41 = 128 '\200'
(gdb) n
584         if (include_image)
(gdb) p include_image
$42 = false
(gdb) 

데이터 포함 필요
(gdb) n
691         if (needs_data)
(gdb) 
697             bkpb.fork_flags |= BKPBLOCK_HAS_DATA;
(gdb) 
698             bkpb.data_length = regbuf->rdata_len;
(gdb) 
699             total_len += regbuf->rdata_len;
(gdb) 
701             rdt_datas_last->next = regbuf->rdata_head;
(gdb) 
702             rdt_datas_last = regbuf->rdata_tail;
(gdb) p bkpb
$43 = {id = 0 '\000', fork_flags = 96 '`', data_length = 32}
(gdb) p total_len
$44 = 32
(gdb) p *rdt_datas_last
$45 = {next = 0x18a22c0, data = 0x18a24c0 "r", len = 26}

OK, 머리 정 보 를 scratch 버퍼 에 복사
(gdb) n
705         if (prev_regbuf && RelFileNodeEquals(regbuf->rnode, prev_regbuf->rnode))
(gdb) p prev_regbuf
$46 = (registered_buffer *) 0x0
(gdb) n
711             samerel = false;
(gdb) 
712         prev_regbuf = regbuf;
(gdb) 
715         memcpy(scratch, &bkpb, SizeOfXLogRecordBlockHeader);

뒤에 RefFileNode + BlockNumber.
(gdb) 
716         scratch += SizeOfXLogRecordBlockHeader;
(gdb) 
717         if (include_image)
(gdb) 
728         if (!samerel)
(gdb) 
730             memcpy(scratch, &regbuf->rnode, sizeof(RelFileNode));
(gdb) 
731             scratch += sizeof(RelFileNode);
(gdb) 
733         memcpy(scratch, &regbuf->block, sizeof(BlockNumber));
(gdb) 
734         scratch += sizeof(BlockNumber);
(gdb) 
524     for (block_id = 0; block_id < max_registered_block_id; block_id++)

순환 을 끝내다
524     for (block_id = 0; block_id < max_registered_block_id; block_id++)
(gdb) 

다음은 replorginsession_origin (실제 필요 하지 않 음)
738     if ((curinsert_flags & XLOG_INCLUDE_ORIGIN) &&
(gdb) p curinsert_flags
$47 = 1 '\001'
(gdb) 
$48 = 1 '\001'
(gdb) n
739         replorigin_session_origin != InvalidRepOriginId)
(gdb) 
738     if ((curinsert_flags & XLOG_INCLUDE_ORIGIN) &&

다음은 main data.
(gdb) 
747     if (mainrdata_len > 0)
(gdb) 
749         if (mainrdata_len > 255)
(gdb) 
757             *(scratch++) = (char) XLR_BLOCK_ID_DATA_SHORT;
(gdb) 
(gdb) 
758             *(scratch++) = (uint8) mainrdata_len;
(gdb) 
760         rdt_datas_last->next = mainrdata_head;
(gdb) 
761         rdt_datas_last = mainrdata_last;
(gdb) 
762         total_len += mainrdata_len;
(gdb) 

크기 를 계산 하 다
764     rdt_datas_last->next = NULL;
(gdb) 
766     hdr_rdt.len = (scratch - hdr_scratch);
(gdb) p scratch
$49 = 0x18a24ee ""
(gdb) p hdr_scratch
$50 = 0x18a24c0 "r"
(gdb) p hdr_rdt.len
$51 = 26
(gdb) p total_len
$52 = 35
(gdb) 
(gdb) n
767     total_len += hdr_rdt.len;
(gdb) 

계산 CRC
(gdb) 
777     INIT_CRC32C(rdata_crc);
(gdb) 
778     COMP_CRC32C(rdata_crc, hdr_scratch + SizeOfXLogRecord, hdr_rdt.len - SizeOfXLogRecord);
(gdb) 
779     for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
(gdb) n
780         COMP_CRC32C(rdata_crc, rdt->data, rdt->len);
(gdb) 
779     for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
(gdb) 
780         COMP_CRC32C(rdata_crc, rdt->data, rdt->len);
(gdb) 
779     for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
(gdb) 
780         COMP_CRC32C(rdata_crc, rdt->data, rdt->len);
(gdb) 
779     for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
(gdb) 
787     rechdr->xl_xid = GetCurrentTransactionIdIfAny();

머리 정 보 를 기록 하 는 다른 필드 를 채 웁 니 다.
(gdb) n
788     rechdr->xl_tot_len = total_len;
(gdb) 
789     rechdr->xl_info = info;
(gdb) 
790     rechdr->xl_rmid = rmid;
(gdb) 
791     rechdr->xl_prev = InvalidXLogRecPtr;
(gdb) 
792     rechdr->xl_crc = rdata_crc;
(gdb) 
794     return &hdr_rdt;
(gdb) 
795 }
(gdb) p rechdr
$62 = (XLogRecord *) 0x18a24c0
(gdb) p *rechdr
$63 = {xl_tot_len = 81, xl_xid = 1998, xl_prev = 0, xl_info = 128 '\200', xl_rmid = 10 '
', xl_crc = 1852971194} (gdb)

full - page - write 장면 후속 재 분석
참고 자료
Write Ahead Logging - WAL PostgreSQL 소스 코드 판독 (4) - 데이터 삽입 \ # 3 (heap insert) PostgreSQL 트 랜 잭 션 로그 WAL 구조 분석 PG 소스 코드
"ITPUB 블 로그" 에서 왔 습 니 다. 링크:http://blog.itpub.net/6906/viewspace-2374772/전재 가 필요 하 다 면 출처 를 밝 혀 주 십시오. 그렇지 않 으 면 법 적 책임 을 추궁 할 것 입 니 다.
다음으로 전송:http://blog.itpub.net/6906/viewspace-2374772/

좋은 웹페이지 즐겨찾기