Выделение пространства в Firebird 2.1 и выше
Vlad Khorsun, 20-OCT-2010
С самого начала в Firebird не было правил относительно того, как выделять дисковое пространство для файла(ов) базы данных. Он просто записывает вновь выделенные страницы в неопределённом порядке (из-за зависимостей между страницами для реализации стратегии «осторожной записи»).
Такой подход очень прост, но имеет некоторые недостатки:
• из-за неопределённого порядка записи может возникнуть ситуация, когда кэш страниц содержит много «грязных» страниц в момент, когда необходимо записать вновь выделенную страницу, но это невозможно из-за нехватки дискового пространства. В таких случаях часто теряются все остальные «грязные» страницы, поскольку администраторы предпочитают завершить работу базы данных до того, как освободят место на диске. Это приводит к серьёзным повреждениям.
• выделение дискового пространства относительно небольшими фрагментами может привести к значительной фрагментации файла на уровне файловой системы и снизить производительность при больших сканированиях (например, во время резервного копирования).
Используя новый ODS 11.1, Firebird изменяет свой алгоритм выделения дискового пространства, чтобы избежать повреждений при нехватке дискового пространства и дать файловой системе шанс избежать фрагментации. Эти изменения описаны ниже.
a) Каждая вновь выделенная страница немедленно записывается на диск до возврата управления движку. Если страница не может быть записана, то выделение не происходит, бит PIP не сбрасывается и возникает соответствующая ошибка ввода/вывода. Эта ошибка не может привести к повреждениям, поскольку у нас есть гарантия, что все «грязные» страницы в кэше имеют выделенное дисковое пространство и могут быть безопасно записаны.
Это изменение приводит к одному дополнительному обращению к записи для каждой вновь выделенной страницы по сравнению со старым поведением. Таким образом, ожидается снижение производительности во время роста файла базы данных. Чтобы уменьшить это снижение, Firebird группирует записи вновь выделенных страниц порциями до 128 КБ за раз и отслеживает количество «инициализированных» страниц в заголовке PIP.
Примечание: вновь выделенная страница будет записана на диск дважды только в том случае, если эта страница выделяется впервые. Т.е. если страница была выделена, освобождена и выделена снова, она не будет записана дважды при втором выделении.
b) Чтобы избежать фрагментации файла, Firebird использует соответствующий API файловой системы для предварительного выделения дискового пространства относительно большими фрагментами. В настоящее время такой API существует только в Windows, но недавно он был добавлен в API Linux и в будущем может быть реализован в таких популярных файловых системах, как ext2 и других. Поэтому эта функция в настоящее время реализована только в сборках Firebird для Windows и может быть реализована в сборках для Linux в будущем.
Для лучшего контроля над предварительным выделением дискового пространства в Firebird.conf была добавлена новая настройка: DatabaseGrowthIncrement. Это верхняя граница размера фрагмента предварительного выделения в байтах. Значение по умолчанию - 128 МБ. Когда движку требуется больше дискового пространства, он выделяет 1/16 от уже выделенного пространства, но не менее 128 КБ и не более значения DatabaseGrowthIncrement. Если DatabaseGrowthIncrement установлен в ноль, то предварительное выделение отключается. Пространство для теневых файлов базы данных не предварительно выделяется.
Также предварительное выделение отключается, если для базы данных установлена опция «No reserve».
Примечание: предварительное выделение также позволяет избежать повреждений в условиях нехватки дискового пространства - в таком случае есть большая вероятность, что база данных имеет достаточно предварительно выделенного пространства для работы, пока администратор не освободит немного дискового пространства.
Автор: Vlad Khorsun,