本篇内容主要讲解“PostgreSQL中mdread函数有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中mdread函数有什么作用”吧!
PostgreSQL存储管理的mdread函数是magnetic disk存储管理中负责读取的函数.
一、数据结构
smgrsw
f_smgr函数指针结构体定义了独立的存储管理模块和smgr.c之间的API函数.
md是magnetic disk的缩写.
除了md,先前PG还支持Sony WORM optical disk jukebox and persistent main memory这两种存储方式,
但在后面只剩下magnetic disk,其余的已被废弃不再支持.
“magnetic disk”本身的名称也存在误导,实际上md可以支持操作系统提供标准文件系统的任何类型的设备.
typedef struct f_smgr
{
void (*smgr_init) (void);
void (*smgr_shutdown) (void);
void (*smgr_close) (SMgrRelation reln, ForkNumber forknum);
void (*smgr_create) (SMgrRelation reln, ForkNumber forknum,
bool isRedo);
bool (*smgr_exists) (SMgrRelation reln, ForkNumber forknum);
void (*smgr_unlink) (RelFileNodeBackend rnode, ForkNumber forknum,
bool isRedo);
void (*smgr_extend) (SMgrRelation reln, ForkNumber forknum,
BlockNumber blocknum, char *buffer, bool skipFsync);
void (*smgr_prefetch) (SMgrRelation reln, ForkNumber forknum,
BlockNumber blocknum);
void (*smgr_read) (SMgrRelation reln, ForkNumber forknum,
BlockNumber blocknum, char *buffer);
void (*smgr_write) (SMgrRelation reln, ForkNumber forknum,
BlockNumber blocknum, char *buffer, bool skipFsync);
void (*smgr_writeback) (SMgrRelation reln, ForkNumber forknum,
BlockNumber blocknum, BlockNumber nblocks);
BlockNumber (*smgr_nblocks) (SMgrRelation reln, ForkNumber forknum);
void (*smgr_truncate) (SMgrRelation reln, ForkNumber forknum,
BlockNumber nblocks);
void (*smgr_immedsync) (SMgrRelation reln, ForkNumber forknum);
void (*smgr_pre_ckpt) (void);
void (*smgr_sync) (void);
void (*smgr_post_ckpt) (void);
} f_smgr;
static const f_smgr smgrsw[] = {
{
.smgr_init = mdinit,
.smgr_shutdown = NULL,
.smgr_close = mdclose,
.smgr_create = mdcreate,
.smgr_exists = mdexists,
.smgr_unlink = mdunlink,
.smgr_extend = mdextend,
.smgr_prefetch = mdprefetch,
.smgr_read = mdread,
.smgr_write = mdwrite,
.smgr_writeback = mdwriteback,
.smgr_nblocks = mdnblocks,
.smgr_truncate = mdtruncate,
.smgr_immedsync = mdimmedsync,
.smgr_pre_ckpt = mdpreckpt,
.smgr_sync = mdsync,
.smgr_post_ckpt = mdpostckpt
}
};
MdfdVec
magnetic disk存储管理在自己的描述符池中跟踪打开的文件描述符.
之所以这样做是因为便于支持超过os文件大小上限(通常是2GB)的关系.
为了达到这个目的,我们拆分关系为多个比OS文件大小上限要小的”segment”文件.
段大小通过pg_config.h中定义的RELSEG_SIZE配置参数设置.
typedef struct _MdfdVec
{
//文件描述符池中该文件的编号
File mdfd_vfd;
//段号,从0起算
BlockNumber mdfd_segno;
} MdfdVec;
二、源码解读
mdread() — 从relation中读取相应的block.
源码较为简单,主要是调用FileRead函数执行实际的读取操作.
void
mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
char *buffer)
{
off_t seekpos;//seek的位置
int nbytes;//bytes
MdfdVec *v;//md文件描述符向量数组
TRACE_POSTGRESQL_SMGR_MD_READ_START(forknum, blocknum,
reln->smgr_rnode.node.spcNode,
reln->smgr_rnode.node.dbNode,
reln->smgr_rnode.node.relNode,
reln->smgr_rnode.backend);
//获取向量数组
v = _mdfd_getseg(reln, forknum, blocknum, false,
EXTENSION_FAIL | EXTENSION_CREATE_RECOVERY);
//获取block偏移
seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
//验证
Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
//读取文件,读入buffer中,返回读取的字节数
nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ, seekpos, WAIT_EVENT_DATA_FILE_READ);
//跟踪
TRACE_POSTGRESQL_SMGR_MD_READ_DONE(forknum, blocknum,
reln->smgr_rnode.node.spcNode,
reln->smgr_rnode.node.dbNode,
reln->smgr_rnode.node.relNode,
reln->smgr_rnode.backend,
nbytes,
BLCKSZ);
if (nbytes != BLCKSZ)
{
//读取的字节数不等于块大小,报错
if (nbytes < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read block %u in file \"%s\": %m",
blocknum, FilePathName(v->mdfd_vfd))));
if (zero_damaged_pages || InRecovery)
MemSet(buffer, 0, BLCKSZ);
else
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("could not read block %u in file \"%s\": read only %d of %d bytes",
blocknum, FilePathName(v->mdfd_vfd),
nbytes, BLCKSZ)));
}
}
三、跟踪分析
测试脚本
11:15:11 (xdb@[local]:5432)testdb=# insert into t1(id) select generate_series(100,500);
启动gdb,跟踪
查看调用栈
(gdb) b mdread
Breakpoint 3 at 0x8b669b: file md.c, line 738.
(gdb) c
Continuing.
Breakpoint 3, mdread (reln=0x2d09be0, forknum=MAIN_FORKNUM, blocknum=50, buffer=0x7f3823369c00 "") at md.c:738
738 TRACE_POSTGRESQL_SMGR_MD_READ_START(forknum, blocknum,
(gdb) bt
#0 mdread (reln=0x2d09be0, forknum=MAIN_FORKNUM, blocknum=50, buffer=0x7f3823369c00 "") at md.c:738
#1 0x00000000008b92d5 in smgrread (reln=0x2d09be0, forknum=MAIN_FORKNUM, blocknum=50, buffer=0x7f3823369c00 "")
at smgr.c:628
#2 0x00000000008793f9 in ReadBuffer_common (smgr=0x2d09be0, relpersistence=112 'p', forkNum=MAIN_FORKNUM, blockNum=50,
mode=RBM_NORMAL, strategy=0x0, hit=0x7ffd5fb2948b) at bufmgr.c:890
#3 0x0000000000878cd4 in ReadBufferExtended (reln=0x7f3836e1e788, forkNum=MAIN_FORKNUM, blockNum=50, mode=RBM_NORMAL,
strategy=0x0) at bufmgr.c:664
#4 0x0000000000878bb1 in ReadBuffer (reln=0x7f3836e1e788, blockNum=50) at bufmgr.c:596
#5 0x00000000004eeb96 in ReadBufferBI (relation=0x7f3836e1e788, targetBlock=50, bistate=0x0) at hio.c:87
#6 0x00000000004ef387 in RelationGetBufferForTuple (relation=0x7f3836e1e788, len=32, otherBuffer=0, options=0,
bistate=0x0, vmbuffer=0x7ffd5fb295ec, vmbuffer_other=0x0) at hio.c:415
#7 0x00000000004df1f8 in heap_insert (relation=0x7f3836e1e788, tup=0x2ca6770, cid=0, options=0, bistate=0x0)
at heapam.c:2468
#8 0x0000000000709dda in ExecInsert (mtstate=0x2ca4c40, slot=0x2ca3418, planSlot=0x2ca3418, estate=0x2ca48d8,
canSetTag=true) at nodeModifyTable.c:529
#9 0x000000000070c475 in ExecModifyTable (pstate=0x2ca4c40) at nodeModifyTable.c:2159
#10 0x00000000006e05cb in ExecProcNodeFirst (node=0x2ca4c40) at execProcnode.c:445
#11 0x00000000006d552e in ExecProcNode (node=0x2ca4c40) at ../../../src/include/executor/executor.h:247
#12 0x00000000006d7d66 in ExecutePlan (estate=0x2ca48d8, planstate=0x2ca4c40, use_parallel_mode=false,
operation=CMD_INSERT, sendTuples=false, numberTuples=0, direction=ForwardScanDirection, dest=0x2d41a30,
execute_once=true) at execMain.c:1723
#13 0x00000000006d5af8 in standard_ExecutorRun (queryDesc=0x2ca24b8, direction=ForwardScanDirection, count=0,
execute_once=true) at execMain.c:364
#14 0x00000000006d5920 in ExecutorRun (queryDesc=0x2ca24b8, direction=ForwardScanDirection, count=0, execute_once=true)
at execMain.c:307
#15 0x00000000008c1092 in ProcessQuery (plan=0x2d418b8,
sourceText=0x2c7eec8 "insert into t1(id) select generate_series(100,500);", params=0x0, queryEnv=0x0, dest=0x2d41a30,
---Type <return> to continue, or q <return> to quit---
completionTag=0x7ffd5fb29b80 "") at pquery.c:161
#16 0x00000000008c29a1 in PortalRunMulti (portal=0x2ce4488, isTopLevel=true, setHoldSnapshot=false, dest=0x2d41a30,
altdest=0x2d41a30, completionTag=0x7ffd5fb29b80 "") at pquery.c:1286
#17 0x00000000008c1f7a in PortalRun (portal=0x2ce4488, count=9223372036854775807, isTopLevel=true, run_once=true,
dest=0x2d41a30, altdest=0x2d41a30, completionTag=0x7ffd5fb29b80 "") at pquery.c:799
#18 0x00000000008bbf16 in exec_simple_query (query_string=0x2c7eec8 "insert into t1(id) select generate_series(100,500);")
at postgres.c:1145
#19 0x00000000008c01a1 in PostgresMain (argc=1, argv=0x2ca8af8, dbname=0x2ca8960 "testdb", username=0x2c7bba8 "xdb")
at postgres.c:4182
#20 0x000000000081e07c in BackendRun (port=0x2ca0940) at postmaster.c:4361
#21 0x000000000081d7ef in BackendStartup (port=0x2ca0940) at postmaster.c:4033
#22 0x0000000000819be9 in ServerLoop () at postmaster.c:1706
#23 0x000000000081949f in PostmasterMain (argc=1, argv=0x2c79b60) at postmaster.c:1379
#24 0x0000000000742941 in main (argc=1, argv=0x2c79b60) at main.c:228
(gdb)
获取读取的偏移
(gdb) n
744 v = _mdfd_getseg(reln, forknum, blocknum, false,
(gdb)
747 seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
(gdb) p *v
$1 = {mdfd_vfd = 26, mdfd_segno = 0}
(gdb) p BLCKSZ
$2 = 8192
(gdb) p blocknum
$3 = 50
(gdb) p RELSEG_SIZE
$4 = 131072
(gdb) n
749 Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
(gdb) p seekpos
$5 = 409600
(gdb)
执行读取操作
(gdb) n
751 if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
(gdb)
757 nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ, WAIT_EVENT_DATA_FILE_READ);
(gdb)
759 TRACE_POSTGRESQL_SMGR_MD_READ_DONE(forknum, blocknum,
(gdb) p nbytes
$6 = 8192
(gdb) p *buffer
$7 = 1 '\001'
(gdb) n
767 if (nbytes != BLCKSZ)
(gdb)
792 }
(gdb)
smgrread (reln=0x2d09be0, forknum=MAIN_FORKNUM, blocknum=50, buffer=0x7f3823369c00 "\001") at smgr.c:629
629 }
(gdb)
到此,相信大家对“PostgreSQL中mdread函数有什么作用”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!