代码编织梦想

背景

  在绝大多数据库系统中,其存储管理涉及的问题本质上是一致的:尽可能减少IO操作次数。因此,尽可能让最近访问过的文件块停留在内存中,有效减小IO的代价。合理有效的内存管理对整个数据库系统来说是非常最要的。postgreSQL中的内存管理包括共享内存和本地内存的管理(如图所示)接下里几小节将从源码角度进行学习。
在这里插入图片描述

内存上下文

** 1 简介**
  内存上下文借鉴操作系统中进程环境的概念。在程序运行的时,操作系统会为每个进程分配执行环境,进程环境之间不会互相影响,由操作系统进行上下文切换,进程可以在其环境调用库函数进行内存分配与回收等。postgreSQL采用类似的方法通过内存上下文来实现内存管理。

** 2 MemoryContext 结构**
  PostgreSQL中的每一个backend process都有自己的私有上下文,且该内存上下文为树形结构(如下图),根节点为 TopMemoryContext,其下包含多个子节点,每个子结点负责不同的功能:CacheMemoery用于管理Cache、ErrorContext用于错误处理等,每个子结点根据实际工作划分为多个子节点,
在这里插入图片描述
  申请新的内存上下文时只需将其添加至某个内存上下文的子节点。释放时需要从根节点遍历找到指定待删除的上下文。

2.1 关键数据结构
2.1.1 MemoryContextData
MemoryContextData结构体包含上下文类型,内存上下文操作函数以及该内存上下文父节点、兄弟节点等信息。

typedef struct MemoryContextData
{
	NodeTag		type;			/* identifies exact kind of context */
	/* these two fields are placed here to minimize alignment wastage: */
	bool		isReset;		/* T = no space alloced since last reset */
	bool		allowInCritSection; /* allow palloc in critical section */
	Size		mem_allocated;	/* track memory allocated for this context */
	const MemoryContextMethods *methods;	/* virtual function table */
	MemoryContext parent;		/* NULL if no parent (toplevel context) */
	MemoryContext firstchild;	/* head of linked list of children */
	MemoryContext prevchild;	/* previous child of same parent */
	MemoryContext nextchild;	/* next child of same parent */
	const char *name;			/* context name (just for debugging) */
	const char *ident;			/* context ID if any (just for debugging) */
	MemoryContextCallback *reset_cbs;	/* list of reset/delete callbacks */
} MemoryContextData;
typedef struct MemoryContextData *MemoryContext;

2.1.2 MemoryContextMethods
MemoryContextMethods 结构体由一系列函数指针组成,包括分配/释放删除等操作。

typedef struct MemoryContextMethods
{
	void	   *(*alloc) (MemoryContext context, Size size);
	/* call this free_p in case someone #define's free() */
	void		(*free_p) (MemoryContext context, void *pointer);
	void	   *(*realloc) (MemoryContext context, void *pointer, Size size);
	void		(*reset) (MemoryContext context);
	void		(*delete_context) (MemoryContext context);
	Size		(*get_chunk_space) (MemoryContext context, void *pointer);
	bool		(*is_empty) (MemoryContext context);
	void		(*stats) (MemoryContext context,
						  MemoryStatsPrintFunc printfunc, void *passthru,
						  MemoryContextCounters *totals,
						  bool print_to_stderr);
	void		(*check) (MemoryContext context);
} MemoryContextMethods;

在PostgreSQL中使用全局变量CurrentMemoryContext表示当前工作内存上下文,在需要切换上下文,调用 MemoryContextSwitchTo 函数切换至目标上下文

2.1.3 AllocSetContext
AllocSetContext结构体包含 header信息、该内存上下文所有内存块链表头、空闲内存片数组、块大小等信息

typedef struct AllocSetContext
{
	MemoryContextData header;	/* Standard memory-context fields */
	/* Info about storage allocated in this context: */
	AllocBlock	blocks;			/* head of list of blocks in this set */
	AllocChunk	freelist[ALLOCSET_NUM_FREELISTS];	/* free chunk lists */
	/* Allocation parameters for this context: */
	Size		initBlockSize;	/* initial block size */
	Size		maxBlockSize;	/* maximum block size */
	Size		nextBlockSize;	/* next block size to allocate */
	Size		allocChunkLimit;	/* effective chunk size limit */
	AllocBlock	keeper;			/* keep this block over resets */
	/* freelist this context could be put in, or -1 if not a candidate: */
	int			freeListIndex;	/* index in context_freelists[], or -1 */
} AllocSetContext;
typedef AllocSetContext *AllocSet;

2.1.4 AllocBlockData
AllocBlockData结构体记录了该内存块所在上下文、该块前后块信息、该块空闲区域首地址和该块的结束地址

typedef struct AllocBlockData
{
	AllocSet	aset;			/* aset that owns this block */
	AllocBlock	prev;			/* prev block in aset's blocks list, if any */
	AllocBlock	next;			/* next block in aset's blocks list, if any */
	char	   *freeptr;		/* start of free space in this block */
	char	   *endptr;			/* end of space in this block */
}AllocBlockData;
typedef struct AllocBlockData *AllocBlock;

