pg_orphaned扩展分析(二)

简介: pg_orphaned扩展是用于维护PostgreSQL孤儿文件的扩展,通过分析学习了查找孤儿文件的方法,同时还将学习在PostgreSQL后端(backend)如何查找指定表/视图、如何创建cache、如何使用hash表、如何使用List、如何使用正则表达式、C语言扩展如何返回结果集。

后端系统表扫描

pg_orphaned扩展通过在pg_class表中查找reltablespace和relfilenode以确定指定文件是否为孤儿文件,pg_orphaned是如何做呢?首先使用 InitDirtySnapshot 宏初始化一个类型为 SNAPSHOT_DIRTY SnapshotData结构,然后使用 open_table(>=pg12)或者tuple_open 打开表,最后使用 systable_beginscan 扫描,参考下面的代码片断:

SnapshotDataDirtySnapshot;
ScanKeyDataskey[2];
InitDirtySnapshot(DirtySnapshot);
......
#if PG_VERSION_NUM >= 120000relation=table_open(RelationRelationId, AccessShareLock);
#elserelation=heap_open(RelationRelationId, AccessShareLock);
#endif/* copy scankey to local copy, it will be modified during the scan */memcpy(skey, relfilenode_skey_dirty, sizeof(skey));
/* set scan arguments */skey[0].sk_argument=ObjectIdGetDatum(reltablespace);
skey[1].sk_argument=ObjectIdGetDatum(relfilenode);
scandesc=systable_beginscan(relation,
ClassTblspcRelfilenodeIndexId,
true,
&DirtySnapshot,
2,
skey);

SnapshotData 结构见 include/server/utils/snapshot.h。

open_table的实现在src/backend/access/table/table.c中,原型如下:

Relationtable_open(OidrelationId, LOCKMODElockmode)

参数relationId为要打开的表的oid,lockmode为加锁模式,定义如下:

/* NoLock is not a lock mode, but a flag value meaning "don't get a lock" */#define NoLock                  0#define AccessShareLock         1   /* SELECT */#define RowShareLock            2   /* SELECT FOR UPDATE/FOR SHARE */#define RowExclusiveLock        3   /* INSERT, UPDATE, DELETE */#define ShareUpdateExclusiveLock 4  /* VACUUM (non-FULL),ANALYZE, CREATE INDEX* CONCURRENTLY */#define ShareLock               5   /* CREATE INDEX (WITHOUT CONCURRENTLY) */#define ShareRowExclusiveLock   6   /* like EXCLUSIVE MODE, but allows ROW* SHARE */#define ExclusiveLock           7   /* blocks ROW SHARE/SELECT...FOR UPDATE */#define AccessExclusiveLock     8   /* ALTER TABLE, DROP TABLE, VACUUM FULL,* and unqualified LOCK TABLE */#define MaxLockMode             8   /* highest standard lock mode */

systable_beginscan 实现于src/backend/access/index/genam.c,用于对指定系统表进行heap-or-index扫描,共有六个参数,原型如下:

SysScanDescsystable_beginscan(RelationheapRelation,
OidindexId,
boolindexOK,
Snapshotsnapshot,
intnkeys, ScanKeykey)

共有六个参数:

heapRelation: 要扫描的oid,已经打开并加了合适的锁;

indexId: 查找条件的索引id;

indexOk: false强制heap scan;

snapshot: 为NULL时使用最近的catalog快照;

nkeys, key: 扫描使用的键值。

返回 SysScanDesc结构,定义如下:

/* Struct for storage-or-index scans of system tables */typedefstructSysScanDescData{
Relationheap_rel;       /* catalog being scanned */Relationirel;           /* NULL if doing heap scan */structTableScanDescData*scan; /* only valid in storage-scan case */structIndexScanDescData*iscan;    /* only valid in index-scan case */structSnapshotData*snapshot;  /* snapshot to unregister at end of scan */structTupleTableSlot*slot;
} SysScanDescData;

扫描后结果获取:

