iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >PostgreSQL中heap_insert函数有什么作用
  • 170
分享到

PostgreSQL中heap_insert函数有什么作用

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

这篇文章主要讲解了“postgresql中heap_insert函数有什么作用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Postgresql中heap_

这篇文章主要讲解了“postgresql中heap_insert函数有什么作用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Postgresql中heap_insert函数有什么作用”吧!

一、数据结构

宏定义
包括Pointer/Page/XLOG_HEAP_INSERT/XLogRecPtr等

typedef char* Pointer;//指针
typedef Pointer Page;//Page

#define XLOG_HEAP_INSERT   0x00


typedef uint64 XLogRecPtr;


#define PageGetLSN(page) \
    PageXLogRecPtrGet(((PageHeader) (page))->pd_lsn)
#define PageSetLSN(page, lsn) \
    PageXLogRecPtrSet(((PageHeader) (page))->pd_lsn, lsn)

xl_heap_insert
插入时需要获知的信息结构



#define XLH_INSERT_ALL_VISIBLE_CLEARED          (1<<0)
#define XLH_INSERT_LAST_IN_MULTI                (1<<1)
#define XLH_INSERT_IS_SPECULATIVE               (1<<2)
#define XLH_INSERT_CONTaiNS_NEW_TUPLE           (1<<3)


//这是在插入时需要获知的信息
typedef struct xl_heap_insert
{
    //元组在page中的偏移
    OffsetNumber offnum;        
    uint8       flags;          //标记位

    
    //xl_heap_header & TUPLE DATA在备份块0中
} xl_heap_insert;
//xl_heap_insert大小
#define SizeOfHeapinsert    (offsetof(xl_heap_insert, flags) + sizeof(uint8))

xl_heap_header
PG不会在WAL中存储插入/更新的元组的全部固定部分(HeapTupleHeaderData)
xl_heap_header是必须存储的结构.


typedef struct xl_heap_header
{
    uint16      t_infomask2;//t_infomask2标记
    uint16      t_infomask;//t_infomask标记
    uint8       t_hoff;//t_hoff
} xl_heap_header;
//HeapHeader的大小
#define SizeOfHeapHeader    (offsetof(xl_heap_header, t_hoff) + sizeof(uint8))

二、源码解读

heap_insert的主要逻辑是插入元组到堆中,其中存在对WAL(XLog)进行处理的部分.