2.1.5 AllocChunk

typedef struct AllocChunkData
{
	/* size is always the size of the usable space in the chunk */
	Size		size;					// 内存片可使用空间
	Size		requested_size;			// 请求内存大小
	/* aset is the owning aset if allocated, or the freelist link if free */
	void	   *aset;					// 该内存片所在 AllocSet
	/* there must not be any padding to reach a MAXALIGN boundary here! */
}			AllocChunkData;

为方便理解,将上述数据数据结构衔接,可得如下图【转载PostgreSQL数据库内核分析书籍】
在这里插入图片描述

2.1.6 FreeList数组
Freelist数组中的每一个元素指向一个特定"大小"空闲内存片组成的链表,这个“大小”与该元素所在数组中的顺序有关。比如,Freelist数组中第K个元素所指向链表的每个空闲数据块大小的2 <<(k + 2)字节,空闲内存片大小为8B,最大内存片大小为 8K.

/*--------------------
 * Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
 * for k = 0 .. ALLOCSET_NUM_FREELISTS-1.
 *
 * Note that all chunks in the freelists have power-of-2 sizes.  This
 * improves recyclability: we may waste some space, but the wasted space
 * should stay pretty constant as requests are made and released.
 *
 * A request too large for the last freelist is handled by allocating a
 * dedicated block from malloc().  The block still has a block header and
 * chunk header, but when the chunk is freed we'll return the whole block
 * to malloc(), not put it on our freelists.
 *
 * CAUTION: ALLOC_MINBITS must be large enough so that
 * 1<<ALLOC_MINBITS is at least MAXALIGN,
 * or we may fail to align the smallest chunks adequately.
 * 8-byte alignment is enough on all currently known machines.
 *
 * With the current parameters, request sizes up to 8K are treated as chunks,
 * larger requests go into dedicated blocks.  Change ALLOCSET_NUM_FREELISTS
 * to adjust the boundary point; and adjust ALLOCSET_SEPARATE_THRESHOLD in
 * memutils.h to agree.  (Note: in contexts with small maxBlockSize, we may
 * set the allocChunkLimit to less than 8K, so as to avoid space wastage.)
 *--------------------
 */

#define ALLOC_MINBITS		3	/* smallest chunk size is 8 bytes */
#define ALLOCSET_NUM_FREELISTS	11
#define ALLOC_CHUNK_LIMIT	(1 << (ALLOCSET_NUM_FREELISTS-1+ALLOC_MINBITS))
/* Size of largest chunk that we use a fixed size for */
#define ALLOC_CHUNK_FRACTION	4
/* We allow chunks to be at most 1/4 of maxBlockSize (less overhead) */

在这里插入图片描述

参考:PostgreSQL数据库内核分析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_52668274/article/details/127142627

postgresql 源码解读(93)- 查询语句#77(exechashjoin函数#3)-爱代码爱编程

本节是ExecHashJoin函数介绍的第三部分,主要介绍了ExecHashJoin中依赖的其他函数的实现逻辑,这些函数在HJ_NEED_NEW_OUTER阶段中使用,包括ExecHashJoinOuterGetTuple、ExecPrepHashTableForUnmatched、ExecHashGetBucketAndBatch、Exec

postgresql 源码解读(95)- 查询语句#78(exechashjoin函数#4-h...-爱代码爱编程

