SlideShare une entreprise Scribd logo
1  sur  87
Télécharger pour lire hors ligne
Функциональные (персистентные) структуры данных и
их влияние на архитектуру приложений
Vadim Shalts
Vadim Shalts Функциональные структуры данных и архитектура 1 / 86
Персистентные структуры данных и их анализ
Оговорки
Vadim Shalts Функциональные структуры данных и архитектура 2 / 86
Персистентные структуры данных и их анализ
Сase классы
Scala:
case class Foo(myval: String)
Java:
final class Foo {
private final String myval;
public Foo(String initialValue) {
this.myval = initialValue;
}
public String getValue() {
return this.myval;
}
@Override
public boolean equals(Object o) {
// ....
}
@Override
public int hashCode() {
// ...
}
}
Vadim Shalts Функциональные структуры данных и архитектура 3 / 86
Персистентные структуры данных и их анализ
Сase классы
Scala:
case class Foo(myval: String)
Java:
final class Foo {
private final String myval;
public Foo(String initialValue) {
this.myval = initialValue;
}
public String getValue() {
return this.myval;
}
@Override
public boolean equals(Object o) {
// ....
}
@Override
public int hashCode() {
// ...
}
}
Возможные решения для Java
projectlombok.org
immutables.org
github.com/google/auto
www.jannocessor.org
Scala, Groovy, Clojure :)
Vadim Shalts Функциональные структуры данных и архитектура 3 / 86
Персистентные структуры данных и их анализ
Project valhalla. JEP 169: Value Objects
Vadim Shalts Функциональные структуры данных и архитектура 4 / 86
Персистентные структуры данных и их анализ
Важные свойства неизменяемых (immutable) объектов
Легко создавать, тестировать и использовать
Являются потокобезопасными
Хорошие кандидаты для кэширования
Поддерживают инвариант состояния
Исключения не могут “разломать” состояние
Vadim Shalts Функциональные структуры данных и архитектура 5 / 86
Персистентные структуры данных и их анализ
Класс будет неизменяемым, если верно следующее:
Класс объявляется как final
Все его поля являются final
Ссылка this не должна пропасть во время конструирования
Не содержат методов, которые могли бы изменить наблюдаемое
состояние объекта
Любые поля, содержащие ссылки на изменяемые объекты,
например массивы, совокупности или изменяемые классы,
например Date:
Являются приватными
Никогда не возвращаются и никаким другим образом не
становятся доступными вызывающим операторам
Являются единственными ссылками на те объекты, на которые они
ссылаются
Не изменяют после конструирования состояние объектов, на
которые они ссылаются
Vadim Shalts Функциональные структуры данных и архитектура 6 / 86
Персистентные структуры данных и их анализ
JLS. Семантика final полей
«A thread-safe immutable object is seen as immutable by all threads,
even if a data race is used to pass references to the immutable object
between threads»
JLS 17.5
Vadim Shalts Функциональные структуры данных и архитектура 7 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Data Processing in Exascale-class Computing Systems | April 27, 2011 | CRM3
Transistors
(thousands)
Single-thread
Performance
(SpecINT)
Frequency
(MHz)
Typical Power
(Watts)
Number of
Cores
Original data collected and plotted by M. Horowitz, F. Labonte, O. Shacham, K. Olukotun, L. Hammond and C. Batten
Dotted line extrapolations by C. Moore
35 YEARS OF MICROPROCESSOR TREND DATA
Vadim Shalts Функциональные структуры данных и архитектура 8 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Закон Амдала. Рост производительности
вычислительной системы
Vadim Shalts Функциональные структуры данных и архитектура 9 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Функциональное программирование
«In computer science, functional programming is a
programming paradigm, a style of building the structure and
elements of computer programs, that treats computation as
the evaluation of mathematical functions and avoids state
and mutable data.»
wikipedia
Vadim Shalts Функциональные структуры данных и архитектура 10 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Простая нотация
f (x)
Что скрывается за простой нотацией?
Vadim Shalts Функциональные структуры данных и архитектура 11 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Сложность f(x)
int[] func(int[] param);
Какова сложность, если параметр:
простой тип
простой объект
коллекция простых типов
...
Vadim Shalts Функциональные структуры данных и архитектура 12 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Традиционный подход
class Order {
private ArrayList<Item> items = EMPTY_LIST;
private double total = 0.0;
void addItem(Item item) {
items.add(item);
total = calcTotal();
}
String createCheck() {
// use items and total ...
// ....
}
// ....
}
Vadim Shalts Функциональные структуры данных и архитектура 13 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Традиционный подход
class Order {
private ArrayList<Item> items = EMPTY_LIST;
private double total = 0.0;
synchronized void addItem(Item item) {
items.add(item);
total = calcTotal();
}
synchronized String createCheck() {
// use items and total ...
// ....
}
// ....
}
Vadim Shalts Функциональные структуры данных и архитектура 14 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Java Language and Virtual Machine Specifications (14.19)
If execution of the Block completes normally, then the
monitor is unlocked and the synchronized statement
completes normally.
If execution of the Block completes abruptly for any
reason, then the monitor is unlocked and the
synchronized statement completes abruptly for the
same reason.
Vadim Shalts Функциональные структуры данных и архитектура 15 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Потеряна предсказуемость
Потеряна предсказуемость.
Что можно сделать?
Vadim Shalts Функциональные структуры данных и архитектура 16 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Традиционный подход. Сохраняем состояние ошибки
class Order {
private ArrayList<Item> items = EMPTY_LIST;
private double total = 0.0;
private boolean incorrectState = false;
synchronized void addItem(Item item) {
if (incorrectState)
throw new IllegalStateException();
incorrectState = true;
items.add(item);
total = calcTotal();
incorrectState = false;
}
// ....
}
Vadim Shalts Функциональные структуры данных и архитектура 17 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Традиционный подход. Предотвращаем потерю
состояния
class Order {
private List<Item> items = EMPTY_LIST;
private double total = 0.0;
synchronized void addItem(Item item) {
List<Item> newItems =
fastCopyAndAppend(items, item); // Как?
double newTotal = calcTotal(newItems);
items = newItems;
total = newTotal;
}
// ....
}
Vadim Shalts Функциональные структуры данных и архитектура 18 / 86
Персистентные структуры данных и их анализ Необходимость (или в чём проблемы)
Еще лучше сделать класс Order неизменяемым
(immutable)!
«Classes should be immutable unless there’s a very good
reason to make them mutable.»
Joshua Bloch
«If an object cannot change state, then it can never
encounter conflicts or inconsistencies when multiple activities
attempt to change its state in incompatible ways. Programs
are much simpler to understand if existing objects are never
changed, but instead new ones are continually created during
the course of any computation.»
Doug Lea
Vadim Shalts Функциональные структуры данных и архитектура 19 / 86
Персистентные структуры данных и их анализ Определимся с терминологией
Термины
Неизменяемые (Immutable) структуры данных после
создания не могут быть изменены
Immutable структуры данных (обычно) могут быть скопированы с
изменениями для создания новой версии
Создание новой версии требует столько же памяти сколько
потребляет оригинал.
Персистентные (Persistent) структуры данных после
изменения содержат старую и новую версию данных
Persistent структуры данных являются Immutable в том смысле, что
создание новой версии не приводит к изменению старых версий
Создание новой версии может потребовать копирования данных из
оригинала. При этом старая и новые версии будут содержать
общие данные
Vadim Shalts Функциональные структуры данных и архитектура 20 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Обозначения
val x = X Y Z null
val x = X Y Z
Vadim Shalts Функциональные структуры данных и архитектура 21 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Список. Начальный
val x1 = X Y Z
Vadim Shalts Функциональные структуры данных и архитектура 22 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Список. Добавление
val x1 = X Y Z
val x2 = W
Vadim Shalts Функциональные структуры данных и архитектура 23 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Список. Удаление
val x1 = X Y Z
val x2 = W
val x3 =
Vadim Shalts Функциональные структуры данных и архитектура 24 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Как получить такие коллекции в Java?
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>1.6.0</version>
</dependency>
Или
github.com/krukow/clj-ds
pcollections.org
www.functionaljava.org
Vadim Shalts Функциональные структуры данных и архитектура 25 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Использование списка из Java
import com.github.krukow.clj_ds.*;
import java.util.LinkedList;
public class ClojureListTest {
public static void main(String[] args) {
PersistentList<String>
listCopy = Persistents.linkedList(new LinkedList());
PersistentList<String> list =
Persistents.linkedList("my", "list");
PersistentList<String> extended = list.plus("!!!");
PersistentList<String> cutted = extended.minus().minus();
System.out.println(list); // ("my" "list")
System.out.println(extended); // ("!!!" "my" "list")
System.out.println(cutted); // ("list")
}
}
Vadim Shalts Функциональные структуры данных и архитектура 26 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
FIFO очередь. Начальное состояние
val x1 =
Queue
enqueue list
dequeue list
5 4
1 2 3
Vadim Shalts Функциональные структуры данных и архитектура 27 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
FIFO очередь. Вставка
val x1 =
Queue
enqueue list
dequeue list
5 4
1 2 3
Queue
enqueue list
dequeue list
val x2 =
6
Vadim Shalts Функциональные структуры данных и архитектура 28 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
FIFO очередь. Удаление
val x1 =
Queue
enqueue list
dequeue list
5 4
1 2 3
Queue
enqueue list
dequeue list
val x2 =
6
Queue
enqueue list
dequeue list
val x3 =
Vadim Shalts Функциональные структуры данных и архитектура 29 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
FIFO очередь. Удаление
val x5 =
Queue
enqueue list
dequeue list
Queue
enqueue list
dequeue list
Queue
enqueue list
dequeue list
val x6 =
6 5 4
4 5 6
Vadim Shalts Функциональные структуры данных и архитектура 30 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Использование очереди из Java
import com.github.krukow.clj_lang.PersistentQueue;
public class ClojureQueueTest {
public static void main(String[] args) {
PersistentQueue empty = PersistentQueue.EMPTY;
PersistentQueue queue = empty.cons("my").cons("queue");
PersistentQueue extended = queue.cons("!!!");
PersistentQueue cutted = extended.pop();
System.out.println(queue.seq()); // ("my" "queue")
System.out.println(extended.seq()); // ("my" "queue" "!!!")
System.out.println(cutted.seq()); // ("queue" "!!!")
}
}
Vadim Shalts Функциональные структуры данных и архитектура 31 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Вектор (Vector)Bit-partitioned hash tries
... 00000 00000 00000 = 0
... 00000 00000 11111 = 31
... 00000 00001 00000 = 32
... 00000 00001 11111 = 63
Values
bits 0-4
bits 5-9
Root
0 1 31 32 33 63
0 1 ... ... 31 0 1 ... ... 31
0 1
v1
Vadim Shalts Функциональные структуры данных и архитектура 32 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Вектор (Vector). Замена элемента
Values
bits 0-4
bits 5-9
Root
0 1 31 32 33 63 Z
0 1 ... ... 31 0 1 ... ... 31 0 1 ... ... 31
0 1 0 1
v1 v2
Vadim Shalts Функциональные структуры данных и архитектура 33 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Вектор (Vector). Полная структура
Values
bits 0-4
bits 5-9
Root
0 1 31 32 33 63 64 65
0 1 ... ... 31 0 1 ... ... 31
0 1
0 1
v1
Vadim Shalts Функциональные структуры данных и архитектура 34 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Вектор (Vector). Добавление
Values
bits 0-4
bits 5-9
Root
0 1 31 32 33 63 64 65 66
0 1 ... ... 31 0 1 ... ... 31
0 1 0 1 2
0 1
v1 v2
Vadim Shalts Функциональные структуры данных и архитектура 35 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Vector. Пример
import com.github.krukow.clj_ds.*;
public class PersistentVectorTest {
public static void main(String[] args) {
PersistentVector<Integer> p = Persistents.vector(1, 2, 3);
PersistentVector<Integer> extended = p.plus(4).plus(5);
PersistentVector<Integer> updated = p.plusN(1, 22);
PersistentVector<Integer> cutted = p.minus();
System.out.println(p); // [1 2 3]
System.out.println(extended); // [1 2 3 4 5]
System.out.println(updated); // [1 22 3]
System.out.println(cutted); // [1 2]
}
}
Vadim Shalts Функциональные структуры данных и архитектура 36 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Улучшаем скорость. Переходные (Transient) структуры
данных
Инсоляция в рамках одного потока
O 1 создание из персистентных структур данных
Общие данных с персистентным источником
O 1 создание персистентных структур данных, когда
редактирование завершено
Нельзя использовать после создания конечной персистентной
версии
Быстрые
Vadim Shalts Функциональные структуры данных и архитектура 37 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Transient структуры данных. Пример
import com.github.krukow.clj_ds.*;
public class TransienVectorTest {
public static void main(String[] args) {
PersistentVector p = Persistents.vector(1, 2, 3);
TransientVector t = p.asTransient();
TransientVector tf = t.plus(4).plus(5); // efficient bulk modification
PersistentVector p2 = tf.persist();
System.out.println(p); // [1 2 3]
System.out.println(p2); // [1 2 3 4 5]
}
}
Vadim Shalts Функциональные структуры данных и архитектура 38 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
До создания Transient
Values
bits 0-4
bits 5-9
Root
0 1 31 32 33 63 64 65
0 1 ... ... 31 0 1 ... ... 31
0 1
0 1
v1
Vadim Shalts Функциональные структуры данных и архитектура 39 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Transient Vector
Values
bits 0-4
bits 5-9
Root
0 1 31 32 33 63 64 65
0 1 ... ... 31 0 1 ... ... 31
0 1
0 1
v1 Transient
Vadim Shalts Функциональные структуры данных и архитектура 40 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Transient Vector. Дешёвое добавление
Values
bits 0-4
bits 5-9
Root
0 1 31 32 33 63 64 65 66
0 1 ... ... 31 0 1 ... ... 31
0 1 0 1 ... ... 31
0 1
v1 Transient
Vadim Shalts Функциональные структуры данных и архитектура 41 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Transient Vector. Дешёвое добавление
Values
bits 0-4
bits 5-9
Root
0 1 31 32 33 63 64 65 66 67
0 1 ... ... 31 0 1 ... ... 31
0 1 0 1 ... ... 31
0 1
v1 Transient
Vadim Shalts Функциональные структуры данных и архитектура 42 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Возврат к Persistent Vector
Values
bits 0-4
bits 5-9
Root
0 1 31 32 33 63 64 65 66 67
0 1 ... ... 31 0 1 ... ... 31
0 1 0 1 2 3
0 1
v1 v2
Vadim Shalts Функциональные структуры данных и архитектура 43 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
RRB trees - Relaxed Radix Balanced Trees
“RRB-Trees: Efficient Immutable Vectors”,
EPFL-REPORT-169879, September, 2011:
http://infoscience.epfl.ch/record/169879/files/RMTrees.pdf
Дополнительные операции c O log N :
объединение коллекций (concatenation)
вставка в позицию (insert-at)
разделение на части (splits-at)
Реализации:
github.com/clojure/core.rrb-vector
github.com/TiarkRompf/rrbtrees
Vadim Shalts Функциональные структуры данных и архитектура 44 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
HashMap. Hash Array Mapped Trie (HAMT)
Bit-partitioned hash tries
Vadim Shalts Функциональные структуры данных и архитектура 45 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
HashMap. ДобавлениеPath Copying
int count 15
INode root
HashMap
int count 16
INode root
HashMap
Vadim Shalts Функциональные структуры данных и архитектура 46 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Общие свойства
Версионность
Потоковая безопасность
Безопасность для итерирования
Уменьшение потребление памяти (для нескольких
копий)
Возможно увеличение потребления памяти (для
одной копии)
Простота использования
Производительность?
Vadim Shalts Функциональные структуры данных и архитектура 47 / 86
Персистентные структуры данных и их анализ Примеры структур данных и их анализ
Теория за бортом
Детальный анализ производительности
Линзы (Functional lenses) - упрощают работу с
вложенными неизменяемыми структурами данных
Zipper - техника представления объединённых
структур данных. Ускоряет обработку персистентных
коллекций.
Ctrie - concurrent hash-trie
Vadim Shalts Функциональные структуры данных и архитектура 48 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Архитектура
Vadim Shalts Функциональные структуры данных и архитектура 49 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Undo/Redo. Команды
trait UndoableCommand {
def redo()
def undo()
}
var currentState = new StringBuilder()
class InsertCommand(pos: Int, value: String)
extends UndoableCommand {
def redo() = currentState.insert(pos, value)
def undo() = currentState.delete(pos, value.length)
}
Vadim Shalts Функциональные структуры данных и архитектура 50 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Undo/Redo + шаблон Хранитель (Memento)
case class Memento(storedState: String)
var currentState = new StringBuilder()
val stateHistory = collection.mutable.Stack[Memento]()
class InsertCommand(pos: Int, value: String)
extends UndoableCommand {
def redo() = {
stateHistory.push( new Memento(currentState.mkString) )
currentState.insert(pos, value)
}
def undo() = {
currentState.clear()
currentState.append( stateHistory.pop.storedState )
}
}
Vadim Shalts Функциональные структуры данных и архитектура 51 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Undo/Redo + Персистентные структуры данных
case class Article(name: String, price: Double)
case class Order(goods: Vector[Article], total: Double)
type State = Order
type UndoableCommand = State => State
var currentState = new State(Vector.empty, 0)
val stateHistory = collection.mutable.Stack[State]()
def executeCommand(command: UndoableCommand) = {
stateHistory.push( currentState )
currentState = command(currentState)
}
def undoCommand() =
currentState = stateHistory.pop()
Vadim Shalts Функциональные структуры данных и архитектура 52 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Undo/Redo + Персистентные структуры данных
def buyArticle(article: Article): UndoableCommand =
(state: State) =>
new State(state.goods :+ article,
state.total + article.price)
// someCommand is function: State => State
val someCommand = buyArticle(new Article("iPad", 499))
executeCommand(someCommand)
println(state.total) // 499.0
undoCommand()
println(state.total) // 0.0
Vadim Shalts Функциональные структуры данных и архитектура 53 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Блокировки. synchronized и ReentrantLock
Now t
Thread 1
Thread 2
Thread 3
Thread 4
Vadim Shalts Функциональные структуры данных и архитектура 54 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Блокировки. ReentrantReadWriteLock
Now t
Thread 1
Thread 2
Thread 3
Thread 4
Vadim Shalts Функциональные структуры данных и архитектура 55 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Блокировки. ReentrantReadWriteLock другой пример
Now t
Thread 1
Thread 2
Thread 3
Thread 4
Vadim Shalts Функциональные структуры данных и архитектура 56 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Блокировки. StampedLock
Now t
Thread 1
Thread 2
Thread 3Thread 3
Thread 4
Vadim Shalts Функциональные структуры данных и архитектура 57 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
StampedLock. Лучше масштабируется
class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
void move(double deltaX, double deltaY) { // an exclusively locked method
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
}
// ...
}
Vadim Shalts Функциональные структуры данных и архитектура 58 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
StampedLock. Оптимистичные блокировки
class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
double distanceFromOrigin() { // A read-only method
long stamp = sl.tryOptimisticRead();
double currentX = x, currentY = y;
if (!sl.validate(stamp)) {
stamp = sl.readLock();
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
// ...
}
Vadim Shalts Функциональные структуры данных и архитектура 59 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Оптимистичные блокировки через StampedLock.
Проблемы и ограничения
«The use of optimistic mode for short read-only code
segments often reduces contention and improves throughput.
However, its use is inherently fragile. Optimistic read sections
should only read fields and hold them in local variables for
later use after validation. Fields read while in optimistic
mode may be wildly inconsistent, so usage applies only when
you are familiar enough with data representations to check
consistency and/or repeatedly invoke method validate()»
StampedLock. Java Documentation
Vadim Shalts Функциональные структуры данных и архитектура 60 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Блокировки. StampedLock
Now t
Thread 1
Thread 2
Thread 3
Thread 4
Vadim Shalts Функциональные структуры данных и архитектура 61 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Блокировки. Неизменяемые данные
t
Thread 1Thread 1
Thread 2Thread 2Thread 2
Thread 3Thread 3
Thread 4Thread 4
Vadim Shalts Функциональные структуры данных и архитектура 62 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Блокировки. Много писателей
@volatile var currentState: State = initialState
val writersLock = new StampedLock
def readState() = {
val latestState = currentState
// ...
}
def updateState(command: Command) = {
val stamp = writersLock.writeLockInterruptibly()
val latestState = currentState
try {
currentState = command(currentState)
} catch {
case AbortException => // ...
case ex: Throwable => // ...
} finally {
writersLock.unlockWrite(stamp)
}
}
Vadim Shalts Функциональные структуры данных и архитектура 63 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Реализация с неизменяемым Point классом.
Общий код
trait ReferenceManager[T] {
def setState(state: T) = updateState(_ => state)
def getState(): T
def updateState(stateReplacer: T => T)
}
Vadim Shalts Функциональные структуры данных и архитектура 64 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Реализация с неизменяемым Point классом.
Общий код
class LockBasedReferenceManager[T] extends ReferenceManager[T] {
@volatile private var currentState: T = _
private val writersLock = new StampedLock
def getState() = currentState
def updateState(stateReplacer: T => T) = {
val stamp = writersLock.writeLockInterruptibly()
val latestState = currentState
try {
currentState = stateReplacer(latestState)
} catch {
case ex: Throwable => // ...
} finally {
writersLock.unlockWrite(stamp)
}
}
}
Vadim Shalts Функциональные структуры данных и архитектура 65 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Реализация с неизменяемым Point классом.
Основная логика
case class Point(x: Double, y: Double) {
def distanceFromOrigin() = Math.sqrt(x * x + y * y)
def move(deltaX: Double, deltaY: Double) =
new Point(x + deltaX, y + deltaY)
}
class PointHolder(reference: ReferenceManager[Point]) {
reference.setState(Point(0, 0)) // Initial state
def distanceFromOrigin() =
reference.getState().distanceFromOrigin()
def move(deltaX: Double, deltaY: Double) =
reference.updateState { s => s.move(deltaX, deltaY) }
}
Vadim Shalts Функциональные структуры данных и архитектура 66 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Блокировки. Оптимистичное обновление состояния
t
Thread 1Thread 1Thread 1Thread 1
Thread 2
Thread 3Thread 3
Thread 4Thread 4
Vadim Shalts Функциональные структуры данных и архитектура 67 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Реализация через CAS. Сходство с MVCC
class OptimisticReferenceManager[T] extends ReferenceManager[T] {
val ref = new AtomicReference[T]
override def setState(state: T) = ref.set(state)
def getState() = ref.get
def updateState(stateReplacer: T => T) = {
var continue = true
while(continue) {
val latestState = getState()
val newState = stateReplacer(latestState)
if (ref.compareAndSet(latestState, newState))
continue = false
}
}
}
Vadim Shalts Функциональные структуры данных и архитектура 68 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
STM - Software transactional memory
Механизм управления параллелизмом аналогичный
механизму транзакций баз данных.
Используется для управления доступом к совместно
используемой памяти в параллельных вычислениях.
Альтернатива для синхронизации на основе
блокировок.
Vadim Shalts Функциональные структуры данных и архитектура 69 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Clojure STM
Реализация основана на MVCC
Транзакции обеспечиваются изоляцией снимков
(Snapshot isolation)
Оптимистичный подход, рассчитываем на малую
вероятность коллизий на запись
Невозможны deadlocks, livelocks или гонки
Компонуемые операции
Vadim Shalts Функциональные структуры данных и архитектура 70 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
STM - полезен
Если паттерны доступа укладываются в:
частые чтения
достаточно редкие конфликты на запись
Почему?
Если транзакция не удалась, то нужно выполнить
откат
Нужно минимизировать пенальти за откат и
максимизировать параллелизм.
Vadim Shalts Функциональные структуры данных и архитектура 71 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
STM - Механика
Значения вычитанные внутри транзакции:
гарантированно целостные и отражают все
изменения
относятся к транзакциям, которые были завершены
до начала этой транзакции.
Изменения внутри транзакция:
локальны и видимы только внутри транзакции
становятся целиком видимыми после коммита
Vadim Shalts Функциональные структуры данных и архитектура 72 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
STM. Работа с ссылками
Слайд Neale Swinnerton (Clojure STM - What? Why? How?)
Vadim Shalts Функциональные структуры данных и архитектура 73 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
И снова менеджер
def as[T](value: AnyRef) = value.asInstanceOf[T]
class StmReferenceManager[T <: AnyRef]
extends ReferenceManager[T] {
private val ref = new Ref(null)
override def setState(state: T) = as[T]( ref.set(state) )
def getState() = as[T]( ref.deref() )
def updateState(stateReplacer: T => T) = ref.alter(new AFn() {
override def invoke(state: AnyRef): AnyRef = as[T]{
as[AnyRef]( stateReplacer( as[T](state) ) )
}
}, null)
}
Vadim Shalts Функциональные структуры данных и архитектура 74 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Скрываем работу с транзакциями
def atomic[T](func: => T) = as[T] {
LockingTransaction.runInTransaction(new Callable[T] {
def call = func
})
}
Vadim Shalts Функциональные структуры данных и архитектура 75 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Надёжный, дерзкий, губернский банк
case class History(change: Double, balanceBeforeChange: Double)
case class Account(balance: Double, history: Vector[History]) {
if (balance < 0 || history.length > 100)
throw new IllegalArgumentException("Not today")
if (history.length > 0 && history.last.change < 0.10)
throw new IllegalArgumentException("Suspicious behavior")
def changeBalanceBy(amount: Double) =
new Account(balance + amount, history :+ History(amount, balance))
}
class AccountHolder(reference: ReferenceManager[Account]) {
reference.setState(Account(0, Vector())) // Initial state
def balance = reference.getState().balance
def changeBalanceBy(amount: Double) =
reference.updateState ( s => s.changeBalanceBy(amount) )
}
Vadim Shalts Функциональные структуры данных и архитектура 76 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Соединяем всё вместе
val (source, target) = atomic {
(new AccountHolder(new StmReferenceManager()),
new AccountHolder(new StmReferenceManager()))
}
try {
atomic {
target.changeBalanceBy(200)
println(target.balance) // 200.0
source.changeBalanceBy(-200) // IllegalStateException: Balance negative
}
} catch {
case ex: Throwable => ex.printStackTrace();
}
println(source.balance) // 0.0
println(target.balance) // 0.0
source.changeBalanceBy(200) // IllegalStateException: No transaction running
Vadim Shalts Функциональные структуры данных и архитектура 77 / 86
Влияние на архитектуру приложений Применение и примеры архитектуры
Транзакции. ACI(D) для персистентных структур
✓ Atomicity (Атомарность)
✓ Consistency (Согласованность)
✓ Isolation (Изолированность)
✗ Durability (Долговечность)
Vadim Shalts Функциональные структуры данных и архитектура 78 / 86
Влияние на архитектуру приложений Персистентные базы данных (Datomic)
Базы данных. Классика
Vadim Shalts Функциональные структуры данных и архитектура 79 / 86
Влияние на архитектуру приложений Персистентные базы данных (Datomic)
Datomic. Общая идея
Vadim Shalts Функциональные структуры данных и архитектура 80 / 86
Влияние на архитектуру приложений Персистентные базы данных (Datomic)
Datomic
Иммутабильная база данных с поддержкой ACID
Явным образом оперирует временем - время всегда частью
модели данных
Основная единица хранения данных - факт привязанный ко
времени (datom)
Datom - запись со списком атрибутов.
Атрибуты могут ссылаться на другие факты - отношения
Изменения модели происходит путём добавления новых
фактов
Vadim Shalts Функциональные структуры данных и архитектура 81 / 86
Влияние на архитектуру приложений Персистентные базы данных (Datomic)
Datomic 2
Полагается на внешнюю реализацию хранилища данных
(RAM, DynamoDB, RDBMS, ...)
Изменения/транзакции отделены от чтения и проходят через
специальный компонент (transactor).
Возможно симулирование состояния базы без коммитов
Практически безграничное масштабирование запросов на
чтение и встроенная поддержка кеширования
Запросы могут использовать функции на Java/Clojure.
Vadim Shalts Функциональные структуры данных и архитектура 82 / 86
Влияние на архитектуру приложений Персистентные базы данных (Datomic)
Datomic - возможные проблемы.
Платная дорогая лицензия (есть бесплатная урезанная
версия и версия для разработчиков)
Плохо подходит для хранения больших (BLOB) или часто
меняющихся данных.
Значительно увеличивается потребность в дисковом
пространстве (особенно индексы)
Для узлов сети желательно использовать большой кеш
Законы могут требовать возможности удалять данные
пользователя.
Vadim Shalts Функциональные структуры данных и архитектура 83 / 86
Влияние на архитектуру приложений Персистентные базы данных (Datomic)
Персистентные структуры данных - итоги
Выгодный компромисс - платим памятью за
масштабируемость
Изменения общих данных не блокируют обработку текущих
запросов (настройки, текущее состояние и т.д)
Долгие чтения не блокируют записи (обращение по сети,
построение отчета)
Упрощается обработка долгих запросов (не связаны
ограничениями по времени)
Vadim Shalts Функциональные структуры данных и архитектура 84 / 86
Влияние на архитектуру приложений Персистентные базы данных (Datomic)
Персистентные структуры данных - итоги 2
Стратегия работы с блокировками стала гибкой и не связана
жестко с реализацией логики
Упрощается тестирование и разработка бизнес логики
(наиболее часто меняющийся код)
Повышается надёжность - случайные ошибки (исключения)
имеют меньше шансов навредить
Доступность старых фактов/данных упрощает разработку и
открывает новые возможности (datomic + blueprints)
Vadim Shalts Функциональные структуры данных и архитектура 85 / 86
Вопросы
Вопросы?
Vadim Shalts Функциональные структуры данных и архитектура 86 / 86

Contenu connexe

Tendances

работа с потоками ввода вывода
работа с потоками ввода выводаработа с потоками ввода вывода
работа с потоками ввода выводаmetaform
 
интелектуальный анализ экономических данных в системе каркас
интелектуальный анализ экономических данных в системе каркасинтелектуальный анализ экономических данных в системе каркас
интелектуальный анализ экономических данных в системе каркасVladimir Burdaev
 
Работа с БД в Java
Работа с БД в JavaРабота с БД в Java
Работа с БД в Javametaform
 
C++ Базовый. Занятие 08.
C++ Базовый. Занятие 08.C++ Базовый. Занятие 08.
C++ Базовый. Занятие 08.Igor Shkulipa
 
C++ осень 2012 лекция 4
C++ осень 2012 лекция 4C++ осень 2012 лекция 4
C++ осень 2012 лекция 4Technopark
 
Java. Generic - шаблонные типы.
Java.  Generic - шаблонные типы.Java.  Generic - шаблонные типы.
Java. Generic - шаблонные типы.Unguryan Vitaliy
 
Классы и объекты в Java
Классы и объекты в JavaКлассы и объекты в Java
Классы и объекты в Javametaform
 
MySQL
MySQLMySQL
MySQLNoveo
 

Tendances (9)

работа с потоками ввода вывода
работа с потоками ввода выводаработа с потоками ввода вывода
работа с потоками ввода вывода
 
интелектуальный анализ экономических данных в системе каркас
интелектуальный анализ экономических данных в системе каркасинтелектуальный анализ экономических данных в системе каркас
интелектуальный анализ экономических данных в системе каркас
 
Работа с БД в Java
Работа с БД в JavaРабота с БД в Java
Работа с БД в Java
 
C++ Базовый. Занятие 08.
C++ Базовый. Занятие 08.C++ Базовый. Занятие 08.
C++ Базовый. Занятие 08.
 
C++ осень 2012 лекция 4
C++ осень 2012 лекция 4C++ осень 2012 лекция 4
C++ осень 2012 лекция 4
 
Uml
UmlUml
Uml
 
Java. Generic - шаблонные типы.
Java.  Generic - шаблонные типы.Java.  Generic - шаблонные типы.
Java. Generic - шаблонные типы.
 
Классы и объекты в Java
Классы и объекты в JavaКлассы и объекты в Java
Классы и объекты в Java
 
MySQL
MySQLMySQL
MySQL
 

En vedette

Getting ready to java 8
Getting ready to java 8Getting ready to java 8
Getting ready to java 8DataArt
 
Java collections the force awakens
Java collections  the force awakensJava collections  the force awakens
Java collections the force awakensRichardWarburton
 
Development of the Logistics Sector in the United States: Past, Present and F...
Development of the Logistics Sector in the United States: Past, Present and F...Development of the Logistics Sector in the United States: Past, Present and F...
Development of the Logistics Sector in the United States: Past, Present and F...Technopreneurs Association of Malaysia
 
Callture turnkey platform presentation
Callture turnkey platform presentationCallture turnkey platform presentation
Callture turnkey platform presentationCallture Inc
 
Agent web site_set_up_guide v2
Agent web site_set_up_guide v2Agent web site_set_up_guide v2
Agent web site_set_up_guide v2Falcon Homes
 
Customer Services for Frontline Managers
Customer Services for Frontline ManagersCustomer Services for Frontline Managers
Customer Services for Frontline ManagersDr. Muhammad Iqbal
 
Ba hay PM quyết định sự thành công của dự án phần mềm
Ba hay PM  quyết định sự thành công của dự án phần mềmBa hay PM  quyết định sự thành công của dự án phần mềm
Ba hay PM quyết định sự thành công của dự án phần mềmTrung. Le Thanh
 
Hdfs introduction
Hdfs introductionHdfs introduction
Hdfs introductionbaggioss
 
Kozłowska - projekt
Kozłowska - projektKozłowska - projekt
Kozłowska - projektRobert
 
Peugeot RCZ: примеряем на себя
Peugeot RCZ: примеряем на себяPeugeot RCZ: примеряем на себя
Peugeot RCZ: примеряем на себяPeugeotUA
 

En vedette (20)

Getting ready to java 8
Getting ready to java 8Getting ready to java 8
Getting ready to java 8
 
Java collections the force awakens
Java collections  the force awakensJava collections  the force awakens
Java collections the force awakens
 
Development of the Logistics Sector in the United States: Past, Present and F...
Development of the Logistics Sector in the United States: Past, Present and F...Development of the Logistics Sector in the United States: Past, Present and F...
Development of the Logistics Sector in the United States: Past, Present and F...
 
Words
WordsWords
Words
 
CETS2010, Nancy Munro & Allison Black, From Addie to Improv
CETS2010, Nancy Munro & Allison Black, From Addie to ImprovCETS2010, Nancy Munro & Allison Black, From Addie to Improv
CETS2010, Nancy Munro & Allison Black, From Addie to Improv
 
Callture turnkey platform presentation
Callture turnkey platform presentationCallture turnkey platform presentation
Callture turnkey platform presentation
 
Crcsd boe presentation 080910
Crcsd boe presentation 080910Crcsd boe presentation 080910
Crcsd boe presentation 080910
 
Agent web site_set_up_guide v2
Agent web site_set_up_guide v2Agent web site_set_up_guide v2
Agent web site_set_up_guide v2
 
Unit 7 lesson d
Unit 7  lesson dUnit 7  lesson d
Unit 7 lesson d
 
Demystifying and Monetizing the Cloud
Demystifying and Monetizing the CloudDemystifying and Monetizing the Cloud
Demystifying and Monetizing the Cloud
 
Customer Services for Frontline Managers
Customer Services for Frontline ManagersCustomer Services for Frontline Managers
Customer Services for Frontline Managers
 
Cets 2014 kanter wordpress as an lms
Cets 2014 kanter wordpress as an lmsCets 2014 kanter wordpress as an lms
Cets 2014 kanter wordpress as an lms
 
Ba hay PM quyết định sự thành công của dự án phần mềm
Ba hay PM  quyết định sự thành công của dự án phần mềmBa hay PM  quyết định sự thành công của dự án phần mềm
Ba hay PM quyết định sự thành công của dự án phần mềm
 
Be
Be Be
Be
 
Hdfs introduction
Hdfs introductionHdfs introduction
Hdfs introduction
 
CETS 2010, Judy Martins, Creating Engaging Elearning
CETS 2010, Judy Martins, Creating Engaging ElearningCETS 2010, Judy Martins, Creating Engaging Elearning
CETS 2010, Judy Martins, Creating Engaging Elearning
 
Kozłowska - projekt
Kozłowska - projektKozłowska - projekt
Kozłowska - projekt
 
Unit 7 lesson d
Unit 7  lesson dUnit 7  lesson d
Unit 7 lesson d
 
Peugeot RCZ: примеряем на себя
Peugeot RCZ: примеряем на себяPeugeot RCZ: примеряем на себя
Peugeot RCZ: примеряем на себя
 
Insider’s Briefing: Entertainment and Media Sector in Los Angeles
Insider’s Briefing: Entertainment and Media Sector in Los AngelesInsider’s Briefing: Entertainment and Media Sector in Los Angeles
Insider’s Briefing: Entertainment and Media Sector in Los Angeles
 

Similaire à Персистентные структуры данных и архитектура

Лекция 3 Элементарные структуры данных Часть 1
Лекция 3 Элементарные структуры данных Часть 1Лекция 3 Элементарные структуры данных Часть 1
Лекция 3 Элементарные структуры данных Часть 1simple_people
 
Java осень 2012 лекция 8
Java осень 2012 лекция 8Java осень 2012 лекция 8
Java осень 2012 лекция 8Technopark
 
Шаблоны проектирования 1
Шаблоны проектирования 1Шаблоны проектирования 1
Шаблоны проектирования 1Constantin Kichinsky
 
Oop java.generics
Oop java.genericsOop java.generics
Oop java.genericsmuqaddas_m
 
Зачем нужна Scala?
Зачем нужна Scala?Зачем нужна Scala?
Зачем нужна Scala?Vasil Remeniuk
 
Java осень 2013 лекция 8
Java осень 2013 лекция 8Java осень 2013 лекция 8
Java осень 2013 лекция 8Technopark
 
Алгоритмы и структуры данных осень 2013 лекция 2
Алгоритмы и структуры данных осень 2013 лекция 2Алгоритмы и структуры данных осень 2013 лекция 2
Алгоритмы и структуры данных осень 2013 лекция 2Technopark
 
Java весна 2013 лекция 9
Java весна 2013 лекция 9Java весна 2013 лекция 9
Java весна 2013 лекция 9Technopark
 
Java Core. Lecture# 4. Collections.
Java Core. Lecture# 4. Collections.Java Core. Lecture# 4. Collections.
Java Core. Lecture# 4. Collections.Anton Moiseenko
 
C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 01.C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 01.Igor Shkulipa
 
Scala and LiftWeb presentation (Russian)
Scala and LiftWeb presentation (Russian)Scala and LiftWeb presentation (Russian)
Scala and LiftWeb presentation (Russian)Dmitry Stropalov
 
C# Web. Занятие 04.
C# Web. Занятие 04.C# Web. Занятие 04.
C# Web. Занятие 04.Igor Shkulipa
 
Java осень 2014 занятие 7
Java осень 2014 занятие 7Java осень 2014 занятие 7
Java осень 2014 занятие 7Technopark
 
C++ Базовый. Занятие 17.
C++ Базовый. Занятие 17.C++ Базовый. Занятие 17.
C++ Базовый. Занятие 17.Igor Shkulipa
 
Msu.Center.Lectures.J01 Introducing Java
Msu.Center.Lectures.J01 Introducing JavaMsu.Center.Lectures.J01 Introducing Java
Msu.Center.Lectures.J01 Introducing Javaolegol
 
Классы и объекты в Java
Классы и объекты в JavaКлассы и объекты в Java
Классы и объекты в Javametaform
 

Similaire à Персистентные структуры данных и архитектура (20)

Лекция 3 Элементарные структуры данных Часть 1
Лекция 3 Элементарные структуры данных Часть 1Лекция 3 Элементарные структуры данных Часть 1
Лекция 3 Элементарные структуры данных Часть 1
 
Java осень 2012 лекция 8
Java осень 2012 лекция 8Java осень 2012 лекция 8
Java осень 2012 лекция 8
 
Шаблоны проектирования 1
Шаблоны проектирования 1Шаблоны проектирования 1
Шаблоны проектирования 1
 
Oop java.generics
Oop java.genericsOop java.generics
Oop java.generics
 
Зачем нужна Scala?
Зачем нужна Scala?Зачем нужна Scala?
Зачем нужна Scala?
 
Lec 4
Lec 4Lec 4
Lec 4
 
Лекция #7. Django ORM
Лекция #7. Django ORMЛекция #7. Django ORM
Лекция #7. Django ORM
 
Java осень 2013 лекция 8
Java осень 2013 лекция 8Java осень 2013 лекция 8
Java осень 2013 лекция 8
 
Алгоритмы и структуры данных осень 2013 лекция 2
Алгоритмы и структуры данных осень 2013 лекция 2Алгоритмы и структуры данных осень 2013 лекция 2
Алгоритмы и структуры данных осень 2013 лекция 2
 
Lec 13
Lec 13Lec 13
Lec 13
 
Java весна 2013 лекция 9
Java весна 2013 лекция 9Java весна 2013 лекция 9
Java весна 2013 лекция 9
 
Java Core. Lecture# 4. Collections.
Java Core. Lecture# 4. Collections.Java Core. Lecture# 4. Collections.
Java Core. Lecture# 4. Collections.
 
C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 01.C++ STL & Qt. Занятие 01.
C++ STL & Qt. Занятие 01.
 
Scala and LiftWeb presentation (Russian)
Scala and LiftWeb presentation (Russian)Scala and LiftWeb presentation (Russian)
Scala and LiftWeb presentation (Russian)
 
C# Web. Занятие 04.
C# Web. Занятие 04.C# Web. Занятие 04.
C# Web. Занятие 04.
 
Java осень 2014 занятие 7
Java осень 2014 занятие 7Java осень 2014 занятие 7
Java осень 2014 занятие 7
 
C++ Базовый. Занятие 17.
C++ Базовый. Занятие 17.C++ Базовый. Занятие 17.
C++ Базовый. Занятие 17.
 
Msu.Center.Lectures.J01 Introducing Java
Msu.Center.Lectures.J01 Introducing JavaMsu.Center.Lectures.J01 Introducing Java
Msu.Center.Lectures.J01 Introducing Java
 
Backbone js
Backbone jsBackbone js
Backbone js
 
Классы и объекты в Java
Классы и объекты в JavaКлассы и объекты в Java
Классы и объекты в Java
 

Персистентные структуры данных и архитектура

  • 1. Функциональные (персистентные) структуры данных и их влияние на архитектуру приложений Vadim Shalts Vadim Shalts Функциональные структуры данных и архитектура 1 / 86
  • 2. Персистентные структуры данных и их анализ Оговорки Vadim Shalts Функциональные структуры данных и архитектура 2 / 86
  • 3. Персистентные структуры данных и их анализ Сase классы Scala: case class Foo(myval: String) Java: final class Foo { private final String myval; public Foo(String initialValue) { this.myval = initialValue; } public String getValue() { return this.myval; } @Override public boolean equals(Object o) { // .... } @Override public int hashCode() { // ... } } Vadim Shalts Функциональные структуры данных и архитектура 3 / 86
  • 4. Персистентные структуры данных и их анализ Сase классы Scala: case class Foo(myval: String) Java: final class Foo { private final String myval; public Foo(String initialValue) { this.myval = initialValue; } public String getValue() { return this.myval; } @Override public boolean equals(Object o) { // .... } @Override public int hashCode() { // ... } } Возможные решения для Java projectlombok.org immutables.org github.com/google/auto www.jannocessor.org Scala, Groovy, Clojure :) Vadim Shalts Функциональные структуры данных и архитектура 3 / 86
  • 5. Персистентные структуры данных и их анализ Project valhalla. JEP 169: Value Objects Vadim Shalts Функциональные структуры данных и архитектура 4 / 86
  • 6. Персистентные структуры данных и их анализ Важные свойства неизменяемых (immutable) объектов Легко создавать, тестировать и использовать Являются потокобезопасными Хорошие кандидаты для кэширования Поддерживают инвариант состояния Исключения не могут “разломать” состояние Vadim Shalts Функциональные структуры данных и архитектура 5 / 86
  • 7. Персистентные структуры данных и их анализ Класс будет неизменяемым, если верно следующее: Класс объявляется как final Все его поля являются final Ссылка this не должна пропасть во время конструирования Не содержат методов, которые могли бы изменить наблюдаемое состояние объекта Любые поля, содержащие ссылки на изменяемые объекты, например массивы, совокупности или изменяемые классы, например Date: Являются приватными Никогда не возвращаются и никаким другим образом не становятся доступными вызывающим операторам Являются единственными ссылками на те объекты, на которые они ссылаются Не изменяют после конструирования состояние объектов, на которые они ссылаются Vadim Shalts Функциональные структуры данных и архитектура 6 / 86
  • 8. Персистентные структуры данных и их анализ JLS. Семантика final полей «A thread-safe immutable object is seen as immutable by all threads, even if a data race is used to pass references to the immutable object between threads» JLS 17.5 Vadim Shalts Функциональные структуры данных и архитектура 7 / 86
  • 9. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Data Processing in Exascale-class Computing Systems | April 27, 2011 | CRM3 Transistors (thousands) Single-thread Performance (SpecINT) Frequency (MHz) Typical Power (Watts) Number of Cores Original data collected and plotted by M. Horowitz, F. Labonte, O. Shacham, K. Olukotun, L. Hammond and C. Batten Dotted line extrapolations by C. Moore 35 YEARS OF MICROPROCESSOR TREND DATA Vadim Shalts Функциональные структуры данных и архитектура 8 / 86
  • 10. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Закон Амдала. Рост производительности вычислительной системы Vadim Shalts Функциональные структуры данных и архитектура 9 / 86
  • 11. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Функциональное программирование «In computer science, functional programming is a programming paradigm, a style of building the structure and elements of computer programs, that treats computation as the evaluation of mathematical functions and avoids state and mutable data.» wikipedia Vadim Shalts Функциональные структуры данных и архитектура 10 / 86
  • 12. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Простая нотация f (x) Что скрывается за простой нотацией? Vadim Shalts Функциональные структуры данных и архитектура 11 / 86
  • 13. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Сложность f(x) int[] func(int[] param); Какова сложность, если параметр: простой тип простой объект коллекция простых типов ... Vadim Shalts Функциональные структуры данных и архитектура 12 / 86
  • 14. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Традиционный подход class Order { private ArrayList<Item> items = EMPTY_LIST; private double total = 0.0; void addItem(Item item) { items.add(item); total = calcTotal(); } String createCheck() { // use items and total ... // .... } // .... } Vadim Shalts Функциональные структуры данных и архитектура 13 / 86
  • 15. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Традиционный подход class Order { private ArrayList<Item> items = EMPTY_LIST; private double total = 0.0; synchronized void addItem(Item item) { items.add(item); total = calcTotal(); } synchronized String createCheck() { // use items and total ... // .... } // .... } Vadim Shalts Функциональные структуры данных и архитектура 14 / 86
  • 16. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Java Language and Virtual Machine Specifications (14.19) If execution of the Block completes normally, then the monitor is unlocked and the synchronized statement completes normally. If execution of the Block completes abruptly for any reason, then the monitor is unlocked and the synchronized statement completes abruptly for the same reason. Vadim Shalts Функциональные структуры данных и архитектура 15 / 86
  • 17. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Потеряна предсказуемость Потеряна предсказуемость. Что можно сделать? Vadim Shalts Функциональные структуры данных и архитектура 16 / 86
  • 18. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Традиционный подход. Сохраняем состояние ошибки class Order { private ArrayList<Item> items = EMPTY_LIST; private double total = 0.0; private boolean incorrectState = false; synchronized void addItem(Item item) { if (incorrectState) throw new IllegalStateException(); incorrectState = true; items.add(item); total = calcTotal(); incorrectState = false; } // .... } Vadim Shalts Функциональные структуры данных и архитектура 17 / 86
  • 19. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Традиционный подход. Предотвращаем потерю состояния class Order { private List<Item> items = EMPTY_LIST; private double total = 0.0; synchronized void addItem(Item item) { List<Item> newItems = fastCopyAndAppend(items, item); // Как? double newTotal = calcTotal(newItems); items = newItems; total = newTotal; } // .... } Vadim Shalts Функциональные структуры данных и архитектура 18 / 86
  • 20. Персистентные структуры данных и их анализ Необходимость (или в чём проблемы) Еще лучше сделать класс Order неизменяемым (immutable)! «Classes should be immutable unless there’s a very good reason to make them mutable.» Joshua Bloch «If an object cannot change state, then it can never encounter conflicts or inconsistencies when multiple activities attempt to change its state in incompatible ways. Programs are much simpler to understand if existing objects are never changed, but instead new ones are continually created during the course of any computation.» Doug Lea Vadim Shalts Функциональные структуры данных и архитектура 19 / 86
  • 21. Персистентные структуры данных и их анализ Определимся с терминологией Термины Неизменяемые (Immutable) структуры данных после создания не могут быть изменены Immutable структуры данных (обычно) могут быть скопированы с изменениями для создания новой версии Создание новой версии требует столько же памяти сколько потребляет оригинал. Персистентные (Persistent) структуры данных после изменения содержат старую и новую версию данных Persistent структуры данных являются Immutable в том смысле, что создание новой версии не приводит к изменению старых версий Создание новой версии может потребовать копирования данных из оригинала. При этом старая и новые версии будут содержать общие данные Vadim Shalts Функциональные структуры данных и архитектура 20 / 86
  • 22. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Обозначения val x = X Y Z null val x = X Y Z Vadim Shalts Функциональные структуры данных и архитектура 21 / 86
  • 23. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Список. Начальный val x1 = X Y Z Vadim Shalts Функциональные структуры данных и архитектура 22 / 86
  • 24. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Список. Добавление val x1 = X Y Z val x2 = W Vadim Shalts Функциональные структуры данных и архитектура 23 / 86
  • 25. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Список. Удаление val x1 = X Y Z val x2 = W val x3 = Vadim Shalts Функциональные структуры данных и архитектура 24 / 86
  • 26. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Как получить такие коллекции в Java? <dependency> <groupId>org.clojure</groupId> <artifactId>clojure</artifactId> <version>1.6.0</version> </dependency> Или github.com/krukow/clj-ds pcollections.org www.functionaljava.org Vadim Shalts Функциональные структуры данных и архитектура 25 / 86
  • 27. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Использование списка из Java import com.github.krukow.clj_ds.*; import java.util.LinkedList; public class ClojureListTest { public static void main(String[] args) { PersistentList<String> listCopy = Persistents.linkedList(new LinkedList()); PersistentList<String> list = Persistents.linkedList("my", "list"); PersistentList<String> extended = list.plus("!!!"); PersistentList<String> cutted = extended.minus().minus(); System.out.println(list); // ("my" "list") System.out.println(extended); // ("!!!" "my" "list") System.out.println(cutted); // ("list") } } Vadim Shalts Функциональные структуры данных и архитектура 26 / 86
  • 28. Персистентные структуры данных и их анализ Примеры структур данных и их анализ FIFO очередь. Начальное состояние val x1 = Queue enqueue list dequeue list 5 4 1 2 3 Vadim Shalts Функциональные структуры данных и архитектура 27 / 86
  • 29. Персистентные структуры данных и их анализ Примеры структур данных и их анализ FIFO очередь. Вставка val x1 = Queue enqueue list dequeue list 5 4 1 2 3 Queue enqueue list dequeue list val x2 = 6 Vadim Shalts Функциональные структуры данных и архитектура 28 / 86
  • 30. Персистентные структуры данных и их анализ Примеры структур данных и их анализ FIFO очередь. Удаление val x1 = Queue enqueue list dequeue list 5 4 1 2 3 Queue enqueue list dequeue list val x2 = 6 Queue enqueue list dequeue list val x3 = Vadim Shalts Функциональные структуры данных и архитектура 29 / 86
  • 31. Персистентные структуры данных и их анализ Примеры структур данных и их анализ FIFO очередь. Удаление val x5 = Queue enqueue list dequeue list Queue enqueue list dequeue list Queue enqueue list dequeue list val x6 = 6 5 4 4 5 6 Vadim Shalts Функциональные структуры данных и архитектура 30 / 86
  • 32. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Использование очереди из Java import com.github.krukow.clj_lang.PersistentQueue; public class ClojureQueueTest { public static void main(String[] args) { PersistentQueue empty = PersistentQueue.EMPTY; PersistentQueue queue = empty.cons("my").cons("queue"); PersistentQueue extended = queue.cons("!!!"); PersistentQueue cutted = extended.pop(); System.out.println(queue.seq()); // ("my" "queue") System.out.println(extended.seq()); // ("my" "queue" "!!!") System.out.println(cutted.seq()); // ("queue" "!!!") } } Vadim Shalts Функциональные структуры данных и архитектура 31 / 86
  • 33. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Вектор (Vector)Bit-partitioned hash tries ... 00000 00000 00000 = 0 ... 00000 00000 11111 = 31 ... 00000 00001 00000 = 32 ... 00000 00001 11111 = 63 Values bits 0-4 bits 5-9 Root 0 1 31 32 33 63 0 1 ... ... 31 0 1 ... ... 31 0 1 v1 Vadim Shalts Функциональные структуры данных и архитектура 32 / 86
  • 34. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Вектор (Vector). Замена элемента Values bits 0-4 bits 5-9 Root 0 1 31 32 33 63 Z 0 1 ... ... 31 0 1 ... ... 31 0 1 ... ... 31 0 1 0 1 v1 v2 Vadim Shalts Функциональные структуры данных и архитектура 33 / 86
  • 35. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Вектор (Vector). Полная структура Values bits 0-4 bits 5-9 Root 0 1 31 32 33 63 64 65 0 1 ... ... 31 0 1 ... ... 31 0 1 0 1 v1 Vadim Shalts Функциональные структуры данных и архитектура 34 / 86
  • 36. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Вектор (Vector). Добавление Values bits 0-4 bits 5-9 Root 0 1 31 32 33 63 64 65 66 0 1 ... ... 31 0 1 ... ... 31 0 1 0 1 2 0 1 v1 v2 Vadim Shalts Функциональные структуры данных и архитектура 35 / 86
  • 37. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Vector. Пример import com.github.krukow.clj_ds.*; public class PersistentVectorTest { public static void main(String[] args) { PersistentVector<Integer> p = Persistents.vector(1, 2, 3); PersistentVector<Integer> extended = p.plus(4).plus(5); PersistentVector<Integer> updated = p.plusN(1, 22); PersistentVector<Integer> cutted = p.minus(); System.out.println(p); // [1 2 3] System.out.println(extended); // [1 2 3 4 5] System.out.println(updated); // [1 22 3] System.out.println(cutted); // [1 2] } } Vadim Shalts Функциональные структуры данных и архитектура 36 / 86
  • 38. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Улучшаем скорость. Переходные (Transient) структуры данных Инсоляция в рамках одного потока O 1 создание из персистентных структур данных Общие данных с персистентным источником O 1 создание персистентных структур данных, когда редактирование завершено Нельзя использовать после создания конечной персистентной версии Быстрые Vadim Shalts Функциональные структуры данных и архитектура 37 / 86
  • 39. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Transient структуры данных. Пример import com.github.krukow.clj_ds.*; public class TransienVectorTest { public static void main(String[] args) { PersistentVector p = Persistents.vector(1, 2, 3); TransientVector t = p.asTransient(); TransientVector tf = t.plus(4).plus(5); // efficient bulk modification PersistentVector p2 = tf.persist(); System.out.println(p); // [1 2 3] System.out.println(p2); // [1 2 3 4 5] } } Vadim Shalts Функциональные структуры данных и архитектура 38 / 86
  • 40. Персистентные структуры данных и их анализ Примеры структур данных и их анализ До создания Transient Values bits 0-4 bits 5-9 Root 0 1 31 32 33 63 64 65 0 1 ... ... 31 0 1 ... ... 31 0 1 0 1 v1 Vadim Shalts Функциональные структуры данных и архитектура 39 / 86
  • 41. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Transient Vector Values bits 0-4 bits 5-9 Root 0 1 31 32 33 63 64 65 0 1 ... ... 31 0 1 ... ... 31 0 1 0 1 v1 Transient Vadim Shalts Функциональные структуры данных и архитектура 40 / 86
  • 42. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Transient Vector. Дешёвое добавление Values bits 0-4 bits 5-9 Root 0 1 31 32 33 63 64 65 66 0 1 ... ... 31 0 1 ... ... 31 0 1 0 1 ... ... 31 0 1 v1 Transient Vadim Shalts Функциональные структуры данных и архитектура 41 / 86
  • 43. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Transient Vector. Дешёвое добавление Values bits 0-4 bits 5-9 Root 0 1 31 32 33 63 64 65 66 67 0 1 ... ... 31 0 1 ... ... 31 0 1 0 1 ... ... 31 0 1 v1 Transient Vadim Shalts Функциональные структуры данных и архитектура 42 / 86
  • 44. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Возврат к Persistent Vector Values bits 0-4 bits 5-9 Root 0 1 31 32 33 63 64 65 66 67 0 1 ... ... 31 0 1 ... ... 31 0 1 0 1 2 3 0 1 v1 v2 Vadim Shalts Функциональные структуры данных и архитектура 43 / 86
  • 45. Персистентные структуры данных и их анализ Примеры структур данных и их анализ RRB trees - Relaxed Radix Balanced Trees “RRB-Trees: Efficient Immutable Vectors”, EPFL-REPORT-169879, September, 2011: http://infoscience.epfl.ch/record/169879/files/RMTrees.pdf Дополнительные операции c O log N : объединение коллекций (concatenation) вставка в позицию (insert-at) разделение на части (splits-at) Реализации: github.com/clojure/core.rrb-vector github.com/TiarkRompf/rrbtrees Vadim Shalts Функциональные структуры данных и архитектура 44 / 86
  • 46. Персистентные структуры данных и их анализ Примеры структур данных и их анализ HashMap. Hash Array Mapped Trie (HAMT) Bit-partitioned hash tries Vadim Shalts Функциональные структуры данных и архитектура 45 / 86
  • 47. Персистентные структуры данных и их анализ Примеры структур данных и их анализ HashMap. ДобавлениеPath Copying int count 15 INode root HashMap int count 16 INode root HashMap Vadim Shalts Функциональные структуры данных и архитектура 46 / 86
  • 48. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Общие свойства Версионность Потоковая безопасность Безопасность для итерирования Уменьшение потребление памяти (для нескольких копий) Возможно увеличение потребления памяти (для одной копии) Простота использования Производительность? Vadim Shalts Функциональные структуры данных и архитектура 47 / 86
  • 49. Персистентные структуры данных и их анализ Примеры структур данных и их анализ Теория за бортом Детальный анализ производительности Линзы (Functional lenses) - упрощают работу с вложенными неизменяемыми структурами данных Zipper - техника представления объединённых структур данных. Ускоряет обработку персистентных коллекций. Ctrie - concurrent hash-trie Vadim Shalts Функциональные структуры данных и архитектура 48 / 86
  • 50. Влияние на архитектуру приложений Применение и примеры архитектуры Архитектура Vadim Shalts Функциональные структуры данных и архитектура 49 / 86
  • 51. Влияние на архитектуру приложений Применение и примеры архитектуры Undo/Redo. Команды trait UndoableCommand { def redo() def undo() } var currentState = new StringBuilder() class InsertCommand(pos: Int, value: String) extends UndoableCommand { def redo() = currentState.insert(pos, value) def undo() = currentState.delete(pos, value.length) } Vadim Shalts Функциональные структуры данных и архитектура 50 / 86
  • 52. Влияние на архитектуру приложений Применение и примеры архитектуры Undo/Redo + шаблон Хранитель (Memento) case class Memento(storedState: String) var currentState = new StringBuilder() val stateHistory = collection.mutable.Stack[Memento]() class InsertCommand(pos: Int, value: String) extends UndoableCommand { def redo() = { stateHistory.push( new Memento(currentState.mkString) ) currentState.insert(pos, value) } def undo() = { currentState.clear() currentState.append( stateHistory.pop.storedState ) } } Vadim Shalts Функциональные структуры данных и архитектура 51 / 86
  • 53. Влияние на архитектуру приложений Применение и примеры архитектуры Undo/Redo + Персистентные структуры данных case class Article(name: String, price: Double) case class Order(goods: Vector[Article], total: Double) type State = Order type UndoableCommand = State => State var currentState = new State(Vector.empty, 0) val stateHistory = collection.mutable.Stack[State]() def executeCommand(command: UndoableCommand) = { stateHistory.push( currentState ) currentState = command(currentState) } def undoCommand() = currentState = stateHistory.pop() Vadim Shalts Функциональные структуры данных и архитектура 52 / 86
  • 54. Влияние на архитектуру приложений Применение и примеры архитектуры Undo/Redo + Персистентные структуры данных def buyArticle(article: Article): UndoableCommand = (state: State) => new State(state.goods :+ article, state.total + article.price) // someCommand is function: State => State val someCommand = buyArticle(new Article("iPad", 499)) executeCommand(someCommand) println(state.total) // 499.0 undoCommand() println(state.total) // 0.0 Vadim Shalts Функциональные структуры данных и архитектура 53 / 86
  • 55. Влияние на архитектуру приложений Применение и примеры архитектуры Блокировки. synchronized и ReentrantLock Now t Thread 1 Thread 2 Thread 3 Thread 4 Vadim Shalts Функциональные структуры данных и архитектура 54 / 86
  • 56. Влияние на архитектуру приложений Применение и примеры архитектуры Блокировки. ReentrantReadWriteLock Now t Thread 1 Thread 2 Thread 3 Thread 4 Vadim Shalts Функциональные структуры данных и архитектура 55 / 86
  • 57. Влияние на архитектуру приложений Применение и примеры архитектуры Блокировки. ReentrantReadWriteLock другой пример Now t Thread 1 Thread 2 Thread 3 Thread 4 Vadim Shalts Функциональные структуры данных и архитектура 56 / 86
  • 58. Влияние на архитектуру приложений Применение и примеры архитектуры Блокировки. StampedLock Now t Thread 1 Thread 2 Thread 3Thread 3 Thread 4 Vadim Shalts Функциональные структуры данных и архитектура 57 / 86
  • 59. Влияние на архитектуру приложений Применение и примеры архитектуры StampedLock. Лучше масштабируется class Point { private double x, y; private final StampedLock sl = new StampedLock(); void move(double deltaX, double deltaY) { // an exclusively locked method long stamp = sl.writeLock(); try { x += deltaX; y += deltaY; } finally { sl.unlockWrite(stamp); } } // ... } Vadim Shalts Функциональные структуры данных и архитектура 58 / 86
  • 60. Влияние на архитектуру приложений Применение и примеры архитектуры StampedLock. Оптимистичные блокировки class Point { private double x, y; private final StampedLock sl = new StampedLock(); double distanceFromOrigin() { // A read-only method long stamp = sl.tryOptimisticRead(); double currentX = x, currentY = y; if (!sl.validate(stamp)) { stamp = sl.readLock(); try { currentX = x; currentY = y; } finally { sl.unlockRead(stamp); } } return Math.sqrt(currentX * currentX + currentY * currentY); } // ... } Vadim Shalts Функциональные структуры данных и архитектура 59 / 86
  • 61. Влияние на архитектуру приложений Применение и примеры архитектуры Оптимистичные блокировки через StampedLock. Проблемы и ограничения «The use of optimistic mode for short read-only code segments often reduces contention and improves throughput. However, its use is inherently fragile. Optimistic read sections should only read fields and hold them in local variables for later use after validation. Fields read while in optimistic mode may be wildly inconsistent, so usage applies only when you are familiar enough with data representations to check consistency and/or repeatedly invoke method validate()» StampedLock. Java Documentation Vadim Shalts Функциональные структуры данных и архитектура 60 / 86
  • 62. Влияние на архитектуру приложений Применение и примеры архитектуры Блокировки. StampedLock Now t Thread 1 Thread 2 Thread 3 Thread 4 Vadim Shalts Функциональные структуры данных и архитектура 61 / 86
  • 63. Влияние на архитектуру приложений Применение и примеры архитектуры Блокировки. Неизменяемые данные t Thread 1Thread 1 Thread 2Thread 2Thread 2 Thread 3Thread 3 Thread 4Thread 4 Vadim Shalts Функциональные структуры данных и архитектура 62 / 86
  • 64. Влияние на архитектуру приложений Применение и примеры архитектуры Блокировки. Много писателей @volatile var currentState: State = initialState val writersLock = new StampedLock def readState() = { val latestState = currentState // ... } def updateState(command: Command) = { val stamp = writersLock.writeLockInterruptibly() val latestState = currentState try { currentState = command(currentState) } catch { case AbortException => // ... case ex: Throwable => // ... } finally { writersLock.unlockWrite(stamp) } } Vadim Shalts Функциональные структуры данных и архитектура 63 / 86
  • 65. Влияние на архитектуру приложений Применение и примеры архитектуры Реализация с неизменяемым Point классом. Общий код trait ReferenceManager[T] { def setState(state: T) = updateState(_ => state) def getState(): T def updateState(stateReplacer: T => T) } Vadim Shalts Функциональные структуры данных и архитектура 64 / 86
  • 66. Влияние на архитектуру приложений Применение и примеры архитектуры Реализация с неизменяемым Point классом. Общий код class LockBasedReferenceManager[T] extends ReferenceManager[T] { @volatile private var currentState: T = _ private val writersLock = new StampedLock def getState() = currentState def updateState(stateReplacer: T => T) = { val stamp = writersLock.writeLockInterruptibly() val latestState = currentState try { currentState = stateReplacer(latestState) } catch { case ex: Throwable => // ... } finally { writersLock.unlockWrite(stamp) } } } Vadim Shalts Функциональные структуры данных и архитектура 65 / 86
  • 67. Влияние на архитектуру приложений Применение и примеры архитектуры Реализация с неизменяемым Point классом. Основная логика case class Point(x: Double, y: Double) { def distanceFromOrigin() = Math.sqrt(x * x + y * y) def move(deltaX: Double, deltaY: Double) = new Point(x + deltaX, y + deltaY) } class PointHolder(reference: ReferenceManager[Point]) { reference.setState(Point(0, 0)) // Initial state def distanceFromOrigin() = reference.getState().distanceFromOrigin() def move(deltaX: Double, deltaY: Double) = reference.updateState { s => s.move(deltaX, deltaY) } } Vadim Shalts Функциональные структуры данных и архитектура 66 / 86
  • 68. Влияние на архитектуру приложений Применение и примеры архитектуры Блокировки. Оптимистичное обновление состояния t Thread 1Thread 1Thread 1Thread 1 Thread 2 Thread 3Thread 3 Thread 4Thread 4 Vadim Shalts Функциональные структуры данных и архитектура 67 / 86
  • 69. Влияние на архитектуру приложений Применение и примеры архитектуры Реализация через CAS. Сходство с MVCC class OptimisticReferenceManager[T] extends ReferenceManager[T] { val ref = new AtomicReference[T] override def setState(state: T) = ref.set(state) def getState() = ref.get def updateState(stateReplacer: T => T) = { var continue = true while(continue) { val latestState = getState() val newState = stateReplacer(latestState) if (ref.compareAndSet(latestState, newState)) continue = false } } } Vadim Shalts Функциональные структуры данных и архитектура 68 / 86
  • 70. Влияние на архитектуру приложений Применение и примеры архитектуры STM - Software transactional memory Механизм управления параллелизмом аналогичный механизму транзакций баз данных. Используется для управления доступом к совместно используемой памяти в параллельных вычислениях. Альтернатива для синхронизации на основе блокировок. Vadim Shalts Функциональные структуры данных и архитектура 69 / 86
  • 71. Влияние на архитектуру приложений Применение и примеры архитектуры Clojure STM Реализация основана на MVCC Транзакции обеспечиваются изоляцией снимков (Snapshot isolation) Оптимистичный подход, рассчитываем на малую вероятность коллизий на запись Невозможны deadlocks, livelocks или гонки Компонуемые операции Vadim Shalts Функциональные структуры данных и архитектура 70 / 86
  • 72. Влияние на архитектуру приложений Применение и примеры архитектуры STM - полезен Если паттерны доступа укладываются в: частые чтения достаточно редкие конфликты на запись Почему? Если транзакция не удалась, то нужно выполнить откат Нужно минимизировать пенальти за откат и максимизировать параллелизм. Vadim Shalts Функциональные структуры данных и архитектура 71 / 86
  • 73. Влияние на архитектуру приложений Применение и примеры архитектуры STM - Механика Значения вычитанные внутри транзакции: гарантированно целостные и отражают все изменения относятся к транзакциям, которые были завершены до начала этой транзакции. Изменения внутри транзакция: локальны и видимы только внутри транзакции становятся целиком видимыми после коммита Vadim Shalts Функциональные структуры данных и архитектура 72 / 86
  • 74. Влияние на архитектуру приложений Применение и примеры архитектуры STM. Работа с ссылками Слайд Neale Swinnerton (Clojure STM - What? Why? How?) Vadim Shalts Функциональные структуры данных и архитектура 73 / 86
  • 75. Влияние на архитектуру приложений Применение и примеры архитектуры И снова менеджер def as[T](value: AnyRef) = value.asInstanceOf[T] class StmReferenceManager[T <: AnyRef] extends ReferenceManager[T] { private val ref = new Ref(null) override def setState(state: T) = as[T]( ref.set(state) ) def getState() = as[T]( ref.deref() ) def updateState(stateReplacer: T => T) = ref.alter(new AFn() { override def invoke(state: AnyRef): AnyRef = as[T]{ as[AnyRef]( stateReplacer( as[T](state) ) ) } }, null) } Vadim Shalts Функциональные структуры данных и архитектура 74 / 86
  • 76. Влияние на архитектуру приложений Применение и примеры архитектуры Скрываем работу с транзакциями def atomic[T](func: => T) = as[T] { LockingTransaction.runInTransaction(new Callable[T] { def call = func }) } Vadim Shalts Функциональные структуры данных и архитектура 75 / 86
  • 77. Влияние на архитектуру приложений Применение и примеры архитектуры Надёжный, дерзкий, губернский банк case class History(change: Double, balanceBeforeChange: Double) case class Account(balance: Double, history: Vector[History]) { if (balance < 0 || history.length > 100) throw new IllegalArgumentException("Not today") if (history.length > 0 && history.last.change < 0.10) throw new IllegalArgumentException("Suspicious behavior") def changeBalanceBy(amount: Double) = new Account(balance + amount, history :+ History(amount, balance)) } class AccountHolder(reference: ReferenceManager[Account]) { reference.setState(Account(0, Vector())) // Initial state def balance = reference.getState().balance def changeBalanceBy(amount: Double) = reference.updateState ( s => s.changeBalanceBy(amount) ) } Vadim Shalts Функциональные структуры данных и архитектура 76 / 86
  • 78. Влияние на архитектуру приложений Применение и примеры архитектуры Соединяем всё вместе val (source, target) = atomic { (new AccountHolder(new StmReferenceManager()), new AccountHolder(new StmReferenceManager())) } try { atomic { target.changeBalanceBy(200) println(target.balance) // 200.0 source.changeBalanceBy(-200) // IllegalStateException: Balance negative } } catch { case ex: Throwable => ex.printStackTrace(); } println(source.balance) // 0.0 println(target.balance) // 0.0 source.changeBalanceBy(200) // IllegalStateException: No transaction running Vadim Shalts Функциональные структуры данных и архитектура 77 / 86
  • 79. Влияние на архитектуру приложений Применение и примеры архитектуры Транзакции. ACI(D) для персистентных структур ✓ Atomicity (Атомарность) ✓ Consistency (Согласованность) ✓ Isolation (Изолированность) ✗ Durability (Долговечность) Vadim Shalts Функциональные структуры данных и архитектура 78 / 86
  • 80. Влияние на архитектуру приложений Персистентные базы данных (Datomic) Базы данных. Классика Vadim Shalts Функциональные структуры данных и архитектура 79 / 86
  • 81. Влияние на архитектуру приложений Персистентные базы данных (Datomic) Datomic. Общая идея Vadim Shalts Функциональные структуры данных и архитектура 80 / 86
  • 82. Влияние на архитектуру приложений Персистентные базы данных (Datomic) Datomic Иммутабильная база данных с поддержкой ACID Явным образом оперирует временем - время всегда частью модели данных Основная единица хранения данных - факт привязанный ко времени (datom) Datom - запись со списком атрибутов. Атрибуты могут ссылаться на другие факты - отношения Изменения модели происходит путём добавления новых фактов Vadim Shalts Функциональные структуры данных и архитектура 81 / 86
  • 83. Влияние на архитектуру приложений Персистентные базы данных (Datomic) Datomic 2 Полагается на внешнюю реализацию хранилища данных (RAM, DynamoDB, RDBMS, ...) Изменения/транзакции отделены от чтения и проходят через специальный компонент (transactor). Возможно симулирование состояния базы без коммитов Практически безграничное масштабирование запросов на чтение и встроенная поддержка кеширования Запросы могут использовать функции на Java/Clojure. Vadim Shalts Функциональные структуры данных и архитектура 82 / 86
  • 84. Влияние на архитектуру приложений Персистентные базы данных (Datomic) Datomic - возможные проблемы. Платная дорогая лицензия (есть бесплатная урезанная версия и версия для разработчиков) Плохо подходит для хранения больших (BLOB) или часто меняющихся данных. Значительно увеличивается потребность в дисковом пространстве (особенно индексы) Для узлов сети желательно использовать большой кеш Законы могут требовать возможности удалять данные пользователя. Vadim Shalts Функциональные структуры данных и архитектура 83 / 86
  • 85. Влияние на архитектуру приложений Персистентные базы данных (Datomic) Персистентные структуры данных - итоги Выгодный компромисс - платим памятью за масштабируемость Изменения общих данных не блокируют обработку текущих запросов (настройки, текущее состояние и т.д) Долгие чтения не блокируют записи (обращение по сети, построение отчета) Упрощается обработка долгих запросов (не связаны ограничениями по времени) Vadim Shalts Функциональные структуры данных и архитектура 84 / 86
  • 86. Влияние на архитектуру приложений Персистентные базы данных (Datomic) Персистентные структуры данных - итоги 2 Стратегия работы с блокировками стала гибкой и не связана жестко с реализацией логики Упрощается тестирование и разработка бизнес логики (наиболее часто меняющийся код) Повышается надёжность - случайные ошибки (исключения) имеют меньше шансов навредить Доступность старых фактов/данных упрощает разработку и открывает новые возможности (datomic + blueprints) Vadim Shalts Функциональные структуры данных и архитектура 85 / 86
  • 87. Вопросы Вопросы? Vadim Shalts Функциональные структуры данных и архитектура 86 / 86