Сразу за заголовком страницы идёт массив указателей строк (line pointers). Каждый указатель - всего 4 байта и описывает одну строку: где она лежит (смещение), сколько занимает (длина) и в каком она состоянии (флаг). Раскладку страницы целиком разбирает page-layout.
Указатель нужен, чтобы у строки был стабильный адрес. Адрес строки
внутри таблицы - это пара «номер страницы, номер указателя», она же
ctid. Когда страница уплотняется и кортеж физически переезжает,
меняется только смещение внутри указателя. Номер указателя, а значит и
ctid, остаётся прежним. Без этого слоя любое движение строки ломало бы
ссылки на неё.
Четыре состояния указателя
Флаг lp_flags (2 бита) говорит, что за указателем стоит:
| lp_flags | Имя | Смысл |
|---|---|---|
| 0 | LP_UNUSED | слот свободен, можно переиспользовать |
| 1 | LP_NORMAL | ведёт на нормальный кортеж |
| 2 | LP_REDIRECT | ведёт на другой указатель (звено HOT-цепочки) |
| 3 | LP_DEAD | строка мертва, место под кортеж уже освобождено |
Посмотреть флаги всех строк на странице:
SELECT lp, lp_off, lp_len, lp_flags
FROM heap_page_items(get_raw_page('flights', 0));-- lp | lp_off | lp_len | lp_flags
-- ----+--------+--------+----------
-- 1 | 8144 | 48 | 1
-- 2 | 8096 | 48 | 1
lp_flags = 1 (LP_NORMAL) - обычная живая строка. lp_off - смещение
кортежа от начала страницы, lp_len - его длина в байтах. Указатели
лежат по возрастанию (1, 2, 3 ...), а смещения lp_off убывают: кортежи
заполняют страницу с конца.
Redirect и dead - следы очистки
Два «странных» состояния появляются после обновлений и очистки.
LP_REDIRECT возникает при внутристраничной очистке HOT-цепочки. Когда
старая версия строки удаляется, но на её указатель ещё ссылаются, указатель
превращают в перенаправление: он не хранит кортеж, а отправляет к началу
живой цепочки версий. lp_len у такого указателя равен 0.
LP_DEAD помечает указатель, чья строка уже не видна ни одной транзакции. Место под сам кортеж может быть уже освобождено, а указатель ждёт, когда его переведут в UNUSED. Это промежуточное состояние между «живой» и «полностью свободный».
Зачем это знать
Когда в heap_page_items встречаются нули в lp_len или флаги 2 и 3 -
это не мусор, а рабочая механика. Redirect-указатели объясняют, почему
обновление строки иногда не трогает индекс. Dead-указатели показывают, что
вакуум уже прошёлся по странице. Без этого слоя не понять ни HOT, ни то,
как ctid остаётся валидным, пока строка ездит по странице.