Oid
heap_insert(Relation relation, HeapTuple tup, CommandId cid,
            int options, BulkInsertState bistate)
{
    TransactionId xid = GetCurrentTransactionId();//事务id
    HeapTuple   heaptup;//Heap Tuple数据,亦即数据行
    Buffer      buffer;//数据缓存块
    Buffer      vmbuffer = InvalidBuffer;//vm缓冲块
    bool        all_visible_cleared = false;//标记

    
    //插入前准备工作,比如设置t_infomask标记等
    heaptup = heap_prepare_insert(relation, tup, xid, cid, options);

    
    //获取相应的buffer,详见上面的子函数解析
    buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
                                       InvalidBuffer, options, bistate,
                                       &vmbuffer, NULL);

    
    //检查序列化是否冲突
    CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);

    
    //开始,变量+1
    START_CRIT_SECTION();
    //插入数据(详见上一节对该函数的解析)
    RelationPutHeapTuple(relation, buffer, heaptup,
                         (options & HEAP_INSERT_SPECULATIVE) != 0);
    //如Page is All Visible
    if (PageIsAllVisible(BufferGetPage(buffer)))
    {
        //复位
        all_visible_cleared = true;
        PageClearAllVisible(BufferGetPage(buffer));
        visibilitymap_clear(relation,
                            ItemPointerGetBlockNumber(&(heaptup->t_self)),
                            vmbuffer, VISIBILITYMAP_VALID_BITS);
    }

    
    //设置缓冲块为脏块
    MarkBufferDirty(buffer);

    
    //记录日志
    if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
    {
        xl_heap_insert xlrec;
        xl_heap_header xlhdr;
        XLogRecPtr  recptr;//uint64
        Page        page = BufferGetPage(buffer);//获取相应的Page
        uint8       info = XLOG_HEAP_INSERT;//XLOG_HEAP_INSERT -> 0x00
        int         bufflags = 0;

        
        if (RelationIsAccessibleInLogicalDecoding(relation))
            log_heap_new_cid(relation, heaptup);

        
        if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
            PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
        {
            info |= XLOG_HEAP_INIT_PAGE;
            bufflags |= REGBUF_WILL_INIT;
        }
        //Item在页面中的偏移
        xlrec.offnum = ItemPointerGetOffsetNumber(&heaptup->t_self);
        xlrec.flags = 0;//标记
        if (all_visible_cleared)
            xlrec.flags |= XLH_INSERT_ALL_VISIBLE_CLEARED;
        if (options & HEAP_INSERT_SPECULATIVE)
            xlrec.flags |= XLH_INSERT_IS_SPECULATIVE;
        Assert(ItemPointerGetBlockNumber(&heaptup->t_self) == BufferGetBlockNumber(buffer));


        
        if (RelationIsLogicallyLogged(relation))
        {
            xlrec.flags |= XLH_INSERT_CONTAINS_NEW_TUPLE;
            bufflags |= REGBUF_KEEP_DATA;
        }

        XLogBeginInsert();//开始WAL插入
        XLogReGISterData((char *) &xlrec, SizeOfHeapInsert);//注册数据
        //设置标记
        xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
        xlhdr.t_infomask = heaptup->t_data->t_infomask;
        xlhdr.t_hoff = heaptup->t_data->t_hoff;

        
        XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);//标记
        XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);//tuple头部
        
        XLogRegisterBufData(0,
                            (char *) heaptup->t_data + SizeofHeapTupleHeader,
                            heaptup->t_len - SizeofHeapTupleHeader);//tuple实际数据

        
        //根据行级别上的原点进行过滤要有效得多
        XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
        //插入数据
        recptr = XLogInsert(RM_HEAP_ID, info);
        //设置LSN
        PageSetLSN(page, recptr);
    }
    //完成!
    END_CRIT_SECTION();
    //解Buffer,包括vm buffer
    UnlockReleaseBuffer(buffer);
    if (vmbuffer != InvalidBuffer)
        ReleaseBuffer(vmbuffer);

    
    //缓存操作后变“无效”的Tuple
    CacheInvalidateHeapTuple(relation, heaptup, NULL);

    
    //注意:speculative insertions也会统计(即使终止此事务)
    //更新统计信息
    pgstat_count_heap_insert(relation, 1);

    
    if (heaptup != tup)
    {
        tup->t_self = heaptup->t_self;
        heap_freetuple(heaptup);
    }

    return HeapTupleGetOid(tup);
}

三、跟踪分析

测试脚本如下

-- Hash Partition
drop table if exists t_wal_partition;
create table t_wal_partition (c1 int not null,c2  varchar(40),c3 varchar(40)) partition by hash(c1);
create table t_wal_partition_1 partition of t_wal_partition for values with (modulus 6,remainder 0);
create table t_wal_partition_2 partition of t_wal_partition for values with (modulus 6,remainder 1);
create table t_wal_partition_3 partition of t_wal_partition for values with (modulus 6,remainder 2);
create table t_wal_partition_4 partition of t_wal_partition for values with (modulus 6,remainder 3);
create table t_wal_partition_5 partition of t_wal_partition for values with (modulus 6,remainder 4);
create table t_wal_partition_6 partition of t_wal_partition for values with (modulus 6,remainder 5);

-- 插入路由
-- delete from t_wal_partition where c1 = 0;
insert into t_wal_partition(c1,c2,c3) VALUES(0,'HASH0','HAHS0');

启动gdb,设置断点,进入heap_insert

(gdb) b heap_insert
Breakpoint 1 at 0x4df4d1: file heapam.c, line 2449.
(gdb) c
Continuing.

Breakpoint 1, heap_insert (relation=0x7f9c470a8bd8, tup=0x2908850, cid=0, options=0, bistate=0x0) at heapam.c:2449
2449        TransactionId xid = GetCurrentTransactionId();

构造Heap Tuple数据/获取相应的Buffer(102号)

