Версия:

Модуль net.box

Модуль net.box

Общие сведения

The net.box module contains connectors to remote database systems. One variant, to be discussed later, is for connecting to MySQL or MariaDB or PostgreSQL (see SQL DBMS modules reference). The other variant, which is discussed in this section, is for connecting to Tarantool server instances via a network.

Можно вызвать следующие методы:

  • require('net.box') для получения объекта net.box (который называется net_box для примеров в данном разделе),
  • net_box.connect() для подключения и получения объекта подключения (который называется conn для примеров в данном разделе),
  • other net.box() routines, passing conn:, to execute requests on the remote database system,
  • conn:close для отключения.

All net.box methods are fiber-safe, that is, it is safe to share and use the same connection object across multiple concurrent fibers. In fact that is perhaps the best programming practice with Tarantool. When multiple fibers use the same connection, all requests are pipelined through the same network socket, but each fiber gets back a correct response. Reducing the number of active sockets lowers the overhead of system calls and increases the overall server performance. However for some cases a single connection is not enough —- for example, when it is necessary to prioritize requests or to use different authentication IDs.

В большинстве методов net.box можно использовать заключительный аргумент {options}, который может быть:

  • {timeout=...}. Например, метод с заключительным аргументом {timeout=1.5} остановится через 1,5 секунды на локальном узле, хотя это не гарантирует, что выполнение остановится на удаленном сервере.
  • {buffer=...}. Например, см. модуль buffer.
  • {is_async=...}. For example, a method whose final argument is {is_async=true} will not wait for the result of a request. See the is_async description.
  • {on_push=... on_push_ctx=...}. For receiving out-of-band messages. See the box.session.push description.

На диаграмме ниже представлены возможные состояния и варианты перехода из одного состояния в другое:

net_states.svg

На этой диаграмме:

  • Работа начинается с начального состояния „initial“.
  • Выполнение метода net_box.connect() переводит состояние в „connecting“, создается рабочий файбер.
  • Если требуются аутентификация и загрузка схемы, можно позднее повторно войти в состояние загрузки схемы „fetch_schema“ из активного „active“, если запрос не будет выполнен из-за ошибки несовпадения версий схемы, то есть будет вызвана перезагрузка схемы.
  • Метод conn.close() изменяет состояние на закрытое „closed“ и отключает рабочий процесс. Если транспорт уже находится в состоянии ошибки „error“, close() не делает ничего.

Индекс

Ниже приведен перечень всех функций модуля net.box.

Имя Использование
net_box.connect()
net_box.new()
Создание подключения
conn:ping() Выполнение команды проверки состояния PING
conn:wait_connected() Ожидание активности или закрытия подключения
conn:is_connected() Проверка активности или закрытия подключения
conn:wait_state() Ожидание нужного состояния
conn:close() Закрытие подключения
conn.space.space-name:select{field-value} Выбор одного или более кортежей
conn.space.space-name:get{field-value} Выбор кортежа
conn.space.space-name:insert{field-value} Вставка кортежа
conn.space.space-name:replace{field-value} Вставка или замена кортежа
conn.space.space-name:update{field-value} Обновление кортежа
conn.space.space-name:upsert{field-value} Обновление кортежа
conn.space.space-name:delete{field-value} Удаление кортежа
conn:call() Вызов хранимой процедуры
conn:eval() Оценка и выполнение выражения в строке
conn:timeout() Установка времени ожидания
net_box.connect(URI[, {option[s]}])
net_box.new(URI[, {option[s]}])

Примечание

The names connect() and new() are synonyms: connect() is preferred; new() is retained for backward compatibility.

Создание нового подключения. Подключение устанавливается по требованию во время первого запроса. Можно повторно установить подключение автоматически после отключения (см. ниже опцию reconnect_after). Возвращается объект conn, который поддерживает методы создание удаленных запросов, таких как select, update или delete.

Для локального Tarantool-сервера есть заданный объект всегда установленного подключения под названием net_box.self. Он создан с целью облегчить полиморфное использование API модуля net_box. Таким образом, conn = net_box.connect('localhost:3301') можно заменить на conn = net_box.self. Однако, есть важно отличие встроенного подключения от удаленного. При встроенном подключении запросы без изменения данных не передают управление. При использовании удаленного подключения любой запрос может передавать управление исходя из правил неявной передачи управления, и состояние базы данных может измениться к тому времени, как управление вернется.

