SlideShare a Scribd company logo
1 of 45
Download to read offline
Purely practical data
     structures
   Evgeny Lazin (@Lazin),
       Fprog 2012-11
План
1. CIMDB, постановка задачи
2. Решение задачи, использующее могучую
   персистентную структуру данных
3. Еще больше интересных структур данных
CIMDB
● Main memory база данных, созданная в
  компании "Монитор Электрик" (Пятигорск)
CIMDB
1. Common Information Model (CIM).
2. Большой граф объектов, порядка 1KK
элементов.
3. Используется для представления
элементов энергосистемы.
4. Нужно поддерживать целостность
данных.
5. Используется сложными расчетными
задачами.
Немного истории
● Первая реализация - реляционная
  модель.
  ○ Каждая расчетная задача реализует чтение и
    кеширование объектов модели.
  ○ Множество дублирующих друг друга ad-hoc
    реализаций.
  ○ SQL JOIN
    ■ Дай мне все высоковольтные линии,
       связанные с подстанциями, принадлежащими
       определенной генерирующей компании.
  ○ Нет API
Немного истории
● Вторая реализация - client-side cache.
  ○ Решает проблемы:
    ■ изобретения велосипеда.
    ■ общий API.
    ■ могучие join-ы выполняются на клиенте, в
       памяти.
  ○ И создает:
    ■ Проблему целостности данных.
        ●   Инвалидация кэша
     ■ Shared mutable state.
        ●   Shared + mutable = PITA
     ■ Пессимистичные блокировки.
        ●   Блокировки реализованы на уровне БД
     ■ Использует очень много памяти.
Требования
● Распределенность.
● Транзакционность.
  ○ Нужно поддерживать ACID свойства.
  ○ Tradeoff - целостность достаточно поддерживать
    в рамках модели timeline consistency.
  ○ Оптимистичные блокировки.
● Performance.
  ○ Нужно очень быстро читать, на уровне
    предыдущей версии.
  ○ Писать можно не очень быстро.
Странное и необъяснимое
1. Инспектирование изменений и
   управление "миром".
  a. Нужно для технологических задач.
2. Очень быстрое создание снепшотов и
   веток изменений.
  a. Нужно для расчетных задач.
Возможные решения
Чтение данных через TCP/UDP/Pipes
слишком медленно.
  a. Время одного round trip-а - десятки/сотни
     микросекунд.
  b. Требует кэширования на клиенте.
  c. Кэш должен уметь prefetch.
Выход
Поместить клиент и сервер на одну машину,
обмениваться данными через общую
память.

Проблема синхронизации доступа к общей
памяти.
Архитектура.
● Все объекты - неизменяемы. При
  изменении объекта, создается новая
  версия (MVCC).
● У объекта нет номера ревизии, версии
  или метки времени.
● Поиск объектов производится через
  индекс. Для каждой версии существует
  отдельный индекс.
Архитектура
Это позволяет естественным образом
реализовать MVCC и избавиться от
синхронизации при чтении.

Но теперь нам нужен очень эффективный
индекс!
Архитектура
Персистентные структуры данных -
естественный выбор в данной ситуации.
● Позволяют иметь одновременно
  несколько версий одной структуры
  данных, соответствующих разным
  моментам времени.
● Версии не являются полными копиями и
  разделяют часть данных.
Persistency
1. Partially persistent
   ○ Линейная история
   ○ Достаточно для реализации MVCC
2. Fully persistent
   ○ История изменений имеет форму дерева
   ○ Нужно для реализации веток изменений и
     изоляции транзакций
Хэш таблицы
● Очень быстрый поиск по ключу
● Коллизии
  ○ Коллизии возможны даже в том случае, если
    значения hash функции отличаются.
  ○ В нашем случае, у всех объектов есть
    уникальный hash.
● Невозможно сделать неизменяемой
  ○ Можно держать индекс в памяти каждого
    приложения, но это все усложняет.
Бинарные деревья + path copying

Функциональные
версии различных
сбалансированны
х деревьев.
Бинарные деревья
● Медленно
  ○ Скорость поиска по Id должна быть сравнима с
    hash таблицей.
● Глубина пропорциональна log2 N
● Для N = 1KK глубина дерева ~= 20
Префиксные деревья
●   Глубина дерева ограничена длиной ключа
●   Find, Insert, Delete - O(1)
●   Компактное представление в памяти
●   Можно сделать персистентным
Префиксные деревья
● Задача состоит в том, чтобы эффективно
  находить следующий узел.
● Можно использовать фрагмент ключа в
  качестве индекса массива.
Префиксные деревья
struct Node {
    Node[32] array;
}
Префиксные деревья
Для поиска следующего элемента в дереве
мы должны вычислить:

Find(int hash)
    index = hash & 0x1F
    next = this.array[index]
    if next != null:
        next.Find(hash >> 5)
    ...
Префиксные деревья
[00][01001][11001][10001][00011][00001][00000]

                           ...   00000




                 ...    00010    00001   00000




         ...    00011   00010    00001   00000
Префиксные деревья
● Существует множество реализаций
  префиксных деревьев, решающих
  проблему нулевых указателей
● Ideal Hash Trees. Phil Bagwell [2001]
Hash Array Mapped Trie
Реализации:
● Clojure's hash map
  ○ immutable
● Scala - Ctrie
  ○ mutable/concurrent
● Haskell - unordered-containers
● ...
HAMT
Каждый узел хранит:
● Количество дочерних элементов
● Массив дочерних элементов
  ○ Пара ключ - значение
  ○ Указатель на следующий узел
● Bitmap
HAMT
struct Node {
    int count;
    Node[count] array;
    int bitmap;
}


● Узел хранит только неравные null
  элементы
● А также битовую маску для вычисления
  индекса
HAMT
Find(int hash)
    int shift = hash & 0x1F
    int mask = (1 << shift) - 1
    int index = Popcnt(this.bitmap & mask)
    next = this.array[index]
    next.Find(hash >> 5)


Вычисляем значение ключа для поиска
HAMT
Find(int hash)
    int shift = hash & 0x1F
    int mask = (1 << shift) - 1
    int index = Popcnt(this.bitmap & mask)
    next = this.array[index]
    next.Find(hash >> 5)


(1 << shift) вернет слово, в котором будет
установлен 1 бит, индекс которого равен
индексу в несжатом массиве из 32х
элементов
HAMT
Find(int hash)
    int shift = hash & 0x1F
    int mask = (1 << shift) - 1
    int index = Popcnt(this.bitmap & mask)
    next = this.array[index]
    next.Find(hash >> 5)


(1 << shift) - 1 - мы получаем маску, в
которой установлены все биты, чей индекс
меньше индекса искомого элемента
HAMT
Find(int hash)
    int shift = hash & 0x1F
    int mask = (1 << shift) - 1
    int index = Popcnt(this.bitmap & mask)
    next = this.array[index]
    next.Find(hash >> 5)


Popcnt - возвращает количество ненулевых
бит в слове.
HAMT
Find(int hash = 5)
    int shift = 5 & 0x1F
    int mask = (1 << 5) - 1
    int index = Popcnt(100001b & 11111b)
    next = this.array[1]
    next.Find(hash >> 5)

bitmap =
00000000000000000000000000100001b

