Перейти к содержанию

Публичный API Picodata

Описание публичного интерфейса Picodata состоит из нескольких разделов:

  • Lua API — интерфейс Lua
  • Proc API — интерфейс хранимых процедур

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

Lua API

Данный раздел интерфейса относится к работе в консоли Picodata при использовании ввода в режиме Lua.

Пример:

picodata> pico.help("help")
-- Печатает данную справку
-- и список доступных разделов (topics)

Вызов функций pico.* возможен и через iproto, но влечет за собой накладные расходы, связанные с конвертацией из формата MessagePack в Lua и обратно.

Функция Описание
pico.LUA_API_VERSION Версия Lua API.
pico.PICODATA_VERSION Версия Picodata.
pico.abort_ddl Отмена ожидающей операции по изменению схемы данных.
pico.cas() Запрос на изменение параметров методом Compare and Swap.
pico.create_table() Создание таблицы.
pico.drop_table() Удаление таблицы.
pico.exit() Корректное завершение работы указанного инстанса.
pico.expel() Контролируемый вывод инстанса из кластера.
pico.help() Доступ к встроенной справочной системе.
pico.instance_info() Получение информации об инстансе (идентификаторы, уровни (state) и прочее).
pico.raft_compact_log() Компактизация raft-журнала c удалением указанного числа наиболее старых записей.
pico.raft_log() Чтение содержимого raft-журнала.
pico.raft_propose_nop() Добавление в raft-журнал запись Nop (no operation).
pico.raft_read_index() Кворумное чтение индекса raft-журнала.
pico.raft_status() Получение данных о текущем состоянии raft (терм, лидер и т.д.).
pico.raft_term() Получение номера терма (текущего или для указанной записи).
pico.raft_wait_index() Ожидание локального применения указанного raft-индекса.
pico.sql() Выполнение кластерных SQL-запросов.
pico.wait_ddl_finalize() Ожидание применения (финализации) DDL-операции.
pico.wait_vclock() Ожидание момента, когда значение Vclock достигнет целевого.
pico.whoami() Отображение данных о текущем инстансе.

pico.LUA_API_VERSION

Строковая переменная (не функция), которая содержит версию Lua API Picodata. Формат соответствует семантическому версионированию (Semantic Versioning).

Пример:

picodata> pico.LUA_API_VERSION
---
- 1.0.0
...

pico.PICODATA_VERSION

Строковая переменная (не функция), которая содержит версию Picodata. Формат соответствует календарному версионированию (Calendar Versioning) с форматом YY.0M.MICRO.

Пример:

picodata> pico.PICODATA_VERSION
---
- 23.06.0
...

pico.abort_ddl

Отменяет изменение схемы данных.

function abort_ddl(timeout)

Параметры:

  • timeout: (number)

Функция принимает в качестве параметра число секунд, в течение которых она будет ожидать подтверждения отмены операции. Возвращает индекс соответствующей операции DdlAbort в raft-журнале, либо ошибку в случае отсутствия ожидающих операций.

pico.cas

Функция проверяет предикат на лидере. Если проверка не выявляет конфликтов, то функция добавляет новую запись в raft-журнал и возвращает ее индекс (пока еще не зафиксированный в кластере). Функция применяется только для глобальных таблиц и работает на всем кластере.

Предикат состоит из трех частей:

  • номера индекса схемы данных (index);
  • номера терма (term);
  • диапазона значений самого проверяемого параметра (ranges).

Если предикат не указан, он будет автоматически сгенерирован на основе текущих index и term и пустого диапазона ranges. Запрос без диапазонов ranges означает "запись вслепую" и поэтому не рекомендуется к использованию.

Функция возвращает индекс сделанной записи в raft-журнале.

function cas(dml[, predicate])