Возможные опции

  • wait_connected: по умолчанию, создание подключения блокируется до тех пор, пока подключение не будет установлено, но передача wait_connected=false заставит метод сразу же вернуться. Передача времени ожидания заставит метод ждать до возвращения (например, wait_connected=1.5 заставит ожидать подключения максимум 1,5 секунды).

    Примечание

    Если присутствует reconnect_after, wait_connected проигнорирует неустойчивые отказы. Ожидание заканчивается, когда подключение установлено или явным образом закрыто.

  • reconnect_after: a net.box instance automatically reconnects any time the connection is broken or if a connection attempt fails. This makes transient network failures become transparent to the application. Reconnect happens automatically in the background, so queries/requests that suffered due to connectivity loss are transparently retried. The number of retries is unlimited, connection attempts are done over the specified timeout (e.g. reconnect_after=5 for 5 secs). Once a connection is explicitly closed, or once the Lua garbage collector removes it, reconnects stop.

  • call_16: [с 1.7.2] по умолчанию, подключения net.box соответствуют команде CALL нового бинарного протокола, который не поддерживает обратную совместимость с предыдущими версиями. Команда нового бинарного протокола для вызова CALL больше не ограничивает функцию в возврате массива кортежей и позволяет возвращать произвольный результат в формате MsgPack/JSON, включая scalar (скалярные значения), nil (нулевые значения) и void (пусто). Старый метод CALL оставлен нетронутым для обратной совместимости. В следующей основной версии он будет удален. Все драйверы для языков программирования будут постепенно переведены на использование нового метода CALL. Для подключения к экземпляру Tarantool’а, в котором используется старый метод CALL, укажите call_16=true.

  • console: в зависимости от значения параметра поддерживаются различные методы (как если бы возвращались экземпляры разных классов). Если console = true, можно использовать методы conn: close(), is_connected(), wait_state(), eval() (в этом случае поддерживаются и бинарный сетевой протокол, и протокол Lua-консоли). Если console = false (по умолчанию), также можно использовать методы conn для работы с базой данных (в этом случае поддерживается только бинарный протокол).

  • connect_timeout: количество секунд ожидания до возврата ошибки «error: Connection timed out».

Параметры:
  • URI (string) – URI объекта подключения
  • options – возможные опции: wait_connected, reconnect_after, call_16 и console
возвращается:

объект подключения

тип возвращаемого значения:
 

пользовательские данные

Примеры:

conn = net_box.connect('localhost:3301')
 conn = net_box.connect('127.0.0.1:3302', {wait_connected = false})
 conn = net_box.connect('127.0.0.1:3303', {reconnect_after = 5, call_16 = true})
object conn
conn:ping()

Выполнение команды проверки состояния PING.

возвращается:true (правда), если выполнено, false (ложь) в случае ошибки
тип возвращаемого значения:
 boolean (логический)

Пример:

net_box.self:ping()
conn:wait_connected([timeout])

Ожидание активности или закрытия подключения.

Параметры:
  • timeout (number) – в секундах
возвращается:

true (правда) при подключении, false (ложь), если не выполнено.

тип возвращаемого значения:
 

boolean (логический)

Пример:

net_box.self:wait_connected()
conn:is_connected()

Проверка активности или закрытия подключения.

возвращается:true (правда) при подключении, false (ложь), если не выполнено.
тип возвращаемого значения:
 boolean (логический)

Пример:

net_box.self:is_connected()
conn:wait_state(state[s][, timeout])

[с 1.7.2] Ожидание нужного состояния.

Параметры:
  • states (string) – необходимое состояние
  • timeout (number) – в секундах
возвращается:

true (правда) при подключении, false (ложь) при окончании времени ожидания или закрытии подключения

тип возвращаемого значения:
 

boolean (логический)

Примеры:

-- бесконечное ожидание состояния 'active':
 conn:wait_state('active')

 -- ожидание в течение максимум 1,5 секунд:
 conn:wait_state('active', 1.5)

 -- бесконечное ожидание состояния `active` или `fetch_schema`:
 conn:wait_state({active=true, fetch_schema=true})
conn:close()

Закрытие подключения.

Connection objects are destroyed by the Lua garbage collector, just like any other objects in Lua, so an explicit destruction is not mandatory. However, since close() is a system call, it is good programming practice to close a connection explicitly when it is no longer needed, to avoid lengthy stalls of the garbage collector.

Пример:

conn:close()
conn.space.<space-name>:select({field-value, ...} [, {options}])

conn.space.имя-спейса:select({...}) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:select{...}.

Пример:

conn.space.testspace:select({1,'B'}, {timeout=1})

Примечание

Исходя из правил неявной передачи управления, локальный запрос box.space.имя-спейса:select{...} не передает управление, а удаленный conn.space.имя-спейса:select{...} передаст, поэтому глобальные переменные или кортежи в базе данных могут измениться во время удаленного conn.space.имя-спейса:select{...}.

conn.space.<space-name>:get({field-value, ...} [, {options}])

conn.space.имя-спейса:get(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:get(...).

Пример:

conn.space.testspace:get({1})
conn.space.<space-name>:insert({field-value, ...} [, {options}])

conn.space.имя-спейса:insert(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:insert(...).

Пример:

conn.space.testspace:insert({2,3,4,5}, {timeout=1.1})
conn.space.<space-name>:replace({field-value, ...} [, {options}])

conn.space.имя-спейса:replace(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:replace(...).

Пример:

conn.space.testspace:replace({5,6,7,8})
conn.space.<space-name>:update({field-value, ...} [, {options}])

conn.space.имя-спейса:update(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:update(...).

Пример:

conn.space.Q:update({1},{{'=',2,5}}, {timeout=0})
conn.space.<space-name>:upsert({field-value, ...} [, {options}])

conn.space.имя-спейса:upsert(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:upsert(...).

conn.space.<space-name>:delete({field-value, ...} [, {options}])

conn.space.имя-спейса:delete(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:delete(...).

conn:call(function-name[, {arguments}[, {options}]])

conn:call('func', {'1', '2', '3'}) – это удаленный вызов, аналогичный func('1', '2', '3'). Таким образом, conn:call представляет собой удаленный вызов хранимой процедуры.

Ограничение: вызванная функция не может вернуть функцию, например, если func2 определяется как function func2 () return func end, то conn:call(func2) вернет ошибку «error: unsupported Lua type „function“».

Примеры:

conn:call('function5')
 conn:call('fx',{1,'B'},{timeout=99})
conn:eval(Lua-string[, {arguments}[, {options}]])

conn:eval(Lua-строка) оценивает и выполняет выражение в Lua-строке, которое может представлять собой любое выражение или несколько выражений. Требуются права на выполнение; если у пользователя таких прав нет, администратор может их выдать с помощью box.schema.user.grant(имя-пользователя, 'execute', 'universe').

Пример:

conn:eval('return 5+5')
 conn:eval('return ...', {1,2,3})
 conn:eval('return 5+5, {}, {timeout=0.1})
conn:timeout(timeout)

timeout(...) – это надстройка, которая определяет время ожидания для запроса. С версии 1.7.4 этот метод объявлен устаревшим – лучше передать значение времени ожидания с помощью параметра {options}.

Пример:

conn:timeout(0.5).space.tester:update({1}, {{'=', 2, 15}})

Хотя timeout(...) объявлен устаревшим, все удаленные вызовы поддерживают его. Использование надстройки обеспечивает совместимость API удаленного соединения с локальным, поэтому отпадает необходимость в отдельном аргументе timeout, который проигнорирует локальная версия. После отправки запроса его нельзя отменить с удаленного сервера даже по истечении времени задержки: окончание времени задержки прерывает только ожидание ответа от удаленного сервера, а не сам запрос.

conn:request(... {is_async=...})

{is_async=true|false} is an option which is applicable for all net_box requests including conn:call, conn:eval, and the conn.space.space-name requests.

The default is is_async=false, meaning requests are synchronous for the fiber. The fiber is blocked, waiting until there is a reply to the request or until timeout expires. Before Tarantool version 1.10, the only way to make asynchronous requests was to put them in separate fibers.

The non-default is is_async=true, meaning requests are asynchronous for the fiber. The request causes a yield but there is no waiting. The immediate return is not the result of the request, instead it is an object that the calling program can use later to get the result of the request.

This immediately-returned object, which we’ll call «future», has its own methods:

  • future:is_ready() which will return true when the result of the request is available,
  • future:result() to get the result of the request,
  • future:wait_result(timeout) to wait until the result of the request is available and then get it,
  • future:discard() to abandon the object.

Typically a user would say future=request-name(...{is_async=true}), then either loop checking future:is_ready() until it is true and then say request_result=future:result(), or say request_result=future:wait_result(...).

Пример:

tarantool> future = conn.space.tester:insert({900},{is_async=true})
---
...
tarantool> future
---
- method: insert
  response: [900]
  cond: cond
  on_push_ctx: []
  on_push: 'function: builtin#91'
...
tarantool> future:is_ready()
---
- true
...
tarantool> future:result()
---
- [900]
...

Typically {is_async=true} is used only if the load is large (more than 100,000 requests per second) and latency is large (more than 1 second), or when it is necessary to send multiple requests in parallel then collect responses (sometimes called a «map-reduce» scenario).

Примечание

Although the final result of an async request is the same as the result of a sync request, it is structured differently: as a table, instead of as the unpacked values.

Пример

Ниже приводится пример использования большинства методов net.box.

Данный пример сработает на конфигурации из песочницы, предполагается, что:

  • экземпляр Tarantool’а запущен на localhost 127.0.0.1:3301,
  • создан спейс под названием tester с первичным числовым ключом и кортежем, в котором есть ключ со значением= 800,
  • у текущего пользователя есть права на чтение, запись и выполнение.

Ниже приведены команды для быстрой настройки песочницы:

box.cfg{listen = 3301}
 s = box.schema.space.create('tester')
 s:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}})
 t = s:insert({800, 'TEST'})
 box.schema.user.grant('guest', 'read,write,execute', 'universe')

А здесь приведен пример:

tarantool> net_box = require('net.box')
 ---
 ...
 tarantool> function example()
          >   local conn, wtuple
          >   if net_box.self:ping() then
          >     table.insert(ta, 'self:ping() succeeded')
          >     table.insert(ta, '  (no surprise -- self connection is pre-established)')
          >   end
          >   if box.cfg.listen == '3301' then
          >     table.insert(ta,'The local server listen address = 3301')
          >   else
          >     table.insert(ta, 'The local server listen address is not 3301')
          >     table.insert(ta, '(  (maybe box.cfg{...listen="3301"...} was not stated)')
          >     table.insert(ta, '(  (so connect will fail)')
          >   end
          >   conn = net_box.connect('127.0.0.1:3301')
          >   conn.space.tester:delete({800})
          >   table.insert(ta, 'conn delete done on tester.')
          >   conn.space.tester:insert({800, 'data'})
          >   table.insert(ta, 'conn insert done on tester, index 0')
          >   table.insert(ta, '  primary key value = 800.')
          >   wtuple = conn.space.tester:select({800})
          >   table.insert(ta, 'conn select done on tester, index 0')
          >   table.insert(ta, '  number of fields = ' .. #wtuple)
          >   conn.space.tester:delete({800})
          >   table.insert(ta, 'conn delete done on tester')
          >   conn.space.tester:replace({800, 'New data', 'Extra data'})
          >   table.insert(ta, 'conn:replace done on tester')
          >   conn.space.tester:update({800}, {{'=', 2, 'Fld#1'}})
          >   table.insert(ta, 'conn update done on tester')
          >   conn:close()
          >   table.insert(ta, 'conn close done')
          > end
 ---
 ...
 tarantool> ta = {}
 ---
 ...
 tarantool> example()
 ---
 ...
 tarantool> ta
 ---
 - - self:ping() succeeded
   - '  (no surprise -- self connection is pre-established)'
   - The local server listen address = 3301
   - conn delete done on tester.
   - conn insert done on tester, index 0
   - '  primary key value = 800.'
   - conn select done on tester, index 0
   - '  number of fields = 1'
   - conn delete done on tester
   - conn:replace done on tester
   - conn update done on tester
   - conn close done
 ...