lesson ── postgres-labs ── ~20 мин ── 4 шагов
Поймай момент, когда чтение меняет страницу. Вставь строку, посмотри на её infomask до и после обычного SELECT. Перед каждым замером предсказывай: стоит ли бит HEAP_XMIN_COMMITTED (значение 256).
интерактивный sandbox
Поднимется контейнер postgreslab/postgres-base с PostgreSQL 17 и psql. В браузере откроется терминал, база lab уже настроена. Каждый шаг проверяется автоматически. Сеть air-gapped, наружу контейнер не ходит.
stack ── PostgreSQL 17 · psql · 1 GB RAM · air-gapped · самоуничтожается через 45 мин простоя
Создай таблицу и вставь строку. Не читай её обычным SELECT - сначала посмотрим на сырую страницу. Число строк проверим через pageinspect, чтобы не запускать обычное сканирование раньше времени.
CREATE TABLE hb (id int);
INSERT INTO hb VALUES (1);
SELECT count(*) FROM heap_page_items(get_raw_page('hb', 0));heap_page_items читает сырые байты и подсказку не ставит - в отличие от обычного SELECT.
✓ Строка на странице. Обычным SELECT её пока не трогали.
Посмотри бит HEAP_XMIN_COMMITTED (значение 256) в infomask. Предскажи: стоит ли он сразу после вставки?
SELECT (t_infomask & 256) FROM heap_page_items(get_raw_page('hb', 0));Подсказку ставит первое чтение строки, а его ещё не было.
✓ Бит равен 0 - подсказки фиксации пока нет.
Теперь выполни обычный SELECT. Он проверяет видимость строки, идёт за статусом в clog и ставит подсказку - а значит, меняет страницу.
SELECT * FROM hb;
✓ Бит стал 256 - обычный SELECT поставил подсказку и изменил страницу.
Выведи infomask в битах и найди выставленные флаги: HEAP_XMIN_COMMITTED (бит со значением 256) и HEAP_XMAX_INVALID (нет удаления).
SELECT t_infomask::bit(16) FROM heap_page_items(get_raw_page('hb', 0));✓ Видны два флага: xmin зафиксирован, xmax недействителен.
Статус транзакции хранится в clog (два бита на транзакцию). Первое обычное чтение строки идёт за статусом в clog и кэширует ответ подсказкой фиксации в t_infomask. Установка подсказки меняет страницу - поэтому SELECT может вызвать запись.
команды
SELECT (t_infomask & 256) FROM heap_page_items(get_raw_page('t',0));бит HEAP_XMIN_COMMITTEDSELECT t_infomask::bit(16) FROM heap_page_items(get_raw_page('t',0));все флаги infomaskконцепции