Параметры:

  • dml: (table):

    • kind (string), варианты: 'insert' | 'replace' | 'update' | 'delete'
    • table (string)
    • tuple (optional table), обязательно для 'insert' и 'replace'
    • key (optional table), обязательно для 'update' и 'delete'
    • ops (optional table), обязательно для 'update'
  • predicate: (optional table):

    • index (optional number), default: current applied index
    • term (optional number), default: current term
    • ranges (optional table {table CasRange,...}) default: {} (empty table)

Возвращаемое значение:

(number) или
(nil, string) в случае ошибки

Пример без указания предиката:

pico.cas({
    kind = 'insert',
    table = 'WAREHOUSE',
    tuple = {11, 99, 'chunks', 'light'},
})

Здесь, 11 — значение первой колонки (id), 99 — значение bucket_id.

Пример с указанием предиката (проверка, что никакие другие записи не были добавлены ранее):

pico.cas({
    kind = 'replace',
    table = 'WAREHOUSE',
    tuple = {11, 99, 'chunks', 'light'},
}, {
    ranges = {{
        table = 'WAREHOUSE',
        key_min = { kind = 'excluded', key = {1,} },
        key_max = { kind = 'unbounded' },
    }},
})

pico.create_table

Создает таблицу. Функция завершается после того, как таблица создана глобально и доступна с текущего инстанса. Функция возвращает индекс соответствующей записи Op::DdlCommit в raft-журнале, который необходим для синхронизации с остальными инстансами. Если такая таблица уже существует, то запрос игнорируется.

function create_table(opts)

Параметры:

  • opts: (table):
    • name (string)
    • format (table {table TableField,...}), см. table TableField
    • primary_key(table {string,...}) с именами полей
    • id (optional number), по умолчанию генерируется автоматически
    • distribution (string), варианты: 'global' | 'sharded' при использовании sharded также нужно использовать параметр by_field или связку параметров sharding_key+sharding_fn.
    • by_field (optional string), обычно используется bucket_id
    • sharding_key(optional table {string,...}) с именами полей
    • sharding_fn (optional string), поддерживается пока только функция murmur3
    • engine (optional string), движок хранения данных в БД; варианты: 'memtx' | 'vinyl'. По умолчанию используется 'memtx'. См подробнее.
    • timeout (optional number), число в секундах. По умолчанию используется бесконечное значение.

Возвращаемое значение:

(number) или
(nil, string) в случае ошибки

Примеры:

Создание глобальной таблицы с двумя полями:

pico.create_table({
    name = 'WAREHOUSE',
    format = {
        {name = 'ID', type = 'unsigned', is_nullable = false},
        {name = 'ITEM', type = 'string', is_nullable = false},
        {name = 'TYPE', type = 'string', is_nullable = false}
    },
    primary_key = {'ID'},
    distribution = 'global',
    timeout = 3,
})

Запись в глобальную таблицу происходит посредством функции pico.cas:

pico.cas({
    kind = 'insert',
    table = 'WAREHOUSE',
    tuple = {1, 'bricks', 'heavy'},
})

Для чтения из глобальной таблицы используется box-API Tarantool:

box.space.WAREHOUSE:fselect()

Создание шардированной таблицы с двумя полями:

pico.create_table({
    name = 'DELIVERIES',
    format = {
        {name = 'nmbr', type = 'unsigned', is_nullable = false},
        {name = 'product', type = 'string', is_nullable = true},
        {name = 'quantity', type = 'unsigned', is_nullable = true},
    },
    primary_key = {'product'},
    distribution = 'sharded',
    sharding_key = {'product'},
    timeout = 3,
})

Вычисление совместимого с SQL хеша для параметра bucket_id:

local key = require('key_def').new({{fieldno = 2, type = 'string'}})
local tuple = box.tuple.new({'metalware'})
local bucket_id = key:hash(tuple) % vshard.router.bucket_count()

Добавление данных в шардированную таблицу происходит с помощью VShard API:

