Классика баз данных - статьи

       

Решения с разделением


Оптимизация при реализации CU-классов направлена, прежде всего, на то, чтобы избегать конфликтов. Цель состоит в разделении агрегатного объекта на объекты-подкомпоненты, на которые указывает корневой объект, представляющий исходный агрегат. Все сообщения направляются в корневой объект, который выполняет, по крайней мере, две функции.

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

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

    Одним из примеров разделения является реализация CuHashDictionary. В этом случае сама хэш-таблица обеспечивает естественное разделение данных. Каждый элемент таблицы представляет собой кластерный бакет, и только для операций над одним и тем же кластерным бакетом требуется анализ их CU-поведения.

    Реализация класса CuCounter иллюстрирует другой способ разбиения объекта на несколько подкомпонентов. Счетчик в CuCounter реализуется не как одиночное числовое значение, а как несколько значений, каждое из которых инкапсулируется в отдельном объекте-подкомпоненте. Корневой объект CuCounter в действительности является массивом подкомпонентов. Когда в CuCounter посылается сообщение с запросом текущего значения счетчика, в ответ передается сумма значений подкомпонентов. Когда в CuCounter посылается сообщение для увеличения или уменьшения значения, CuCounter модифицирует значение только одного подкомпонента. CuCounter выбирает подкомпонент в соответствии с уникальным идентификатором сессии текущей транзакции, который используется в качестве индекса в массиве подкомпонентов. Этот метод гарантирует, что транзакции одновременно выполняющихся сессий не модифицируют один и тот же подкомпонент, и поэтому никогда не испытывают конфликт "запись-запись".

    Третий пример разделения можно найти в реализации CuQueue. Обычно для очереди поддерживаются указатели на голову и хвост. Рассмотрим взамен этого CuQueue, которая содержит ссылки на два отдельных объекта, в одним из которых инкапсулируется ссылка на голову, а в другом - на хвост. При использовании этой структуры производители обновляют только промежуточный объект-голову, а потребители - только промежуточный объект-хвост. Таким образом, одиночные производитель и потребитель могут работать с очередью без каких-либо конфликтов "запись-запись". Если с CuQueue параллельно работает несколько производителей, то при возникновении конфликта "запись-запись" над промежуточным объектом для разрешения конфликта можно повторно выполнить операцию добавления элемента и сохранить CuQueue в согласованном состоянии.



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