PostgreSQL local buffer 分析

源码版本:pg 11.3
源码文件:src/backend/storage/buffer/localbuf.c

local buffer 主要用于临时表的快速缓存管理,减少磁盘 IO 操作,提升性能。对 local buffer 的操作不需要写 wal log 和 checkpoint。它是在 backend 进程的本地内存空间进行内存分配,而不是共享内存。

local buffer 的大小由参数 temp_buffers 设置,默认值为 1024,即 1024 个 page 或者称之为 block。

全局变量:
  • NLocBuffer:对应于 temp_buffers,即 local buffer 的 page 数量
  • LocalBufferDescriptors:BufferDesc 数组,大小为 NLocBuffer,每一个元素对应一个 local buffer
  • LocalBufferBlockPointers:Block 数组,大小为 NLocBuffer,每一个元素指向一个 local buffer 内存块
  • LocalRefCount:int32 类型的数组,大小为 NLocBuffer,每一个元素表示一个 local buffer 的引用计数
  • LocalBufHash:HTAB 哈希表,用于 local buffer 的快速查找

初始化:
InitLocalBuffers(),初始化的时候只会初始化用于存储 buffer 元数据的内存,并不会申请 buffer 内存,buffer 内存在真正使用时才会申请。

在初始化函数中,可以看到一个比较有趣的现象,即 BufferDesc 的 buf_id 是负数,即从 -2 递减,而共享内存的 buffer id 是从 0 递增,这是 local buffer 与 share buffer 的一个区别。
    for (i = 0; i < nbufs; i++)
    {
        BufferDesc *buf = GetLocalBufferDescriptor(i);
        buf->buf_id = -i - 2;
    }

在使用 local buffer 时,需要做一个转换,比如下面的 MarkLocalBufferDirty() 函数,如下:
void
MarkLocalBufferDirty(Buffer buffer)
{
    int bufid;
    Assert(buffer < 0);
    bufid = -(buffer + 1);
}

local buffer 的使用方式:
外部代码调用 LocalBufferAlloc() 函数,如下:
LocalBufferAlloc()
    InitLocalBuffers() 如果没有初始化,则调用一次进行初始化。
    GetLocalBufferStorage() 申请本地 buffer 内存

GetLocalBufferStorage() 函数一次会申请多个 block 块,但只返回一个,下次调用时,如果还有未分配的 block,直接返回 block,直到上一次申请的所有 block 块都用完,才会再次进行本地内存申请。申请的总的 block 数量不能超过 temp_buffers 设置的数量。

LocalBufHash 结构用于 local buffer 的快速查找,主要在 GetLocalBufferStorage() 函数中使用。

文章评论

0条评论