10.4. Индексно-последовательный файл
Индексно-последователъный файл организуется по принципу многоуровневого справочника. Индексно-последовательная организация представляет собой компромисс между последовательной и прямой организациями: при обеспечении возможности прямого доступа к записям сохраняется последовательная упорядоченность файла, что бывает крайне полезно для многих приложений. Каждая логическая запись индексно-последовательного файла должна содержать атрибут, являющийся ключом.
Прямой доступ к записям по ключу становится возможным только в том случае, когда устройство ВП обеспечивает необходимый тип доступа. ЗУ на МЛ является устройством с последовательным доступом. Оно непригодно для хранения индексно-последовательных файлов. Чаще всего для этих целей используют НМД, поэтому в дальнейшем предполагается, что файловые структуры размещены именно на этих устройствах.
Индексно-последовательный файл состоит из трех областей: основной, индексной и области переполнения.
Основная область служит для записи при его первоначальном создании. Логические записи записываются последовательно на дорожки цилиндра начиная с первой в порядке возрастания значений ключа. Формат записей основной области приведен на рис. 10.1. Запись содержит поле ключа и поле данных. В поле ключа размещается ключ записи, в поле данных - сама запись.
Индексная область (область многоуровневого справочника) - вторая большая область индексно-последовательного файла. Она создается автоматически программами управления данными операционной системы. В индексной области размещаются служебные наборы данных - индексы. Обычно их два: индекс дорожек и индекс цилиндров.
Индекс дорожек — это нижний уровень индекса. Формат записей индекса дорожек приведен на рис. 10.2. Записи также состоят из двух полей. В поле данных запись индекса дорожек содержит адрес (номер) дорожки, с которой эта запись связана. В поле ключа содержится значение ключа последней записи на этой дорожке. Этот ключ самый большой на дорожке, так как записи в пределах ее упорядочены по возрастанию значений ключа. Количество записей в индексе дорожек равно числу дорожек цилиндра, занятого записями файла. Индекс дорожек размещается на нулевой дорожке цилиндра.
Индекс цилиндров указывает, как записи размещаются на нескольких цилиндрах. Каждая запись индекса цилиндров (рис. 10.3) в поле ключа содержит значение ключа последней записи цилиндра (это максимальный ключ цилиндра). В поле данных содержится адрес этого цилиндра. Количество записей в индексе цилиндров равно числу цилиндров дискового пакета, занятых хранимым файлом. Индекс цилиндров размещается на отдельном цилиндре.
Пример, иллюстрирующий фрагмент структуры индексно-последовательного файла, размещенного на шестидисковом пакете, приведен на рис. 10.4. Файл занимает цилиндры с 51-го по 66-й. Максимальный ключ файла — 1385. Индекс цилиндра размещен на трех дорожках цилиндра 50. На рисунке приведены фрагменты файла, размещенные на двух цилиндрах, и указаны связи, устанавливаемые индексом цилиндров. Значения ключей отделены от адресов цилиндров и дорожек наклонной чертой.
Для обращения к записи с ключом 721 сначала последовательно просматриваются дорожки индекса цилиндров и находится запись с ключом, большим или равным заданному. Поле данных этой записи содержит номер цилиндра, на котором должна быть размещена запись с ключом 721 (если она вообще содержится в файле) . Из рис. 10.4 видно, что соответствующая запись индекса цилиндров отсылает к цилиндру 58. Механизм доступа НМД устанавливается для чтения информации с этого цилиндра и осуществляется последовательный просмотр нулевой дорожки, на которой хранится индекс дорожек. В индексе дорожек находится запись, ключ которой больше или равен заданному ключу. Поле данных этой записи содержит адрес дорожки, на которой должна находиться запись с заданным ключом. Как следует из примера, запись с ключом 721 необходимо искать на восьмой дорожке цилиндра 58. Головки записи -воспроизведения механизма доступа переключаются на эту дорожку и последовательным просмотром дорожки ищется нужная запись.
Время доступа к записям файла увеличивается с увеличением объема индекса цилиндров. Поэтому для очень больших файлов, занимающих много цилиндров, создается еще один, самый верхний, уровень индекса— главный индекс. В поле ключа записей главного индекса содержится максимальное значение ключа на соответствующей дорожке индекса цилиндров. Записи главного индекса обеспечивают прямой доступ к дорожкам индекса цилиндров. Связи, устанавливаемые главным индексом, указаны на рис. 10.4. Главный индекс, будучи запрошенным, находится в ОП в течение всего времени работы с файлом.
Индексно-последовательная организация допускает как последовательный, так и прямой режим обработки файла.
Последовательная обработка индексно-последовательного файла логически идентична последовательной обработке последовательного файла. Записи обрабатываются в порядке, определяемом значениями ключа. Так как записи файла упорядочены по возрастанию значений ключа, то записи при последовательной обработке фактически читаются в том же порядке, в котором они были записаны в файл.
Несмотря на то что в представлении пользователя последовательная обработка индексно-последовательного файла ничем не отличается от последовательной обработки последовательного файла, следует помнить, что доступ к записям для этих типов файлов существенно различен.
Последовательный режим обработки индексно-последовательного файла имеет и свою особенность. Так, например, последовательно обрабатываться может не весь файл, а лишь его часть начиная с указанной записи. Предварительный просмотр всех предшествующих записей при этом не нужен, так как к записи, с которой следует начать последовательную обработку, обеспечивается прямой доступ.
При произвольной обработке прикладные программы задают в любой последовательности ключи. Логические записи в заданной последовательности передаются на обработку.
В режиме корректировки решается проблема добавления и удаления записей файла. Проблема добавления записей решается созданием области (или областей) переполнения, как правило, на том же устройстве, на котором располагается файл. Возможны два типа областей переполнения: область переполнения цилиндра и независимая область переполнения.
Область переполнения цилиндра представляет собой несколько специально отведенных дорожек того же цилиндра, на котором содержатся дорожки основной области. Если новая запись в соответствии со значением ее ключа должна быть вставлена между уже существующими записями, то происходит следующее. По ключу новой записи с помощью индекса цилиндров и индекса дорожек ищется дорожка, на которой следует поместить новую запись. Эта запись размещается в нужном месте дорожки основной области, для чего все записи с большими ключами сдвигаются. При этом запись с самым большим значением ключа вытесняется с дорожки основной области и переносится в область переполнения цилиндра. Теперь эта дорожка основной области характеризуется другим значением ключа и в индекс дорожек необходимо внести соответствующие изменения.
Для часто обновляемых файлов индекс дорожек содержит обычно по две записи для каждой. Первая запись для дорожки основной области, вторая — для дорожки области переполнения. После первого создания файла эти записи идентичны. После корректировки файла в поле ключа второй записи заносятся максимальный ключ дорожки переполнения, а в поле данных помещается адрес этой дорожки и номер записи с минимальным значением ключа. Поле ключа первой записи корректируется.
Записи на дорожке переполнения размещаются друг за другом, физический порядок; их следования не соответствует упорядоченности по возрастанию ключей. Для поддержания этой упорядоченности записи области переполнения в отличие от записей основной области содержат поле указателя. Указатель каждой записи дорожки переполнения устанавливается на запись, имеющую следующее большее значение ключа. Дорожек переполнения может быть несколько и записи всех дорожек образуют связанный список, построенный по возрастанию значений ключа записей. Голова этого списка задается адресом дорожки переполнения, указанным во второй записи индекса дорожек.
Пусть в файл, фрагмент которого изображен на рис. 10.4, добавляются последовательно две записи с ключами 564 и 565: сначала первая, потом вторая. Под область переполнения цилиндра выделена девятая дорожка цилиндра 58. Новые записи в соответствии со значениями их ключа следует расположить на второй дорожке 58-го цилиндра. Для этого запись с ключом 569 переносится на девятую дорожку. Вслед за ней на эту же дорожку переносится запись с ключом 566, а ее указатель устанавливается на запись с ключом 569. Размещение записей цилиндра 58 после корректировки изображено на рис. 10.5. В индексе дорожек, который содержит теперь по две записи на каждую дорожку, произведены соответствующие изменения.
По мере добавления в индексно-последовательный файл новых записей область переполнения цилиндра исчерпывается и вновь поступающие записи передаются в независимую область переполнения. Эта область должна описываться при создании файла. Под независимую область отводится свободный цилиндр или группа цилиндров. Записи в независимой области переполнения связываются так же, как и в области переполнения цилиндров.
Использование независимой области переполнения может привести к существенному увеличению времени доступа, поскольку на перемещение механизма доступа между цилиндрами основной и независимой областей переполнения тратится много времени. Поэтому длительно эксплуатируемые файлы периодически реорганизуют. Обычно реорганизацию проводят, как только записи начинают попадать в независимую область переполнения. При этом записи файла последовательно копируются во временный файл, а затем основной файл создается заново. В результате реорганизации все записи переполнения включаются в основной файл.
При удалении записи не исключаются из файла, а только помечаются как удаленные. В качестве метки удаления может использоваться, например, строка битов '1111111ГВ, размещенная в первом байте записи. Если со временем в файл добавляется новая запись с тем же самым ключом, что и удаленная запись, то ячейка памяти, занятая удаленной записью, используется повторно.
Файл может длительное время существовать без реорганизации, если при его инициализации оставляют свободные блоки на всех дорожках и свободные дорожки на всех цилиндрах. Однако всегда существует опасность необоснованно большого расхода памяти.
Индексно-последовательные средства доступа обычно обеспечиваются операционной системой, освобождая программиста от необходимости ведения индексов и установления связей в областях переполнения.
10.5. ПРЯМОЙ ФАЙЛ
В прямых файлах (иногда их называют файлами прямого доступа) существует непосредственная связь между ключом записи и ее местоположением на носителе. При занесении логической записи в файл выполняется преобразование или отображение ключа записи в адрес памяти, по которому запись будет размещена. Методы преобразования ключа записи в ее адрес подробно рассмотрены в п. 9.6.
Записи, размещаемые на ВЗУ, блокируются и прямой доступ обеспечивается не к одной записи, а к блоку логических записей. Здесь размещаются записи, получившие один и тот же адрес, являющийся адресом блока. При обращении к логической записи рандомизирующая процедура по ключу записи генерирует адрес блока, в пределах которого должна храниться искомая запись. Содержимое блока переносится в буферную область ОП, где из блока извлекается нужная логическая запись. Для устройств дисковой памяти, в которых минимальной адресуемой единицей является сектор, размер блока выбирается равным сектору.
Поскольку размер блока ограничен, то назначение многим логическим записям адреса, соответствующего адресу одного и того же блока, приводит к переполнению последнего. Поэтому проблема разрешения коллизий для прямого файла сводится к проблеме размещения записей переполнения. Для этого обычно используются средства, применяемые при страничной организации памяти. Для записей переполнения выделяются специальные блоки памяти (области переполнения), связанные указателем с соответствующим блоком основной области. В блоке переполнения записи располагаются последовательно друг за другом. Каждая очередная запись, оказавшаяся в состоянии коллизии, размещается на первом же свободном участке памяти. При обращении к нужной логической записи по ее ключу вычисляется адрес основного блока, где должна быть размещена эта запись. Блок перемещается в буфер, где выясняется, найдена ли запись. Если запись отсутствует в основном блоке, то в буфер переносится содержимое блока переполнения. Поиск заканчивается успешно, если нужная запись находится. Поиск считается неудачным, если обнаружится свободный участок памяти или если поиск возвращается к первоначально просмотренному блоку.
Блоки переполнения желательно размещать в той же адресуемой единице памяти, что и основная область, например в пределах одного и того же цилиндра. Это позволяет избежать перемещения головок записи - воспроизведения. Однако возникающее чередование блоков переполнения и основных блоков в пределах одной и той же адресуемой единицы памяти приводит к нарушению линейной схемы адресации, что является существенным недостатком такого способа размещения записей переполнения.
При другом способе разрешения коллизий получившие один и тот же адрес записи размещаются в любых свободных блоках основной области и связываются указателями в цепочку. Такой способ приводит, однако, к увеличению длины записей за счет указателей. Это обстоятельство может оказаться существенным, если файл состоит из множества небольших записей. Обращение к записям переполнения в этом случае чаще всего приводит к перемещениям механизма доступа.
Если число записей в файле мало, а размер записей достаточно велик, то для организации прямого файла можно использовать схему прямой адресации. При этом соответствие между ключами записей и их адресами устанавливается так называемой таблицей перекрестных ссылок. В этой таблице, состоящей из адресов и ключей, каждому ключу назначен уникальный адрес внешней памяти. Для осуществления доступа к логической записи нужно по заданному значению ключа найти в таблице внешний адрес и извлечь командой ввода - вывода по этому адресу требуемую запись. Таблица может быть организована как последовательный неупорядоченный список. В этом случае в нее легко добавлять новые записи, но поиск можно вести только последовательным просмотром (перебором). Таблица может быть упорядочена по значению ключа, и тогда для ускорения поиска в ней удобно применять двоичный поиск: Однако добавление и удаление записи в упорядоченную таблицу связано с ее перестройкой.
Адресами записей прямого файла могут быть абсолютные (адреса конкретных физических устройств) или относительные адреса. В последнем случае адрес представляет собой номер блока или дорожки, отсчитанный от начала участка памяти, занимаемого файлом. Преобразование относительных адресов в абсолютные осуществляют в этом случае программы ввода — вывода. При использовании относительной адресации прикладные программы становятся независимыми от типа НМД, от местоположения файла на пакете, от количества дорожек на цилиндре.
Эффективность прямого доступа в прямом файле достигается за счет устранения требования такой организации файла, при которой допускался бы как прямой, так и последовательный доступ к записям. Поэтому прямой файл в явном виде не ориентирован на последовательную обработку, хотя, в общем случае, записи прямого файла могут обрабатываться последовательно.
При последовательной обработке прикладная программа может задать адрес какой-либо записи, а затем при каждом обращении к файлу увеличивать этот адрес на единицу. При этом будут последовательно читаться записи в том порядке, в котором они физически размещены на диске. Никакой логики следования записей при этом не обеспечивается. Этот режим необходим при возникновении задачи обработки всех без исключения записей файла или его фрагмента.
В произвольном режиме обработки, естественном для прямого файла, ключ обрабатываемой записи преобразуется в адрес и в зависимости от характера обработки запись создается, удаляется, модифицируется, извлекается по этому адресу. Модифицируемая запись может возвращаться в память по прежнему адресу, если модификации не подвергался ее ключ.
В режиме корректировки файла новые записи добавляются в основную область или в область переполнения в соответствии со значениями их ключей и назначенными адресами. Удаленные записи обычно помечаются символом удаления. Пространство памяти, занятое удаленной записью, может использоваться под новую запись, получившую этот же адрес. Физическое существование в файле удаленных записей требует лишнего анализа при поиске, поэтому динамичные прямые файлы необходимо периодически реорганизовывать. Реорганизация выполняется последовательным чтением файла и последующим созданием прямого файла, состоящего из активных записей.