array = [a, b]
naive = [a, 0, 0, 0, 0, b, ...
HAMT
Можно не сжимать узлы, имеющие
множество дочерних элементов.

Если предполагается наличие дубликатов,
нужен еще один тип узла для разрешения
конфликтов.
HAMT
Реализация на С# (прототип)
● В 2.5 - 3 раза медленнее чем Dictionary
● Расходует сопоставимое количество
  памяти
● Нет коллизий
● Нагружает GC
HAMT
Реализация на Си (production)
● В несколько раз быстрее чем Dictionary
● Использует подсчет ссылок и не
  нагружает GC
● Не использует атомарные инструкции
  (lock xchg и тп) - очень быстро работает в
  одном потоке
Pros
● Простота архитектуры
  ○   Клиент отправляет на сервер транзакции
  ○   В ответ получает указатель на root
  ○   Сообщает о переходе на новую версию
  ○   Очень похоже на VCS
● Сложные вещи реализуются очень просто
  ○ Очень дешево иметь множество слегка
    отличающихся версий одной структуры данных
  ○ Очень легко реализуется изоляция транзакций
● Нет блокировок
  ○ Только координация посредством сообщений
Cons
● Возможны утечки памяти
  ○ Но только если клиент неправильно работает
● Все еще низкая производительность в
  некоторых случаях :)
Ссылки
● Каждый объект может ссылаться на
  другие объекты.
● Физически, эти ссылки реализованы как
  массивы идентификаторов связанных
  объектов.
● Всегда есть обратные ссылки.
Ссылки
● Ходить по ссылкам через индекс -
  достаточно дорого.
● Можно ли хранить внутри объектов не
  только идентификаторы, но и указатели
  на другие объекты?
Ссылки
● Любую связную структуру данных можно
  сделать частично или полностью
  персистентной
● При определенных условиях - за O(1)
  времени и памяти
● "Making Data Structures Persistent" by
  James R. Driscoll, Neil Sarnak, Daniel D.
  Sleator, Robert E. Tarjan
Принцип работы
● Каждый объект может опционально
  хранить один или несколько указателей
  на связанные с ним объекты.
● Каждый объект получает дополнительное
  поле - modification box (m-box)
● m-box может хранить информацию об
  изменениях указателей
● С каждым изменением связан номер
  версии
Пример
immutable list update

                      old value



                      new value




mutable list update

                      old value

       mbox

                      new value
Pros
● Быстрый переход по ссылкам
● Более быстрая проверка ссылочной
  целостности при commit-е
Cons
● Нужно больше памяти
● И процессорного времени при
  обновлениях
● Для чтения нужно знать номер ревизии
● Можно обеспечить только частичную
  персистентность, это означает что:
  ○ Никаких указателей в ветках
  ○ Никаких указателей в транзакциях
Вывод
Данный подход выгодно использовать
только опционально, не для всех типов
объектов и не для всех ссылок.
Вопросы?

More Related Content

What's hot

FreeRTOS
FreeRTOSFreeRTOS
FreeRTOSquakke
 
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Mikhail Kurnosov
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Mikhail Kurnosov
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3Eugeniy Tyumentcev
 
Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)Mikhail Kurnosov
 
Проблемы 64-битного кода на примерах
Проблемы 64-битного кода на примерахПроблемы 64-битного кода на примерах
Проблемы 64-битного кода на примерахTatyanazaxarova
 
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...Mikhail Kurnosov
 
04 ос взаимодействие_процессов_1
04 ос взаимодействие_процессов_104 ос взаимодействие_процессов_1
04 ос взаимодействие_процессов_1921519
 
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...Alexey Paznikov
 
Multiprocessor Programming Intro (lecture 1)
Multiprocessor Programming Intro (lecture 1)Multiprocessor Programming Intro (lecture 1)
Multiprocessor Programming Intro (lecture 1)Dmitry Tsitelov
 
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Mikhail Kurnosov
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Alexey Paznikov
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksMikhail Kurnosov
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, paral...Mikhail Kurnosov
 
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...Mikhail Kurnosov
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухинcorehard_by
 
Денис Колодин: Low-latency и soft-realtime на Python
Денис Колодин: Low-latency и soft-realtime на PythonДенис Колодин: Low-latency и soft-realtime на Python
Денис Колодин: Low-latency и soft-realtime на Pythonit-people
 
Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)Mikhail Kurnosov
 
Паттерны 64-битных ошибок в играх
Паттерны 64-битных ошибок в играхПаттерны 64-битных ошибок в играх
Паттерны 64-битных ошибок в играхAndrey Karpov
 

What's hot (19)

