From 3f585e4d3519622405ee89f651db2bd875c6e9be Mon Sep 17 00:00:00 2001 From: Cachuela Date: Thu, 5 Oct 2023 22:29:04 +0800 Subject: [PATCH] enter --- src/gausskernel/storage/buffer/freelist.cpp | 143 ++++++++++++-------- 1 file changed, 89 insertions(+), 54 deletions(-) diff --git a/src/gausskernel/storage/buffer/freelist.cpp b/src/gausskernel/storage/buffer/freelist.cpp index 339544080..2c3808e99 100644 --- a/src/gausskernel/storage/buffer/freelist.cpp +++ b/src/gausskernel/storage/buffer/freelist.cpp @@ -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) { - // 如果已经重试了最大���数,并且脏页数量超过了阈值 + // 如果已经重试了最大�����数,并且脏页数量超过了阈值 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;