Подсистема SO SysConf 2

Введение

Основная схема работы sysconf

Использование конфигурационного файла

Формат конфигурационного файла

Пример конфигурационного файла

Завершение работы SObjectizer и sysconf

Определение состояния sysconf

Введение

Подсистема SO SysConf 2 (сокращенно sysconf) предназначена для того, чтобы состав запущеного SObjectizer-приложения можно было формировать в динамике. Под составом понимаются dll-модули, загруженные процессом, и кооперации, которые могут быть зарегистрированы приложением.

Необходимость в подсистеме sysconf возникла из-за того, что одни и те же функции в разных случаях должны выполняться с помощью различных средств. Например, для установления SSL соединения можно использовать OpenSSL, GnuTLS или какую-либо коммерческую библиотеку. Для идентификации пользователя нужно либо спросить пароль, либо предложить составить изображение из предложенных фрагментов. Отправку уведомлений можно осуществлять либо через e-mail, либо через SMS. И т.д.

Если в приложении необходимо поддерживать несколько альтернативных возможностей, то возникает вопрос о том, как это сделать. Наиболее простой вариант заключается в том, чтобы на этапе трансляции и линковки исполнительного модуля собрать в единое приложение все необходимые библиотеки (как статические, так и динамические). Но этот способ имеет два важных недостатка:

Более сложный вариант состоит в том, чтобы разделить интерфейс и реализацию какой-либо функций на уровне используемых DLL-библиотек. Например, сделать интерфейс по поддержке SSL-соединений общим для различных реализаций. А сами реализации для OpenSSL и GnuTLS вынести в отдельные DLL. При этом исполнимый модуль не линкуется к реализациям вообще. Вместо этого при своем старте исполнимый модуль определяет, какую реализацию ему нужно использовать в конкретном случае (предположим, по конфигурационному файлу) и самостоятельно, вручную, загружает соответствующую DLL. Как только DLL с реализацией SSL-соединения окажется загруженной, конкретная реализация должна автоматически стать доступной для исполнимого модуля.

При реализации варианта с ручной загрузкой DLL так же существуют сложности. В основном, технического характера. Часть из них преодолевается достаточно просто (например, наличие различных API для работы с DLL в различных операционных системах). Наибольшую сложность вызывает, как правило, то, что после загрузки DLL реализация какой-либо функции должна стать доступной исполнимому модулю. Обычно это достигается использованием какой-либо таблицей доступных реализаций в исполнимом модуле. DLL либо сами прописывают себя в эту таблицу при загрузке (для чего могут использоваться либо глобальные переменные, либо точки входа/выхода в DLL). Либо исполнимый модуль сам определяет адрес какой-то интерфейсной функции в загруженной DLL.

В случае с SObjectizer разделение на интерфейс и реализацию осуществляется созданием одного агента (иногда глобального), который служит только владельцем сообщений. Фактически интерфейсом. Для реализации функции создаются агенты, которые подписываются и рассылают сообщения агента-интерфейса. Агенты-реализации должны быть зарегистрированны в SObjectizer run-time. Для этого они должны входить в конкретную кооперацию с уникальным именем.

Sysconf использует это разделение для того, чтобы разместить различные кооперации-реализация в различные DLL. Управление загрузкой/выгрузкой DLL и регистрацией/дерегистрацией находящихся в DLL коопереаций является задачей sysconf.

Основная схема работы sysconf

Для использования sysconf нужно зарегистрировать кооперацию sysconf в уже работающем SObjectizer run-time. Для чего используется so_sysconf_2::register_coop(). После этого подсистема sysconf работает до завершения SObjectizer run-time.

Основным интерфейсным агентом подсистемы sysconf является глобальный агент типа so_sysconf_2::a_sysconf_t, имеющий имя so_sysconf_2::a_sysconf_t::agent_name(). Осуществляя широковещательную рассылку сообщений этого агента можно загружать/выгружать DLL библиотеки, регистрировать и дерегистрировать находящиеся в них кооперации.

Предназначенные для использования с sysconf DLL-библиотеки должны содержать в себе по одной глобальной переменной на каждую из находящихся в DLL коопераций. Эта переменная должна принадлежать к типу, производному от so_sysconf_2::coop_handler_t. Т.е. на этапе разработки DLL необходимо определить, какие кооперации будут находиться в этой DLL. Поскольку в текущей версии sysconf нельзя в динамике изменить состав доступных sysconf коопераций в DLL.

Когда sysconf получает команду на загрузку DLL, указанная DLL загружается в ОП. При этом запускаются конструкторы глобальных переменных coop_handler. Конструктор базового класса so_sysconf_2::coop_handler_t информирует sysconf о появлении очередной доступной кооперации. Т.о. подсистема sysconf формирует список загруженных DLL и доступных коопераций.

Все кооперации во всех DLL должны иметь уникальные имена.