local bucket_id = vshard.router.bucket_id_mpcrc32('metalware')
vshard.router.callrw(bucket_id, 'box.space.DELIVERIES:insert', {{1, 'metalware', 2000}})

Примечание

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

pico.drop_table

Удаляет таблицу (пространство для хранения данных) на всех инстансах кластера. Функция ожидает глобального удаления таблицы. Если ожидание превышает таймаут, функция возвращает ошибку. Если таблицы не существует, то запрос игнорируется.

function drop_table(table, [opts])

Параметры:

  • table (number | string), id или имя таблицы
  • opts: (optional table), таблица:
    • timeout (optional number), число в секундах. По умолчанию используется бесконечное значение.

Возвращаемое значение:

(number) с номером raft-индекса или
(nil, error (ошибка в виде Lua-объекта)) в случае ошибки.

Примечание

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

pico.exit

Корректно завершает работу указанного инстанса.

function exit([code])

Параметры:

  • code: (table)

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

Результат работы:

Завершение текущего инстанса, завершение системных процессов, связанных инстансом. В выводе stdout будет присутствовать строка graceful shutdown succeeded, после чего будет возвращено управление командному интерпретатору.

Перезапуск инстанса позволит ему снова войти в состав кластера в статусе follower.

pico.expel

Выводит инстанс из кластера, но не завершает его работу. Может быть запущена только один раз для инстанса с определенным instance_id. Инстанс в состоянии expelled останется запущенным. Если его остановить и запустить снова, то он не присоединится к raft-группе.

function expel("instance_id")

Параметры:

  • instance_id: (string)

Возвращаемые значения:

  • (true) — при успешном выполнении;

  • (nil, string) — при ошибке;

Пример:

pico.expel("i2")

pico.help

Предоставляет доступ к встроенной справочной системе.

function help(topic)

Параметры:

  • topic: (optional string)

Пример:

picodata> pico.help("help")
-- Печатает данную справку
-- и список доступных разделов (topics)

pico.instance_info

Показывает информацию о текущем инстансе.

function instance_info(instance)

Параметры:

  • instance: (string)

Возвращаемое значение:

  • (table):
    • raft_id(number)
    • advertise_address (string)
    • instance_id (string)
    • instance_uuid (string)
    • replicaset_id(string)
    • replicaset_uuid (string)
    • current_state (table). variant (string), варианты: 'Offline' | 'Online' | 'Expelled'; incarnation (number)
    • target_state (table). variant (string), варианты: 'Offline' | 'Online' | 'Expelled'; incarnation(number),

Пример:

 picodata> pico.instance_info()
 ---
 - raft_id: 1
advertise_address: localhost:3301
instance_id: i1
instance_uuid: 68d4a766-4144-3248-aeb4-e212356716e4
replicaset_id: r1
replicaset_uuid: e0df68c5-e7f9-395f-86b3-30ad9e1b7b07
current_state:
  variant: Online
  incarnation: 26
target_state:
  variant: Online
  incarnation: 26
...

pico.raft_compact_log

Компактизирует raft-журнал до указанного индекса (не включая сам индекс).

Функция имеет эффект только на текущем инстансе.

function raft_compact_log(up_to)

Параметры:

  • up_to: (optional number), значение по умолчанию: inf

Возвращаемое значение:

(number)

Функция возвращает значение first_index — индекс первой записи в raft-журнале.

pico.raft_log

Позволяет ознакомиться с содержимым raft-журнала в человекочитаемом формате. Содержимое журнала предоставляется в виде таблицы со строками, подобно тому как fselect выводит содержимое таблиц.

Параметр opt.justify_contents можно использовать для изменения выравнивания столбцов таблицы.

Параметр opts.max_width позволяет задать максимальную ширину таблицы в знаках. Если фактически таблица шире, то часть данных будет обрезана. Если этот параметр не указывать, то по умолчанию в локальной сессии будет использоваться максимальная ширина терминала (для удаленной сессии используется другое значение, см. ниже).

