Осиротевшие файлы данных OrioleDB
OrioleDB хранит данные таблиц и индексов в директории orioledb_data внутри директории данных PostgreSQL (а также в табличных пространствах). При нормальной работе каждый файл в данном дереве соответствует отношению в pg_class. Осиротевший файл — это файл, не имеющий соответствующей записи в каталоге: данные на диске пережили метаданные отношения.
Это может произойти при внезапном завершении работы бекэнда при открытой транзакции. Например, если бекэнд создает таблицу OrioleDB внутри транзакции и завершается принудительно до COMMIT, PostgreSQL откатывает изменения каталога, но файлы данных, уже записанные в orioledb_data, остаются на диске.
Расширение OrioleDB версии 1.8 добавляет SQL-функции для безопасного перечисления, карантина и удаления таких файлов. Все они требуют прав суперпользователя.
Функции
orioledb_list_orphaned(older_than interval DEFAULT NULL)
Сканирует orioledb_data для текущей базы данных (включая данные OrioleDB в табличных пространствах) и возвращает одну строку на каждый осиротевший файл.
| Столбец | Тип | Описание |
|---|---|---|
dbname | text | Имя сканируемой базы данных |
path | text | Директория, содержащая файл |
name | text | Имя файла |
size | bigint | Размер файла в байтах |
mod_time | timestamptz | Время последнего изменения |
relfilenode | bigint | Разрешенный relfilenode из имени файла |
reloid | bigint | Всегда 0 для осиротевших файлов |
older | bool | true, если mod_time находится до порога возраста или совпадает с ним |
Необязательный аргумент older_than устанавливает порог возраста для столбца older. При опускании по умолчанию составляет 24 часа.
-- Перечислить все осиротевшие файлы
SELECT * FROM orioledb_list_orphaned();
-- Перечислить осиротевшие файлы и отметить те, которым более одного часа
SELECT * FROM orioledb_list_orphaned('1 hour');
orioledb_move_orphaned(older_than interval DEFAULT NULL)
Перемещает осиротевшие файлы в директорию резервного копирования под $PGDATA/orioledb_orphaned_backup/<database_oid>/, сохраняя исходную структуру директорий (пути orioledb_data/... и pg_tblspc/...). Возвращает количество перемещенных файлов.
Перемещаются только файлы, mod_time которых находится до порога возраста или совпадает с ним. При опускании older_than порог по умолчанию составляет 24 часа. Использовать '0 seconds' для перемещения каждого осиротевшего файла независимо от возраста.
-- Переместить осиротевшие файлы старше 24 часов (по умолчанию)
SELECT orioledb_move_orphaned();
-- Переместить все осиротевшие файлы немедленно
SELECT orioledb_move_orphaned('0 seconds');
Если директория резервного копирования уже существует и не пуста, функция завершается с ошибкой и подсказкой проверить оставшиеся файлы с помощью orioledb_list_orphaned_moved(), при необходимости восстановить их через orioledb_move_back_orphaned(), а затем вызвать orioledb_remove_moved_orphaned().
orioledb_list_orphaned_moved()
Перечисляет файлы, в настоящее время хранящиеся в директории резервного копирования. Столбцы результата совпадают с orioledb_list_orphaned(), за исключением отсутствия столбца older.
SELECT * FROM orioledb_list_orphaned_moved();
orioledb_move_back_orphaned()
Восстанавливает все файлы из директории резервного копирования в исходные расположения под orioledb_data. Возвращает количество восстановленных файлов. Если директория резервного копирования отсутствует, возвращается 0.
SELECT orioledb_move_back_orphaned();
orioledb_remove_moved_orphaned()
Безвозвратно удаляет директорию резервного копирования для текущей базы данных (orioledb_orphaned_backup/<database_oid>/). Если директория верхнего уровня orioledb_orphaned_backup становится пустой, она также удаляется.
SELECT orioledb_remove_moved_orphaned();
Вызывать данную функцию только после подтверждения, что перемещенные файлы можно безопасно отбросить.
Операционный рабочий процесс
Типичный процесс очистки:
-
Инспекция — обзор того, что будет затронуто:
SELECT relfilenode, name, size, mod_time, olderFROM orioledb_list_orphaned('1 day')ORDER BY mod_time; -
Карантин — перемещение старых осиротевших файлов из активной директории данных:
SELECT orioledb_move_orphaned('1 day'); -
Верификация — подтверждение, что в активном дереве ничего не осталось:
SELECT count(*) FROM orioledb_list_orphaned(); -
Удаление или восстановление — либо удаление резервной копии, либо возврат файлов:
-- Для безвозвратного удаления карантинных файлов:SELECT orioledb_remove_moved_orphaned();-- Для отмены перемещения:SELECT orioledb_move_back_orphaned();SELECT orioledb_remove_moved_orphaned();
Как работает обнаружение осиротевших файлов
Сканер обходит все обычные файлы под orioledb_data/<database_oid>/ и pg_tblspc/<tablespace_oid>/<version>/orioledb_data/<database_oid>/. Для каждого файла извлекается relfilenode согласно соглашениям именования файлов OrioleDB, затем выполняется поиск соответствующего отношения в pg_class с использованием грязного снимка (чтобы записи каталога в процессе были видимы).
Файл рассматривается как осиротевший, если отсутствует соответствующая запись в pg_class, за одним исключением: пустые базовые файлы (имена файлов без суффикса . или -), измененные после времени последней контрольной точки, записанной в pg_control, пропускаются. Они могут относиться к отношению, которое еще создается.
Структура директории резервного копирования
Перемещенные файлы хранятся под:
$PGDATA/orioledb_orphaned_backup/<database_oid>/
orioledb_data/<database_oid>/...
pg_tblspc/<tablespace_oid>/<version>/orioledb_data/<database_oid>/...
Данная структура зеркально повторяет пути активных данных, чтобы orioledb_move_back_orphaned() могла восстановить файлы в исходные расположения простым переименованием.
Пример: осиротевшие файлы после принудительного завершения бекэнда
BEGIN;
CREATE TABLE o_example (id int PRIMARY KEY) USING orioledb;
INSERT INTO o_example VALUES (1);
-- Бекэнд принудительно завершен здесь (например, SIGKILL) до COMMIT
После восстановления PostgreSQL таблица больше не отображается в pg_class, но ее файлы данных остаются:
SELECT relfilenode, reloid
FROM orioledb_list_orphaned('0 seconds');
relfilenode | reloid
-------------+--------
16384 | 0
16385 | 0
Очистка:
SELECT orioledb_move_orphaned('0 seconds'); -- возвращает количество перемещенных файлов
SELECT orioledb_remove_moved_orphaned();
Ограничения и предостережения
- Все функции работы с осиротевшими файлами требуют доступа суперпользователя.
EXECUTEотозвано уPUBLIC. - Функции работают только с текущей базой данных (
MyDatabaseId). orioledb_move_orphaned()используетrename()— источник и резервная копия должны находиться в одной файловой системе.- Проверить вывод списка перед перемещением или удалением файлов. Хотя истинные осиротевшие файлы не имеют записи в каталоге, всегда подтверждать, что файлы не нужны, перед вызовом
orioledb_remove_moved_orphaned(). - Фильтр возраста по умолчанию в 24 часа в
orioledb_move_orphaned()предотвращает перемещение файлов, которые могут быть частью операции в процессе или недавно прерванной операции. Явный интервал, такой как'0 seconds', использовать только при уверенности в безопасности немедленной очистки.