![]() |
![]() |
|
|
Mumufs: виртуальная файловая система для поддержки IPC типа много-ко-много
Author / Автор: Сергей СацкийPublication date / Опубликовано: 15.07.2007
|
![]() |
Файловая система mumufs монтируется на точку /mnt/mumu. Процесс номер 3 открывает файл /mnt/mumu/file1на запись. Файл еще не существует, поэтому mumufs создает необходимые структуры данных в памяти. Процесс номер 3 записывает в файл блок данных размером 2048 байт. Mumufs размещает в памяти блок подходящего размера и копирует данные от процесса в выделенный блок. Процесс номер 1 открывает файл /mnt/mumu/file1 на чтение и получает 2048 байт. Если буфер чтения процесса номер 1 меньше 2048 байт, процесс получит уведомление об ошибке чтения. Если буфер достаточен, то данные будут скопированы процессу, а mumufs сделает отметку, что процесс уже прочитал текущий доступный блок данных. Далее процесс номер 1 повторяет операцию чтения. Mumufs учитывает, что процесс номер 1 уже прочитал доступный блок данных и блокирует операцию чтения. Далее процесс номер 4 открывает файл /mnt/mumu/file1на запись и производит запись 256 байт. Mumufs замещает первый блок данных новым блоком и разблокирует все заблокированные на чтении процессы, в данном случае процесс номер 1. Процесс номер 1 читает 256 байт второго блока и при последующем чтении снова будет заблокирован. Далее процесс номер 2 открывает файл /mnt/mumu/file1 на чтение и выполняет операцию чтения. Mumufs копирует 256 байт доступного блока в процесс номер 2. При следующем чтении процесс номер 2 будет заблокирован. Далее процесс номер 1 выполняет запись 512 байт. Новый блок замещает старый, а процессы номер 1 и 2 разблокируются для возможности чтения нового доступного блока.
Удаление файла ведет к освобождению блока памяти, ассоциированного с файлом. Закрытие файла всеми заитересованными процессами не приводит к освобождению памяти, занятой последним записанным блоком. Размонтирование файловой системы ведет к освобождению всех размещенных блоков данных.
Таким образом, единицой транзакции для mumufs является блок данных. Имя файла в mumufs используется в качестве уникального идентификатора блока произвольных данных. Время жизни блока совпадает с временем жизни файла в mumufs, то есть либо до момента удаления файла, либо до момента размонтирования файловой системы.
Mumufs может быть смонтирована произвольное количество раз.
Примером применения mumufs могут служить системы с графическим интерфейсом пользователя. Например, состоянием батарейки в мобильном телефоне могут интересоваться сразу несколько процессов. Это могут быть процессы, отображающие иконку в строке состояния, показывающие подробное состояние батарейки в отдельном окошке и процессы, запускающие систему энергосбережения или оповещения и т.п. Всем этим процессам необходимо только текущее состояние, история изменения состояния не требуется. При использовании mumufs процессу поставщику данных нет необходимости знать, сколько потребителей имеется, и сколько их будет в будущем. Поставщик открывает файл и обновляет значение по мере необходимости. Для потребителей реализация обмена также очень проста, необходимо открыть файл и читать подходящим образом данные. Единственное требование это договоренность о формате данных и имени в файловой системе.
Mumufs поддерживает блокируемый и неблокируемый ввод-вывод. Признак блокируемого или неблокируемого ввода-вывода оказывает влияние только на операции чтения.
В случае блокируемого чтения процесс блокируется, если нет блока данных, который процесс успешно прочитал. Разблокировка процесса производится либо когда новый блок данных становится доступен, либо когда процесс принимает сигнал.
Mumufs использует блокировки чтения-записи для обеспечения безопасности доступа к данным. Это определяет приоритет операций записи перед операциями чтения.
Mumufs поддерживает расширенные атрибуты файлов. Это позволяет поставщикам данных документировать назначение блоков произвольным образом, например в виде произвольного текста.
Поскольку mumufs поддерживает интерфейс файловой системы, то возможно использование всех стандартных файловых утилит UNIX. Стоит, однако, помнить об особенностях реализации mumufs. Например, если пользователь выдал команду cat /mnt/mumu/batteryStatus, то на экране будет напечатано содержимое блока данных, однако после этого cat будет заблокирован, так как cat открывает файлы в блокируемом режиме. Как только поставщик данных обновит содержимое /mnt/mumu/batteryStatus, так cat выведет новое значение и будет снова заблокирован. Однако, всегда можно прервать cat с помощью комбинации клавиш Ctrl+C. Эти ограничения затрудняют использование утилит в пакетном режиме, однако, легкость в использовании и наблюдаемость mumufs остается гораздо лучше, чем в случае традиционных механизмов межпроцессного взаимодействия.
Досту к файлам mumufs предоставляет на основе традиционной схемы UNIX для дисковых файловых систем.
Поскольку mumufs использует блок данных как единую транзакцию, то операции записи и чтения всегда должны начинаться со смещения 0, а операции seek вообще не поддерживается (так же как и файловые блокировки). Это обстоятельство ведет к особенностям использования mumufs, которые описаны ниже.
Стандартная библиотека libc предлагает разработчику функции работы с файлами, начинающиеся с префикса f: fopen(:), fclose(:), fread(:), fwrite(:) и т.д. С помощью этих функций можно работать с файлами и, в том числе, казалось бы, с файлами, располагающимися на mumufs. Однако libc версия fwrite(:) выполняет склейку маленьких пакетов данных для оптимизации операции записи (с настройкой системы буферизации по умолчанию). Например, если дважды выполнена операция записи блоков данных по 2 байта каждый, то до файловой системы дойдет только один вызов записи с блоком данных длиной 4 байта. Это делает неудобным использование функций этой группы с mumufs.
Существует возможность воспользоваться и другой группой функций для работы с файлами: open(:), close(:), read(:), write(:) и т.д. Эти функции не выполняют никаких дополнительных действий с блоками данных и хорошо подходят для использования с mumufs файлами.
Для облегчения работы с файлами mumufs разработана C++ библиотека шаблонов libmumu++. Состав библиотеки описан в разделе ниже.
Библиотека шаблонов libmumu++ предлагает всего один шаблонный класс Entry. Класс предлагает C++ обертку для работы с файлами, расположенными на mumufs. Передаваемый шаблону тип используется как блок обмена данными. При этом предполагается, что данные типа занимают непрерывную область в памяти.
Пример программы для записи целых чисел с использованием libmumu++.
#include "mumulib.h" using namespace mumu; int main( int argc, char ** argv ) { try { Entry< int > Value( "/mnt/mumu/one" ); Entry.Write( 154 ); } catch ( std::exception & E ) { return 1; // Writing error } return 0; } |
Шаблон Entry по умолчанию открывает указанный файл в режиме блокируемого ввода-вывода. Вторым параметром конструктора можно указать, что файл надо открывать в неблокируемом режиме.
Шаблон Entry поддерживает две версии функций чтения, ориентированных на блокируемый и неблокируемый ввод-вывод. Поддерживается операция select с возможностью указать таймаут ожидания.
Пример программы, использующей функции чтения и select через libmumu++.
#include "mumulib.h" using namespace mumu; int main( int argc, char ** argv ) { try { int Value; Entry< int > Blocking( "/mnt/mumu/one" ); Entry< int > NonBlocking("/mnt/mumu/one", false ); // Blocking IO // If the file does not exist then we are blocked here // Use the first program to put some value in the file Value = Blocking.Read(); // Non-blocking IO if ( NonBlocking.Read( &Value ) == 0 ) { // No data available } else { // A value is read } // Select example // Use the first program to put update the file content struct timeval Timeout; Timeout.tv_sec = 15; Timeout.tv_usec = 0; if ( Blocking.Select( &Timeout ) ) { // New data arrived Value = Blocking.Read(); } else { // No new data and the timeout exceeded } // 0 - waits forever. Use the first program if ( Blocking.Select( 0 ) ) { // New data arrived Value = Blocking.Read(); } else { // No new data and the timeout exceeded } } catch ( std::exception & E ) { return 1; // Writing error } return 0; } |
Класс Entry поддерживает специализацию всех функций членов для std::string.
Более подробную документацию по библиотеке можно сгенерировать с помощью doxygen - библиотека содержит все необходимые комментарии.