function raft_log([opts])

Параметры:

  • opts: (table), таблица:
    • justify_contents (string), варианты: 'center' | 'left' | 'right', вариант по умолчанию: 'center'
    • max_width (number), значение по умолчанию для удаленной сессии: 80 знаков.

Возвращаемое значение:

(table)

Пример:

pico.raft_log({justify_contents = 'center', max_width = 100})

pico.raft_propose_nop

Добавляет в raft-журнал запись Nop (no operation). Используется для обновления raft-журнала путем добавления в него свежей записи. Функция не имеет передаваемых параметров.

pico.raft_read_index

Выполняет кворумное чтение по следующему принципу:

  1. Инстанс направляет запрос (MsgReadIndex) лидеру raft-группы. В случае, если лидера в данный момент нет, функция возвращает ошибку 'raft: proposal dropped'.
  2. Raft-лидер запоминает текущий commit_index и отправляет всем узлам в статусе follower сообщение (heartbeat) с тем, чтобы убедиться, что он все еще является лидером.
  3. Как только получение этого сообщения подтверждается большинством follower-узлов, лидер возвращает этот индекс инстансу.
  4. Инстанс дожидается применения (apply) указанного raft-индекса. Если таймаут истекает раньше, функция возвращает ошибку 'timeout'.
function raft_read_index(timeout)

Параметры:

  • timeout: (number)

Функция принимает в качестве параметра число секунд, в течение которых она ожидает ответа от инстанса.

Возвращаемое значение:

(number) или
(nil, string) в случае ошибки.

Пример:

picodata> pico.raft_read_index(1)
---
- 42
...

pico.raft_status

Получает данные о текущем состоянии raft-узла (терм, лидер и т.д.). Функция не имеет передаваемых параметров.

Возвращаемые поля:

  • id (number)
  • term (number)
  • leader_id (number | nil), поле может быть пустым если в текущем терме нет лидера или он еще неизвестен
  • raft_state (string), варианты: 'Follower' | 'Candidate' | 'Leader' | 'PreCandidate'

Возвращаемое значение:

(table) или
(nil, string) в случае ошибки (если raft-узел еще не инициализирован).

Пример:

picodata> pico.raft_status()
---
- term: 2
  leader_id: 1
  raft_state: Leader
  id: 1
...

pico.raft_term

Возвращает номера терма для указанной записи, либо текущий номер терма если запись не указана.

function raft_term([index])

Параметры:

  • index: (optional number), номер raft-записи

Возвращаемое значение:

(number) или
(nil, string) в случае ошибки.

pico.raft_wait_index

Ожидает применения (apply) на инстансе указанного raft-индекса. Функция возвращает текущий примененный индекс raft-журнала, который может быть равен или превышать указанный.

function raft_wait_index(target, timeout)

Параметры:

  • target: (number)
  • timeout: (number)

Возвращаемое значение:

(number) или
(nil, string) в случае ошибки.

Если за указанное время (timeout) функция не успеет получить индекс, она вернет сообщение об ошибке.

pico.sql

Выполняет кластерные (распределенные) SQL-запросы по следующей схеме:

  • каждый запрос обрабатывается и проверяется на корректность, после чего составляется распределенный план запроса для выполнения на текущем узле маршрутизации;
  • план запроса посылается на все узлы хранения в виде последовательных фрагментов по принципу "снизу вверх". Промежуточные результаты выполнения локальных запросов сохраняются в памяти узла-маршрутизатора.
function sql(query[, params], [traceable])

Параметры:

  • query (string)
  • params: (optional table), список параметров
  • traceable (optional boolean), признак явной трассировки запроса

Возвращаемое значение:

  • table DqlResult, при чтении данных;
  • table DmlResult, при модификации данных;
  • (nil, string) в случае ошибки.

Пример создания шардированной таблицы:

