A_Storage - DT Structure
DT
DT - Distributed Tree (Распределенное дерево) предназачена для хранения больших последовательностей в кластере
Основные преимущества структуры
- + В ключах есть порядок. Можно итерировать ключи и запрашивать range
- + данных можно поместить в DT очень много - гораздо больше чем "влезет" на любой сервер кластера - вся последовательность хранится "в целом на кластере" - распределенно
- + при чтении данных из Глобального индекса , производительность высокая, как у KV
Недостатки :
- - Небольшая скорость работы (30-60 insert/sec/tree/client , R,W вставленной записи — как в KV (3 реплики, 2 — кворум) для одного DT Tree : все клиенты сталкиваются и rps не превышает 100 rps для этого tree (3 реплики, 2 — кворум) )
Подходит для индексирования (reverse index) большого объёма данных , например wikipedia , который редко изменяется, но часто происходит обращение к индексу на чтение и поиск.
Два режима. Работа со структурой возможна в двух режимах :
- Обычный
- - нет транзакций
- + скорость выше в 10 раз (на уровне касандры в обычном ее режиме)
- Транзакционный
- - медленнее (скорость в 10 раз медленнее кассандры)
- + надежное изменение набора данных
- + сохранение консистентности набора данных
Операции
Основные операции
# чтение значения из ключа await session.tree(random_tree()).get_cursor(random_key()) # запись значения , вставка await session.tree(random_tree()).cursor(random_key()).set(random_value()) # получить вставленное значение tree = session.tree(random_tree()) key = random_key() value = random_value() await tree.cursor(key).set(value) value1 = (await tree.get_cursor(key)).value # assert value1==value
навигация по дереву
# делаем "случайное" дерево tree = session.tree(random_tree()) await tree.cursor(['A', 'A']).set('foo') await tree.cursor(['A', 'B']).set('bar') await tree.cursor(['B', 'A']).set('baz') # читаем ключ, позицию запоминаем c = await tree.get_cursor(['A', 'A']) # NEXT c = await c.next() assert c.key == ['A', 'B'] assert c.value == 'bar' # NEXT again c = await c.next() assert c.key == ['B', 'A'] assert c.value == 'baz' # NEXT again c = await c.next() assert c is None
Аналогично с prev
tree = session.tree(random_tree()) await tree.cursor(['A', 'A']).set('foo') await tree.cursor(['A', 'B']).set('bar') await tree.cursor(['B', 'A']).set('baz') c = await tree.get_cursor(['B', 'A']) c = await c.prev() assert c.key == ['A', 'B'] assert c.value == 'bar' c = await c.prev() assert c.key == ['A', 'A'] assert c.value == 'foo' c = await c.prev() assert c is None
Примеры с транзакциями
в транзакции из Python клиента работать очень просто
# create tree object tree = session.tree(random_tree()) # начинаем транзакцию и в ней работаем , как обычно async with session.transaction() as tx: # запись , вставка await tree.cursor(['A'], tx).set('foo') await tree.cursor(['B'], tx).set('bar') async with session.transaction() as tx: # чтение assert (await tree.get_cursor(['A'], tx)).value == 'foo' assert (await tree.get_cursor(['B'], tx)).value == 'bar'
транзакции добавляют свою логику. Например, если откатить транзакцию :
tree = session.tree(random_tree()) async with session.transaction() as tx: await tree.cursor(['A'], tx).set('foo') await tree.cursor(['B'], tx).set('bar') await tx.rollback() async with session.transaction() as tx: # данные остались старые = никакие assert (await tree.get_cursor(['A'], tx)).value is None assert (await tree.get_cursor(['B'], tx)).value is None
Range
Можно запросить диапазон ключей.
Это сложный функционал с точки зрения транзакционности и гарантий...
все параметры range описаны в документации
цитата оттуда :
Возвращает отсортированный список ключей в дереве в указанный пределах. :param first: начальный ключ, не включается в ответ; по умолчанию - с первого :param last: последий ключ, включается в ответ; по умолчанию - до последнего включительно :param limit: максимальное количество ключей в ответе, начиная с первого; по умолчанию - нет ограничений :param transaction: если указан, запрос выполняется в транзакции :return: список объектов Cursor с данными
tree = session.tree(random_tree()) await tree.cursor(['A', 'A']).set('foo') await tree.cursor(['A', 'B']).set('bar') await tree.cursor(['B', 'A']).set('baz') # параметры по умолчанию. result = await tree.range() assert len(result) == 3 assert result[0].key == ['A', 'A'] assert result[0].value == 'foo' assert result[1].key == ['A', 'B'] assert result[1].value == 'bar' assert result[2].key == ['B', 'A'] assert result[2].value == 'baz'
Указание начальной позиции :
tree = session.tree(random_tree()) await tree.cursor(['A', 'A']).set('foo') await tree.cursor(['A', 'B']).set('bar') await tree.cursor(['B', 'A']).set('baz') result = await tree.range(first=['A', 'A']) assert len(result) == 2 assert result[0].key == ['A', 'B'] assert result[0].value == 'bar' assert result[1].key == ['B', 'A'] assert result[1].value == 'baz'
Указание заключительных позиций :
tree = session.tree(random_tree()) await tree.cursor(['A', 'A']).set('foo') await tree.cursor(['A', 'B']).set('bar') await tree.cursor(['B', 'A']).set('baz') result = await tree.range(last=['A', 'B']) assert len(result) == 2 assert result[0].key == ['A', 'A'] assert result[0].value == 'foo' assert result[1].key == ['A', 'B'] assert result[1].value == 'bar'
Указание предельного размера выборки :
tree = session.tree(random_tree()) await tree.cursor(['A', 'A']).set('foo') await tree.cursor(['A', 'B']).set('bar') await tree.cursor(['B', 'A']).set('baz') result = await tree.range(limit=2) assert len(result) == 2 assert result[0].key == ['A', 'A'] assert result[0].value == 'foo' assert result[1].key == ['A', 'B'] assert result[1].value == 'bar'
Аналогично работает и http api
Comments
Comments powered by Disqus