/*!
\page oess_1__dat_file_struct	oess_1: Физическая структура основного файла данных oess_1::db 

\section oess_1__data_file_struct__common_struct	Общая структура

Основной файл данных oess_1::db разделен на страницы одинакового размера.
Размер страницы определяется параметром
oess_1::db::storage::hard_config_t::m_page_size. Размер страницы должен
быть от 16 байт до 64Kb.
 
Страницы делятся на блоки одинакового размера. Размер блока определяется
параметром oess_1::db::storage::hard_config_t::m_chain_link_size. Размер
блока должен быть не меньше 8 байт и не больше размера страницы. На
странице должно размещаться целое количество блоков, без остатка.

Для всех страниц используется сквозная нумерация блоков. Первый блок на
первой странице имеет индекс 0, первый блок на второй странице имеет
индекс (размер страницы/размер блока).

Информация в БД сохраняется в блоках. Т.е., если объем сохраняемых данных
меньше, чем размер блока, то для их хранения все равно будет выделен
один блок. Если размер блока меньше, чем размер сохраняемых данных,
то будет выделено несколько блоков и эти блоки будут специальным образом
прописаны в цепочку.

Часть страниц хранилища выполняют специальные функции -- являются
заголовками логических частей. Блоки, номера которых соответствуют этим
страницам, для сохранения данных не используются.

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

\section oess_1__dat_file_struct__file_header	Структура заголовка файла

Заголовок файла можно описать следующей структурой:
\code
struct	file_header_t
	{
		// Количество областей, в которых есть свободные блоки.
		oess_1::ushort_t	m_free_area_count;
		// Номера областей, в которых есть свободные блоки.
		oess_1::db::storage::area_ordinal_t	m_free_areas[ m_free_area_count ];
	};
\endcode

Первоначально, в пустом файле данных, в file_header_t::m_free_areas
находятся номера всех областей файла. После того, как в какой-либо области
свободные блоки заканчиваются, номер этой области из m_free_areas
изымается. Если в какую-то область возвращается свободный блок, а до
этого в области свободных блоков не было, то номер области возвращается
в m_free_areas.

Номера областей хранятся в m_free_areas упорядоченными по возрастанию
номеров.

Размер m_free_areas определяется размером страницы. Т.е. в файле данных
не может быть больше, чем (размер страницы/sizeof(oess_1::ushort_t) - 1).
Если в файле физически не может разместиться столько областей, сколько их
можно описать в m_free_areas, то часть заголовка файла оказывается
неиспользуемой.

\section oess_1__dat_file_struct__area_header	Структура области и заголовка области

Область -- это страница заголовка области за которым следует некоторое
количество логических сегментов. Размер области в сегменах зависит от того,
сколько описателей сегменов поместиться в заголовке области, что зависит от
размера страницы. Последняя область файла может содержать меньшее количество
сегментов, если полное количество сегментов не получается разместить из-за
ограничений на размер файла.

Заголовок области можно описать следующей структурой:
\code
struct	area_header_t
	{
		// Количество сегментов, в которых есть свободные блоки.
		oess_1::ushort_t	m_free_segment_count;
		// Номера сегментов, в которых есть свободные блоки.
		oess_1::db::storage::segment_ordinal_t	m_free_segments[ m_free_segment_count ];
	};
\endcode

Первоначально, в пустой области, в area_header_t::m_free_segments находятся
номера всех сегментов области. После того, как в каком-либо сегменте свободные
блоки заканчиваются, номер этого сегмента из m_free_segments изымается. Если в
какой-то сегмент возвращается свободный блок, а до этого в сегменте свободных
блоков не было, то номер сегмента возвращается в m_free_segments.

В m_free_segments хранятся относительные номера сегментов. Т.е. номера
сегментов уникальны только в рамках одной области. Для полной идентификации
сегмента нужно знать порядковый номер области, которой он принадлежит и
порядковый номер сегмента в области.

Номера сегментов хранятся в m_free_segments упорядоченными по возрастанию
номеров.

Количество сегментов, которые могут входить в область определяется размером
страницы: (размер страницы/sizeof(oess_1::ushort_t) - 1).

\section oess_1__dat_file_struct__segment_header	Структура сегмента и заголовка сегмента

Сегмент -- это страница заголовка сегмента, за которым следуют страницы данных,
относящиеся к этому сегменту.

Заголовок сегмента можно описать следующими структурами:
\code
struct	block_info_t
	{
		// Собственный идентификатор блока.
		oess_1::uint_t	m_self_id;
		// Идентификатор следующего блока в цепочке.
		oess_1::uint_t	m_next;
	};

struct	segment_header_t
	{
		// Количество свободных блоков в сегменте.
		oess_1::uint_t	m_free_blocks_count;
		// Количество занятых блоков в сегменте.
		oess_1::uint_t	m_used_blocks_count;

		// Описатели свободных блоков.
		block_info_t	m_free_blocks[ m_free_blocks_count ];
		// Описатели занятых блоков.
		block_info_t	m_used_blocks[ m_used_blocks_count ];
	};
\endcode

Размер сегмента зависит от размера страницы:
(размер страницы/sizeof(block_info_t)). В число страниц сегмента так же
входит и заголовок сегмента. Т.е. реально, в сегменте находится одна
страница заголовка + (размер сегмента - 1) страниц данных.
Т.к. часть блоков, которая попадает на страницу заголовка сегмента, не
может быть использована, то часть segment_header_t не используется.

Для пустого сегмента segment_header_t::m_free_blocks_count содержит
общее количество блоков данных сегмента, а в m_free_blocks находятся
описатели этих блоков. При выделении блока под данные, его описатель
перемещается из m_free_blocks в m_used_blocks. Т.о. в полностью занятом
сегменте описатели всех блоков находятся в m_used_blocks.

Для свободных блоков block_info_t::m_next всегда содержит значение
oess_1::db::storage_t::invalid_chain_id. Для занятых блоков
block_info_t::m_next содержит идентификатор следующего блока цепочки
или oess_1::db::storage_t::invalid_chain_id, если блок является последним
блоком цепочки.

\section oess_1__dat_file_struct__allocation_algorithm	Алгоритм распределения блоков

При необходимости сохранения в файле данных какой-либо сущности в файле
данных должна быть создана цепочка блоков достаточной для сохранения
сущности емкости. Для этого последовательно выделяются блоки, в каждый
блок сохраняется очередная часть сущности. Если требуется выделение еще
одного блока, то он выделяется и ссылка на него помещается в
block_info_t::m_next предыдущего блока.

Алгоритм выделения блоков следующий:
- запросить у заголовка файла номер области, в которой есть свободные блоки;
- запросить у заголовка области номер сегмента, у которого есть свободные
блоки;
- указать заголовку этого сегмента выделить блок. В заголовке этого сегмента
описатель выделенного блока перемещается из m_free_blocks в
m_used_blocks;
- если в сегменте больше не осталось свободных блоков, то данный сегмент
вычеркивается из заголовка области;
- если в области больше не осталось свободных сегментов, то данная область
вычеркивается из заголовка файла.

Этот алгоритм позволяет:
- сразу обращаться к сегментам, у которых есть свободные блоки;
- блоки выделяются в порядке увеличения их номеров. Т.е. при записи или
чтении всей цепочки блоков будет производиться однократный проход по
файлу данных в прямом направлении.

*/
