kb/buffers-wal
Буферный кеш, его состояния и вытеснение, буферное кольцо для seq scan, журнал предзаписи WAL, LSN, full-page images, контрольные точки и восстановление после сбоя.
При первом изменении страницы после контрольной точки PostgreSQL пишет в журнал не дельту, а всю страницу целиком (FPI) - чтобы при восстановлении починить «рваную» страницу после сбоя. Каждая WAL-запись защищена CRC; битая запись считается концом журнала.
WAL - последовательный журнал изменений. Правило write-ahead: запись об изменении попадает на диск раньше самой страницы данных, поэтому сбой не теряет подтверждённые данные. LSN - смещение в потоке журнала. COMMIT при synchronous_commit=on ждёт сброса журнала на диск.
Большой последовательный скан или VACUUM не используют весь кеш, а крутят данные через маленькое буферное кольцо в несколько сотен КБ - иначе один отчёт вымыл бы весь кеш. Кольцо включается, когда таблица больше четверти shared_buffers.
Буферный кеш - разделяемая память (shared_buffers), нарезанная на буферы по 8 КБ. Все бэкенды работают с одним кешем. Когда место кончается, буфер выселяется по приближённому алгоритму clock-sweep (счётчик usage_count), а не по честному LRU.
Контрольная точка сбрасывает все грязные буферы на диск и фиксирует redo point - позицию журнала, с которой начнётся восстановление. Crash recovery проигрывает WAL от redo point вперёд; незакоммиченные транзакции откатываются через clog. Запускается по checkpoint_timeout / max_wal_size.
wal_level задаёт детальность журнала: minimal (только crash recovery), replica (по умолчанию: репликация, архивация, PITR), logical (плюс логическое декодирование). Уровни вложены, смена требует перезапуска. Заглянуть в WAL можно через pg_walinspect и pg_waldump.
Любое обращение к данным сводится к одному из четырёх исходов: hit (страница в кеше), read (промах, чтение с диска), dirtied (изменён в памяти), written (сброшен на диск). Соотношение hit к read показывает эффективность кеша; в PG16 их детально считает pg_stat_io.