[Tarantool-patches] [PATCH 05/15] cord_buf: introduce cord_buf API

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Thu Mar 25 00:24:31 MSK 2021


There was a global ibuf object called tarantool_lua_ibuf. It was
used in all the places working with Lua which didn't have yields,
and where fiber's region could be potentially slower due to not
being able to guarantee the allocated memory is contiguous.

Yields during the ibuf usage were prohibited because another fiber
would take the same ibuf and override its previous content which
was still used by another fiber.

But it wasn't taken into account that there is Lua GC. It can be
invoked from any Lua function in Lua C code, and almost on any
line in the Lua scripts. During GC some deleted objects might have
GC handlers installed as __gc metamethods. From the handler they
could call Tarantool functions, including the ones using the
global ibuf.

Therefore ibuf could be overridden not only at yields, but almost
in any moment. Because with the Lua GC at hand, the multitasking
is not strictly "cooperative" anymore.

It is necessary to implement ownership for the global buffer. The
patch prepares the API for this: the buffer is moved to its own
file, and has methods take(), put(), and drop().

Take() is supposed to make the current fiber own the buffer. Put()
makes it available again. Drop() does the same but also clears the
buffer (frees its memory). The ownership itself is a subject for
the next patches. Here only the API is prepared.

The patch "hits" performance a little. Previously the get of
buffer.IBUF_SHARED cost around 1 ns. Now cord_ibuf_take() +
cord_ibuf_put() cost around 5 ns together. The next patches will
make it worse, up to 15 ns until #5871 is done.

Part of #5632

(cherry picked from commit ade45685f4fdab47204e11cbd82048bb68bbd03b)
---
 extra/exports              |  4 ++-
 src/CMakeLists.txt         |  1 +
 src/box/lua/schema.lua     | 47 ++++++++++++++++++++++++-----------
 src/box/lua/tuple.c        | 28 ++++++++++-----------
 src/box/lua/tuple.lua      | 14 +++++++----
 src/cord_buf.c             | 47 +++++++++++++++++++++++++++++++++++
 src/cord_buf.h             | 45 +++++++++++++++++++++++++++++++++
 src/lua/buffer.lua         | 51 ++++++++++++++++++++++++++++++++++++--
 src/lua/iconv.lua          |  8 +++---
 src/lua/init.c             |  3 ---
 src/lua/msgpack.c          |  6 ++---
 src/lua/msgpackffi.lua     |  7 +++---
 src/lua/socket.lua         | 14 +++++------
 src/lua/utf8.c             | 16 +++++++-----
 src/lua/utils.h            |  1 -
 test/unit/luaT_tuple_new.c |  4 ---
 16 files changed, 229 insertions(+), 67 deletions(-)
 create mode 100644 src/cord_buf.c
 create mode 100644 src/cord_buf.h

diff --git a/extra/exports b/extra/exports
index 94e04264e..91094206d 100644
--- a/extra/exports
+++ b/extra/exports
@@ -44,7 +44,6 @@ tnt_iconv
 exception_get_string
 exception_get_int
 
-tarantool_lua_ibuf
 uuid_nil
 tt_uuid_create
 tt_uuid_str
@@ -111,6 +110,9 @@ fiber_cond_signal
 fiber_cond_broadcast
 fiber_cond_wait_timeout
 fiber_cond_wait
+cord_ibuf_drop
+cord_ibuf_put
+cord_ibuf_take
 cord_slab_cache
 coio_wait
 coio_close
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d14997413..1e840aab9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -107,6 +107,7 @@ set (core_sources
      http_parser.c
      coll.c
      coll_def.c
+     cord_buf.c
  )
 
 if (TARGET_OS_NETBSD)
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index a23fe0813..513dab1be 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -1,6 +1,7 @@
 -- schema.lua (internal file)
 --
 local ffi = require('ffi')
