enter
This commit is contained in:
parent
e87d746b45
commit
3f585e4d35
|
|
@ -85,7 +85,7 @@ static void perform_delay(StrategyDelayStatus *status)//这个函数的目的是
|
|||
{
|
||||
if (++(status->retry_times) > MAX_RETRY_TIMES &&
|
||||
get_dirty_page_num() > g_instance.attr.attr_storage.NBuffers * NEED_DELAY_RETRY_GET_BUF) {
|
||||
// 如果已经重试了最大<E69C80><E5A4A7><EFBFBD>数,并且脏页数量超过了阈值
|
||||
// 如果已经重试了最大<E69C80><E5A4A7><EFBFBD><EFBFBD><EFBFBD>数,并且脏页数量超过了阈值
|
||||
|
||||
if (status->cur_delay_time == 0) {
|
||||
// 如果当前延迟时间为0,则初始化为最小延迟时间
|
||||
|
|
@ -430,19 +430,30 @@ void StrategyNotifyBgWriter(int bgwproc_no)
|
|||
* Note: for somewhat historical reasons, the buffer lookup hashtable size
|
||||
* is also determined here.
|
||||
*/
|
||||
Size StrategyShmemSize(void)
|
||||
/*
|
||||
这段代码首先调用 BufTableShmemSize 函数计算了查找哈希表的共享内存大小,
|
||||
其中 TOTAL_BUFFER_NUM 表示缓冲区的总数,
|
||||
NUM_BUFFER_PARTITIONS 表示缓冲区分区的数量。
|
||||
然后,它计算了共享替换策略控制块的大小,
|
||||
并使用 MAXALIGN 函数对齐到内存中的最大对齐大小。
|
||||
最后,将这两个大小相加得到了总的共享内存大小,并返回给调用者。
|
||||
这个大小通常用于初始化共享内存段,以便在多个进程之间共享缓冲区管理策略的信息。
|
||||
*/
|
||||
Size StrategyShmemSize(void)
|
||||
{
|
||||
Size size = 0;
|
||||
|
||||
/* size of lookup hash table ... see comment in StrategyInitialize */
|
||||
/* 计算查找哈希表的共享内存大小,详情见 StrategyInitialize 函数的注释 */
|
||||
size = add_size(size, BufTableShmemSize(TOTAL_BUFFER_NUM + NUM_BUFFER_PARTITIONS));
|
||||
|
||||
/* size of the shared replacement strategy control block */
|
||||
/* 计算共享替换策略控制块的大小,需要对齐到 MAXALIGN 大小 */
|
||||
size = add_size(size, MAXALIGN(sizeof(BufferStrategyControl)));
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* StrategyInitialize -- initialize the buffer cache replacement
|
||||
* strategy.
|
||||
|
|
@ -450,49 +461,56 @@ Size StrategyShmemSize(void)
|
|||
* Assumes: All of the buffers are already built into a linked list.
|
||||
* Only called by postmaster and only during initialization.
|
||||
*/
|
||||
/*
|
||||
这段代码首先调用 InitBufTable 函数初始化共享缓冲区查找哈希表,以用于在缓冲区的管理中查找缓冲区。
|
||||
哈希表的大小被设置为 TOTAL_BUFFER_NUM + NUM_BUFFER_PARTITIONS,以确保足够的哈希表大小来处理缓冲区的管理。
|
||||
|
||||
然后,它通过 ShmemInitStruct 函数获取或创建共享策略控制块 t_thrd.storage_cxt.StrategyControl。
|
||||
如果该控制块尚不存在,则会进行初始化,包括初始化互斥锁、时钟扫描指针等。
|
||||
|
||||
这个函数通常在 PostgreSQL 的启动阶段被调用一次,用于初始化缓冲区管理策略的共享内存数据结构和控制块。
|
||||
*/
|
||||
void StrategyInitialize(bool init)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
/*
|
||||
* Initialize the shared buffer lookup hashtable.
|
||||
* 初始化共享缓冲区查找哈希表。
|
||||
*
|
||||
* Since we can't tolerate running out of lookup table entries, we must be
|
||||
* sure to specify an adequate table size here. The maximum steady-state
|
||||
* usage is of course NBuffers entries, but BufferAlloc() tries to insert
|
||||
* a new entry before deleting the old. In principle this could be
|
||||
* happening in each partition concurrently, so we could need as many as
|
||||
* NBuffers + NUM_BUFFER_PARTITIONS entries.
|
||||
* 由于我们不能容忍查找表条目用尽,因此必须确保在这里指定足够大的表大小。最大稳态使用的条目数量
|
||||
* 当然是 NBuffers,但 BufferAlloc() 在删除旧条目之前尝试插入新条目。从原理上讲,这可能在每个
|
||||
* 分区中同时发生,因此我们可能需要多达 NBuffers + NUM_BUFFER_PARTITIONS 个条目。
|
||||
*/
|
||||
InitBufTable(TOTAL_BUFFER_NUM + NUM_BUFFER_PARTITIONS);
|
||||
|
||||
/*
|
||||
* Get or create the shared strategy control block
|
||||
* 获取或创建共享策略控制块
|
||||
*/
|
||||
t_thrd.storage_cxt.StrategyControl =
|
||||
(BufferStrategyControl *)ShmemInitStruct("Buffer Strategy Status", sizeof(BufferStrategyControl), &found);
|
||||
|
||||
if (!found) {
|
||||
/*
|
||||
* Only done once, usually in postmaster
|
||||
* 仅在初始化时执行一次,通常在 postmaster 中执行
|
||||
*/
|
||||
Assert(init);
|
||||
SpinLockInit(&t_thrd.storage_cxt.StrategyControl->buffer_strategy_lock);
|
||||
|
||||
/* Initialize the clock sweep pointer */
|
||||
/* 初始化时钟扫描指针 */
|
||||
pg_atomic_init_u32(&t_thrd.storage_cxt.StrategyControl->nextVictimBuffer, 0);
|
||||
|
||||
/* Clear statistics */
|
||||
/* 清空统计信息 */
|
||||
t_thrd.storage_cxt.StrategyControl->completePasses = 0;
|
||||
pg_atomic_init_u32(&t_thrd.storage_cxt.StrategyControl->numBufferAllocs, 0);
|
||||
|
||||
/* No pending notification */
|
||||
/* 没有挂起的通知 */
|
||||
t_thrd.storage_cxt.StrategyControl->bgwprocno = -1;
|
||||
} else {
|
||||
Assert(!init);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const int MIN_REPAIR_FILE_SLOT_NUM = 32;
|
||||
/* ----------------------------------------------------------------
|
||||
* Backend-private buffer ring management
|
||||
|
|
@ -503,20 +521,26 @@ const int MIN_REPAIR_FILE_SLOT_NUM = 32;
|
|||
*
|
||||
* The object is allocated in the current memory context.
|
||||
*/
|
||||
/*
|
||||
这个函数首先根据不同的访问策略类型 btype 计算所需的环大小 ring_size。
|
||||
然后,它分配了一个 BufferAccessStrategy 对象,并根据计算的参数对其进行了初始化。
|
||||
策略对象的类型、环的大小和刷新率等属性都会根据不同的访问策略类型进行设置。
|
||||
|
||||
最后,函数返回创建的策略对象,该对象可以用于后续的缓冲区访问操作,以实现不同的访问策略。
|
||||
*/
|
||||
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
|
||||
{
|
||||
BufferAccessStrategy strategy;
|
||||
int ring_size;
|
||||
|
||||
/*
|
||||
* Select ring size to use. See buffer/README for rationales.
|
||||
* 选择要使用的环大小。请参阅buffer/README中的原理说明。
|
||||
*
|
||||
* Note: if you change the ring size for BAS_BULKREAD, see also
|
||||
* SYNC_SCAN_REPORT_INTERVAL in access/heap/syncscan.c.
|
||||
* 注意:如果更改了BAS_BULKREAD的环大小,请同时查看access/heap/syncscan.c中的SYNC_SCAN_REPORT_INTERVAL。
|
||||
*/
|
||||
switch (btype) {
|
||||
case BAS_NORMAL:
|
||||
/* if someone asks for NORMAL, just give 'em a "default" object */
|
||||
/* 如果有人要求NORMAL,只需给他们一个“默认”对象 */
|
||||
return NULL;
|
||||
|
||||
case BAS_BULKREAD:
|
||||
|
|
@ -535,22 +559,22 @@ BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
|
|||
default:
|
||||
ereport(ERROR, (errcode(ERRCODE_INVALID_OPERATION),
|
||||
(errmsg("unrecognized buffer access strategy: %d", (int)btype))));
|
||||
return NULL; /* keep compiler quiet */
|
||||
return NULL; /* 保持编译器安静 */
|
||||
}
|
||||
|
||||
/* If the shared buffers is too small, make sure ring size not equal zero. */
|
||||
/* 如果共享缓冲区太小,请确保环大小不等于零。 */
|
||||
ring_size = Max(ring_size, 4);
|
||||
|
||||
/* Make sure ring isn't an undue fraction of shared buffers */
|
||||
/* 确保环不是共享缓冲区的过大比例 */
|
||||
if (btype != BAS_BULKWRITE && btype != BAS_BULKREAD)
|
||||
ring_size = Min(g_instance.attr.attr_storage.NBuffers / 8, ring_size);
|
||||
else
|
||||
ring_size = Min(g_instance.attr.attr_storage.NBuffers / 4, ring_size);
|
||||
|
||||
/* Allocate the object and initialize all elements to zeroes */
|
||||
/* 分配对象并将所有元素初始化为零 */
|
||||
strategy = (BufferAccessStrategy)palloc0(offsetof(BufferAccessStrategyData, buffers) + ring_size * sizeof(Buffer));
|
||||
|
||||
/* Set fields that don't start out zero */
|
||||
/* 设置初始不为零的字段 */
|
||||
strategy->btype = btype;
|
||||
strategy->ring_size = ring_size;
|
||||
strategy->flush_rate = Min(u_sess->attr.attr_storage.backwrite_quantity, ring_size);
|
||||
|
|
@ -558,6 +582,7 @@ BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
|
|||
return strategy;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FreeAccessStrategy -- release a BufferAccessStrategy object
|
||||
*
|
||||
|
|
@ -566,13 +591,14 @@ BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
|
|||
*/
|
||||
void FreeAccessStrategy(BufferAccessStrategy strategy)
|
||||
{
|
||||
/* don't crash if called on a "default" strategy */
|
||||
/* 不要在“默认”策略上调用时崩溃 */
|
||||
if (strategy != NULL) {
|
||||
pfree(strategy);
|
||||
strategy = NULL;
|
||||
pfree(strategy); // 释放策略对象占用的内存
|
||||
strategy = NULL; // 将策略对象指针设置为 NULL,以避免引用已释放的内存
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const int MAX_RETRY_RING_TIMES = 100;
|
||||
const float MAX_RETRY_RING_PCT = 0.1;
|
||||
/*
|
||||
|
|
@ -581,15 +607,21 @@ const float MAX_RETRY_RING_PCT = 0.1;
|
|||
*
|
||||
* The bufhdr spin lock is held on the returned buffer.
|
||||
*/
|
||||
/*
|
||||
这段代码的主要功能是从环形缓冲区策略中获取一个缓冲区描述符,
|
||||
该策略用于管理缓冲区的分配和使用。
|
||||
代码中包含了许多条件和逻辑,用于确定是否可以分配特定的缓冲区描述符,
|
||||
以及何时进行异步刷新等操作。
|
||||
*/
|
||||
static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state)
|
||||
{
|
||||
BufferDesc *buf = NULL;
|
||||
Buffer buf_num;
|
||||
uint32 local_buf_state; /* to avoid repeated (de-)referencing */
|
||||
uint16 retry_times = 0;
|
||||
BufferDesc *buf = NULL; // 用于存储缓冲区描述符的指针
|
||||
Buffer buf_num; // 用于存储缓冲区编号的变量
|
||||
uint32 local_buf_state; // 用于存储缓冲区状态的变量,以避免重复引用
|
||||
uint16 retry_times = 0; // 用于记录重试次数的变量
|
||||
|
||||
RETRY:
|
||||
/* Advance to next ring slot */
|
||||
/* 移动到下一个环形槽位 */
|
||||
if (++strategy->current >= strategy->ring_size)
|
||||
strategy->current = 0;
|
||||
retry_times++;
|
||||
|
|
@ -597,9 +629,9 @@ RETRY:
|
|||
ADIO_RUN()
|
||||
{
|
||||
/*
|
||||
* Flush out buffers asynchronously from behind the current slot.
|
||||
* This is a kludge because the PageListBackWrite() is not strictly
|
||||
* asynchronous and this function really shouldn't be doing the actual I/O.
|
||||
* 异步刷新位于当前槽位之后的缓冲区。
|
||||
* 这是一种权宜之计,因为 PageListBackWrite() 不是严格异步的,
|
||||
* 而且这个函数实际上不应该执行实际的 I/O 操作。
|
||||
*/
|
||||
if (AioCompltrIsReady() &&
|
||||
((strategy->btype == BAS_BULKWRITE) && (strategy->current % strategy->flush_rate == 0))) {
|
||||
|
|
@ -625,9 +657,8 @@ RETRY:
|
|||
ADIO_END();
|
||||
|
||||
/*
|
||||
* If the slot hasn't been filled yet, tell the caller to allocate a new
|
||||
* buffer with the normal allocation strategy. He will then fill this
|
||||
* slot by calling AddBufferToRing with the new buffer.
|
||||
* 如果槽位尚未填充,则告诉调用者使用正常的分配策略来分配新的缓冲区。
|
||||
* 调用者将通过调用 AddBufferToRing 来填充这个槽位。
|
||||
*/
|
||||
buf_num = strategy->buffers[strategy->current];
|
||||
if (buf_num == InvalidBuffer) {
|
||||
|
|
@ -636,13 +667,10 @@ RETRY:
|
|||
}
|
||||
|
||||
/*
|
||||
* If the buffer is pinned we cannot use it under any circumstances.
|
||||
* 如果缓冲区被固定,无论如何都不能使用它。
|
||||
*
|
||||
* If usage_count is 0 or 1 then the buffer is fair game (we expect 1,
|
||||
* since our own previous usage of the ring element would have left it
|
||||
* there, but it might've been decremented by clock sweep since then). A
|
||||
* higher usage_count indicates someone else has touched the buffer, so we
|
||||
* shouldn't re-use it.
|
||||
* 如果 usage_count 为 0 或 1,则可以使用缓冲区(我们期望为 1,因为我们之前使用了环形元素,
|
||||
* 但可能已经被时钟扫描减少了)。更高的 usage_count 表示其他进程已经访问了缓冲区,所以我们不应该重用它。
|
||||
*/
|
||||
buf = GetBufferDescriptor(buf_num - 1);
|
||||
if (pg_atomic_read_u32(&buf->state) & (BM_DIRTY | BM_IS_META)) {
|
||||
|
|
@ -666,13 +694,14 @@ RETRY:
|
|||
|
||||
UnlockBufHdr(buf, local_buf_state);
|
||||
/*
|
||||
* Tell caller to allocate a new buffer with the normal allocation
|
||||
* strategy. He'll then replace this ring element via AddBufferToRing.
|
||||
* 告诉调用者使用正常的分配策略来分配新的缓冲区。
|
||||
* 他将通过 AddBufferToRing 来替换这个环形元素。
|
||||
*/
|
||||
strategy->current_was_in_ring = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AddBufferToRing -- add a buffer to the buffer ring
|
||||
*
|
||||
|
|
@ -695,25 +724,31 @@ static void AddBufferToRing(BufferAccessStrategy strategy, volatile BufferDesc *
|
|||
* Returns true if buffer manager should ask for a new victim, and false
|
||||
* if this buffer should be written and re-used.
|
||||
*/
|
||||
/*
|
||||
这段代码的主要目的是在特定条件下拒绝缓冲区
|
||||
,通常在批量读取模式下,如果当前槽位在环中且与给定的缓冲区描述符匹配。如
|
||||
果满足这些条件,它会将当前槽位中的缓冲区标记为无效,并返回 true,
|
||||
表示已经拒绝了缓冲区。否则,它返回 false,表示不拒绝缓冲区。
|
||||
*/
|
||||
bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf)
|
||||
{
|
||||
/* We only do this in bulkread mode */
|
||||
/* 只在批量读取模式下执行此操作 */
|
||||
if (strategy->btype != BAS_BULKREAD)
|
||||
return false;
|
||||
return false; // 如果不是批量读取模式,则不进行拒绝操作
|
||||
|
||||
/* Don't muck with behavior of normal buffer-replacement strategy */
|
||||
/* 不要改变正常缓冲区替换策略的行为 */
|
||||
if (!strategy->current_was_in_ring || strategy->buffers[strategy->current] != BufferDescriptorGetBuffer(buf))
|
||||
return false;
|
||||
return false; // 如果当前槽位不在环中,或者环中的缓冲区与给定的缓冲区描述符不匹配,则不进行拒绝操作
|
||||
|
||||
/*
|
||||
* Remove the dirty buffer from the ring; necessary to prevent infinite
|
||||
* loop if all ring members are dirty.
|
||||
* 从环中移除脏缓冲区;这是为了防止如果所有环成员都是脏的时出现无限循环。
|
||||
*/
|
||||
strategy->buffers[strategy->current] = InvalidBuffer;
|
||||
|
||||
return true;
|
||||
return true; // 返回true表示已经拒绝了缓冲区
|
||||
}
|
||||
|
||||
|
||||
void StrategyGetRingPrefetchQuantityAndTrigger(BufferAccessStrategy strategy, int *quantity, int *trigger)
|
||||
{
|
||||
int threshold;
|
||||
|
|
|
|||
Loading…
Reference in New Issue