本节是ExecHashJoin函数介绍的第四部分,主要介绍了ExecHashJoin中依赖的其他函数的实现逻辑,这些函数在HJ_SCAN_BUCKET阶段中使用,主要的函数是ExecScanHashBucket。 一、数据结构 JoinState Hash/NestLoop/Merge Join的基类 /* --------

postgresql 源码解读(140)- buffer manager#5(buftableinsert函数)-爱代码爱编程

本节简单介绍了PostgreSQL缓存管理(Buffer Manager)中的实现函数ReadBuffer_common->BufferAlloc->BufTableInsert,该函数对于给定的tag和buffer ID,插入到哈希表中。 一、数据结构 BufferDesc 共享缓冲区的共享描

Thingsboard 3.1.0 - 源码编译-爱代码爱编程

网上有很多资料,每个人遇到的情况也都不一样。本人成功编译花费将近一周时间,过程整理如下: 1、下载GIT源码 目录右键,选择Git Bash Here输入git命令克隆源代码:git clone https://github.com/thingsboard/thingsboard.git 进入thingsboard文件夹:cd thingsboar

openGauss数据库源码解析系列文章--openGauss简介(一)-爱代码爱编程

openGauss数据库是华为深度融合在数据库领域多年经验,结合企业级场景要求推出的新一代企业级开源数据库。此前,Gauss松鼠会已经发布了openGauss数据库核心技术系列文章,介绍了openGauss的技术原理。从本期开始,Gauss松鼠会将陆续推出openGauss数据库源码解析系列文章,带你解析openGauss各功能模块的源代码逻辑和实现原理。

openGauss数据库源码解析系列文章——公共组件源码解析(上)-爱代码爱编程

在数据库组件中,一些组件是专用的,如词法解析只用于SQL引擎;而另外一些组件是公共的,用于整个数据库系统。openGauss的公共组件包括系统表、数据库初始化、多线程架构、线程池、内存管理、多维监控和模拟信号机制等。每个组件实现了一个独立的功能。本篇将从系统表、数据库初始化、多线程架构及线程池技术四个方面对公共组件的源代码实现进行介绍。 一、系统表 系

PG系列1-postgresql的源码编译安装(CentOS7.8)-爱代码爱编程

文章目录 前言1、选择源码包2、编译安装2.1简单安装2.2 自定义安装2.2.1 配置普通用户权限安装3、熟悉配置文件3.1 postgresql.conf 数据库相关配置3.1.1连接配置与安全认证3.1.2 安全认证Security and Authentication3.1.3 内存 Memory3.1.4 资源(空闲空间映射)3.1.5

postgreSQL源码分析综述-爱代码爱编程

2021SC@SDUSC 目录 综合分析安装过程主要源码分工情况我的任务分析方式 综合分析 经过小组讨论和分析,大家一致认为postgreSQL的核心部分在于对SQL功能的实现。而postgreSQL的核心代码则在于其后端的完成实现。 由上图,可以看出postgresql处理查询请求(核心功能)都是依托postgres这个进程完成的。而查询请求

python操作mysql, python操作postgres, mysql-pymysql, postgres-psycopg2 - pythonweb(2)-爱代码爱编程

Python操作数据库 - python-web(2) ​      Java的开发者使用JDBC操作数据库, C开发者需要借助mysql-devel原生操作数据库,在python中如何操作数据库? 在python多用pymysql操作MySQL, psycopg2操作Postgresql。 ​      python数据库操作模块都基本遵循 db-ap

OpenGauss数据库中事务管理源码解析-爱代码爱编程

一、事务 事务的定义事务是数据库操作的执行单位,需要满足最基本的ACID(原子性、一致性、隔离性、持久性)属性。 (1) 原子性:一个事务提交之后要么全部执行,要么全部不执行。 (2) 一致性:事务的执行不能破坏数据库的完整性和一致性。 (3) 隔离性:事务的隔离性是指在并发中,一个事务的执行不能被其他事务干扰。 (4) 持久性:一旦事务完成提交

Java笔记--实时更新-爱代码爱编程

Java一学期复习 & 基础入门 前言一、Java开发入门1.1 Java概述1.2 JDK, JRE, JVM二、Java编程基础2.1 基本语法2.2 数据类型2.3 运算符2.4 选择结构2.5 循环结构三、面向对象3.1 概念3.2 特性(封装, 继承, 多态)3.2.1 封装访问修饰符:3.2.2 继承3.2.3 多态非访问修饰符

postgres源码解析 缓冲池管理器--1_serendipity_shy的博客-爱代码爱编程

背景   缓冲区管理器管理共享内存和持久存储之间的数据传输,对 DBMS 的性能产生重大影响。 PostgreSQL也不例外,通过缓冲区管理器的减少对磁盘的IO操作。 Shared buffer pool 管理 参考T

postgres 源码解析 缓冲池管理器-3_serendipity_shy的博客-爱代码爱编程

  本文讲解缓冲块的选择策略BufferAlloc,同时该函数也是替换策略的核心函数, 知识回顾: postgres源码解析 缓冲池管理–1 postgres源码解析 缓冲池管理–2 总结<执行流程图>

postgres 源码解析 元组插入流程 heap_insert_serendipity_shy的博客-爱代码爱编程

  本文从源码角度分析postgre元组插入流程,知识回顾:postgres Page 与 Tuple 组织方式 1 示意图 根据用户输入的SQL语句,进行语义、语法分析生成解析树,后对解析树进行分析重写,生成查询树,最

postgresql 在wal文件中查找drop table、update、delete操作_kmblack1的博客-爱代码爱编程

配套视频 要还原数据前必须查找对应的wal文件中的lsn号,步骤如下: 根据大致的操作时间先确认大至wal文件的范围. 解析此范围内的wal文件然后输出至文本. 在文本中根据特征中查找.如果未找到请扩大wal文件范

postgres 源码解析16 checkpoint源码学习-爱代码爱编程

  本小节着重讲解CheckpointerMain中的CreateCheckPoint接口函数源码学习,相关知识回顾postgres checkpoint源码学习-1 源码分析 CreateCheckPoint函数主要有

postgres 源码解析9 clog管理器-爱代码爱编程

1 背景介绍   在Postgres数据库的日志管理系统中,采用CLOG日志记录集群中每个事务的最终状态,在内存中形式是基于SLRU缓冲实现的,有兴趣的回顾下SLRU相关知识:   1 postgres源码分析 Slru缓