Необычные файловые серверы
Plan 9 характеризуется множеством необычных серверов с файловоподобными интерфейсами. Многие из них реализованы процессами на уровне пользователя, хотя отличие для их клиентов не так уж важно; предоставлена ли служба ядром, процессом пользователя или удаленным сервером не имеет отношения к тому, как она используется. Имеются десятки таких серверов; в этом разделе мы представим описания трех из них.
Возможно, наиболее заметным файловым сервером в Plan 9 можно назвать оконную систему 8½. Она уже рассматривалась подробно [8], но стоит привести здесь ее краткое описание. 8½ обеспечивает два интерфейса: пользователю, сидящему перед терминалом, она предлагает взаимодействие в традиционном стиле с множеством управляемых с помощью мыши и клавиатуры окон, в каждом из которых выполняется приложение. Для клиентских программ вид также достаточно традиционен: программы, выполняющиеся в окне, видят набор файлов в /dev с именами типа mouse, screen и пр. Программы, которым необходимо напечатать текст в своем окне, производят запись в /dev/cons; чтобы обратиться к мыши, они считывают /dev/mouse. В стиле Plan 9 побитовая графика применятся обращением к файлу /dev/bitblt, куда клиенты записывают кодированные сообщения для исполнения таких графических операций, как bitblt (RasterOp). Необычно то, как это делается: 8½ является файловым сервером, предоставляющим файлы из каталога /dev клиентам, работающим в каждом окне. Хотя каждое из окон выглядит для ее клиентов одинаково, все они имеют отдельные наборы файлов в /dev. 8½ мультиплексирует доступ своих клиентов к ресурсам терминала путем обслуживания множества наборов файлов. Каждому клиенту предоставляется личное пространство имен с различным набором файлов, которые одинаково работают и во всех других окнах. Такая структура имеет много преимуществ. Одно из них заключается в том, что 8½ обслуживает те же файлы, которые необходимы для его собственного внедрения (он мультиплексирует свой собственный интерфейс), и поэтому может работать рекурсивно, как клиент самого себя. Кроме того, рассмотрим внедрение /dev/tty в Unix, требующее специального кода в ядре для перенаправления вызовов open соответствующим устройствам. Вместо этого в 8½ эквивалентная служба выпадает автоматически: 8½ обслуживает /dev/cons как свою основную функцию; ничего другого он не делает. Когда программа хочет считать с клавиатуры, она открывает /dev/cons, но это личный файл, а не совместно используемый со специальными свойствами. Снова это становится возможным из-за локальности пространства имен; соглашения о совместимости файлов делают эту возможность легко осуществимой.
8½ имеет уникальную особенность, вытекающую из ее строения. Реализуясь как файловый сервер, он обладает возможностью отложенного ответа на запросы чтения для конкретного окна. Эта опция переключается зарезервированной клавишей клавиатуры. Нажав ее один раз, вы приостановите чтение клиента из окна; повторное нажатие восстанавливает нормальное чтение, которое построчно поглощает любой текст. Таким образом, пользователь сможет редактировать многострочный входной текст на экране до того, как приложение видит его; устраняется необходимость включения отдельного редактора для подготовки текста, например, почтовых сообщений. С этим связана и возможность ответа на считывания непосредственно из структуры данных, определяющих текст на дисплее: текст можно редактировать до тех пор, пока его конечная новая строка делает подготовленную строку текста считываемой для клиента. Даже в то время, когда строка считывается, текст, который увидит клиент, может быть изменен. Например, после набора в оболочке, пользователь может вернуться назад на конечную новую строку в любое время, пока не кончится работа make и не появится следующее приглашение оболочки перед rm. Пользователь может прервать выполнение команды rm или даже указать мышью до rm и набрать другую команду, чтобы она исполнялась первой.
В Plan 9 отсутствует команда ftp. Вместо нее файловый сервер на уровне пользователя генерирует вызовы ftpfs к узлу FTP, входит в него от имени пользователя и использует протокол FTP для исследования файлов в удаленном каталоге. Для локального пользователя он предлагает иерархию файлов, присоединенных к /n/ftp в локальном пространстве имен, отражая содержание узла FTP. Такая реализация рискованна: для эффективности ftpfs придется делать некоторый усложненный захват с использованием эвристического подхода для декодирования информации удаленного каталога. Однако результат стоит того: все локальные средства управления файлами, такие как ср, grep, diff и, конечно, ls, доступны для обслуживаемых FTP-файлов точно так же, как если бы они были локальными файлами. Другие системы, например Jade and Prospero, используют ту же возможность[6; 11].
Один сервер, exportfs, является процессом пользователя, занимающим часть его собственного пространства имен и делающим его доступным для других процессов путем трансляции запросов 9Р в системные вызовы ядра Plan 9. Иерархия файлов, которую он экспортирует, может содержать файлы из множества серверов. Exportfs обычно исполняется как удаленный сервер, инициируемый локальной программой, или import, или cpu. Import производит сетевой вызов удаленной машины, затем стартует exportfs и подсоединяется к локальному пространству имен. Например, команда
import helix /net
делает интерфейс сети Helix видимым в локальной директории /proc, позволяя локальным отладчикам исследовать удаленные процессы.
Команда cpu подключает локальный терминал к удаленному серверу CPU. Она работает в направлении, обратном команде import после вызова сервера, она запускает локальную exportfs и встраивает ее в пространство имен процесса на сервере, обычно через вновь создаваемую оболочку. Затем она перекомпонует пространство имен, чтобы сделать локальные файлы устройства (как те, которые обслуживаются оконной системой терминала) видимыми в каталоге сервера /dev. Эффект действия команды cpu сводится, следовательно, к запуску оболочки на быстрой машине с пространством имен, аналогичном локальному, при наличии еще одной, тесно связанной с файловым сервером. Все локальные файлы устройств видимы с удаленной машины, так что удаленные приложения имеют полный доступ к локальным службам, таким как растровая графика, /dev/cons и т. д. Это не то же, что rlogin, которая не делает ничего для воспроизводства локального пространства имен на удаленной системе, и не то же, что совместное использование файлов при работе, например, с NFS, при котором можно достичь некоторой эквивалентности пространства имен, но не такой же комбинации доступа к локальным аппаратным устройствам, удаленным файлам и удаленным ресурсам вычислительного сервера. Команда cpu является уникальным прозрачным механизмом. Например, разумно запустить систему окон в окне с работающей командой cpu; все окна, созданные в нем, автоматически запускают процесс на вычислительном сервере.
Конфигурируемость и управление
Однородные взаимные связи компонентов в Plan 9 делают возможным конфигурирование инсталляции Plan 9 многими различными способами. Один ПК-лэптоп может функционировать как отдельная система Plan 9, использующая локальный диск для хранения файлов; в другом предельном случае наша система имеет центральные многопроцессорные вычислительные серверы, файловые серверы и множество терминалов в диапазоне от небольших ПК до графических станций высокого уровня. Именно на таких больших системах наилучшим образом проявляется работа Plan 9.
Системное ПО переносимо, и та же самая операционная система может выполняться на любой аппаратуре. Кроме производительности, проявления системы на, скажем, рабочей станции SGI, будут такими же, как и на ноутбуке. Поскольку вычислительные и файловые серверы централизованы, а терминалы не имеют постоянного места хранения файлов, все терминалы функционально идентичны. Таким образом, Plan 9 обладает одним из хороших качеств старых систем с разделением времени, когда пользователь может сидеть перед любой машиной и видеть одну и ту же систему. В современном сообществе рабочих станций имеется тенденция, когда машины принадлежат людям, которые подстраивают их под себя путем хранения личной информации на локальном диске. Мы отвергли этот стиль использования, хотя сама система может быть использована и таким образом. В своей группе мы имеем лабораторию с множеством машин с публичным доступом — терминальную комнату, — и пользователь может работать за любой из них.
Центральные файловые серверы централизуют не только файлы, но и их администрирование и обслуживание. В действительности один сервер является главным, содержащим все системные файлы; другие серверы обеспечивают дополнительное место для хранения или доступны для отлаживания и другого специального использования, однако системное ПО размещено на одной машине. Это означает, что каждая программа имеет единственную копию двоичного кода для каждой архитектуры, так что инсталляция новых версий и поиск ошибок достаточно тривиальны. Имеется также единственная база данных пользователя; нет необходимости синхронизировать отдельные файлы /etc/passwd. С другой стороны, зависимость от единого центрального сервера не ограничивает размер инсталляции и непрерывность сервиса. Хотя центральный сервер обычно остается включенным в течение месяцев, когда он выключен, зависящие от него машины не могут функционировать.
Другим примером мощи централизованной файловой службы является то, как Plan 9 управляет сетевой информацией. На центральном сервере существует директория /lib/ndb, которая содержит всю информацию, необходимую для управления локальной сетью Ethernet и другими сетями. Все машины используют для обращения к сети одну и ту же базу данных; нет необходимости управлять распределенной системой наименований или сохранять параллельные файлы до последнего момента. Чтобы инсталлировать новую машину в локальную сеть Ethernet, надо выбрать имя и IP-адрес и добавить их к единственному файлу в /lib/ndb; все машины в инсталляции смогут обратиться к ней сразу же. Чтобы начать работу, подсоедините машину к сети, включите ее и используйте ВООТР и TFTP для загрузки ядра. Все остальное произойдет автоматически.
Наконец, автоматический дамп файловой системы освобождает всех пользователей от необходимости обслуживать свои системы, предоставляя легкий доступ к файлам резервного копирования без лент, специальных команд или привлечения персонала поддержки. Трудно переоценить улучшение образа жизни, обеспечиваемое этим сервисом.
Plan 9 работает на множестве аппаратных средств без ограничения на конфигурацию инсталляции. В нашей лаборатории мы выбрали использование центральных серверов, поскольку при этом снижаются расходы и облегчается управление. Признаком того, что такое решение является правильным, является то, что наши дешевые терминалы оставались удобным местом для работы в течение пяти лет, намного дольше, чем рабочие станции, которые должны обеспечивать полную вычислительную среду. Мы, однако, обновили центральные машины, так что производительность вычислений даже со старых терминалов Plan 9 со временем повысилась. Средства, сэкономленные за счет отказа от обычного обновления терминалов, были потрачены на новейшие, самые быстрые многопроцессорные серверы. Мы считаем, что эти затраты составляют примерно половину стоимости рабочих станций в сети, но обеспечивают общий доступ к более мощным машинам.
Программирование на С
Утилиты Plan 9 написаны на нескольких языках. Некоторые из них представляют собой сценарии оболочки rc [2], многие написаны на новом языке-конкуренте, подобном С, названном Alef и описанном ниже. Большая же часть написана на диалекте ANSI С. Из них большинство являются полностью новыми программами, однако происхождение некоторых идет от Unix-кода, предшественника ANSI С. Эти части были обновлены до ANSI С и переработаны для большей мобильности и чистоты.
Диалект Plan 9 имеет некоторые небольшие добавления, описанные ранее [10], и несколько основных ограничений. Наиболее важные из них — это требование компилятора, чтобы все определения функций имели прототипы ANSI и все вызовы функций появлялись в контексте прототипной декларации функций. Как стилистическое правило, прототипная декларация помещена в файл заголовка, включенный во все файлы, которые вызывают функцию. Каждая системная библиотека имеет ассоциированный файл заголовка, декларирующий все функции в этой библиотеке. Например, стандартная библиотека Plan 9 называется libc, так что все файлы-источники включают <libc.h>. (Имена файлов заголовка не соответствуют ANSI С.) Эти правила гарантируют, что все функции вызываются с аргументами, имеющими ожидаемые типы, что не было свойственно программам на языке, предшествующем ANSI С.
Другое ограничение заключается в том, что для компиляторов С приемлем только поднабор препроцессорных директив, требуемых ANSI. Основное опущенное звено — #if, поскольку мы считаем, что оно никогда не было необходимым и часто использовалось неправильно. Кроме того, его эффект лучше достигался другими средствами. Например, #if, используемый для переключения характеристик во время компиляции, может быть переписан как обычный оператор if, основанный на свертке с константой времени компилирования и исключении мертвого кода для отбрасывания объектного кода.
Условная компиляция, даже с #ifdef, в Plan 9 используется как резервная. Единственные зависимые от архитектуры операторы #ifdef в системе находятся в процедурах низкого уровня в графической библиотеке. Мы избегали таких зависимостей или, когда это было необходимо, выделяли их в отдельные файлы-источники или библиотеки. Кроме того, что применение #ifdef делает код трудночитаемым, становится невозможным узнать, какой источник скомпилирован в двоичный вид или будет ли источник, защищенный ими, компилироваться или работать правильно. Они также затрудняют поддержку ПО.
Стандартная библиотека Plan 9 перекрывается во многом с ANSI С и POSIX, но расходится с ними при адаптации к целям или реализации Plan 9. Когда изменялась семантика функции, мы изменяли также и имя. Например, вместо оператора Unix create, Plan 9 имеет функцию create, которая воспринимает три аргумента — два исходных, плюс третий, который, подобно второму аргументу open, определяет, должен ли возвращенный дескриптор файла быть открыт для чтения, записи или того и другого. Такой подход был вынужденным из-за способа, которым 9Р выполняет создание, однако он упрощает также общее использование create для инициализации временного файла.
Другое отступление от ANSI С заключалось в том, что Plan 9 использует 16-разрядный набор символов, называемый Unicode. Хотя мы совершенно прекратили полную интернационализацию, Plan 9 обрабатывает представление всех основных языков однородно по всему своему ПО. Для упрощения обмена текстами между программами, символы скомпонованы в поток битов путем сконструированной нами процедуры кодировки, названной UTF-8, которая в настоящее время начинает приниматься в качестве стандартной. Она имеет несколько привлекательных свойств, включая независимость от порядка байт, обратную совместимость с ASCII и легкость внедрения.
Существует много проблем в адаптировании существующего ПО к большому набору символов с кодировкой, которая описывает символы переменным количеством байтов. ANSI С обращается к некоторым из этих аспектов, однако не решает их все. В этом диалекте нельзя выбрать кодировку набора символов и определить все необходимые библиотечные процедуры ввода/вывода. Более того, функции, которые определить можно, имеют технические проблемы. Поскольку этот стандарт оставляет слишком много проблем нерешенными, мы решили создать свой собственный интерфейс.
Небольшой класс программ Plan 9 не следует соглашениям, обозначенным в этом разделе. Это программы, импортированные из сообщества Unix или им поддерживаемые; представительным их примером является TeX. Чтобы избежать многократного конвертирования таких программ всякий раз, когда выпускается новая версия, мы создали переносимую среду, названную ANSI C/POSIX Environment (АРЕ) [13]. АРЕ включает отдельные файлы, библиотеки и команды, соответствующие насколько можно более точно спецификациям ANSI С и базового POSIX. Для возможности переносимости сетевого ПО, такого как Х Window, к этим спецификациям было необходимо добавить некоторые дополнения, такие как сетевые функции BSD.