Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

На главную -> MyLDP -> Электронные книги по ОС Linux -> Архитектура приложений с открытым исходным кодом

Архитектура приложений с открытым исходным кодом. Том 1. Глава 4. Berkeley DB

Оригинал: "Berkeley DB"
Авторы: Margo Seltzer and Keith Bostic
Дата публикации: 2012 г.
Перевод: Н.Ромоданов
Дата перевода: октябрь 2012 г.

4.4. Интерфейсный слой библиотеки

Со временем, когда мы добавили дополнительные функциональные возможности, мы обнаружили, что как для приложений, так и для внутреннего кода нужны одни и те же функции высокого уровня (например, для выполнения операции объединения таблиц необходимо несколько курсоров для итерации по строкам точно также, как и в приложение может использоваться курсор для итерации по тем же самым строкам).

Четвертый урок конструирования

Не имеет значения, как вы называете свои переменные, методы, функции, что комментируете или какой стиль кодирования вы используете; то есть, существует большое количество форматов и стилей, которые считаются «достаточно хорошими». Что действительно значимо, причем имеет большое значение, это чтобы имена и стиль были согласованными. Опытные программисты получают массу сведений из текста кода и именования объектов. Вы должны следить за тем, чтобы не было несоответствия между именами и стилем, поскольку некоторые программисты тратят время и усилия на то, чтобы не передавать другим верные сведения, и наоборот. Несоблюдение принятых соглашений о кодировании является тяжким преступлением.

По этой причине, мы разбили интерфейсы API методов доступа на строго определенные слои. В этих слоях, содержащих интерфейсные процедуры, выполняются все необходимые общие проверки ошибок, проверки ошибок конкретных функций, отслеживается работа интерфейса, а также выполняются другие задачи, такие как автоматическое управление транзакциями. Когда приложения обращаются к Berkeley DB, они обращаются к интерфейсным процедурам первого уровня, использующим метоты работы с дескрипторами объектов. (Например, __dbc_put_pp является обращением к интерфейсу вызова метода «put», использующего курсор Berkeley DB, с помощью которого обновляется элемент данных. «_pp» является суффиксом, используемым нами для идентификации всех функций, к которым могут обращаться приложения).

Одной из задач Беркли DB, которые выполняются в интерфейсном слое, является отслеживание запуска потоков исполнения внутри библиотеки Berkeley DB. Это необходимо потому, что некоторые внутренние операции Berkeley DB можно выполнять только тогда, когда ни один из потоков не работает внутри библиотеки. Отслеживание работы потоков в библиотеке Berkeley DB реализуется с помощью установки флага, указывающего, что внутри библиотеки был запущен поток, в начале каждого библиотечного API и сброса этого флага в момент, когда происходит выход из вызова этого API. Такая проверка входа/выхода всегда выполняется в интерфейсном слое, поскольку она эквивалентна проверке, определяющей, выполнен ли вызов в реплицируемой среде.

Возникает естественный вопрос: «а почему бы не передать идентификатор потока внутрь библиотеки, не будет ли это проще»? Ответ – да, было бы гораздо проще, и мы, конечно, хотели сделать именно так. Но такое изменение потребовало бы изменить каждое отдельное приложение Berkeley DB и большинство обращений каждого из приложений к Berkeley DB, а во многих случаях также потребовалось бы переделать структуру приложений.

Пятый урок конструирования

Архитекторы программ должны аккуратно относиться к обновлениям в реально используемых проектах: пользователи воспримут нормально незначительные изменения, осуществляемые при обновлениях до новых версий (если вы гарантируете отсутствие ошибок времени компиляции, то есть отсутствие очевидных отказов до тех пор, пока не будет завершено обновление; изменения при обновлении никогда не должны приводить к плохо диагностируемым отказам). Но чтобы сделать по-настоящему фундаментальные изменения, вы должны решиться на использование нового кода базы данных и потребовать от ваших пользователей портировать их базы данных. Очевидно, что новый код и портирование являются не дешевыми с точки зрения затраты времени или ресурсов, но никто из ваших пользователей не рассердится, если вы расскажете им, что огромный капитальный ремонт является в действительности незначительным обновлением.

Другой задачей, выполняемой в интерфейсном слое, является создание транзакций. Библиотека Berkeley DB поддерживает режим, в котором каждая операция выполняется в рамках автоматически создаваемой транзакции (это освобождает приложение от создания и подтверждение своих собственных явно указываемых транзакции). Для поддержки этого режима требуется, чтобы транзакция создавалась автоматически каждый раз, когда приложение осуществляет обращение через API и не указывает, что оно использует свои собственные транзакции.

Наконец, во всех интерфейсах API в Berkeley DB API необходима проверка аргументов. В Berkeley DB есть два вида проверки ошибок - общая проверка, которая определяет, была ли наша база данных повреждена во время предыдущей операции и не находимся ли мы в процессе изменения реплицируемого состояния (например, выполняются изменения, при которых можно писать реплики). Есть также конкретные проверки для интерфейса API: правильность использования флага, правильность использования параметров, правильность комбинации параметров, а также отсутствие любых других видов ошибок, что мы должны поверить перед тем, как действительно будем выполнять требуемую операцию.

Эти проверки, необходимые для определенных API, инкапсулированных внутри функций, имеющих суффикс _arg. Таким образом, проверка ошибок для метода put, используемого с курсором, находится в функции __dbc_put_arg, которая вызывается из функции __dbc_put_pp.

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

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


Назад К оглавлению книги Вперед