Обзор менеджера буферов PostgreSQL
В этом подразделе описываются ключевые понятия, необходимые для понимания последующих разделов.
Структура менеджера буферов
Менеджер буферов состоит из буферной таблицы, дескриптера буферов, а также буферного пула, описание которых дано чуть ниже.
Буферный пул хранит таблицы и индексы, а также карты свободного пространства и карты видимости.
Буферный пул представляет собой массив, в котором каждый слот хранит одну страницу файла данных. Индексы массива буферного пула называются buffer_ids.
Подразделы 8.2 и 8.3 подробно описывают составлящие менеджера буферов.
Тег буфера
В PostgreSQL каждой странице файлов данных может быть присвоен уникальный тег или тег буфера. Когда менеджер буферов получает запрос, PostgreSQL использует тег буфера нужной страницы.
Buffer_tag содержит следующую информацию:
- specOid: OID табличного пространства, к которому принадлежит отношение, содержащее целевую страницу;
- dbOid: OID базы данных, к которой принадлежит отношение, содержащее целевую страницу.
- relNumber: Номер файла отношения, содержащего целевую страницу.
- blockNum: Номер блока целевой страницы в отношении.
- forkNum: Номер форка отношения, к которому принадлежит страница. Номера форка таблиц, карт свободного пространства и карт видимости определены как 0, 1 и 2 соответственно.
Buffer_tag:
/*
* Buffer tag identifies which disk block the buffer contains.
*
* Note: the BufferTag data must be sufficient to determine where to write the
* block, without reference to pg_class or pg_tablespace entries. It's
* possible that the backend flushing the buffer doesn't even believe the
* relation is visible yet (its xact may have started before the xact that
* created the rel). The storage manager must be able to cope anyway.
*
* Note: if there's any pad bytes in the struct, InitBufferTag will have
* to be fixed to zero them, since this struct is used as a hash key.
*/
typedef struct buftag
{
Oid spcOid; /* tablespace oid */
Oid dbOid; /* database oid */
RelFileNumber relNumber; /* relation file number */
ForkNumber forkNum; /* fork number */
BlockNumber blockNum; /* blknum relative to begin of reln */
} BufferTag;
Например, buffer_tag '{16821, 16384, 37721, 0, 7}' идентифицирует страницу, которая находится в седьмом блоке таблицы, чьи OID и номер форка равны 37721 и 0 соответственно. Таблица находится в базе данных, чей OID равен 16384, в табличном пространстве, чей OID равен 16821.
Аналогично, buffer_tag '{16821, 16384, 37721, 1, 3}' идентифицирует страницу, находящуюся в третьем блоке карты свободного пространства, чьи OID и номер форка равны 37721 и 1 соответственно.
Как обслуживающий процесс Backend читает страницы
В этом подразделе описывается то, как Backend процесс считывает страницу из буферного менеджера (рис. 86).
- (1) При чтении страницы таблицы или индекса Backend процесс посылает запрос, включающий буферный тег страницы, менеджеру буферов;
- (2) Менеджер буферов возвращает buffer_id слота, в котором хранится запрашиваемая страница. Если запрашиваемой страницы нет в буферном пуле, менеджер буферов загружает страницу из постоянного хранилища в один из слотов буферного пула, а затем возвращает buffer_ID слота:
- (3) Backend процесс получает доступ к слоту buffer_id и может прочитать нужную страницу.
Как только Backend процесс изменяет страницу в буферном пуле (например, вставляет кортежи), измененная страница становится грязной страницей.
Когда все слоты буферного пула заняты, менеджер буфера должен выбрать одну страницу в буферном пуле, которая будет заменена запрошенной страницей. Обычно в компьютерной науке алгоритмы выбора страницы называются алгоритмами замещения страниц, а выбранная страница называется страницей-жертвой.
Исследования алгоритмов замены страниц ведутся с момента появления информатики. Было предложено множество алгоритмов замещения, в PostgreSQL, начиная с версии 8.1, используется алгоритм clock sweep, который гораздо проще и эффективнее, чем алгоритм LRU, использовавшийся в предыдущих версиях.
Подраздел 8.4.4 посвящен данному алгоритму.
Сбрасывание грязных страниц
Грязные страницы в конечном итоге должны быть сброшены в хранилище. Однако для выполнения этой задачи менеджеру буфера требуется помощь. В PostgreSQL за эту задачу отвечают два фоновых процесса, а именно процесс котрольной точки (checkpointer) и процесс фоновой записи (background writer).
Подробное описание этих двух процессов Вы найдете в подразделе 8.6.
Примечание: Прямой ввод/вывод
PostgreSQL версии 15 и более ранние версии не поддерживают функцию прямого ввода/вывода, хотя разработчики уже давно хотели внедрить ее (предпосылки ее появления в PostgreSQL подробно описаны в данных статьях: статья 1 и статья 2).
В версии 16 появилась опция debug-io-direct ,предназначенная для разработчиков. Благодаря ей можно существенно улучшить использование прямого ввода-вывода в PostgreSQL.




