Switch lang: Русский \ English

A_Storage - KV Structure

Использование , Примеры простых операций

Формат ключей

Для того чтобы упростить описание ключей, состоящих из нескольких уровней, была введена поддержка составных ключей в виде json-массива строк. Например, описать год рождения пользователя <user_name> можно следующим образом:

["users", "<user_name>", "birth-date", "year"]

Такими ключами легко манипулировать программно.

Реплики

Сервис поддерживает возможность задавать количество реплик для каждого ключа в отдельности. Для этого в каждом запросе задаются параметры N, R, W, которые ответственны за следующее:

  • N - количество реплик у данного ключа.
  • R - количество, необходимое для поддтверждения чтения, то есть сколько реплик должны ответить, прежде чем значение будет считаться правильно прочитаным.
  • W - количество, необходимое для поддтверждения записи, то есть сколько реплик должны сообщить об успешной записи нового значения.

подробнее о репликах

Операции с Key-Value

Установка значения

Есть возможность установки одного или нескольких значений с помощью одного POST запроса /kv/set.

Важно: если в запросах сразу же читается или пишется несколько значений, то это не гарантирует атомарность. Групповые запросы введены для уменьшения количества обращений к сервису. Если до момента выполнения запроса значение не существовало, то оно будет создано.

Пример установки одного значения:

    # set some
    @async_test
    async def test_set(self):
        await session.entry(random_key()).set(random_value())

   # set None 
   @async_test
   async def test_set_none(self):
        await session.entry(random_key()).set(None)

    # set and check 
    @async_test
    async def test_return_set_value(self):
        key = random_key()
        value = random_value()
        await session.entry(key).set(value)
        assert (await session.get_entry(key)).value == value
# set ["k1","k2","k3"] <= "123"
$ curl -X PUT "http://api.acapella.ru:12000/v2/kv/keys/k1:k2:k3?&n=3&r=2&w=2" -H  "accept: application/json" -H  "content-type: application/json" -d "{  \"foo\": 123,  \"bar\": 456}"
{"version":"1"}

Если в запросе нет ошибок и он корректно обработан, ответ будет со статусом 200 OK. Если запрос составлен неправильно, вернётся код ошибки 400 Bad Request.

Установка нескольких значений аналогична ситуации с одним значением:

TODO 

Чтение значения

Чтение одного или нескольких значений производится с помощью POST запроса /kv/get. Чтение по ключу, которому ещё не было присвоено ни одно значение, выдаёт null. В ответе приходит json-массив значений указанных ключей.

Пример:

# get ["k1", "k2", "k3"] - чтение по одному ключу
$ curl -X GET "http://api.acapella.ru:12000/v2/kv/keys/k1:k2:k3?wait-timeout=60&transaction=0&n=3&r=2&w=2" -H  "accept: application/json" -H  "content-type: application/json"
{"version":"0","value":{"foo":123.0,"bar":456.0}}

# чтение по нескольким ключам
TODO 
# Аргумент запроса `keys` - это массив ключей, которые будут прочитаны. Значения приходят в ответе в том-же порядке, как и ключи в запросе.


# get ["not_exists_key"] - чтение не существующего ключа
$ curl -X GET "http://api.acapella.ru:12000/v2/kv/keys/not_exists_key?wait-timeout=60&transaction=0&n=3&r=2&w=2" -H  "accept: application/json" -H  "content-type: application/json"
{"version":"0"}

Если в запросе нет ошибок и он корректно обработан, ответ будет со статусом 200 OK. Если запрос составлен неправильно, вернётся код ошибки 400 Bad Request.

Удаление значения

Данная операция эквивалентна установке значения в null, для любых других операций нет разницы, было ли значение установлено в null, удалено или ещё не было задано. Выполняется удаление с помощью POST запроса /kv/delete.

# del ["foo"] - удаление одного ключа
TODO 

# удаление нескольких ключей
TODO 

Аргумент keys - это массив ключей, которые будут удалены. Если в запросе нет ошибок и он корректно обработан, ответ будет со статусом 200 OK. Если запрос составлен неправильно, вернётся код ошибки 400 Bad Request.

CAS без транзакций

Если ваша модель данных работает без транзакций , то допустимы одиночные Cas операции, по одному ключу в каждом

        # тут все хорошо
        key = random_key()
        value = random_value()
        await session.entry(key).cas(value)
        assert (await session.get_entry(key)).value == value

        # этот код бросит исключение CasError
        key = random_key()
        value = random_value()
        entry = await session.get_entry(key)
        await entry.cas(value, entry.version + 1)

Транзакциионные операции

Создание транзакции \ commit \ rollback

Работа с транзакией требует от клиента знания идентификатора транзакции и только. Никакие объекты и ресурсы ОС не требуются.

    # Библиотека для python явно не работает c иджентификатором транзакции
    async def test_create_tx(self):
        async with session.transaction():
            pass
    # но можно работать и в "ручном" режиме в особых случаях 
    # https://github.com/AcapellaSoft/AStorageClient/blob/develop/python/src/acapella/kv/Session.py#L53
    # example :
    tr =    await session.transaction_manual()
    e =     await tr.get_entry( ['k1_1','k1_2'] )
$ curl -X POST "http://api.acapella.ru:12000/v2/tx" -H  "accept: application/json" -H  "content-type: application/json"
{"index":"8083882192603548991"}

откат транзакции на python

        async with session.transaction() as tx:
            await tx.rollback()

если транзакцию откатили - значение останется старым

        key = random_key()
        async with session.transaction() as tx:
            e = await tx.get_entry(key)
            value = e.value
            await e.set(random_value())
            await tx.rollback()

        async with session.transaction() as tx:
            e = await tx.get_entry(key)
            assert value == e.value

Если случиться ошибка - транзакция откатится автоматически

        key = random_key()
        value = None
        try:
            async with session.transaction() as tx:
                e = await tx.get_entry(key)
                value = e.value
                await e.set(random_value())
                raise Exception()
        except Exception:
            pass

        async with session.transaction() as tx:
            e = await tx.get_entry(key)
            assert value == e.value

транзакции изолированы

        key = random_key()
        value = random_value()

        async with session.transaction() as tx:
            await tx.entry(key).set(value)

        async with session.transaction() as tx:
            e = await tx.get_entry(key)
            assert value == e.value

чтение и запись ключа из под транзакции

просто указываем transaction= в параметрах запроса

$ curl -X GET "http://api.acapella.ru:12000/v2/kv/keys/k1/k2/k3?wait-timeout=60&transaction=8083882192603548991&n=3&r=2&w=2" -H  "accept: application/json" -H  "content-type: application/json"
{"version":"0","value":{"foo":123.0,"bar":456.0}}

cas операция из под транзакции

Сas операция блокирует на время транзакции прочитанный ключ и отмечает его новое значение (внутри транзакции) до конца транзакции.

Commit транзакции пройдеттолько если все cas ключи не модифицированы , но соответствуют изначальным версиям (первое обращение в транзакции)

Комментарии

Comments powered by Disqus
Перейти к главному содержимому