OLTP в Зазеркалье

         

Архитектура Shore


В Shore имеется несколько компонентов, которые не описываются в данной статье, поскольку не являются для нее существенными. В их число входят управление дисковыми томами (авторы статьи загружают всю базу данных в основную память), восстановление (авторы не рассматривают ситуации аварийных отказов приложений), распределенные транзакции и методы доступа, отличные от B-деревьев (такие как R-деревья). Примерная организация оставшихся компонентов показана на рис. 2.


Рис. 2. Основные компоненты Shore (подробное описание см. в тексте)

Shore предоставляется пользователям в виде некоторой библиотеки. Пользовательский код (в данном случае – реализация тестового набора TPC-C) компонуется с этой библиотекой, и в нем должна использоваться библиотека потоков управления, которая используется и в Shore. Каждая транзакция выполняется в некотором потоке Shore, имея доступ как к локальным переменным пользовательского пространства, так и к поддерживаемым Shore структурам данных и методам. К OLTP имеют отношения методы, требуемые для создания и заполнения файла базы данных, загрузки его в буферный пул, начала, фиксации или аварийного завершения транзакции, выполнения операций уровня записи, таких как выборка, модификация, создание и удаление, а также связанных с ними операций над первичными и вторичными индексами в виде B-деревьев.

Внутри тела транзакции (ограниченного операторами начала и фиксации) прикладной программист использует методы Shore для доступа к структурам хранения – файлам и индексам, а также к каталогам для их поиска. Во всех структурах данных для хранения информации используются слоттированные страницы (slotted page). Методы Shore выполняются под управлением менеджера транзакций, который тесно взаимодействует со всеми другими компонентами. При доступе к структурам хранения производятся вызовы менеджера журнала, менеджера блокировок и менеджера буферного пула. Эти вызовы всегда проходят через уровень управления параллелизмом, который отслеживает попытки совместного и монопольного доступа к различным ресурсам.
Этот уровень не является отдельным модулем; во всем коде все виды доступа к общим ресурсам производятся с синхронизацией на основе защелок. Защелки похожи на блокировки (в том, что они могут быть совместными и монопольными), но они являются легковесными и не сопровождаются механизмом обнаружения синхронизационных тупиков. Прикладной программист должен гарантировать, что синхронизация на основе защелок не приведет к тупику.

Далее авторы обсуждают архитектуру потока управления и приводят подробности блокировок, журнализации и управления пулом буферов.

Поддержка потоков управления. В Shore обеспечивается собственный пакет поддержки невытесняемых потоков управления на пользовательском уровне. Этот пакет был получен на основе пакета NewThreads (первоначально разрабатывавшегося в Университете Вашингтона). В пакете поддержки нитей Shore поддерживается API стандарта POSIX. Этот выбор пакета поддержки потоков управления повлиял на разработку кода и поведение Shore. Поскольку потоки поддерживаются на пользовательском уровне, приложение выполняется в рамках некоторого процесса, объединяющего все нити Shore. Блокировки этого процесса по причине ввода-вывода избегаются путем порождения отдельных процессов, ответственных за устройства ввода-вывода (все процессы общаются через разделяемую память). Тем не менее, приложения не могут напрямую пользоваться преимуществами многоядерных (или SMP) систем, если не входят в распределенные приложения. Однако последний вариант привел бы к избыточным накладным расходам для многоядерного центрального процессора в тех случаях, когда достаточно было бы использовать простой многопотоковый режим на системном уровне.

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


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

Блокировки и журнализация. В Shore реализована стандартная двухфазная схема блокировок для поддержки транзакций со стандартными свойствами ACID. Поддерживаются иерархические блокировки, эскалация которых (record, page, store, volume) по умолчанию выполняется менеджером блокировок. Для каждой транзакции поддерживается список удерживаемых ею блокировок, так что блокировки можно журнализовать при входе транзакции в состояние подготовки и освобождать в конце транзакции. В Shore также реализуется упреждающая запись в журнал (write ahead logging, WAL), для чего требуется тесное взаимодействие между менеджерами журнала и буферов. До выталкивания страницы из буферного пула должна быть вытолкнута соответствующая журнальная запись. Для этого требуется тесное взаимодействие между менеджерами транзакций и журнала. Все три мененджера понимают смысл последовательных номеров журнальных записей (log sequence numbers, LSN), которые служат для идентификации и обнаружения записей в журнале, расстановки в страницах временных меток, определения последней модификации, выполненной данной транзакцией, и нахождения последней журнальной записи, записанной транзакцией. С каждой страницей связывается LSN последней модификации, воздействовавшей на эту страницу. Страница не может быть записана на диск, пока журнальная запись с LSN, ассоциированным с этой страницей, не попадет в стабильную память.

Менеджер буферов. С помощью менеджера буферов все остальные модули (за исключением менеджера журнала) читают и записывают страницы. Страница читается путем вызова метода fix менеджера буферов. Если база данных целиком размещается в основной памяти, любая страница всегда будет располагаться в буферном пуле (в противном случае, если запрашиваемая страница не содержится в буферном пуле, соответствующий поток покидает процессор и ожидает, пока процесс, ответственный за ввод-вывод не поместит эту страницу в буферный пул).


Метод fix обновляет отображение между идентификаторами страниц и буферными фреймами и статистическую информацию буферного пула. Для обеспечения согласованности имеется защелка, регулирующая доступ к методу fix. При чтении записи (после того, как ее идентификатор найден путем поиска в индексе) происходит следующее:



  1. эта запись блокируется (как и содержащая ее страница, посредством иерархической блокировки);
  2. страница фиксируется в буферном пуле;
  3. вычисляется смещение от начала этой страницы до начала записи.


Чтение записи выполняется путем вызова методов pin/unpin. Модификация записей выполняется посредством копирования части записи или записи целиком из буферного пула в пользовательское адресное пространство, выполнения там требуемой модификации и передачи новых данных менеджеру хранения данных.

Подробности архитектуры Shore можно найти на Web-сайте проекта. В следующем подразделе описываются дополнительные механизмы и возможности системы; в этом же подразделе обсуждаются модификации системы, произведенные авторами статьи.


Содержание раздела