while (HeapTupleIsValid(ntp=systable_getnext(scandesc)))
        {
#if PG_VERSION_NUM >= 120000Form_pg_classclassform= (Form_pg_class) GETSTRUCT(ntp);
found=true;
Assert(classform->reltablespace==reltablespace);
Assert(classform->relfilenode==relfilenode);
relid=classform->oid;
#elsefound=true;
relid=HeapTupleGetOid(ntp);
#endif        }

结果后调用 systable_endscan 关闭扫描并释放资源,然后调用 close_table 关闭表。

systable_endscan(scandesc);
#if PG_VERSION_NUM >= 120000table_close(relation, AccessShareLock);
#elseheap_close(relation, AccessShareLock);
#endif

使用后端List

PostgreSQL后端实现了List包,位于src/backend/nodes/list.c。pg_orphaned扩展使用List保存孤独文件列表。

List*list_orphaned_relations=NULL;
typedefstructOrphanedRelation {
char*dbname;
char*path;
char*name;
intsize;
TimestampTzmod_time;
Oidrelfilenode;
Oidreloid;
} OrphanedRelation;

主要操作如下:

//新增oidrel=RelidByRelfilenodeDirty(reltablespace, relfilenode);
if (!OidIsValid(oidrel)) {
orph->dbname=strdup(dbname);
orph->path=strdup(dir);
orph->name=strdup(de->d_name);
orph->size= (int64) attrib.st_size;
orph->mod_time=time_t_to_timestamptz(attrib.st_mtime);
orph->relfilenode=relfilenode;
orph->reloid=oidrel;
*flist=lappend(*flist, orph);                             
}
......
//遍历#if (PG_VERSION_NUM < 130000)for (cell=list_head(list_orphaned_relations); cell!=NULL; cell=lnext(cell))
#elsefor (cell=list_head(list_orphaned_relations); cell!=NULL; cell=lnext(list_orphaned_relations, cell))
#endif    {
charorphaned_file[MAXPGPATH+21+sizeof(TABLESPACE_VERSION_DIRECTORY) +10+6] = {0};
charorphaned_file_backup_dir[MAXPGPATH+21+sizeof(TABLESPACE_VERSION_DIRECTORY) +10+6] = {0};
charorphaned_file_backup[MAXPGPATH+21+sizeof(TABLESPACE_VERSION_DIRECTORY) +10+6] = {0};
OrphanedRelation*orph= (OrphanedRelation*)lfirst(cell);

C语言自定义函数如何返回结果集

根据fmgr的定义,如果返回的是结果集而不是简单类型,需要使用指向ReturnSetInfo类型的节点的fcinfo->resultinfo调用该函数,该结构会由调用者初始化并传递给要调用的函数,参考代码如下(节选自pg_list_orphaned_internal):

ReturnSetInfo*rsinfo= (ReturnSetInfo*) fcinfo->resultinfo;
Tuplestorestate*tupstore;
TupleDesctupdesc;
MemoryContextper_query_ctx;
MemoryContextoldcontext;
ListCell*cell;
per_query_ctx=rsinfo->econtext->ecxt_per_query_memory;
oldcontext=MemoryContextSwitchTo(per_query_ctx);
/** 为我们的返回类型构造元组描述符*/if (get_call_result_type(fcinfo, NULL, &tupdesc) !=TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
/* 在work_mem中创建tuplestore */tupstore=tuplestore_begin_heap(true, false, work_mem);
rsinfo->returnMode=SFRM_Materialize;
rsinfo->setResult=tupstore;
rsinfo->setDesc=tupdesc;
MemoryContextSwitchTo(oldcontext);
for(...)
{
/* 获取数据 */OrphanedRelation*orph= (OrphanedRelation*)lfirst(cell);
/* 填充返回数据 */Datumvalues[8];
boolnulls[8];
memset(values, 0, sizeof(values));
memset(nulls, 0, sizeof(nulls));
values[0] =CStringGetTextDatum(orph->dbname);
values[1] =CStringGetTextDatum(orph->path);
values[2] =CStringGetTextDatum(orph->name);
values[3] =Int64GetDatum(orph->size);
values[4] =TimestampTzGetDatum(orph->mod_time);
values[5] =Int64GetDatum(orph->relfilenode);
values[6] =Int64GetDatum(orph->reloid);
if (orph->mod_time<=limitts)
values[7] =BoolGetDatum(true);
elsevalues[7] =BoolGetDatum(false);
/* 结果放入tuplestore中 */tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
/* 清理 */tuplestore_donestoring(tupstore);

正则表达式

正则表达式需要使用宽字符集,实现位于src/backend/utils/adt/regexp.c、/src/backend/regex/regcomp.c、/src/backend/regex/regexec.c,使用起来相对简单,见如下示例:

} elseif (de->d_name[0] =='t') {
inti;
pg_wchar*wstr;
intwlen;
pg_wchar*regwstr;
intregwlen;
intr;
char*regex="^t[0-9]*_[0-9]";
intregcomp_result;
charerrMsg[100];
regex_t*preg=palloc(sizeof(regex_t));
char*t;
char*tokptr=NULL;
char*temprel;
regwstr=palloc((strlen(regex) +1) *sizeof(pg_wchar));
regwlen=pg_mb2wchar_with_len(regex, regwstr, strlen(regex));
/* 编译正则表达式 */regcomp_result=pg_regcomp(preg,
regwstr,
regwlen,
REG_ADVANCED|REG_NOSUB,
DEFAULT_COLLATION_OID);
pfree(regwstr);
if (regcomp_result==REG_OKAY) {
wstr=palloc((strlen(de->d_name) +1) *sizeof(pg_wchar));
wlen=pg_mb2wchar_with_len(de->d_name, wstr, strlen(de->d_name));
/* 匹配正则表达式 */r=pg_regexec(preg, wstr, wlen, 0, NULL, 0, NULL, 0);
if (r!=REG_NOMATCH) {
            ......
相关文章
|
存储 SQL 监控
22 PostgreSQL 监控3PostgreSQL 性能快照和图形化分析工具 pg_stats_info 的使用|学习笔记
快速学习22 PostgreSQL 监控3PostgreSQL 性能快照和图形化分析工具 pg_stats_info 的使用
22 PostgreSQL 监控3PostgreSQL 性能快照和图形化分析工具 pg_stats_info 的使用|学习笔记
|
7月前
|
SQL 关系型数据库 数据库
一文熟悉PolarDB-PG 分区表核心特性
在 PolarDB-PG 数据库中,分区表 (Partitioned Table) 使您能够将非常大的表分解为更小且更易于管理的部分,这个部分称为分区 (Partition) 。 每个分区都是一个独立的对象,具有自己的名称和可选的存储特性。本文首先简单的介绍了分区表策略以及它的优势特点,然后介绍了PolarDB-PG 分区表支持的查询优化特性,最后介绍了分区表上的本地索引和全局索引,从而帮助用户对PolarDB-PG 分区表有一个全面的了解。
|
7月前
|
关系型数据库 C语言 PostgreSQL
pg_orphaned扩展分析(一)
pg_orphaned扩展是用于维护PostgreSQL孤儿文件的扩展,通过分析学习了查找孤儿文件的方法,同时还将学习在PostgreSQL后端(backend)如何查找指定表/视图、如何创建cache、如何使用hash表、如何使用List、如何使用正则表达式、C语言扩展如何返回结果集。
|
SQL 关系型数据库
[翻译]利用pg_stat_statments分析业务瓶颈
[翻译]利用pg_stat_statments分析业务瓶颈
108 0
|
SQL 监控 网络协议
优化PG查询:一问一答
优化PG查询:一问一答
128 0
|
关系型数据库 Shell 调度
|
关系型数据库 PostgreSQL 索引
|
SQL 关系型数据库 数据库
|
SQL 监控 Go
MSSQL-应用案例-日志表设计优化与实现
--- title: MSSQL-应用案例-日志表设计优化与实现 author: 风移 --- # 摘要 这篇文章从日志表问题引入、日志表的共有特性、日志表的设计需求、设计思路以及设计详细实现的角度,阐述了在SQL Server数据库中如何最优化设计日志表来降低系统资源的占用和提高系统吞吐量。 # 问题引入 在平时与客户服务与交流过程中,我们不止一次的被客人问及这样的场景:我们现
2075 0
|
SQL Oracle 关系型数据库
《Oracle高性能SQL引擎剖析:SQL优化与调优机制详解》一3.2 基于代价的查询转换
本节书摘来自华章出版社《Oracle高性能SQL引擎剖析:SQL优化与调优机制详解》一 书中的第3章,第3.2节,作者:黄玮,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1208 0