+local buffer = require('buffer')
 local msgpack = require('msgpack')
 local msgpackffi = require('msgpackffi')
 local fun = require('fun')
@@ -20,6 +21,8 @@ local tuple_encode = box.tuple.encode
 local tuple_bless = box.tuple.bless
 local is_tuple = box.tuple.is
 assert(tuple_encode ~= nil and tuple_bless ~= nil and is_tuple ~= nil)
+local cord_ibuf_take = buffer.internal.cord_ibuf_take
+local cord_ibuf_put = buffer.internal.cord_ibuf_put
 
 local INT64_MIN = tonumber64('-9223372036854775808')
 local INT64_MAX = tonumber64('9223372036854775807')
@@ -1145,9 +1148,12 @@ base_index_mt.__len = base_index_mt.len
 -- min and max
 base_index_mt.min_ffi = function(index, key)
     check_index_arg(index, 'min')
-    local pkey, pkey_end = tuple_encode(key)
-    if builtin.box_index_min(index.space_id, index.id,
-                             pkey, pkey_end, ptuple) ~= 0 then
+    local ibuf = cord_ibuf_take()
+    local pkey, pkey_end = tuple_encode(ibuf, key)
+    local nok = builtin.box_index_min(index.space_id, index.id, pkey, pkey_end,
+                                      ptuple) ~= 0
+    cord_ibuf_put(ibuf)
+    if nok then
         box.error() -- error
     elseif ptuple[0] ~= nil then
         return tuple_bless(ptuple[0])
@@ -1162,9 +1168,12 @@ base_index_mt.min_luac = function(index, key)
 end
 base_index_mt.max_ffi = function(index, key)
     check_index_arg(index, 'max')
-    local pkey, pkey_end = tuple_encode(key)
-    if builtin.box_index_max(index.space_id, index.id,
-                             pkey, pkey_end, ptuple) ~= 0 then
+    local ibuf = cord_ibuf_take()
+    local pkey, pkey_end = tuple_encode(ibuf, key)
+    local nok = builtin.box_index_max(index.space_id, index.id, pkey, pkey_end,
+                                      ptuple) ~= 0
+    cord_ibuf_put(ibuf)
+    if nok then
         box.error() -- error
     elseif ptuple[0] ~= nil then
         return tuple_bless(ptuple[0])
@@ -1197,10 +1206,12 @@ end
 -- iteration
 base_index_mt.pairs_ffi = function(index, key, opts)
     check_index_arg(index, 'pairs')
-    local pkey, pkey_end = tuple_encode(key)
+    local ibuf = cord_ibuf_take()
+    local pkey, pkey_end = tuple_encode(ibuf, key)
     local itype = check_iterator_type(opts, pkey + 1 >= pkey_end);
 
     local keybuf = ffi.string(pkey, pkey_end - pkey)