Для идентификации DLL sysconf требует, чтобы каждой DLL так же был назначен уникальный идентификатор. Он необходим для того, чтобы не использовать в качестве идентификатора имя файла DLL (т.к. имена файлов DLL сильно зависят от операционной системы). При загрузке DLL идентификатор указывается в команде загрузки. Глобальные же переменные coop_handler в DLL должны уже знать идентификатор DLL. Т.е. идентификатор DLL должен быть определен на этапе разработки DLL.

Для регистрации/дерегистрации кооперации подсистеме sysconf выдаются специальные команды. Если регистрация кооперации прошла успешно, то sysconf увеличивает счетчик ссылок на DLL. Sysconf не позволяет выгрузить DLL с ненулевым счетчиком ссылок. При дерегистрации кооперации счетчик ссылок уменьшается.

Особенность регистрации/дерегистрации кооперации.
При регистрации кооперации происходит вызов so_sysconf_2::coop_handler_t::reg(). Если этот метод возращает true, то кооперация считается зарегистрированной и счетчик ссылок на DLL увеличивается. Подразумевается, что метод so_sysconf_2::coop_handler_t::reg() обращается к so_4::api::register_coop() и возврат из register_coop() осуществляется только тогда, когда кооперация реально зарегистрирована. При дерегистрации кооперации происходит вызов so_sysconf_2::coop_handler_t::dereg(). Но возврат из этого метода еще не означает, что кооперация окончательно дерегистрирована. Момент окончания дерегистрации определяется по сообщению so_4::rt::msg_coop_deregistered. И только после этого счетчик ссылок на DLL уменьшается.
Особенности регистрации/дерегистрации необходимо учитывать при создании DLL с т.н. "псевдо-кооперациями". Т.е. когда sysconf используется только для загрузки произвольных DLL. Если в такой DLL создать coop_handler, который не регистрирует реальной SObjectizer-кооперации, но в методе reg() возвращает true, то sysconf не сможет выгрузить DLL. Т.к. для этой кооперации не будет получено сообщение so_4::rt::msg_coop_deregistered. Поэтому, использовать sysconf для загрузки произвольных DLL, не содержащих реальных коопераций можно. Но в таких DLL нельзя описывать coop_handler-ы для "псевдо-коопераций" и выдавать команды на регистрацию "псевдо-коопераций".

Использование конфигурационного файла

Управлять подсистемой sysconf с помощью сообщений агента so_sysconf_2::a_sysconf_t достаточно сложно. Из-за того, что команды и результаты команд передаются асинхронными сообщениями. К тому же, в большинстве случаев, нужно в начале работы по конфигурационному файлу определить, из чего будет состоять приложение, один раз загрузить все необходимые DLL и начать работу.

Для облегчения этой задачи sysconf поддерживает работу с конфигурационными файлами специального формата. Функция so_sysconf_2::run_script() запускает на обработку указанный конфигурационный файл.

Формат конфигурационного файла

{sysconf-script
	[{load-dll <str-dll-file-name>
		{alias <str-dll-alias> }
	}]*

	[{reg-coop <str-coop-name>
		[{cfg-file <coop-cfg-file-name> }]
	}]*

	[{make-coop
		{factory <str-factory-name>}
		{coop <str-coop-name>}
		[{cfg-file <str-coop-cfg-file-name>}]
	}]*
}

Подробнее о make-coop см. Новое в версии 2.1.0.

Пример конфигурационного файла

Вот пример реального конфигурационного файла для подсистемы sysconf.
||
|| Скрипт начальной инициализации AGGREGATE
||
{sysconf-script
	|#
		Загрузка и инициализация подсистемы сохранения
		истории отправленных SMS в CURL-подобных файлах.
	#|
	{load-dll	"smsg_2.3.0.subsys.sms_hist_cls.dll"
		{alias	"smsg_2::subsys::sms_hist_cls"}
	}
	{reg-coop	"smsg_2::subsys::sms_hist_cls"
		{cfg-file	"etc/safe_sms_history.cfg"}
	}

	|#
		Загрузка подсистемы мобильного оператора БиЛайн.
		Содержит кооперации:
			smsg_2::subsys::bee_line::moscow
			smsg_2::subsys::bee_line::region
	#|
	{load-dll	"smsg.subsys.bee_line.2.3.0.dll"
		{alias	"smsg_2::subsys::bee_line"}
	}
	|| Инициализация Московского SMSC БиЛайна.
	{reg-coop	"smsg_2::subsys::bee_line::moscow"
		{cfg-file	"etc/bee_line/moscow.cfg"}
	}
	|| Инициализация регионального SMSC БиЛайна.
	{reg-coop	"smsg_2::subsys::bee_line::region"
		{cfg-file	"etc/bee_line/region.cfg"}
	}

	|#
		Загрузка подсистемы мобильного оператора МТС.
		Содержит кооперации:
			smsg_2::subsys::mts::moscow
	#|
	{load-dll	"smsg.subsys.mts.2.3.0.dll"
		{alias	"smsg_2::subsys::mts"}
	}
	|| Инициализация Московского SMSC МТС.
	{reg-coop	"smsg_2::subsys::mts::moscow"
		{cfg-file	"etc/mts/moscow.cfg"}
	}

	|#
		Загрузка подсистемы мобильного оператора Мегафон.
		Содержит кооперации:
			smsg_2::subsys::megafon::moscow
	#|
	{load-dll	"smsg.subsys.megafon.2.3.0.dll"
		{alias	"smsg_2::subsys::megafon"}
	}
	|| Инициализация Московского SMSC Соник Доу.
	{reg-coop	"smsg_2::subsys::megafon::moscow"
		{cfg-file	"etc/megafon/moscow.cfg"}
	}

	|#
		Загрузка подсистемы AGGREGATE.
		Содержит кооперации:
			aggregate_1::main::main
	#|
	{load-dll	"aggregate.main.1.3.dll"
		{alias	"aggregate_1::main"}
	}
	|| Инициализация AGGREGATE.
	{reg-coop	"aggregate_1::main::main"
		{cfg-file	"etc/aggregate/main.cfg"}
	}

	|#
		Имитация SMSC
	#|
|| В данный момент не используется.
|#
	{load-dll	"test_smsc_imit.dll"
		{alias	"smsc_imit"}
	}
	{reg-coop	"smsc_imit::bee_line_moscow"
	}
#|
}