pico.sql([[
    create table "wonderland" (
        "property" text not null,
        "value" integer,
        primary key ("property")
    ) using memtx distributed by ("property")
    option (timeout = 3.0)
]])
---
- row_count: 1
...

Пример удаления шардированной таблицы:

pico.sql([[
    drop table "wonderland"
    option (timeout = 3.0)
]])
---
- row_count: 1
...

Пример параметризированной вставки в шардированную таблицу:

pico.sql([[
  insert into "wonderland" ("property", "value") values (?, ?)]],
  {"dragon", 13}
)
---
- row_count: 1
...

Пример чтения из шардированной таблицы:

pico.sql([[
  select * from "wonderland" where "property" = 'dragon'
  ]])
---
- metadata:
    - {'name': 'property', 'type': 'string'}
    - {'name': 'value', 'type': 'integer'}
  rows:
    - ['dragon', 13]
...

Пример создания пользователя:

pico.sql([[
  create user "alice"
  with password 't0tallysecret'
  using chap-sha1
  ]])

См. также:

pico.wait_ddl_finalize

Ожидает применения (финализации) DDL-операции для указанного raft-индекса. Возвращает raft-индекс финализированной записи.

function wait_ddl_finalize(index, opts)

Параметры:

  • index (number), raft-index
  • opts: (table), таблица:
    • timeout (number), в секундах (значение по умолчанию: 3 с.)

Возвращаемое значение:

(number) с номером raft-индекса или
(nil, string) в случае ошибки.

pico.wait_vclock

Ожидает момента, когда значение Vclock в Tarantool достигнет целевого.

function wait_vclock(target, timeout)

Параметры:

  • target: (table Vclock)
  • timeout: (number)

pico.whoami

function whoami()

Возвращает идентификаторы инстанса.

Возвращаемое значение:

  • (table):
    • raft_id: (number)
    • cluster_id: (string)
    • instance_id: (string)

Пример:

picodata> pico.whoami()
- raft_id: 1
  cluster_id: demo
  instance_id: i1

table CasBound

Lua-таблица, используемая для обозначения минимального (key_min) или максимального (key_max) значения в таблице table CasRange.

Поля:

  • kind (string), варианты: 'included' | 'excluded' | 'unbounded'
  • key (optional table), обязательно для вариантов included и excluded

table CasRange

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

Поля:

  • table (string)
  • key_min (table CasBound), см. выше
  • key_max (table CasBound)

Пример:

local unbounded = { kind = 'unbounded' }
local including_1 = { kind = 'included', key = {1,} }
local excluding_3 = { kind = 'excluded', key = {3,} }

local range_a = {
    table = 'WAREHOUSE',
    key_min = unbounded,
    key_max = unbounded,
}

-- [1, 3)
local range_a = {
    table = 'WAREHOUSE',
    key_min = including_1,
    key_max = excluding_3,
}

table DqlResult

Lua-таблица, содержащая данные чтения из шардированной таблицы.

Поля:

  • metadata (table), массив столбцов таблицы (таблицы) в формате {{name = string, type = string}, ...}.
  • rows (table), результат выполнения читающего запроса в формате {row, ...}.

table DmlResult

Lua-таблица, содержащая количество измененных строк при модификации шардированной таблицы.

Поля:

  • row_count (number), количество измененных строк.

table TableField

Lua-таблица, описывающая поле в составе таблицы (см. pico.create_table).

Поля:

  • name (string)
  • type (string)
  • is_nullable (boolean)

Пример:

{name = 'id', type = 'unsigned', is_nullable = false}
{name = 'value', type = 'unsigned', is_nullable = false}

См. также:

table Vclock

Lua-таблица, отражающая соответствие id инстанса его LSN-номеру.

Пример:

{[0] = 2, [1] = 101}
{[0] = 148, [1] = 9086, [3] = 2}

См. подробнее описание Vclock. Нулевое значение Vclock зарезервировано для отслеживания локальных изменений, которые не реплицируются.