此博客旨在帮助您理解章节的内侧概念:8 [Buffer Manager] The Internals of PostgreSQL 。
注意:确保您对
有透彻的了解 在我们进入第8章第2章之前,Chapter 8 Part-1和Posttresql的基础是我们探索的基础。
所以,让我们继续:
缓冲区描述符层
-
缓冲区描述符的集合形成了数组。在本文档中,数组称为缓冲区描述符层。
-
当PostgreSQL Server启动时,所有缓冲区描述符的状态均为 empty 。在PostgreSQL中,这些描述符包含一个链接列表,称为 freelist 。
Buffer Manager初始状态 PostgreSQL中的如下图:
在PostgreSQL中加载第一页如下图:
缓冲池
-
缓冲池是一个简单的数组,它存储数据文件页面,例如表和索引。缓冲池阵列的索引称为 buffer_ids 。
-
缓冲池插槽大小为 8 kb ,等于页面的大小。因此,每个插槽都可以存储整个页面。
缓冲管理器锁
缓冲桌锁
-
bufmappinglock 保护整个缓冲区表的数据完整性。
-
是轻巧可以在共享模式和独家模式中使用的锁。在缓冲表中搜索条目时,后端进程保存共享 bufmappinglock 。
-
bufmappinglock分为分区以减少缓冲表中的争论(默认值为 128个分区)。每个bufmappinglock分区守护相应的哈希桶插槽的一部分。
两个过程同时以独家模式以bufmappinglock的相应分区插入了新的数据条目在PostgreSQL中插入:
锁定每个缓冲区描述符
- 每个缓冲区描述符都使用两个轻量重量锁, content_lock 和 io_in_progress_lock ,控制对相应缓冲池中存储的页面的访问投币口。当检查或更改自己的字段的值时,使用 Spinlock 。
content_lock
-
content_lock是强制执行访问限制的典型锁。它可以用于共享和独家模式。
-
阅读页面时,后端过程获取了存储页面的缓冲区描述符的共享 content_lock 。
-
在以下方案中获取独家content_lock :
- 将行(元组)插入存储的页面。
- 更改存储页面内的t_xmin/t_xmax字段。
- 在存储的页面上删除物理或压实的自由空间。
- 存储页面中的冻结元素。
io_in_progress_lock
-
io_in_progress锁用于在缓冲区上等待 i/o 完成。
-
当postgresql加载/从/到存储中写页数据数据时,该过程在访问存储时包含相应描述符的独家 io_in_progress lock 。
Spinlock
-
检查或更改了标志或其他字段(例如重新数和usage_count)时,使用 spinlock 。
-
两个 spinlock使用的特定示例如下:
1. The following shows how to pin the buffer descriptor:
- 获取缓冲区描述符的单锁。
- 将其重新计算的值和USAGE_COUNT的值增加1。
- 释放自旋锁。
2. The following shows how to set the dirty bit to '1':
- 获取缓冲区描述符的单锁。
- 使用位操作将脏点设置为“ 1”。
- 释放自旋锁。
缓冲区管理器的工作方式
-
当后端进程想要访问所需的页面时,它将调用 deadBufferextended 函数。
-
读取功能的行为取决于三个逻辑案例。
1。访问存储在缓冲池中的页面
-
首先,描述了最简单的情况,即所需的页面已经存储在 buffer池中。
-
在这种情况下,缓冲区管理器执行以下步骤:
-
(1)创建所需页面的buffer_tag(在此示例中,buffer_tag是'tag_c'),并使用哈希函数来计算包含创建buffer_tag的关联条目的哈希桶插槽。
-
(2)获取涵盖共享模式下获得的哈希桶插槽的bufmappinglock分区(此锁将在步骤(5)中发布)。
-
(3)查找标签为'tag_c'的条目,并从条目中获取Buffer_ID。在此示例中,Buffer_ID为2。
-
(4)固定buffer_id 2的缓冲区描述符,即描述符的重新数和usage_count增加了1。
-
(5)释放bufmappinglock。
-
(6)使用Buffer_ID2。
访问缓冲池插槽
访问postgresql中存储在缓冲池中的页面如下图:
-
从缓冲池插槽中的页面读取行时,PostgreSQL进程将获取相应的缓冲区描述符的共享 content_lock 。因此,缓冲池可以通过多个过程读取插槽。
-
在插入(并更新或删除)行插入页面时,Postgres进程获取相应的缓冲区描述符的 exclusive content_lock 页面的位必须设置为'1')。
-
访问页面后,相应的缓冲区描述符的重新数值减少了1 。
2。从存储到空插槽
加载页面-
在第二种情况下,假设所需的页面是不是缓冲池中的,而自由主义者具有免费元素(空描述符)。
-
在这种情况下,缓冲区管理器执行以下步骤:
-
(1)查找缓冲台(我们假设找不到)。
- 创建所需页面的buffer_tag(在此示例中,buffer_tag为'tag_e')并计算哈希桶插槽。
- 以共享模式获取bufmappinglock分区。
- 查找缓冲表(未根据假设找到)。
- 释放bufmappinglock。
-
(2)从FreeList获取空的缓冲区描述符,然后将其固定。在此示例中,获得的描述符的Buffer_ID为4。
-
(3)以独家模式获取Bufmappinglock分区(该锁将在步骤(6)中发布)。
-
(4)创建一个新的数据条目,该输入包括buffer_tag'tag_e'和buffer_id 4;将创建的条目插入缓冲区表。
-
(5)使用Buffer_ID 4加载所需的页面数据从存储到缓冲池插槽,如下所示:
-
获得相应描述符的独家io_in_progress_lock。
-
将相应描述符的io_in_progress位设置为'1,以防止其他过程访问。
-
加载所需的页面数据从存储到缓冲池插槽。
-
更改相应描述符的状态; io_in_progress位设置为'0',有效位设置为'1'。
-
释放io_in_progress_lock。
- (6)释放bufmappinglock。
- (7)使用Buffer_ID访问缓冲池插槽4。
在PostgreSQL中从存储中加载页面从存储到空插槽如下图:
我希望,这个博客帮助您理解了postresql中缓冲经理的内侧概念。
的摘要如果您想了解PostgreSQL In-Depth。