Завершение работы SObjectizer и sysconf

При использовании sysconf можно завершать работу SObjectizer как отсылкой сообщений so_4::rt::msg_normal_shutdown, so_4::rt::msg_alarm_shutdown, так и обращением к so_4::api::shutdown(). Но sysconf предоставляет более развитые средства завершения работы SObjectizer run-time.

Иногда перед завершением работы приложения необходимо выполнить ряд сложных действий. Которые требуют времени и активного циркулирования сообщений в SObjectizer run-time. Например, при закрытии SMPP-соединения нужно выдать специальную команду unbind PDU и получить в ответ unbind_resp PDU. Что требует взаимодействия с агентами связи по TCP/IP. В этом случае нельзя начинать закрытие SMPP-соединения при получении so_4::rt::msg_normal_shutdown. Т.к. в этом случае работа SObjectizer run-time уже фактически завершена.

В sysconf входит интерфейсный агент so_sysconf_2::a_shutdowner_t. Его задачей является управление процессом завершения работы SObjectizer run-time.

Каждый агент, который нуждается в специальных процедурах завершения работы должен зарегистрироваться в a_shutdowner_t посредством отсылки сообщения so_sysconf_2::a_shutdowner_t::msg_register.

Для завершения работы SObjectizer run-time необходимо широковещательно отослать сообщение so_sysconf_2::a_shutdowner_t::msg_shutdown. После этого, всем агентам, зарегистрировавшихся в a_shutdowner_t отсылается сообщение so_sysconf_2::a_shutdowner_t::msg_shutdown_started. Получив его агентам нужно начать процедуру завершения своей работы. Когда эта процедура завершится агент должен отослать сообщение so_sysconf_2::a_shutdowner_t::msg_deregister.

Когда все зарегистрировавшиеся агенты пришлют сообщение so_sysconf_2::a_shutdowner_t::msg_deregister подсистема sysconf начнет завершение работы SObjectizer run-time посредством so_4::rt::msg_normal_shutdown.

Определение состояния sysconf

Подсистема sysconf является "черным ящиком" -- все управление осуществляется сообщениями. Снаружи sysconf сложно понять, что сейчас загружено и что зарегистрировано. Для получения информации о своем текущем состоянии sysconf предоставляет два механизма.

Первый состоит в том, что при изменении своего состояние sysconf рассылает сообщение so_sysconf_2::a_sysconf_t::msg_sysconf_info, в котором перечисляются все загруженные в данный момент DLL и доступные кооперации со своим статусом. Запросить эту же информацию можно в любой момент отослав сообщение so_sysconf_2::a_sysconf_t::msg_query_sysconf_info.

Используя тот факт, что агент so_sysconf_2::a_sysconf_t является глобальным, определения состояния sysconf возможно и через специальные внешние программы, взаимодействующие с приложение через SOP.

Второй механизм состоит в том, что подсистеме sysconf при старте может быть назначен специальный объект-журнализатор -- объект производного от so_sysconf_2::sysconf_logger_t типа. В этом случае при выполнении своих действий sysconf будет обращаться к журнализатору сообщая неформальное описание выполненого действия.

Механизм объекта-журнализатора может применяться для журналирования событий, происходящих с sysconf в подходящих для приложения хранилищах (текстовых файлах, базах данных, системых журналах Windows NT и т.д.).


Документация по so_sysconf_2 v.2.4.0. Последние изменения: Wed Oct 31 18:55:07 2007. Создано системой  doxygen1.5.4 Intervale SourceForge.net Logo