FreeRTOS
FreeRTOSFreeRTOS
FreeRTOS
 
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
 
Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)
 
Проблемы 64-битного кода на примерах
Проблемы 64-битного кода на примерахПроблемы 64-битного кода на примерах
Проблемы 64-битного кода на примерах
 
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
 
04 ос взаимодействие_процессов_1
04 ос взаимодействие_процессов_104 ос взаимодействие_процессов_1
04 ос взаимодействие_процессов_1
 
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
 
Multiprocessor Programming Intro (lecture 1)
Multiprocessor Programming Intro (lecture 1)Multiprocessor Programming Intro (lecture 1)
Multiprocessor Programming Intro (lecture 1)
 
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, paral...
 
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
 
Денис Колодин: Low-latency и soft-realtime на Python
Денис Колодин: Low-latency и soft-realtime на PythonДенис Колодин: Low-latency и soft-realtime на Python
Денис Колодин: Low-latency и soft-realtime на Python
 
Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)
 
Паттерны 64-битных ошибок в играх
Паттерны 64-битных ошибок в играхПаттерны 64-битных ошибок в играх
Паттерны 64-битных ошибок в играх
 

Similar to Евгений Лазин. Неизменяемая структура данных HAMT для создания БД в памяти

Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...Ontico
 
BigMemory - работа с сотнями миллионов бизнес-объектов / Дмитрий Хмаладзе (Ag...
BigMemory - работа с сотнями миллионов бизнес-объектов / Дмитрий Хмаладзе (Ag...BigMemory - работа с сотнями миллионов бизнес-объектов / Дмитрий Хмаладзе (Ag...
BigMemory - работа с сотнями миллионов бизнес-объектов / Дмитрий Хмаладзе (Ag...Ontico
 
Константин Осипов
Константин ОсиповКонстантин Осипов
Константин ОсиповCodeFest
 
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ LibraryИнтервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ LibraryTatyanazaxarova
 
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...Ontico
 
Cравнительный анализ хранилищ данных (Олег Царев, Кирилл Коринский)
Cравнительный анализ хранилищ данных (Олег Царев, Кирилл Коринский)Cравнительный анализ хранилищ данных (Олег Царев, Кирилл Коринский)
Cравнительный анализ хранилищ данных (Олег Царев, Кирилл Коринский)Ontico
 
Multithreading in JS. Myth or reality?
Multithreading in JS. Myth or reality?Multithreading in JS. Myth or reality?
Multithreading in JS. Myth or reality?Alexander Syrotenko
 
Machine learning c использованием нейронных сетей, Дмитрий Лапин
Machine learning c использованием нейронных сетей, Дмитрий ЛапинMachine learning c использованием нейронных сетей, Дмитрий Лапин
Machine learning c использованием нейронных сетей, Дмитрий ЛапинIT61
 
Не бойся, это всего лишь данные... просто их много
Не бойся, это всего лишь данные... просто их многоНе бойся, это всего лишь данные... просто их много
Не бойся, это всего лишь данные... просто их многоRoman Dvornov
 
кри 2014 elastic search рациональный подход к созданию собственной системы а...
кри 2014 elastic search  рациональный подход к созданию собственной системы а...кри 2014 elastic search  рациональный подход к созданию собственной системы а...
кри 2014 elastic search рациональный подход к созданию собственной системы а...Vyacheslav Nikulin
 
ORM battle. MyBatis vs Hibernate
ORM battle. MyBatis vs HibernateORM battle. MyBatis vs Hibernate
ORM battle. MyBatis vs HibernateAlexey Zinoviev
 
2012-12-01 03 Битва ORM: Hibernate vs MyBatis. Давайте жить дружно!
2012-12-01 03 Битва ORM: Hibernate vs MyBatis. Давайте жить дружно!2012-12-01 03 Битва ORM: Hibernate vs MyBatis. Давайте жить дружно!
2012-12-01 03 Битва ORM: Hibernate vs MyBatis. Давайте жить дружно!Омские ИТ-субботники
 
Что такое Postgresql (Максим Богук)
Что такое Postgresql (Максим Богук)Что такое Postgresql (Максим Богук)
Что такое Postgresql (Максим Богук)Ontico
 
Сравнительный анализ хранилищ данных, Олег Царев, Кирилл Коринский
Сравнительный анализ хранилищ данных, Олег Царев, Кирилл КоринскийСравнительный анализ хранилищ данных, Олег Царев, Кирилл Коринский
Сравнительный анализ хранилищ данных, Олег Царев, Кирилл КоринскийFuenteovejuna
 
Smirnov Memcached High Load 2008
Smirnov Memcached High Load 2008Smirnov Memcached High Load 2008
Smirnov Memcached High Load 2008Ontico
 
Smirnov Memcached Highload 2008
Smirnov Memcached Highload 2008Smirnov Memcached Highload 2008
Smirnov Memcached Highload 2008Ontico
 
Максим Богук. Postgres-XC
Максим Богук. Postgres-XCМаксим Богук. Postgres-XC
Максим Богук. Postgres-XCPostgreSQL-Consulting
 
20111002 information retrieval raskovalov_lecture3
20111002 information retrieval raskovalov_lecture320111002 information retrieval raskovalov_lecture3
20111002 information retrieval raskovalov_lecture3Computer Science Club
 
Разработка высокопроизводительных серверных приложений для Linux/Unix (Алекса...
Разработка высокопроизводительных серверных приложений для Linux/Unix (Алекса...Разработка высокопроизводительных серверных приложений для Linux/Unix (Алекса...
Разработка высокопроизводительных серверных приложений для Linux/Unix (Алекса...Ontico
 
Tarantool, .net, newsql
Tarantool, .net, newsqlTarantool, .net, newsql
Tarantool, .net, newsqlAnatoly Popov
 

Similar to Евгений Лазин. Неизменяемая структура данных HAMT для создания БД в памяти (20)

Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
 
BigMemory - работа с сотнями миллионов бизнес-объектов / Дмитрий Хмаладзе (Ag...
BigMemory - работа с сотнями миллионов бизнес-объектов / Дмитрий Хмаладзе (Ag...BigMemory - работа с сотнями миллионов бизнес-объектов / Дмитрий Хмаладзе (Ag...
BigMemory - работа с сотнями миллионов бизнес-объектов / Дмитрий Хмаладзе (Ag...
 
Константин Осипов
Константин ОсиповКонстантин Осипов
Константин Осипов
 
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ LibraryИнтервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
 
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
 
Cравнительный анализ хранилищ данных (Олег Царев, Кирилл Коринский)
Cравнительный анализ хранилищ данных (Олег Царев, Кирилл Коринский)Cравнительный анализ хранилищ данных (Олег Царев, Кирилл Коринский)
Cравнительный анализ хранилищ данных (Олег Царев, Кирилл Коринский)
 
Multithreading in JS. Myth or reality?
Multithreading in JS. Myth or reality?Multithreading in JS. Myth or reality?
Multithreading in JS. Myth or reality?
 
Machine learning c использованием нейронных сетей, Дмитрий Лапин
Machine learning c использованием нейронных сетей, Дмитрий ЛапинMachine learning c использованием нейронных сетей, Дмитрий Лапин
Machine learning c использованием нейронных сетей, Дмитрий Лапин
 
Не бойся, это всего лишь данные... просто их много
Не бойся, это всего лишь данные... просто их многоНе бойся, это всего лишь данные... просто их много
Не бойся, это всего лишь данные... просто их много
 
кри 2014 elastic search рациональный подход к созданию собственной системы а...
кри 2014 elastic search  рациональный подход к созданию собственной системы а...кри 2014 elastic search  рациональный подход к созданию собственной системы а...
кри 2014 elastic search рациональный подход к созданию собственной системы а...
 
ORM battle. MyBatis vs Hibernate
ORM battle. MyBatis vs HibernateORM battle. MyBatis vs Hibernate
ORM battle. MyBatis vs Hibernate
 
2012-12-01 03 Битва ORM: Hibernate vs MyBatis. Давайте жить дружно!
2012-12-01 03 Битва ORM: Hibernate vs MyBatis. Давайте жить дружно!2012-12-01 03 Битва ORM: Hibernate vs MyBatis. Давайте жить дружно!
2012-12-01 03 Битва ORM: Hibernate vs MyBatis. Давайте жить дружно!
 
Что такое Postgresql (Максим Богук)
Что такое Postgresql (Максим Богук)Что такое Postgresql (Максим Богук)
Что такое Postgresql (Максим Богук)
 
Сравнительный анализ хранилищ данных, Олег Царев, Кирилл Коринский
Сравнительный анализ хранилищ данных, Олег Царев, Кирилл КоринскийСравнительный анализ хранилищ данных, Олег Царев, Кирилл Коринский
Сравнительный анализ хранилищ данных, Олег Царев, Кирилл Коринский
 
Smirnov Memcached High Load 2008
Smirnov Memcached High Load 2008Smirnov Memcached High Load 2008
Smirnov Memcached High Load 2008
 
Smirnov Memcached Highload 2008
Smirnov Memcached Highload 2008Smirnov Memcached Highload 2008
Smirnov Memcached Highload 2008
 
Максим Богук. Postgres-XC
Максим Богук. Postgres-XCМаксим Богук. Postgres-XC
Максим Богук. Postgres-XC
 
20111002 information retrieval raskovalov_lecture3
20111002 information retrieval raskovalov_lecture320111002 information retrieval raskovalov_lecture3
20111002 information retrieval raskovalov_lecture3
 
Разработка высокопроизводительных серверных приложений для Linux/Unix (Алекса...
Разработка высокопроизводительных серверных приложений для Linux/Unix (Алекса...Разработка высокопроизводительных серверных приложений для Linux/Unix (Алекса...
Разработка высокопроизводительных серверных приложений для Linux/Unix (Алекса...
 
Tarantool, .net, newsql
Tarantool, .net, newsqlTarantool, .net, newsql
Tarantool, .net, newsql
 

Евгений Лазин. Неизменяемая структура данных HAMT для создания БД в памяти

  • 1. Purely practical data structures Evgeny Lazin (@Lazin), Fprog 2012-11
  • 2. План 1. CIMDB, постановка задачи 2. Решение задачи, использующее могучую персистентную структуру данных 3. Еще больше интересных структур данных
  • 3. CIMDB ● Main memory база данных, созданная в компании "Монитор Электрик" (Пятигорск)
  • 4. CIMDB 1. Common Information Model (CIM). 2. Большой граф объектов, порядка 1KK элементов. 3. Используется для представления элементов энергосистемы. 4. Нужно поддерживать целостность данных. 5. Используется сложными расчетными задачами.
  • 5. Немного истории ● Первая реализация - реляционная модель. ○ Каждая расчетная задача реализует чтение и кеширование объектов модели. ○ Множество дублирующих друг друга ad-hoc реализаций. ○ SQL JOIN ■ Дай мне все высоковольтные линии, связанные с подстанциями, принадлежащими определенной генерирующей компании. ○ Нет API
  • 6. Немного истории ● Вторая реализация - client-side cache. ○ Решает проблемы: ■ изобретения велосипеда. ■ общий API. ■ могучие join-ы выполняются на клиенте, в памяти. ○ И создает: ■ Проблему целостности данных. ● Инвалидация кэша ■ Shared mutable state. ● Shared + mutable = PITA ■ Пессимистичные блокировки. ● Блокировки реализованы на уровне БД ■ Использует очень много памяти.
  • 7. Требования ● Распределенность. ● Транзакционность. ○ Нужно поддерживать ACID свойства. ○ Tradeoff - целостность достаточно поддерживать в рамках модели timeline consistency. ○ Оптимистичные блокировки. ● Performance. ○ Нужно очень быстро читать, на уровне предыдущей версии. ○ Писать можно не очень быстро.
  • 8. Странное и необъяснимое 1. Инспектирование изменений и управление "миром". a. Нужно для технологических задач. 2. Очень быстрое создание снепшотов и веток изменений. a. Нужно для расчетных задач.
  • 9. Возможные решения Чтение данных через TCP/UDP/Pipes слишком медленно. a. Время одного round trip-а - десятки/сотни микросекунд. b. Требует кэширования на клиенте. c. Кэш должен уметь prefetch.
  • 10. Выход Поместить клиент и сервер на одну машину, обмениваться данными через общую память. Проблема синхронизации доступа к общей памяти.
  • 11. Архитектура. ● Все объекты - неизменяемы. При изменении объекта, создается новая версия (MVCC). ● У объекта нет номера ревизии, версии или метки времени. ● Поиск объектов производится через индекс. Для каждой версии существует отдельный индекс.
  • 12. Архитектура Это позволяет естественным образом реализовать MVCC и избавиться от синхронизации при чтении. Но теперь нам нужен очень эффективный индекс!
  • 13. Архитектура Персистентные структуры данных - естественный выбор в данной ситуации. ● Позволяют иметь одновременно несколько версий одной структуры данных, соответствующих разным моментам времени. ● Версии не являются полными копиями и разделяют часть данных.
  • 14. Persistency 1. Partially persistent ○ Линейная история ○ Достаточно для реализации MVCC 2. Fully persistent ○ История изменений имеет форму дерева ○ Нужно для реализации веток изменений и изоляции транзакций
  • 15. Хэш таблицы ● Очень быстрый поиск по ключу ● Коллизии ○ Коллизии возможны даже в том случае, если значения hash функции отличаются. ○ В нашем случае, у всех объектов есть уникальный hash. ● Невозможно сделать неизменяемой ○ Можно держать индекс в памяти каждого приложения, но это все усложняет.
  • 16. Бинарные деревья + path copying Функциональные версии различных сбалансированны х деревьев.
  • 17. Бинарные деревья ● Медленно ○ Скорость поиска по Id должна быть сравнима с hash таблицей. ● Глубина пропорциональна log2 N ● Для N = 1KK глубина дерева ~= 20
  • 18. Префиксные деревья ● Глубина дерева ограничена длиной ключа ● Find, Insert, Delete - O(1) ● Компактное представление в памяти ● Можно сделать персистентным
  • 19. Префиксные деревья ● Задача состоит в том, чтобы эффективно находить следующий узел. ● Можно использовать фрагмент ключа в качестве индекса массива.
  • 21. Префиксные деревья Для поиска следующего элемента в дереве мы должны вычислить: Find(int hash) index = hash & 0x1F next = this.array[index] if next != null: next.Find(hash >> 5) ...
  • 22. Префиксные деревья [00][01001][11001][10001][00011][00001][00000] ... 00000 ... 00010 00001 00000 ... 00011 00010 00001 00000
  • 23. Префиксные деревья ● Существует множество реализаций префиксных деревьев, решающих проблему нулевых указателей ● Ideal Hash Trees. Phil Bagwell [2001]
  • 24. Hash Array Mapped Trie Реализации: ● Clojure's hash map ○ immutable ● Scala - Ctrie ○ mutable/concurrent ● Haskell - unordered-containers ● ...
  • 25. HAMT Каждый узел хранит: ● Количество дочерних элементов ● Массив дочерних элементов ○ Пара ключ - значение ○ Указатель на следующий узел ● Bitmap
  • 26. HAMT struct Node { int count; Node[count] array; int bitmap; } ● Узел хранит только неравные null элементы ● А также битовую маску для вычисления индекса
  • 27. HAMT Find(int hash) int shift = hash & 0x1F int mask = (1 << shift) - 1 int index = Popcnt(this.bitmap & mask) next = this.array[index] next.Find(hash >> 5) Вычисляем значение ключа для поиска
  • 28. HAMT Find(int hash) int shift = hash & 0x1F int mask = (1 << shift) - 1 int index = Popcnt(this.bitmap & mask) next = this.array[index] next.Find(hash >> 5) (1 << shift) вернет слово, в котором будет установлен 1 бит, индекс которого равен индексу в несжатом массиве из 32х элементов
  • 29. HAMT Find(int hash) int shift = hash & 0x1F int mask = (1 << shift) - 1 int index = Popcnt(this.bitmap & mask) next = this.array[index] next.Find(hash >> 5) (1 << shift) - 1 - мы получаем маску, в которой установлены все биты, чей индекс меньше индекса искомого элемента
  • 30. HAMT Find(int hash) int shift = hash & 0x1F int mask = (1 << shift) - 1 int index = Popcnt(this.bitmap & mask) next = this.array[index] next.Find(hash >> 5) Popcnt - возвращает количество ненулевых бит в слове.
  • 31. HAMT Find(int hash = 5) int shift = 5 & 0x1F int mask = (1 << 5) - 1 int index = Popcnt(100001b & 11111b) next = this.array[1] next.Find(hash >> 5) bitmap = 00000000000000000000000000100001b array = [a, b] naive = [a, 0, 0, 0, 0, b, ...
  • 32. HAMT Можно не сжимать узлы, имеющие множество дочерних элементов. Если предполагается наличие дубликатов, нужен еще один тип узла для разрешения конфликтов.
  • 33. HAMT Реализация на С# (прототип) ● В 2.5 - 3 раза медленнее чем Dictionary ● Расходует сопоставимое количество памяти ● Нет коллизий ● Нагружает GC
  • 34. HAMT Реализация на Си (production) ● В несколько раз быстрее чем Dictionary ● Использует подсчет ссылок и не нагружает GC ● Не использует атомарные инструкции (lock xchg и тп) - очень быстро работает в одном потоке
  • 35. Pros ● Простота архитектуры ○ Клиент отправляет на сервер транзакции ○ В ответ получает указатель на root ○ Сообщает о переходе на новую версию ○ Очень похоже на VCS ● Сложные вещи реализуются очень просто ○ Очень дешево иметь множество слегка отличающихся версий одной структуры данных ○ Очень легко реализуется изоляция транзакций ● Нет блокировок ○ Только координация посредством сообщений
  • 36. Cons ● Возможны утечки памяти ○ Но только если клиент неправильно работает ● Все еще низкая производительность в некоторых случаях :)
  • 37. Ссылки ● Каждый объект может ссылаться на другие объекты. ● Физически, эти ссылки реализованы как массивы идентификаторов связанных объектов. ● Всегда есть обратные ссылки.
  • 38. Ссылки ● Ходить по ссылкам через индекс - достаточно дорого. ● Можно ли хранить внутри объектов не только идентификаторы, но и указатели на другие объекты?
  • 39. Ссылки ● Любую связную структуру данных можно сделать частично или полностью персистентной ● При определенных условиях - за O(1) времени и памяти ● "Making Data Structures Persistent" by James R. Driscoll, Neil Sarnak, Daniel D. Sleator, Robert E. Tarjan
  • 40. Принцип работы ● Каждый объект может опционально хранить один или несколько указателей на связанные с ним объекты. ● Каждый объект получает дополнительное поле - modification box (m-box) ● m-box может хранить информацию об изменениях указателей ● С каждым изменением связан номер версии
  • 41. Пример immutable list update old value new value mutable list update old value mbox new value
  • 42. Pros ● Быстрый переход по ссылкам ● Более быстрая проверка ссылочной целостности при commit-е
  • 43. Cons ● Нужно больше памяти ● И процессорного времени при обновлениях ● Для чтения нужно знать номер ревизии ● Можно обеспечить только частичную персистентность, это означает что: ○ Никаких указателей в ветках ○ Никаких указателей в транзакциях
  • 44. Вывод Данный подход выгодно использовать только опционально, не для всех типов объектов и не для всех ссылок.