(checkpointer, bgwriter, walwriter, ...); • и в т.ч. autovacuum launcher; • вообще там много всего… AV Launcher будет перезапущен, если что-то пойдет не так.
autovacuum_freeze_max_age. Риск wraparound с самым старым datfrozenxid/datminmxid. Базы, которые давно не посещал вакуум. Пропускаем базы, обработанные недавно.
статистики и параметров таблиц (pg_class.reloptions); • запуск relation_needs_vacanalyze() – vaccum, analyze или wraparound? • таблица является временной (pg_class.relpersistence)? Для TOAST запоминаем ассоциацию с родительской таблицей.
старше должны быть заморожены. vacuum_freeze_table_age – полное сканирование, если достигнут возраст. autovacuum_freeze_max_age – возраст принудительного запуска wraparound-вакуума.
(или все вместе). Определение пороговых параметров: • параметры reloptions (от основной или TOAST-таблицы); • параметры конфигурации (postgresql.conf); • для freeze_max_age выбираем минимум (reloptions vs. postgresql.conf);
• xidForceLimit = recentXid – freeze_max_age; • multiForceLimit = recentMulti – multixact_freeze_max_age; • вакуум обязателен, если pgclass.relfrozenxid или relminmxid старше порогов; • если нет риска wraparound и AV отключен – пропускаем таблицу.
of row updates # before vacuum autovacuum_analyze_threshold = 50 # min number of row updates # before analyze autovacuum_vacuum_scale_factor = 0.2 # fraction of table size # before vacuum autovacuum_analyze_scale_factor = 0.1 # fraction of table size # before analyze
I/O определяется с помощью cost_limit, cost_delay. • autovacuum_vacuum_cost_limit или vacuum_cost_limit; • autovacuum_vacuum_cost_delay или vacuum_cost_delay; Ничего не делать, если параметры не установлены (<= 0).
Обработка таблицы в зависимости от потребности: • vacuum_rel() и analyze_rel(); Завершение обработки: • обновление pg_database.datfrozenxid и чистка pg_clog; • завершение работы.
ShareUpdateExclusiveLock Открываем таблицу и берем блокировку. Не удалось взять блокировку? • autovacuum: пишем в лог "skipping vacuum of %s --- lock not available"; • не удалось открыть (таблица удалена?), завершаем работу.
что объект, вообще vacuumable (таблицы, мат.вью, TOAST). Пропуск временных таблиц других бэкендов. Запоминаем ассоциацию с TOAST (исключение – автовакуум). Переключение userid на владельца таблицы.
--- either FULL or "lazy" vacuum */ VACUUM FULL? • закрываем таблицу, но продолжаем держать блокировку; • cluster_rel() – VACUUM FULL является вариантом CLUSTER; см. cluster.c. В любом другом случае – lazy_vacuum_rel().
multixact_freeze_min_age, multixact_freeze_table_age; • oldestXmin – оценка, когда строка считается DEAD или RECENTLY_DEAD; • freezeLimit – старше этого порога все строки замораживаются; • xidFullScanLimit – полное сканирование таблицы, если relfrozenxid старше порога;
multixact_freeze_min_age, multixact_freeze_table_age; • oldestXmin – оценка, когда строка считается DEAD или RECENTLY_DEAD; • freezeLimit – старше этого порога все строки замораживаются; • xidFullScanLimit – полное сканирование таблицы, если relfrozenxid старше порога; • multiXactCutoff – порог для удаления всех MultiXactIds из Xmax; • mxactFullScanLimit – полное сканирование, если relminmxid старше порога.
multixact_freeze_min_age, multixact_freeze_table_age; • oldestXmin – оценка, когда строка считается DEAD или RECENTLY_DEAD; • freezeLimit – старше этого порога все строки замораживаются; • xidFullScanLimit – полное сканирование таблицы, если relfrozenxid старше порога; • multiXactCutoff – порог для удаления всех MultiXactIds из Xmax; • mxactFullScanLimit – полное сканирование, если relminmxid старше порога. Сравниваем relfrozenxid/relminmxid с пороговыми значениями.
Считаем, вся ли таблица была просканирована: scanned_pages + frozenskipped_pages = rel_pages Если возможно, обрезаем таблицу. Обновляем Free Space Map, pg_class: • relpages, reltuples, relallvisible, relhasindex, refrozenxid/relminmxid (full scan only). Сохраняем статистику в stats коллектор (n_live_tupe, n_dead_tuples). Пишем сообщение в журнал при log_min_duration >= 0. Конец.
память для хранения dead строк (autovacuum_work_mem); Проверяем страницы, которые можно пропустить: • ALL_FROZEN и ALL_VISIBLE флаги (в соотв. с visibility map); • в случае full scan нельзя пропускать ALL_VISIBLE страницы; • всегда пропускаем ALL_FROZEN страницы; • всегда сканируем последний блок – вдруг таблицу можно обрезать. После каждого блока выполняем vacuum_delay_point().
снова ищем следующий блок, который нельзя пропускать; • проверяем хранилище dead строк на предмет переполнения; • читаем содержимое страницы, считаем costs; • пытаемся взять блокировку для чистки блока (для HOT). Блок будет пропущен, если блокировка провалится (искл. full-scan).
• всегда чистим неинициализированные страницы; • пропускаем пустые страницы; • проверяем нормальные страницы; • dead и redirect никогда не нужно морозить; • проверяем, что любое из XID-полей (xmin,xmax,xvac) старше порога.
помечаем как грязные, отмечаем в Free Space Map. Пустые страницы: • ставим отметку ALL_VISIBLE и ALL_FROZEN; • помечаем как грязные, делаем запись в WAL, обновляем VM и FSM.
указатели на предмет HOT-цепочек. • перестраиваем HOT-цепочки (но не вносим никаких изменений в страницу): • чистим dead и битые HOT-цепочки; • перестраиваем редиректы.
указатели; • делаем дефрагментацию. Убираем отметку "page is full", помечаем страницу как грязную, пишем WAL. Завершаем критическую секцию. (Если доступных для чистки цепочек нет, то ничего не делаем)
Проверка указателей: • пропускаем unused, dead, redirects; проверяем только нормальные. HeapTupleSatisfiesVacuum(): • HEAPTUPLE_DEAD: vacuumable (пропускаем, если это HOT-цепочка). • HEAPTUPLE_LIVE: хорошая строка, вакуум не нужен. • HEAPTUPLE_RECENTLY_DEAD: нельзя удалять строку. • HEAPTUPLE_INSERT_IN_PROGRESS и HEAPTUPLE_DELETE_IN_PROGRESS: пропускаем, страница не является ALL_VISIBLE. Запоминаем vacuumable строки в хранилище dead-строк.
если можно морозить (составляем локальный infomask). Если есть строки для заморозки: • открываем критическую секцию; • отмечаем страницу как грязную; • устанавливаем биты в infomask-строки; • пишем изменения в WAL; • завершаем критическую секцию.
строки (vacrelstats) – идем только в те страницы, где есть мертвые строки: • перед началом делаем vacuum_delay_point(); • читаем блок и считаем costs; • пытаемся взять блокировку для очистки – пропускаем блок, если не удалось; • чистим страницу с lazy_vacuum_page(); • обновляем Free Space Map.
изменения в критической секции: • цикл по dead строкам (внутри страницы); • отмечаем указатель ItemID как неиспользуемый (LP_UNUSED); • убираем фрагментацию страницы; • отмечаем страницу как грязную, пишем в WAL. Закрываем критическую секцию. Обновляем Visibility Map.
не оптимальный. Нагрузка регулируется через cost-based опции. Wraparound – не так страшен черт... Вакуум не всегда может вычистить таблицу. Избегайте длинных транзакций.