2449        TransactionId xid = GetCurrentTransactionId();
(gdb) n
2452        Buffer      vmbuffer = InvalidBuffer;
(gdb) 
2453        bool        all_visible_cleared = false;
(gdb) 
2462        heaptup = heap_prepare_insert(relation, tup, xid, cid, options);
(gdb) 
2468        buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
(gdb) 
2487        CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
(gdb) p *heaptup
$1 = {t_len = 172, t_self = {ip_blkid = {bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, t_tableOid = 1247, 
  t_data = 0x2908868}
(gdb) p buffer
$2 = 102

插入到Buffer中,标记Buffer为Dirty

(gdb) n
2490        START_CRIT_SECTION();
(gdb) 
2493                             (options & HEAP_INSERT_SPECULATIVE) != 0);
(gdb) 
2492        RelationPutHeapTuple(relation, buffer, heaptup,
(gdb) 
2495        if (PageIsAllVisible(BufferGetPage(buffer)))
(gdb) 
2515        MarkBufferDirty(buffer);
(gdb) 
2518        if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
(gdb)

进入WAL处理部分,获取page(位于1号Page)等信息

(gdb) n
2523            Page        page = BufferGetPage(buffer);
(gdb) 
2524            uint8       info = XLOG_HEAP_INSERT;
(gdb) 
2525            int         bufflags = 0;
(gdb) 
2531            if (RelationIsAccessibleInLogicalDecoding(relation))
(gdb) p page
$3 = (Page) 0x7f9c1a505380 "\001"
(gdb) p *page
$4 = 1 '\001'
(gdb) p info
$5 = 0 '\000'

设置xl_heap_insert结构体
其中偏移=34,标记位为0x0

(gdb) n
2539            if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
(gdb) 
2546            xlrec.offnum = ItemPointerGetOffsetNumber(&heaptup->t_self);
(gdb) 
2547            xlrec.flags = 0;
(gdb) 
2548            if (all_visible_cleared)
(gdb) 
2550            if (options & HEAP_INSERT_SPECULATIVE)
(gdb) 
2552            Assert(ItemPointerGetBlockNumber(&heaptup->t_self) == BufferGetBlockNumber(buffer));
(gdb) 
2559            if (RelationIsLogicallyLogged(relation) &&
(gdb) 
(gdb) p xlrec
$6 = {offnum = 34, flags = 0 '\000'}

开始插入WAL,并注册相关数据

(gdb) 
2566            XLogBeginInsert();
(gdb) n
2567            XLogRegisterData((char *) &xlrec, SizeOfHeapInsert);
(gdb) 
2569            xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
(gdb) n
2570            xlhdr.t_infomask = heaptup->t_data->t_infomask;
(gdb) n
2571            xlhdr.t_hoff = heaptup->t_data->t_hoff;
(gdb) 
2578            XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
(gdb) 
2579            XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
(gdb) 
2583                                heaptup->t_len - SizeofHeapTupleHeader);
(gdb) 
2581            XLogRegisterBufData(0,
(gdb) 
2582                                (char *) heaptup->t_data + SizeofHeapTupleHeader,
(gdb) 
2581            XLogRegisterBufData(0,
(gdb) 
2586            XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
(gdb) 
2588            recptr = XLogInsert(RM_HEAP_ID, info);
(gdb) 
(gdb) p xlhdr
$8 = {t_infomask2 = 30, t_infomask = 2057, t_hoff = 32 ' '}

调用XLogInsert,插入WAL,并设置LSN

(gdb) n
2590            PageSetLSN(page, recptr);
(gdb) p recptr
$9 = 5411089336
(gdb) p info
$10 = 0 '\000'
(gdb)

执行其他后续操作,完成函数调用

(gdb) n
2593        END_CRIT_SECTION();
(gdb) 
2595        UnlockReleaseBuffer(buffer);
(gdb) 
2596        if (vmbuffer != InvalidBuffer)
(gdb) 
2605        CacheInvalidateHeapTuple(relation, heaptup, NULL);
(gdb) 
2608        pgstat_count_heap_insert(relation, 1);
(gdb) 
2614        if (heaptup != tup)
(gdb) 
2620        return HeapTupleGetOid(tup);
(gdb) 
2621    }
(gdb)

感谢各位的阅读,以上就是“PostgreSQL中heap_insert函数有什么作用”的内容了,经过本文的学习后,相信大家对PostgreSQL中heap_insert函数有什么作用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL中heap_insert函数有什么作用

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

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

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

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

下载Word文档
猜你喜欢
  • PostgreSQL中heap_insert函数有什么作用
    这篇文章主要讲解了“PostgreSQL中heap_insert函数有什么作用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL中heap_...
    99+
    2024-04-02
  • PostgreSQL中heap_insert依赖的函数有哪些
    本篇内容主要讲解“PostgreSQL中heap_insert依赖的函数有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中heap_in...
    99+
    2024-04-02
  • PostgreSQL中heap_insert->XLogInsert函数分析
    本篇内容介绍了“PostgreSQL中heap_insert->XLogInsert函数分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情...
    99+
    2024-04-02
  • PostgreSQL中hash_search_with_hash_value函数有什么作用
    本篇内容主要讲解“PostgreSQL中hash_search_with_hash_value函数有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Pos...
    99+
    2024-04-02
  • PostgreSQL中set_base_rel_pathlists函数有什么作用
    这篇文章主要介绍“PostgreSQL中set_base_rel_pathlists函数有什么作用”,在日常操作中,相信很多人在PostgreSQL中set_base_rel_pathlists函数有什么作...
    99+
    2024-04-02
  • PostgreSQL中grouping_planner函数有什么作用
    这篇文章主要介绍“PostgreSQL中grouping_planner函数有什么作用”,在日常操作中,相信很多人在PostgreSQL中grouping_planner函数有什么作用问题上存在疑惑,小编查...
    99+
    2024-04-02
  • PostgreSQL中BufferAlloc函数有什么作用
    这篇文章主要介绍“PostgreSQL中BufferAlloc函数有什么作用”,在日常操作中,相信很多人在PostgreSQL中BufferAlloc函数有什么作用问题上存在疑惑,小编查阅了各式资料,整理出...
    99+
    2024-04-02
  • PostgreSQL中fsm_search函数有什么作用
    本篇内容介绍了“PostgreSQL中fsm_search函数有什么作用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能...
    99+
    2024-04-02
  • PostgreSQL中StrategyGetBuffer函数有什么作用
    本篇内容介绍了“PostgreSQL中StrategyGetBuffer函数有什么作用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大...
    99+
    2024-04-02
  • PostgreSQL中create_index_path函数有什么作用
    本篇内容主要讲解“PostgreSQL中create_index_path函数有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中cr...
    99+
    2024-04-02
  • PostgreSQL中mdread函数有什么作用
    本篇内容主要讲解“PostgreSQL中mdread函数有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中mdread函数有什么作用...
    99+
    2024-04-02
  • PostgreSQL中RelationGetBufferForTuple函数有什么作用
    这篇文章主要讲解了“PostgreSQL中RelationGetBufferForTuple函数有什么作用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Po...
    99+
    2024-04-02
  • PostgreSQL中BufTableInsert函数有什么作用
    本篇内容介绍了“PostgreSQL中BufTableInsert函数有什么作用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细...
    99+
    2024-04-02
  • PostgreSQL中ReadBuffer_common函数有什么作用
    这篇文章主要介绍“PostgreSQL中ReadBuffer_common函数有什么作用”,在日常操作中,相信很多人在PostgreSQL中ReadBuffer_common函数有什么作用问题上存在疑惑,小...
    99+
    2024-04-02
  • PostgreSQL中fetch_upper_rel和get_cheapest_fractional_path函数有什么作用
    这篇文章主要介绍“PostgreSQL中fetch_upper_rel和get_cheapest_fractional_path函数有什么作用”,在日常操作中,相信很多人在PostgreSQL中fetch_...
    99+
    2024-04-02
  • PostgreSQL的dump函数有什么作用
    本篇内容主要讲解“PostgreSQL的dump函数有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL的dump函数有什么作用”吧!O...
    99+
    2024-04-02
  • PostgreSQL的vacuum过程中lazy_vacuum_heap函数有什么作用
    这篇文章主要介绍“PostgreSQL的vacuum过程中lazy_vacuum_heap函数有什么作用”,在日常操作中,相信很多人在PostgreSQL的vacuum过程中lazy_vacuum_heap...
    99+
    2024-04-02
  • PostgreSQL中函数pg_blocking_pids的作用是什么
    本篇内容介绍了“PostgreSQL中函数pg_blocking_pids的作用是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大...
    99+
    2024-04-02
  • PostgreSQL中​ExecutePlan函数与ExecSeqScan函数的作用是什么
    这篇文章主要介绍“PostgreSQL中ExecutePlan函数与ExecSeqScan函数的作用是什么”,在日常操作中,相信很多人在PostgreSQL中ExecutePlan函数与ExecSeqSca...
    99+
    2024-04-02
  • PostgreSQL中pgbench有什么作用
    本篇内容主要讲解“PostgreSQL中pgbench有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中pgbench有什么作用”吧...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作