Перейти к основному содержимому

Осиротевшие файлы данных 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 в табличных пространствах) и возвращает одну строку на каждый осиротевший файл.

СтолбецТипОписание
dbnametextИмя сканируемой базы данных
pathtextДиректория, содержащая файл
nametextИмя файла
sizebigintРазмер файла в байтах
mod_timetimestamptzВремя последнего изменения
relfilenodebigintРазрешенный relfilenode из имени файла
reloidbigintВсегда 0 для осиротевших файлов
olderbooltrue, если 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();

Вызывать данную функцию только после подтверждения, что перемещенные файлы можно безопасно отбросить.

Операционный рабочий процесс​

Типичный процесс очистки:

  1. Инспекция — обзор того, что будет затронуто:

    SELECT relfilenode, name, size, mod_time, older
    FROM orioledb_list_orphaned('1 day')
    ORDER BY mod_time;
  2. Карантин — перемещение старых осиротевших файлов из активной директории данных:

    SELECT orioledb_move_orphaned('1 day');
  3. Верификация — подтверждение, что в активном дереве ничего не осталось:

    SELECT count(*) FROM orioledb_list_orphaned();
  4. Удаление или восстановление — либо удаление резервной копии, либо возврат файлов:

    -- Для безвозвратного удаления карантинных файлов:
    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', использовать только при уверенности в безопасности немедленной очистки.