+    cord_ibuf_put(ibuf)
     local pkeybuf = ffi.cast('const char *', keybuf)
     local cdata = builtin.box_index_iterator(index.space_id, index.id,
         itype, pkeybuf, pkeybuf + #keybuf);
@@ -1224,10 +1235,12 @@ end
 -- index subtree size
 base_index_mt.count_ffi = function(index, key, opts)
     check_index_arg(index, 'count')
-    local pkey, pkey_end = tuple_encode(key)
+    local ibuf = cord_ibuf_take()
+    local pkey, pkey_end = tuple_encode(ibuf, key)
     local itype = check_iterator_type(opts, pkey + 1 >= pkey_end);
     local count = builtin.box_index_count(index.space_id, index.id,
         itype, pkey, pkey_end);
+    cord_ibuf_put(ibuf)
     if count == -1 then
         box.error()
     end
@@ -1242,9 +1255,12 @@ end
 
 base_index_mt.get_ffi = function(index, key)
     check_index_arg(index, 'get')
-    local key, key_end = tuple_encode(key)
-    if builtin.box_index_get(index.space_id, index.id,
-                             key, key_end, ptuple) ~= 0 then
+    local ibuf = cord_ibuf_take()
+    local key, key_end = tuple_encode(ibuf, key)
+    local nok = builtin.box_index_get(index.space_id, index.id, key, key_end,
+                                      ptuple) ~= 0
+    cord_ibuf_put(ibuf)
+    if nok then
         return box.error() -- error
     elseif ptuple[0] ~= nil then
         return tuple_bless(ptuple[0])
@@ -1275,13 +1291,16 @@ end
 
 base_index_mt.select_ffi = function(index, key, opts)
     check_index_arg(index, 'select')
-    local key, key_end = tuple_encode(key)
+    local ibuf = cord_ibuf_take()
+    local key, key_end = tuple_encode(ibuf, key)
     local iterator, offset, limit = check_select_opts(opts, key + 1 >= key_end)
 
     local port = ffi.cast('struct port *', port_tuple)
 
-    if builtin.box_select(index.space_id, index.id,
-        iterator, offset, limit, key, key_end, port) ~= 0 then
+    local nok = builtin.box_select(index.space_id, index.id, iterator, offset,
+                                   limit, key, key_end, port) ~= 0
+    cord_ibuf_put(ibuf)
+    if nok then
         return box.error()
     end
 
diff --git a/src/box/lua/tuple.c b/src/box/lua/tuple.c
index 00ac3b44c..ad056a3bc 100644
--- a/src/box/lua/tuple.c
+++ b/src/box/lua/tuple.c
@@ -36,6 +36,7 @@
 #include "diag.h" /* diag_set() */
 #include <small/ibuf.h>
 #include <small/region.h>
+#include "cord_buf.h"
 #include <fiber.h>
 
 #include "box/tuple.h"
@@ -279,16 +280,18 @@ luaT_tuple_encode(struct lua_State *L, int idx, size_t *tuple_len_ptr)
 box_tuple_t *
 luaT_tuple_new(struct lua_State *L, int idx, box_tuple_format_t *format)
 {
-	struct ibuf *ibuf = tarantool_lua_ibuf;
-	ibuf_reset(ibuf);
+	struct ibuf *ibuf = cord_ibuf_take();
 	size_t tuple_len;
+	box_tuple_t *tuple;
 	char *tuple_data = luaT_tuple_encode_on_lua_ibuf(L, idx, &tuple_len,
 							 ibuf);
-	if (tuple_data == NULL)
-		return NULL;
-	box_tuple_t *tuple = box_tuple_new(format, tuple_data,
-					   tuple_data + tuple_len);
-	ibuf_reinit(ibuf);
+	if (tuple_data == NULL) {
+		tuple = NULL;
+	} else {
+		tuple = box_tuple_new(format, tuple_data,
+				      tuple_data + tuple_len);
+	}
+	cord_ibuf_drop(ibuf);
 	return tuple;
 }
 
@@ -307,12 +310,11 @@ lbox_tuple_new(lua_State *L)
 	 */
 	box_tuple_format_t *fmt = box_tuple_format_default();
 	if (argc != 1 || (!lua_istable(L, 1) && !luaT_istuple(L, 1))) {
-		struct ibuf *buf = tarantool_lua_ibuf;
-		ibuf_reset(buf);
+		struct ibuf *buf = cord_ibuf_take();
 		luaT_tuple_encode_values(L, buf); /* may raise */
 		struct tuple *tuple = box_tuple_new(fmt, buf->buf,
 						    buf->buf + ibuf_used(buf));
-		ibuf_reinit(buf);
+		cord_ibuf_drop(buf);
 		if (tuple == NULL)
 			return luaT_error(L);
 		luaT_pushtuple(L, tuple);
@@ -586,8 +588,7 @@ lbox_tuple_transform(struct lua_State *L)
 		return 1;
 	}
 
-	struct ibuf *buf = tarantool_lua_ibuf;
-	ibuf_reset(buf);
+	struct ibuf *buf = cord_ibuf_take();
 	struct mpstream stream;
 	mpstream_init(&stream, buf, ibuf_reserve_cb, ibuf_alloc_cb,
 		      luamp_error, L);
@@ -632,12 +633,11 @@ lbox_tuple_transform(struct lua_State *L)
 		new_tuple = tuple_new(box_tuple_format_default(),
 				      new_data, new_data + new_size);
 	region_truncate(region, used);
-
+	cord_ibuf_put(buf);
 	if (new_tuple == NULL)
 		luaT_error(L);
 
 	luaT_pushtuple(L, new_tuple);
-	ibuf_reset(buf);
 	return 1;
 }
 
diff --git a/src/box/lua/tuple.lua b/src/box/lua/tuple.lua
index 63ea73e43..186216420 100644
--- a/src/box/lua/tuple.lua
+++ b/src/box/lua/tuple.lua
@@ -6,6 +6,8 @@ local msgpackffi = require('msgpackffi')
 local fun = require('fun')
 local buffer = require('buffer')
 local internal = require('box.internal')
+local cord_ibuf_take = buffer.internal.cord_ibuf_take
+local cord_ibuf_put = buffer.internal.cord_ibuf_put
 
 ffi.cdef[[
 /** \cond public */
@@ -72,9 +74,7 @@ local encode_fix = msgpackffi.internal.encode_fix
 local encode_array = msgpackffi.internal.encode_array
 local encode_r = msgpackffi.internal.encode_r
 
-local tuple_encode = function(obj)
-    local tmpbuf = buffer.IBUF_SHARED
-    tmpbuf:reset()
+local tuple_encode = function(tmpbuf, obj)
     if obj == nil then
         encode_fix(tmpbuf, 0x90, 0)  -- empty array
     elseif is_tuple(obj) then
@@ -231,8 +231,10 @@ local function tuple_update(tuple, expr)
     if type(expr) ~= 'table' then
         error("Usage: tuple:update({ { op, field, arg}+ })")
     end
-    local pexpr, pexpr_end = tuple_encode(expr)
+    local ibuf = cord_ibuf_take()
+    local pexpr, pexpr_end = tuple_encode(ibuf, expr)
     local tuple = builtin.box_tuple_update(tuple, pexpr, pexpr_end)
+    cord_ibuf_put(ibuf)
     if tuple == nil then
         return box.error()
     end
@@ -244,8 +246,10 @@ local function tuple_upsert(tuple, expr)
     if type(expr) ~= 'table' then
         error("Usage: tuple:upsert({ { op, field, arg}+ })")
     end
-    local pexpr, pexpr_end = tuple_encode(expr)
+    local ibuf = cord_ibuf_take()
+    local pexpr, pexpr_end = tuple_encode(ibuf, expr)
     local tuple = builtin.box_tuple_upsert(tuple, pexpr, pexpr_end)
+    cord_ibuf_put(ibuf)
     if tuple == nil then
         return box.error()
     end
diff --git a/src/cord_buf.c b/src/cord_buf.c
new file mode 100644
index 000000000..cac508c3d
--- /dev/null
+++ b/src/cord_buf.c
@@ -0,0 +1,47 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2010-2021, Tarantool AUTHORS, please see AUTHORS file.
+ */
+#include "cord_buf.h"
+#include "fiber.h"
+
+#include "small/ibuf.h"
+
+enum {
+	/* No any reason why that value. Historical constant. */
+	CORD_IBUF_START_CAPACITY = 16384,
+};
+
+static struct ibuf *cord_buf_global = NULL;
+
+struct ibuf *
+cord_ibuf_take(void)
+{
+	assert(cord_is_main());
+	struct ibuf *buf = cord_buf_global;
+	if (buf != NULL) {
+		ibuf_reset(buf);
+		return buf;
+	}
+	buf = malloc(sizeof(*buf));
+	if (buf == NULL)
+		panic("Couldn't allocate thread buffer");
+	ibuf_create(buf, &cord()->slabc, CORD_IBUF_START_CAPACITY);
+	cord_buf_global = buf;
+	return buf;
+}
+
+void
+cord_ibuf_put(struct ibuf *ibuf)
+{
+	(void)ibuf;
+	assert(ibuf == cord_buf_global);
+}
+
+void
+cord_ibuf_drop(struct ibuf *ibuf)
+{
+	ibuf_reinit(ibuf);
+	assert(ibuf == cord_buf_global);
+}
diff --git a/src/cord_buf.h b/src/cord_buf.h
new file mode 100644
index 000000000..59f429c8f
--- /dev/null
+++ b/src/cord_buf.h
@@ -0,0 +1,45 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2010-2021, Tarantool AUTHORS, please see AUTHORS file.
+ */
+#pragma once
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* defined(__cplusplus) */
+
+struct ibuf;
+
+/**
+ * Take the global ibuf, or allocate a new one if the stash is empty.
+ */
+struct ibuf *
+cord_ibuf_take(void);
+
+/**
+ * Put the global ibuf back.
+ */
+void
+cord_ibuf_put(struct ibuf *ibuf);
+
+/**
+ * Put the global ibuf back and free its memory. So only the buffer object
+ * itself is saved to the stash. Main reason why it is a dedicated function is
+ * because it is often needed from Lua, and allows not to call :recycle() there,
+ * which would be an additional FFI call before cord_ibuf_put().
+ *
+ * XXX: recycle of the global buffer is a workaround for the ibuf being used in
+ * some places working with Lua API, where it wasn't wanted to "reuse" it
+ * anyhow. Instead, the global buffer is used to protect from the buffer leak in
+ * case it would be created locally, and then a Lua error would be raised. When
+ * the buffer is global, it is not a problem, because it is reused/recycled
+ * later. But it hurts the places, where re-usage could be good. Probably it is
+ * worth to separate take/put() from new/drop() API. Or delete drop() entirely.
+ */
+void
+cord_ibuf_drop(struct ibuf *ibuf);
+
+#if defined(__cplusplus)
+}
+#endif /* defined(__cplusplus) */
diff --git a/src/lua/buffer.lua b/src/lua/buffer.lua
index a72d8d1f9..398319cf2 100644
--- a/src/lua/buffer.lua
+++ b/src/lua/buffer.lua
@@ -7,7 +7,15 @@ ffi.cdef[[
 struct slab_cache;
 struct slab_cache *
 tarantool_lua_slab_cache();
-extern struct ibuf *tarantool_lua_ibuf;
+
+struct ibuf *
+cord_ibuf_take(void);
+
+void
+cord_ibuf_put(struct ibuf *ibuf);
+
+void
+cord_ibuf_drop(struct ibuf *ibuf);
 
 struct ibuf
 {
@@ -174,8 +182,47 @@ local function ibuf_new(arg, arg2)
     errorf('Usage: ibuf([size])')
 end
 
+--
+-- Cord buffer is useful for the places, where
+--
+-- * Want to reuse the already allocated memory which might be stored in the
+--   cord buf. Although sometimes the buffer is recycled, so should not rely on
+--   being able to reuse it always. When reused, the win is the biggest -
+--   becomes about x20 times faster than a new buffer creation (~5ns vs ~100ns);
+--
+-- * Want to avoid allocation of a new ibuf because it produces a new GC object
+--   which is additional load for Lua GC. Although according to benches it is
+--   not super expensive;
+--
+-- * Almost always can put the buffer back manually. Not rely on it being
+--   recycled automatically. It is recycled, but still should not rely on that;
+--
+-- It is important to wrap the C functions, not expose them directly. Because
+-- JIT works a bit better when C functions are called as 'ffi.C.func()' than
+-- 'func()' with func being cached. The only pros is to cache 'ffi.C' itself.
+-- It is quite strange though how having them wrapped into a Lua function is
+-- faster than cached directly as C functions.
+--
+local function cord_ibuf_take()
+    return builtin.cord_ibuf_take()
+end
+
+local function cord_ibuf_put(buf)
+    return builtin.cord_ibuf_put(buf)
+end
+
+local function cord_ibuf_drop(buf)
+    return builtin.cord_ibuf_drop(buf)
+end
+
+local internal = {
+    cord_ibuf_take = cord_ibuf_take,
+    cord_ibuf_put = cord_ibuf_put,
+    cord_ibuf_drop = cord_ibuf_drop,
+}
+
 return {
+    internal = internal,
     ibuf = ibuf_new;
-    IBUF_SHARED = ffi.C.tarantool_lua_ibuf;
     READAHEAD = READAHEAD;
 }
diff --git a/src/lua/iconv.lua b/src/lua/iconv.lua
index e68509dec..732b80514 100644
--- a/src/lua/iconv.lua
+++ b/src/lua/iconv.lua
@@ -1,6 +1,8 @@
 local ffi    = require('ffi')
 local errno  = require('errno')
 local buffer = require('buffer')
+local cord_ibuf_take = buffer.internal.cord_ibuf_take
+local cord_ibuf_put = buffer.internal.cord_ibuf_put
 
 ffi.cdef[[
 typedef struct iconv *iconv_t;
@@ -33,10 +35,9 @@ local function iconv_convert(iconv, data)
 
     -- prepare at lease BUF_SIZE and at most data_len bytes in shared buffer
     local output_len = data_len >= BUF_SIZE and data_len or BUF_SIZE
-    local buf      = buffer.IBUF_SHARED;
+    local buf      = cord_ibuf_take();
     local buf_ptr  = char_ptr_arr_t()
     local buf_left = size_t_arr_t()
-    buf:reset()
 
     while data_left[0] > 0 do
         buf_ptr[0]  = buf:reserve(output_len)
@@ -46,6 +47,7 @@ local function iconv_convert(iconv, data)
         if res == ffi.cast('size_t', -1) then
             local err = errno()
             if err ~= E2BIG then
+                cord_ibuf_put(buf)
                 ffi.C.tnt_iconv(iconv, nil, nil, nil, nil)
                 if err == EINVAL then
                     error('Invalid multibyte sequence')
@@ -62,7 +64,7 @@ local function iconv_convert(iconv, data)
     -- iconv function sets cd's conversion state to the initial state
     ffi.C.tnt_iconv(iconv, nil, nil, nil, nil)
     local result = ffi.string(buf.rpos, buf:size())
-    buf:reset()
+    cord_ibuf_put(buf)
     return result
 end
 
diff --git a/src/lua/init.c b/src/lua/init.c
index d11ab8bf3..3809f6068 100644
--- a/src/lua/init.c
+++ b/src/lua/init.c
@@ -70,8 +70,6 @@
  * The single Lua state of the transaction processor (tx) thread.
  */
 struct lua_State *tarantool_L;
-static struct ibuf tarantool_lua_ibuf_body;
-struct ibuf *tarantool_lua_ibuf = &tarantool_lua_ibuf_body;
 /**
  * The fiber running the startup Lua script
  */
@@ -429,7 +427,6 @@ tarantool_lua_init(const char *tarantool_bin, int argc, char **argv)
 	if (L == NULL) {
 		panic("failed to initialize Lua");
 	}
-	ibuf_create(tarantool_lua_ibuf, tarantool_lua_slab_cache(), 16000);
 	luaL_openlibs(L);
 	tarantool_lua_setpaths(L);
 
diff --git a/src/lua/msgpack.c b/src/lua/msgpack.c
index 838f582ff..ea63570bd 100644
--- a/src/lua/msgpack.c
+++ b/src/lua/msgpack.c
@@ -41,6 +41,7 @@
 #include <small/region.h>
 #include <small/ibuf.h>
 
+#include "cord_buf.h"
 #include <fiber.h>
 
 void
@@ -448,8 +449,7 @@ lua_msgpack_encode(lua_State *L)
 					  "must be of type 'struct ibuf'");
 		}
 	} else {
-		buf = tarantool_lua_ibuf;
-		ibuf_reset(buf);
+		buf = cord_ibuf_take();
 	}
 	size_t used = ibuf_used(buf);
 
@@ -466,7 +466,7 @@ lua_msgpack_encode(lua_State *L)
 		lua_pushinteger(L, ibuf_used(buf) - used);
 	} else {
 		lua_pushlstring(L, buf->buf, ibuf_used(buf));
-		ibuf_reinit(buf);
+		cord_ibuf_drop(buf);
 	}
 	return 1;
 }
diff --git a/src/lua/msgpackffi.lua b/src/lua/msgpackffi.lua
index abcbd54fa..ad7998ed1 100644
--- a/src/lua/msgpackffi.lua
+++ b/src/lua/msgpackffi.lua
@@ -10,6 +10,8 @@ local uint16_ptr_t = ffi.typeof('uint16_t *')
 local uint32_ptr_t = ffi.typeof('uint32_t *')
 local uint64_ptr_t = ffi.typeof('uint64_t *')
 local char_ptr_t = ffi.typeof('char *')
+local cord_ibuf_take = buffer.internal.cord_ibuf_take
+local cord_ibuf_drop = buffer.internal.cord_ibuf_drop
 
 ffi.cdef([[
 char *
@@ -280,11 +282,10 @@ local function encode_r(buf, obj, level)
 end
 
 local function encode(obj)
-    local tmpbuf = buffer.IBUF_SHARED
-    tmpbuf:reset()
+    local tmpbuf = cord_ibuf_take()
     encode_r(tmpbuf, obj, 0)
     local r = ffi.string(tmpbuf.rpos, tmpbuf:size())
-    tmpbuf:recycle()
+    cord_ibuf_drop(tmpbuf)
     return r
 end
 
diff --git a/src/lua/socket.lua b/src/lua/socket.lua
index 7c2b1ac6b..f68270876 100644
--- a/src/lua/socket.lua
+++ b/src/lua/socket.lua
@@ -10,6 +10,8 @@ local fiber = require('fiber')
 local fio = require('fio')
 local log = require('log')
 local buffer = require('buffer')
+local cord_ibuf_take = buffer.internal.cord_ibuf_take
+local cord_ibuf_drop = buffer.internal.cord_ibuf_drop
 
 local format = string.format
 
@@ -293,19 +295,15 @@ local function socket_sysread(self, arg1, arg2)
         error('socket:sysread(): size can not be negative')
     end
 
-    local buf = buffer.IBUF_SHARED
-    buf:reset()
+    local buf = cord_ibuf_take()
     local p = buf:alloc(size)
 
     local res = sysread(self, p, size)
     if res then
-        local str = ffi.string(p, res)
-        buf:recycle()
-        return str
-    else
-        buf:recycle()
-        return res
+        res = ffi.string(p, res)
     end
+    cord_ibuf_drop(buf)
+    return res
 end
 
 local function socket_nonblock(self, nb)
diff --git a/src/lua/utf8.c b/src/lua/utf8.c
index 6d3e4d39a..0d9c49a8b 100644
--- a/src/lua/utf8.c
+++ b/src/lua/utf8.c
@@ -33,11 +33,10 @@
 #include <coll.h>
 #include "lua/utils.h"
 #include "lua/utf8.h"
+#include "cord_buf.h"
 #include "diag.h"
 #include "small/ibuf.h"
 
-extern struct ibuf *tarantool_lua_ibuf;
-
 /** Default universal casemap for case transformations. */
 static UCaseMap *root_map = NULL;
 
@@ -54,12 +53,13 @@ utf8_str_to_case(struct lua_State *L, const char *src, int src_bsize,
 	int i = 0;
 	int dst_bsize = src_bsize;
 	(void) i;
+	struct ibuf *ibuf = cord_ibuf_take();
 	do {
 		UErrorCode err = U_ZERO_ERROR;
-		ibuf_reset(tarantool_lua_ibuf);
-		char *dst = ibuf_alloc(tarantool_lua_ibuf, dst_bsize);
+		char *dst = ibuf_alloc(ibuf, dst_bsize);
 		if (dst == NULL) {
 			diag_set(OutOfMemory, dst_bsize, "ibuf_alloc", "dst");
+			cord_ibuf_put(ibuf);
 			return luaT_error(L);
 		}
 		int real_bsize;
@@ -75,11 +75,13 @@ utf8_str_to_case(struct lua_State *L, const char *src, int src_bsize,
 		if (err == U_ZERO_ERROR ||
 		    err == U_STRING_NOT_TERMINATED_WARNING) {
 			lua_pushlstring(L, dst, real_bsize);
+			cord_ibuf_put(ibuf);
 			return 1;
 		} else if (err == U_BUFFER_OVERFLOW_ERROR) {
 			assert(real_bsize > dst_bsize);
 			dst_bsize = real_bsize;
 		} else {
+			cord_ibuf_put(ibuf);
 			lua_pushnil(L);
 			lua_pushstring(L, tt_sprintf("error during ICU case "\
 						     "transform: %s",
@@ -251,9 +253,10 @@ utf8_char(struct lua_State *L)
 		return 1;
 	}
 	/* Slow way - use dynamic buffer. */
-	ibuf_reset(tarantool_lua_ibuf);
-	char *str = ibuf_alloc(tarantool_lua_ibuf, top * U8_MAX_LENGTH);
+	struct ibuf *ibuf = cord_ibuf_take();
+	char *str = ibuf_alloc(ibuf, top * U8_MAX_LENGTH);
 	if (str == NULL) {
+		cord_ibuf_put(ibuf);
 		diag_set(OutOfMemory, top * U8_MAX_LENGTH, "ibuf_alloc",
 			 "str");
 		return luaT_error(L);
@@ -263,6 +266,7 @@ utf8_char(struct lua_State *L)
 		U8_APPEND_UNSAFE(str, len, c);
 	}
 	lua_pushlstring(L, str, len);
+	cord_ibuf_put(ibuf);
 	return 1;
 }
 
diff --git a/src/lua/utils.h b/src/lua/utils.h
index cc2e4211f..a61212102 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -66,7 +66,6 @@ typedef struct ibuf box_ibuf_t;
  * snprintf(m_errmsg, sizeof(m_errmsg), "%s", msg ? msg : "");
  */
 extern struct lua_State *tarantool_L;
-extern struct ibuf *tarantool_lua_ibuf;
 
 /** \cond public */
 
diff --git a/test/unit/luaT_tuple_new.c b/test/unit/luaT_tuple_new.c
index dcf16ef02..60bc522dc 100644
--- a/test/unit/luaT_tuple_new.c
+++ b/test/unit/luaT_tuple_new.c
@@ -25,8 +25,6 @@
  * box/tuple.test.lua.
  */
 
-extern struct ibuf *tarantool_lua_ibuf;
-
 uint32_t
 min_u32(uint32_t a, uint32_t b)
 {
@@ -180,8 +178,6 @@ main()
 	memory_init();
 	fiber_init(fiber_c_invoke);
 
-	ibuf_create(tarantool_lua_ibuf, &cord()->slabc, 16000);
-
 	struct lua_State *L = luaL_newstate();
 	luaL_openlibs(L);
 
-- 
2.24.3 (Apple Git-128)



More information about the Tarantool-patches mailing list