From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
To: tarantool-patches@freelists.org
Cc: kostja@tarantool.org
Subject: [tarantool-patches] [PATCH 04/10] swim: introduce Lua interface
Date: Wed, 15 May 2019 22:36:41 +0300 [thread overview]
Message-ID: <521afc07e66b44f44cd8956d7599942a57f0864d.1557948687.git.v.shpilevoy@tarantool.org> (raw)
In-Reply-To: <cover.1557948686.git.v.shpilevoy@tarantool.org>
SWIM as a library can be useful not only for server internals,
but for users as well. This commit exposes Lua bindings to SWIM
C API. Here only basic bindings are introduced to create, delete,
quit, check a SWIM instance. With sanity tests.
Part of #3234
---
| 25 +++
src/CMakeLists.txt | 1 +
src/lua/init.c | 2 +
src/lua/swim.lua | 408 ++++++++++++++++++++++++++++++++++++++++
test/swim/box.lua | 24 +++
test/swim/suite.ini | 5 +
test/swim/swim.result | 201 ++++++++++++++++++++
test/swim/swim.test.lua | 68 +++++++
8 files changed, 734 insertions(+)
create mode 100644 src/lua/swim.lua
create mode 100644 test/swim/box.lua
create mode 100644 test/swim/suite.ini
create mode 100644 test/swim/swim.result
create mode 100644 test/swim/swim.test.lua
--git a/extra/exports b/extra/exports
index 5375a01e4..b0e20e11f 100644
--- a/extra/exports
+++ b/extra/exports
@@ -87,6 +87,31 @@ tnt_HMAC_CTX_free
lua_static_aligned_alloc
+swim_new
+swim_is_configured
+swim_cfg
+swim_set_payload
+swim_delete
+swim_add_member
+swim_remove_member
+swim_probe_member
+swim_broadcast
+swim_size
+swim_quit
+swim_self
+swim_member_by_uuid
+swim_member_status
+swim_iterator_open
+swim_iterator_next
+swim_iterator_close
+swim_member_uri
+swim_member_uuid
+swim_member_incarnation
+swim_member_payload
+swim_member_ref
+swim_member_unref
+swim_member_is_dropped
+
# Module API
_say
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 492b8712e..c2e0240ab 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -48,6 +48,7 @@ lua_source(lua_sources lua/table.lua)
lua_source(lua_sources ../third_party/luafun/fun.lua)
lua_source(lua_sources lua/httpc.lua)
lua_source(lua_sources lua/iconv.lua)
+lua_source(lua_sources lua/swim.lua)
# LuaJIT jit.* library
lua_source(lua_sources "${CMAKE_BINARY_DIR}/third_party/luajit/src/jit/bc.lua")
lua_source(lua_sources "${CMAKE_BINARY_DIR}/third_party/luajit/src/jit/bcsave.lua")
diff --git a/src/lua/init.c b/src/lua/init.c
index 303369841..5ddc5a4d8 100644
--- a/src/lua/init.c
+++ b/src/lua/init.c
@@ -115,6 +115,7 @@ extern char strict_lua[],
table_lua[],
trigger_lua[],
string_lua[],
+ swim_lua[],
p_lua[], /* LuaJIT 2.1 profiler */
zone_lua[] /* LuaJIT 2.1 profiler */;
@@ -149,6 +150,7 @@ static const char *lua_modules[] = {
"pwd", pwd_lua,
"http.client", httpc_lua,
"iconv", iconv_lua,
+ "swim", swim_lua,
/* jit.* library */
"jit.vmdef", vmdef_lua,
"jit.bc", bc_lua,
diff --git a/src/lua/swim.lua b/src/lua/swim.lua
new file mode 100644
index 000000000..bca98627c
--- /dev/null
+++ b/src/lua/swim.lua
@@ -0,0 +1,408 @@
+local ffi = require('ffi')
+local uuid = require('uuid')
+
+ffi.cdef[[
+ struct swim;
+ struct tt_uuid;
+ struct swim_iterator;
+ struct swim_member;
+
+ enum swim_gc_mode {
+ SWIM_GC_DEFAULT = -1,
+ SWIM_GC_OFF = 0,
+ SWIM_GC_ON = 1,
+ };
+
+ enum swim_member_status {
+ MEMBER_ALIVE = 0,
+ MEMBER_SUSPECTED,
+ MEMBER_DEAD,
+ MEMBER_LEFT,
+ };
+
+ struct swim *
+ swim_new(void);
+
+ bool
+ swim_is_configured(const struct swim *swim);
+
+ int
+ swim_cfg(struct swim *swim, const char *uri, double heartbeat_rate,
+ double ack_timeout, enum swim_gc_mode gc_mode,
+ const struct tt_uuid *uuid);
+
+ int
+ swim_set_payload(struct swim *swim, const char *payload, int payload_size);
+
+ void
+ swim_delete(struct swim *swim);
+
+ int
+ swim_add_member(struct swim *swim, const char *uri,
+ const struct tt_uuid *uuid);
+
+ int
+ swim_remove_member(struct swim *swim, const struct tt_uuid *uuid);
+
+ int
+ swim_probe_member(struct swim *swim, const char *uri);
+
+ int
+ swim_broadcast(struct swim *swim, int port);
+
+ int
+ swim_size(const struct swim *swim);
+
+ void
+ swim_quit(struct swim *swim);
+
+ struct swim_member *
+ swim_self(struct swim *swim);
+
+ struct swim_member *
+ swim_member_by_uuid(struct swim *swim, const struct tt_uuid *uuid);
+
+ enum swim_member_status
+ swim_member_status(const struct swim_member *member);
+
+ struct swim_iterator *
+ swim_iterator_open(struct swim *swim);
+
+ struct swim_member *
+ swim_iterator_next(struct swim_iterator *iterator);
+
+ void
+ swim_iterator_close(struct swim_iterator *iterator);
+
+ const char *
+ swim_member_uri(const struct swim_member *member);
+
+ const struct tt_uuid *
+ swim_member_uuid(const struct swim_member *member);
+
+ uint64_t
+ swim_member_incarnation(const struct swim_member *member);
+
+ const char *
+ swim_member_payload(const struct swim_member *member, int *size);
+
+ void
+ swim_member_ref(struct swim_member *member);
+
+ void
+ swim_member_unref(struct swim_member *member);
+
+ bool
+ swim_member_is_dropped(const struct swim_member *member);
+]]
+
+-- Shortcut to avoid unnecessary lookups in 'ffi' table.
+local capi = ffi.C
+
+local swim_t = ffi.typeof('struct swim *')
+
+--
+-- Check if @a value is something that can be passed as a
+-- URI parameter. Note, it does not validate URI, because it is
+-- done in C module. Here only dynamic typing errors are checked.
+-- Throws on invalid type.
+--
+-- @param value Value to check and probably convert.
+-- @param func_name Caller function name to include into an error
+-- message.
+-- @return String that can be passed as a URI parameter.
+--
+local function swim_check_uri(value, func_name)
+ if value == nil then
+ return nil
+ end
+ if type(value) == 'string' then
+ return value
+ end
+ if type(value) == 'number' then
+ return tostring(value)
+ end
+ return error(func_name..': expected string URI or port number')
+end
+
+--
+-- Check if @a value is a number, that can be passed as a timeout.
+-- Throws on invalid type.
+--
+-- @param value Value to check.
+-- @param func_name Caller function name to include into an error
+-- message.
+-- @param param_name Timeout parameter name to include into an
+-- error message. Examples: 'heartbeat_rate',
+-- 'ack_timeout'.
+-- @return Timeout value. Can be negative - SWIM treats negative
+-- value as an instruction to keep an old timeout.
+--
+local function swim_check_timeout(value, func_name, param_name)
+ if value == nil then
+ return -1
+ end
+ if type(value) ~= 'number' then
+ return error(func_name..': expected number '..param_name)
+ end
+ return value
+end
+
+--
+-- Check if @a value is a valid garbage collection mode.
+-- Throws on invalid type and unknown mode.
+--
+-- @param value Value to check and convert.
+-- @param func_name Caller function name to include into an error
+-- message.
+-- @return GC mode cdata enum value.
+--
+local function swim_check_gc_mode(value, func_name)
+ if value == nil then
+ return capi.SWIM_GC_DEFAULT
+ end
+ if value == 'on' then
+ return capi.SWIM_GC_ON
+ elseif value == 'off' then
+ return capi.SWIM_GC_OFF
+ else
+ return error(func_name..': unknown gc_mode')
+ end
+end
+
+--
+-- Check if @a value is a valid UUID. Throws on invalid type and
+-- UUID.
+--
+-- @param value Value to check.
+-- @param func_name Caller function name to include into an error
+-- message.
+-- @return Struct UUID cdata.
+--
+local function swim_check_uuid(value, func_name)
+ if value == nil then
+ return nil
+ end
+ if type(value) ~= 'string' then
+ return error(func_name..': expected string UUID')
+ end
+ value = uuid.fromstr(value)
+ if not value then
+ return error(func_name..': invalid UUID')
+ end
+ return value
+end
+
+--
+-- Check if @a s is a SWIM instance. It should be a table with
+-- cdata struct swim in 'ptr' attribute. Throws on invalid type.
+--
+-- @param value Value to check.
+-- @param func_name Caller function name to include into an error
+-- message.
+-- @return Pointer to struct swim.
+--
+local function swim_check_instance(s, func_name)
+ if type(s) == 'table' then
+ local ptr = s.ptr
+ if ffi.istype(swim_t, ptr) then
+ return ptr
+ end
+ end
+ return error(func_name..': first argument is not a SWIM instance')
+end
+
+--
+-- When a SWIM instance is deleted or has quited, it can't be used
+-- anymore. This function replaces all methods of a deleted
+-- instance to throw an error on a usage attempt.
+--
+local function swim_error_deleted()
+ return error('the swim instance is deleted')
+end
+-- This is done without 'if' in the original methods, but rather
+-- via metatable replacement after deletion has happened.
+local swim_mt_deleted = {
+ __index = swim_error_deleted
+}
+
+--
+-- Delete a SWIM instance immediately, do not notify cluster
+-- members about that.
+--
+local function swim_delete(s)
+ local ptr = swim_check_instance(s, 'swim:delete')
+ capi.swim_delete(ffi.gc(ptr, nil))
+ s.ptr = nil
+ setmetatable(s, swim_mt_deleted)
+end
+
+--
+-- Quit from a cluster gracefully, notify other members. The SWIM
+-- instance is considered deleted immediately after this function
+-- returned, and can't be used anymore.
+--
+local function swim_quit(s)
+ local ptr = swim_check_instance(s, 'swim:quit')
+ capi.swim_quit(ffi.gc(ptr, nil))
+ s.ptr = nil
+ setmetatable(s, swim_mt_deleted)
+end
+
+--
+-- Size of the local member table.
+--
+local function swim_size(s)
+ return capi.swim_size(swim_check_instance(s, 'swim:size'))
+end
+
+--
+-- Check if a SWIM instance is configured already. Not configured
+-- instance does not provide any methods.
+--
+local function swim_is_configured(s)
+ return capi.swim_is_configured(swim_check_instance(s, 'swim:is_configured'))
+end
+
+--
+-- Configuration options are printed when a SWIM instance is
+-- serialized, for example, in a console.
+--
+local function swim_serialize(s)
+ return s.cfg.index
+end
+
+--
+-- Normal metatable of a configured SWIM instance.
+--
+local swim_mt = {
+ __index = {
+ delete = swim_delete,
+ quit = swim_quit,
+ size = swim_size,
+ is_configured = swim_is_configured,
+ },
+ __serialize = swim_serialize
+}
+
+local swim_cfg_options = {
+ uri = true, heartbeat_rate = true, ack_timeout = true,
+ gc_mode = true, uuid = true
+}
+
+--
+-- SWIM 'cfg' attribute is not a trivial table nor function. It is
+-- a callable table. It allows to strongly restrict use cases of
+-- swim.cfg down to 2 applications:
+--
+-- - Cfg-table. 'swim.cfg' is a read-only table of configured
+-- parameters. A user can't write 'swim.cfg.<key> = value' - an
+-- error is thrown. But it can be indexed like
+-- 'opt = swim.cfg.<key>'. Configuration is cached in Lua, so
+-- the latter example won't even call SWIM C API functions.
+--
+-- - Cfg-function. 'swim:cfg(<new config>)' reconfigures a SWIM
+-- instance and returns normal values: nil+error or true. The
+-- new configuration is cached for further indexing.
+--
+-- All the other combinations are banned. The function below
+-- implements configuration call.
+--
+local function swim_cfg_call(c, s, cfg)
+ local func_name = 'swim:cfg'
+ local ptr = swim_check_instance(s, func_name)
+ if type(cfg) ~= 'table' then
+ return error(func_name..': expected table configuration')
+ end
+ for k in pairs(cfg) do
+ if not swim_cfg_options[k] then
+ return error(func_name..': unknown option '..k)
+ end
+ end
+ local uri = swim_check_uri(cfg.uri, func_name)
+ local heartbeat_rate = swim_check_timeout(cfg.heartbeat_rate,
+ func_name, 'heartbeat_rate')
+ local ack_timeout = swim_check_timeout(cfg.ack_timeout, func_name,
+ 'ack_timeout');
+ local gc_mode = swim_check_gc_mode(cfg.gc_mode, func_name)
+ local uuid = swim_check_uuid(cfg.uuid, func_name)
+ if capi.swim_cfg(ptr, uri, heartbeat_rate, ack_timeout,
+ gc_mode, uuid) ~= 0 then
+ return nil, box.error.last()
+ end
+ local index = c.index
+ for k, v in pairs(cfg) do
+ index[k] = v
+ end
+ return true
+end
+
+local swim_cfg_mt = {
+ __call = swim_cfg_call,
+ __index = function(c, k)
+ return c.index[k]
+ end,
+ __serialize = function(c)
+ return c.index
+ end,
+ __newindex = function()
+ return error('please, use swim:cfg{key = value} instead of '..
+ 'swim.cfg.key = value')
+ end
+}
+
+--
+-- First 'swim:cfg()' call is different from others. On success it
+-- replaces swim metatable with a full one, where all the variety
+-- of methods is available.
+--
+local function swim_cfg_first_call(c, s, cfg)
+ local ok, err = swim_cfg_call(c, s, cfg)
+ if not ok then
+ return ok, err
+ end
+ -- Update 'cfg' metatable as well to never call this
+ -- function again and use ordinary swim_cfg_call() directly.
+ setmetatable(c, swim_cfg_mt)
+ setmetatable(s, swim_mt)
+ return ok
+end
+
+local swim_not_configured_mt = {
+ __index = {
+ delete = swim_delete,
+ is_configured = swim_is_configured,
+ },
+ __serialize = swim_serialize
+}
+
+local swim_cfg_not_configured_mt = table.deepcopy(swim_cfg_mt)
+swim_cfg_not_configured_mt.__call = swim_cfg_first_call
+
+--
+-- Create a new SWIM instance, and configure if @a cfg is
+-- provided.
+--
+local function swim_new(cfg)
+ local ptr = capi.swim_new()
+ if ptr == nil then
+ return nil, box.error.last()
+ end
+ ffi.gc(ptr, capi.swim_delete)
+ local s = setmetatable({
+ ptr = ptr,
+ cfg = setmetatable({index = {}}, swim_cfg_not_configured_mt)
+ }, swim_not_configured_mt)
+ if cfg then
+ local ok, err = s:cfg(cfg)
+ if not ok then
+ s:delete()
+ return ok, err
+ end
+ end
+ return s
+end
+
+return {
+ new = swim_new,
+}
diff --git a/test/swim/box.lua b/test/swim/box.lua
new file mode 100644
index 000000000..b6a39575e
--- /dev/null
+++ b/test/swim/box.lua
@@ -0,0 +1,24 @@
+#!/usr/bin/env tarantool
+
+swim = require('swim')
+fiber = require('fiber')
+listen_uri = tostring(os.getenv("LISTEN"))
+listen_port = require('uri').parse(listen_uri).service
+
+box.cfg{}
+
+function uuid(i)
+ local min_valid_prefix = '00000000-0000-1000-8000-'
+ if i < 10 then
+ return min_valid_prefix..'00000000000'..tostring(i)
+ end
+ assert(i < 100)
+ return min_valid_prefix..'0000000000'..tostring(i)
+end
+
+function uri(port)
+ port = port or 0
+ return '127.0.0.1:'..tostring(port)
+end
+
+require('console').listen(os.getenv('ADMIN'))
diff --git a/test/swim/suite.ini b/test/swim/suite.ini
new file mode 100644
index 000000000..13189c1cf
--- /dev/null
+++ b/test/swim/suite.ini
@@ -0,0 +1,5 @@
+[default]
+core = tarantool
+description = SWIM tests
+script = box.lua
+is_parallel = True
diff --git a/test/swim/swim.result b/test/swim/swim.result
new file mode 100644
index 000000000..2e5025da6
--- /dev/null
+++ b/test/swim/swim.result
@@ -0,0 +1,201 @@
+test_run = require('test_run').new()
+---
+...
+test_run:cmd("push filter '\\.lua.*:[0-9]+: ' to '.lua:<line>: '")
+---
+- true
+...
+--
+-- gh-3234: SWIM gossip protocol.
+--
+-- Invalid cfg parameters.
+swim.new(1)
+---
+- error: 'builtin/swim.lua:<line>: swim:cfg: expected table configuration'
+...
+swim.new({uri = true})
+---
+- error: 'builtin/swim.lua:<line>: swim:cfg: expected string URI or port number'
+...
+swim.new({heartbeat_rate = 'rate'})
+---
+- error: 'builtin/swim.lua:<line>: swim:cfg: expected number heartbeat_rate'
+...
+swim.new({ack_timeout = 'timeout'})
+---
+- error: 'builtin/swim.lua:<line>: swim:cfg: expected number ack_timeout'
+...
+swim.new({gc_mode = 'not a mode'})
+---
+- error: 'builtin/swim.lua:<line>: swim:cfg: unknown gc_mode'
+...
+swim.new({gc_mode = 0})
+---
+- error: 'builtin/swim.lua:<line>: swim:cfg: unknown gc_mode'
+...
+swim.new({uuid = 123})
+---
+- error: 'builtin/swim.lua:<line>: swim:cfg: expected string UUID'
+...
+swim.new({uuid = '1234'})
+---
+- error: 'builtin/swim.lua:<line>: swim:cfg: invalid UUID'
+...
+-- Valid parameters, but invalid configuration.
+swim.new({})
+---
+- null
+- 'swim.cfg: UUID and URI are mandatory in a first config'
+...
+swim.new({uuid = uuid(1)})
+---
+- null
+- 'swim.cfg: UUID and URI are mandatory in a first config'
+...
+swim.new({uri = uri()})
+---
+- null
+- 'swim.cfg: UUID and URI are mandatory in a first config'
+...
+-- Check manual deletion.
+s = swim.new({uuid = uuid(1), uri = uri()})
+---
+...
+s:delete()
+---
+...
+s:cfg({})
+---
+- error: 'builtin/swim.lua:<line>: the swim instance is deleted'
+...
+s = nil
+---
+...
+_ = collectgarbage('collect')
+---
+...
+s = swim.new({uuid = uuid(1), uri = uri()})
+---
+...
+s:quit()
+---
+...
+s:is_configured()
+---
+- error: '[string "return s:is_configured() "]:1: the swim instance is deleted'
+...
+s = nil
+---
+...
+_ = collectgarbage('collect')
+---
+...
+s = swim.new({uuid = uuid(1), uri = uri()})
+---
+...
+s:is_configured()
+---
+- true
+...
+s:size()
+---
+- 1
+...
+s.cfg
+---
+- uuid: 00000000-0000-1000-8000-000000000001
+ uri: 127.0.0.1:0
+...
+s.cfg.gc_mode = 'off'
+---
+- error: '[string "s.cfg.gc_mode = ''off'' "]:1: please, use swim:cfg{key = value}
+ instead of swim.cfg.key = value'
+...
+s:cfg{gc_mode = 'off'}
+---
+- true
+...
+s.cfg
+---
+- gc_mode: off
+ uuid: 00000000-0000-1000-8000-000000000001
+ uri: 127.0.0.1:0
+...
+s.cfg.gc_mode
+---
+- off
+...
+s.cfg.uuid
+---
+- 00000000-0000-1000-8000-000000000001
+...
+s.cfg()
+---
+- error: 'builtin/swim.lua:<line>: swim:cfg: first argument is not a SWIM instance'
+...
+s:cfg({wrong_opt = 100})
+---
+- error: 'swim:cfg: unknown option wrong_opt'
+...
+s:delete()
+---
+...
+-- Reconfigure.
+s = swim.new()
+---
+...
+s:is_configured()
+---
+- false
+...
+-- Check that not configured instance does not provide most of
+-- methods.
+s.quit == nil
+---
+- true
+...
+s:cfg({uuid = uuid(1), uri = uri()})
+---
+- true
+...
+s.quit ~= nil
+---
+- true
+...
+s:is_configured()
+---
+- true
+...
+s:size()
+---
+- 1
+...
+s = nil
+---
+...
+_ = collectgarbage('collect')
+---
+...
+-- Invalid usage.
+s = swim.new()
+---
+...
+s.delete()
+---
+- error: 'builtin/swim.lua:<line>: swim:delete: first argument is not a SWIM instance'
+...
+s.is_configured()
+---
+- error: 'builtin/swim.lua:<line>: swim:is_configured: first argument is not a SWIM instance'
+...
+s.cfg()
+---
+- error: 'builtin/swim.lua:<line>: swim:cfg: first argument is not a SWIM instance'
+...
+s:delete()
+---
+...
+test_run:cmd("clear filter")
+---
+- true
+...
diff --git a/test/swim/swim.test.lua b/test/swim/swim.test.lua
new file mode 100644
index 000000000..719783133
--- /dev/null
+++ b/test/swim/swim.test.lua
@@ -0,0 +1,68 @@
+test_run = require('test_run').new()
+test_run:cmd("push filter '\\.lua.*:[0-9]+: ' to '.lua:<line>: '")
+--
+-- gh-3234: SWIM gossip protocol.
+--
+
+-- Invalid cfg parameters.
+swim.new(1)
+swim.new({uri = true})
+swim.new({heartbeat_rate = 'rate'})
+swim.new({ack_timeout = 'timeout'})
+swim.new({gc_mode = 'not a mode'})
+swim.new({gc_mode = 0})
+swim.new({uuid = 123})
+swim.new({uuid = '1234'})
+
+-- Valid parameters, but invalid configuration.
+swim.new({})
+swim.new({uuid = uuid(1)})
+swim.new({uri = uri()})
+
+-- Check manual deletion.
+s = swim.new({uuid = uuid(1), uri = uri()})
+s:delete()
+s:cfg({})
+s = nil
+_ = collectgarbage('collect')
+
+s = swim.new({uuid = uuid(1), uri = uri()})
+s:quit()
+s:is_configured()
+s = nil
+_ = collectgarbage('collect')
+
+s = swim.new({uuid = uuid(1), uri = uri()})
+s:is_configured()
+s:size()
+s.cfg
+s.cfg.gc_mode = 'off'
+s:cfg{gc_mode = 'off'}
+s.cfg
+s.cfg.gc_mode
+s.cfg.uuid
+s.cfg()
+s:cfg({wrong_opt = 100})
+s:delete()
+
+-- Reconfigure.
+s = swim.new()
+s:is_configured()
+-- Check that not configured instance does not provide most of
+-- methods.
+s.quit == nil
+s:cfg({uuid = uuid(1), uri = uri()})
+s.quit ~= nil
+s:is_configured()
+s:size()
+s = nil
+_ = collectgarbage('collect')
+
+-- Invalid usage.
+s = swim.new()
+s.delete()
+s.is_configured()
+s.cfg()
+s:delete()
+
+test_run:cmd("clear filter")
--
2.20.1 (Apple Git-117)
next prev parent reply other threads:[~2019-05-15 19:36 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-05-15 19:36 [tarantool-patches] [PATCH 00/10] swim Lua API Vladislav Shpilevoy
2019-05-15 19:36 ` [tarantool-patches] [PATCH 01/10] swim: fix an assertion on attempt to chage timeouts Vladislav Shpilevoy
2019-05-16 7:28 ` [tarantool-patches] " Konstantin Osipov
2019-05-15 19:36 ` [tarantool-patches] [PATCH 10/10] swim: cache members in Lua member table Vladislav Shpilevoy
2019-05-16 7:31 ` [tarantool-patches] " Konstantin Osipov
2019-05-15 19:36 ` [tarantool-patches] [PATCH 02/10] swim: make swim_new_round() void Vladislav Shpilevoy
2019-05-16 7:31 ` [tarantool-patches] " Konstantin Osipov
2019-05-15 19:36 ` [tarantool-patches] [PATCH 03/10] swim: validate URI in swim_probe_member() Vladislav Shpilevoy
2019-05-16 7:31 ` [tarantool-patches] " Konstantin Osipov
2019-05-15 19:36 ` Vladislav Shpilevoy [this message]
2019-05-15 19:36 ` [tarantool-patches] [PATCH 05/10] swim: Lua bindings to manipulate member table Vladislav Shpilevoy
2019-05-16 7:32 ` [tarantool-patches] " Konstantin Osipov
2019-05-15 19:36 ` [tarantool-patches] [PATCH 06/10] swim: Lua bindings to access individual members Vladislav Shpilevoy
2019-05-15 19:36 ` [tarantool-patches] [PATCH 07/10] swim: pairs() function to iterate over member table Vladislav Shpilevoy
2019-05-15 19:36 ` [tarantool-patches] [PATCH 08/10] swim: allow to use cdata struct tt_uuid in Lua API Vladislav Shpilevoy
2019-05-15 19:36 ` [tarantool-patches] [PATCH 09/10] swim: cache decoded payload in the Lua module Vladislav Shpilevoy
2019-05-16 7:36 ` [tarantool-patches] " Konstantin Osipov
2019-05-16 11:58 ` Vladislav Shpilevoy
2019-05-16 22:46 ` Vladislav Shpilevoy
2019-05-21 16:57 ` [tarantool-patches] Re: [PATCH 00/10] swim Lua API Vladislav Shpilevoy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=521afc07e66b44f44cd8956d7599942a57f0864d.1557948687.git.v.shpilevoy@tarantool.org \
--to=v.shpilevoy@tarantool.org \
--cc=kostja@tarantool.org \
--cc=tarantool-patches@freelists.org \
--subject='Re: [tarantool-patches] [PATCH 04/10] swim: introduce Lua interface' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox