From 3b1de78db8a1da9200f1ff56b99576a50d52a533 Mon Sep 17 00:00:00 2001
From: Nikolay Shirokovskiy <nshirokovskiy@tarantool.org>
Date: Fri, 22 Sep 2023 10:47:26 +0300
Subject: [PATCH] mpstream: get rid of mpstream_reset

Proposed ASAN implementation of region allocator does not support double
reservation for the sake of simplicity. Every reservation is supposed to
be followed by one or more allocations.

This restiction does not work well with mpstream currently. The issue is
mpstream_init/mpstream_reserve do reservation of size 0. For example In
case of region slab of min order is reserved (a chunk of memory of page
size currently). If the first data we want to write to mpstream is
larger then the reservation done then we make reservation again.

Let's get rid of this reservation at the beginning as it is suboptimal
behaviour. Moreover let's get rid of mpstream_reset as mpstream_init
is lightweight and we can create a new mpstream instead of reusing
exiting.

Also while we at it avoid allocation of 0 size in mpstream_flush as it
is done in mpstream_reserve_slow (see 3.0.0-alpha3-19-g8159347d0 "misc:
avoid allocations of size 0 for region" for details).

NO_TEST=internal
NO_CHANGELOG=internal
NO_DOC=internal
---
 src/lib/mpstream/mpstream.c | 17 +++--------------
 src/lib/mpstream/mpstream.h |  6 ++----
 test/unit/lua_msgpack.c     | 15 ++++++++-------
 3 files changed, 13 insertions(+), 25 deletions(-)

diff --git a/src/lib/mpstream/mpstream.c b/src/lib/mpstream/mpstream.c
index 3cff2dad96..f397dee0b3 100644
--- a/src/lib/mpstream/mpstream.c
+++ b/src/lib/mpstream/mpstream.c
@@ -40,19 +40,6 @@ mpstream_reserve_slow(struct mpstream *stream, size_t size)
 	stream->end = stream->pos + size;
 }
 
-void
-mpstream_reset(struct mpstream *stream)
-{
-	size_t size = 0;
-	stream->buf = stream->reserve(stream->ctx, &size);
-	if (stream->buf == NULL) {
-		diag_set(OutOfMemory, size, "mpstream", "reset");
-		stream->error(stream->error_ctx);
-	}
-	stream->pos = stream->buf;
-	stream->end = stream->pos + size;
-}
-
 /**
  * A streaming API so that it's possible to encode to any output
  * stream.
@@ -67,7 +54,9 @@ mpstream_init(struct mpstream *stream, void *ctx,
 	stream->alloc = alloc;
 	stream->error = error;
 	stream->error_ctx = error_ctx;
-	mpstream_reset(stream);
+	stream->buf = NULL;
+	stream->pos = NULL;
+	stream->end = NULL;
 }
 
 void
diff --git a/src/lib/mpstream/mpstream.h b/src/lib/mpstream/mpstream.h
index 9fdd0c2aba..456b407f04 100644
--- a/src/lib/mpstream/mpstream.h
+++ b/src/lib/mpstream/mpstream.h
@@ -57,9 +57,6 @@ mpstream_panic_cb(void *error_ctx);
 void
 mpstream_reserve_slow(struct mpstream *stream, size_t size);
 
-void
-mpstream_reset(struct mpstream *stream);
-
 /**
  * A streaming API so that it's possible to encode to any output
  * stream.
@@ -72,7 +69,8 @@ mpstream_init(struct mpstream *stream, void *ctx,
 static inline void
 mpstream_flush(struct mpstream *stream)
 {
-	stream->alloc(stream->ctx, stream->pos - stream->buf);
+	if (stream->pos != stream->buf)
+		stream->alloc(stream->ctx, stream->pos - stream->buf);
 	stream->buf = stream->pos;
 }
 
diff --git a/test/unit/lua_msgpack.c b/test/unit/lua_msgpack.c
index ab8a996e60..fd6d194d99 100644
--- a/test/unit/lua_msgpack.c
+++ b/test/unit/lua_msgpack.c
@@ -61,7 +61,6 @@ test_encode_ext(lua_State *L)
 	   "UUID is correctly encoded as MP_EXT");
 	ok(type == MP_EXT, "type of UUID is MP_EXT");
 	ibuf_reset(ibuf);
-	mpstream_reset(&stream);
 
 	cord_ibuf_drop(ibuf);
 	mh_strnu32_delete(translation);
@@ -91,12 +90,12 @@ test_translation_in_encoding(lua_State *L)
 
 	struct ibuf *ibuf = cord_ibuf_take();
 	struct mpstream stream;
-	mpstream_init(&stream, ibuf, ibuf_reserve_cb, ibuf_alloc_cb,
-		      mpstream_error_mock, L);
 
 	lua_createtable(L, 0, 1);
 	lua_pushboolean(L, true);
 	lua_setfield(L, 1, alias);
+	mpstream_init(&stream, ibuf, ibuf_reserve_cb, ibuf_alloc_cb,
+		      mpstream_error_mock, L);
 	luamp_encode_with_translation(L, luaL_msgpack_default, &stream, 1,
 				      translation, NULL);
 	lua_pop(L, 1);
@@ -104,13 +103,14 @@ test_translation_in_encoding(lua_State *L)
 	ok(strncmp(ibuf->buf, "\x81\x00\xc3", ibuf_used(ibuf)) == 0,
 	   "first-level MP_MAP key is translated");
 	ibuf_reset(ibuf);
-	mpstream_reset(&stream);
 
 	lua_createtable(L, 0, 1);
 	lua_createtable(L, 0, 1);
 	lua_pushboolean(L, true);
 	lua_setfield(L, -2, alias);
 	lua_setfield(L, -2, "k");
+	mpstream_init(&stream, ibuf, ibuf_reserve_cb, ibuf_alloc_cb,
+		      mpstream_error_mock, L);
 	luamp_encode_with_translation(L, luaL_msgpack_default, &stream, 1,
 				      translation, NULL);
 	lua_pop(L, 1);
@@ -118,19 +118,19 @@ test_translation_in_encoding(lua_State *L)
 	ok(strncmp(ibuf->buf, "\x81\xa1k\x81\xa1x\xc3", ibuf_used(ibuf)) == 0,
 	   "only first-level MP_MAP key is translated");
 	ibuf_reset(ibuf);
-	mpstream_reset(&stream);
 
 	lua_createtable(L, 0, 1);
 	lua_pushnumber(L, 0);
 	lua_pushboolean(L, true);
 	lua_settable(L, -3);
+	mpstream_init(&stream, ibuf, ibuf_reserve_cb, ibuf_alloc_cb,
+		      mpstream_error_mock, L);
 	luamp_encode_with_translation(L, luaL_msgpack_default, &stream, 1,
 				      translation, NULL);
 	mpstream_flush(&stream);
 	ok(strncmp(ibuf->buf, "\x81\x00\xc3", ibuf_used(ibuf)) == 0,
 	   "only keys with MP_STRING type are translated");
 	ibuf_reset(ibuf);
-	mpstream_reset(&stream);
 
 	lua_createtable(L, 0, 1);
 	lua_pushboolean(L, true);
@@ -138,6 +138,8 @@ test_translation_in_encoding(lua_State *L)
 	lua_pushnumber(L, 0);
 	lua_pushboolean(L, false);
 	lua_settable(L, -3);
+	mpstream_init(&stream, ibuf, ibuf_reserve_cb, ibuf_alloc_cb,
+		      mpstream_error_mock, L);
 	luamp_encode_with_translation(L, luaL_msgpack_default, &stream, 1,
 				      translation, NULL);
 	lua_pop(L, 1);
@@ -147,7 +149,6 @@ test_translation_in_encoding(lua_State *L)
 	   "MP_MAP key that is the value of the translation are translated "
 	   "correctly");
 	ibuf_reset(ibuf);
-	mpstream_reset(&stream);
 
 	cord_ibuf_drop(ibuf);
 	mh_strnu32_delete(translation);
-- 
GitLab