diff --git a/doc/box-protocol.txt b/doc/box-protocol.txt
index bb431b4c5e62b3b4199594e0f348a645958b2c78..62a95bf4d1772c4e98e6131d6e3e5fe5a4ed1138 100644
--- a/doc/box-protocol.txt
+++ b/doc/box-protocol.txt
@@ -226,8 +226,14 @@ Tarantool/Box IPROTO protocol.
 
 <insert_request_body> ::= <space_no><flags><tuple>
 
-; The only defined flag BOX_RETURN_TUPLE (0x01) indicates
+; Flag BOX_RETURN_TUPLE (0x01) indicates
 ; that it is required to return the inserted tuple back:
+; Flag BOX_ADD (0x02) requests that no tuple with the same primary
+; key exists in the space. I.e. it turns INSERT into INSERT,
+; without this flag INSERT behaves like REPLACE: replaces
+; an existing tuple if it is found.
+; Flag BOX_REPLACE (0x04) requests that a tuple with the same
+; primary key is present in the space.
 
 <flags> ::= <int32>
 
diff --git a/include/tarantool.h b/include/tarantool.h
index d46756035ca534530f991b77b6d443ba061dc36b..957e33b3cc1433ca70380b3c1c474e5e47da04c8 100644
--- a/include/tarantool.h
+++ b/include/tarantool.h
@@ -30,9 +30,6 @@
 #include <util.h>
 #include <log_io.h>
 
-struct lua_State;
-struct luaL_Reg;
-
 void mod_init(void);
 void mod_free(void);
 struct tarantool_cfg;
@@ -43,53 +40,6 @@ i32 mod_reload_config(struct tarantool_cfg *old_conf, struct tarantool_cfg *new_
 int mod_cat(const char *filename);
 void mod_snapshot(struct log_io_iter *);
 void mod_info(struct tbuf *out);
-/**
- * This is a callback used by tarantool_lua_init() to open
- * module-specific libraries into given Lua state.
- *
- * @return  L on success, 0 if out of memory
- */
-struct lua_State *mod_lua_init(struct lua_State *L);
-
-void
-tarantool_lua_register_type(struct lua_State *L, const char *type_name,
-			    const struct luaL_Reg *methods);
-
-/**
- * Create an instance of Lua interpreter and load it with
- * Tarantool modules.  Creates a Lua state, imports global
- * Tarantool modules, then calls mod_lua_init(), which performs
- * module-specific imports. The created state can be freed as any
- * other, with lua_close().
- *
- * @return  L on success, 0 if out of memory
- */
-struct lua_State *tarantool_lua_init();
-void tarantool_lua_close(struct lua_State *L);
-
-/*
- * Single global lua_State shared by core and modules.
- * Created with tarantool_lua_init().
- */
-extern struct lua_State *tarantool_L;
-/* Call Lua 'tostring' built-in to print userdata nicely. */
-const char *
-tarantool_lua_tostring(struct lua_State *L, int index);
-
-/* Convert Lua string, number or cdata (u64) to 64bit value */
-uint64_t
-tarantool_lua_tointeger64(struct lua_State *L, int idx);
-
-/* Make a new configuration available in Lua */
-void tarantool_lua_load_cfg(struct lua_State *L,
-			    struct tarantool_cfg *cfg);
-
-/**
- * Load and execute start-up file
- *
- * @param L is Lua State
- */
-void tarantool_lua_load_init_script(struct lua_State *L);
 
 extern struct tarantool_cfg cfg;
 extern const char *cfg_filename;
@@ -106,9 +56,4 @@ void tarantool_free(void);
 char **init_set_proc_title(int argc, char **argv);
 void free_proc_title(int argc, char **argv);
 void set_proc_title(const char *format, ...);
-
-void
-tarantool_lua(struct lua_State *L,
-	      struct tbuf *out, const char *str);
-
 #endif /* TARANTOOL_H_INCLUDED */
diff --git a/include/tarantool_lua.h b/include/tarantool_lua.h
new file mode 100644
index 0000000000000000000000000000000000000000..af20890bde6bec465a9fdcb3cc86071c2df7bb83
--- /dev/null
+++ b/include/tarantool_lua.h
@@ -0,0 +1,87 @@
+#ifndef INCLUDES_TARANTOOL_LUA_H
+#define INCLUDES_TARANTOOL_LUA_H
+/*
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <inttypes.h>
+struct lua_State;
+struct luaL_Reg;
+struct tarantool_cfg;
+struct tbuf;
+
+/**
+ * This is a callback used by tarantool_lua_init() to open
+ * module-specific libraries into given Lua state.
+ *
+ * @return  L on success, 0 if out of memory
+ */
+struct lua_State *mod_lua_init(struct lua_State *L);
+
+void
+tarantool_lua_register_type(struct lua_State *L, const char *type_name,
+			    const struct luaL_Reg *methods);
+
+/**
+ * Create an instance of Lua interpreter and load it with
+ * Tarantool modules.  Creates a Lua state, imports global
+ * Tarantool modules, then calls mod_lua_init(), which performs
+ * module-specific imports. The created state can be freed as any
+ * other, with lua_close().
+ *
+ * @return  L on success, 0 if out of memory
+ */
+struct lua_State *tarantool_lua_init();
+void tarantool_lua_close(struct lua_State *L);
+
+/*
+ * Single global lua_State shared by core and modules.
+ * Created with tarantool_lua_init().
+ */
+extern struct lua_State *tarantool_L;
+/* Call Lua 'tostring' built-in to print userdata nicely. */
+const char *
+tarantool_lua_tostring(struct lua_State *L, int index);
+
+/* Convert Lua string, number or cdata (u64) to 64bit value */
+uint64_t
+tarantool_lua_tointeger64(struct lua_State *L, int idx);
+
+/* Make a new configuration available in Lua */
+void tarantool_lua_load_cfg(struct lua_State *L,
+			    struct tarantool_cfg *cfg);
+
+/**
+ * Load and execute start-up file
+ *
+ * @param L is Lua State
+ */
+void tarantool_lua_load_init_script(struct lua_State *L);
+void
+tarantool_lua(struct lua_State *L,
+	      struct tbuf *out, const char *str);
+#endif /* INCLUDES_TARANTOOL_LUA_H */
diff --git a/mod/box/CMakeLists.txt b/mod/box/CMakeLists.txt
index 790e960cafb5c5e5851d27cd1f86961f4aa0e916..60397d1c27214b4fdb658f1f8f566cc15a44b400 100644
--- a/mod/box/CMakeLists.txt
+++ b/mod/box/CMakeLists.txt
@@ -34,5 +34,5 @@ set_source_files_properties(memcached-grammar.m
 set_source_files_properties(memcached.m
     PROPERTIES COMPILE_FLAGS "-Wno-uninitialized")
 
-tarantool_module("box" tuple.m index.m tree.m space.m box.m box.lua.c
-    box_lua.m memcached.m memcached-grammar.m)
+tarantool_module("box" tuple.m index.m tree.m space.m port.m box.m
+    box.lua.c box_lua.m memcached.m memcached-grammar.m)
diff --git a/mod/box/box.h b/mod/box/box.h
index a02b6024659255fcf5f3ad79d29d73f4c53bd795..ff6ae3eb71aafef97d1495c76fd88da4a78dcc3b 100644
--- a/mod/box/box.h
+++ b/mod/box/box.h
@@ -37,14 +37,9 @@ enum {
 	/** A limit on how many operations a single UPDATE can have. */
 	BOX_UPDATE_OP_CNT_MAX = 128,
 };
+struct port;
 
-struct box_out {
-	void (*add_u32)(u32 *u32);
-	void (*dup_u32)(u32 u32);
-	void (*add_tuple)(struct box_tuple *tuple);
-};
 
-extern struct box_out box_out_quiet;
 @class Index;
 struct space;
 
@@ -53,7 +48,7 @@ struct box_txn {
 	u32 flags;
 
 	struct lua_State *L;
-	struct box_out *out;
+	struct port *port;
 	struct space *space;
 	Index *index;
 
diff --git a/mod/box/box.m b/mod/box/box.m
index 99a50e3d5a32954549f0e7797ded8e8b43f72c8c..ad70b3757c5c1fc1411e38b9c23c96fd83a37fb7 100644
--- a/mod/box/box.m
+++ b/mod/box/box.m
@@ -48,6 +48,7 @@
 #include "memcached.h"
 #include "box_lua.h"
 #include "space.h"
+#include "port.h"
 
 extern pid_t logger_pid;
 
@@ -63,20 +64,6 @@ static int stat_base;
 STRS(messages, MESSAGES);
 STRS(update_op_codes, UPDATE_OP_CODES);
 
-/*
-  For tuples of size below this threshold, when sending a tuple
-  to the client, make a deep copy of the tuple for the duration
-  of sending rather than increment a reference counter.
-  This is necessary to avoid excessive page splits when taking
-  a snapshot: many small tuples can be accessed by clients
-  immediately after the snapshot process has forked off,
-  thus incrementing tuple ref count, and causing the OS to
-  create a copy of the memory page for the forked
-  child.
-*/
-
-const int BOX_REF_THRESHOLD = 8196;
-
 struct box_snap_row {
 	u32 space;
 	u32 tuple_size;
@@ -196,10 +183,10 @@ prepare_replace(struct box_txn *txn, size_t field_count, struct tbuf *data)
 		space_replace(txn->space, NULL, txn->new_tuple);
 	}
 
-	txn->out->dup_u32(1); /* Affected tuples */
+	txn->port->dup_u32(1); /* Affected tuples */
 
 	if (txn->flags & BOX_RETURN_TUPLE)
-		txn->out->add_tuple(txn->new_tuple);
+		txn->port->add_tuple(txn->new_tuple);
 }
 
 static void
@@ -957,10 +944,10 @@ prepare_update(struct box_txn *txn, struct tbuf *data)
 	space_validate(txn->space, txn->old_tuple, txn->new_tuple);
 
 out:
-	txn->out->dup_u32(tuples_affected);
+	txn->port->dup_u32(tuples_affected);
 
 	if (txn->flags & BOX_RETURN_TUPLE && txn->new_tuple)
-		txn->out->add_tuple(txn->new_tuple);
+		txn->port->add_tuple(txn->new_tuple);
 }
 
 /** }}} */
@@ -975,7 +962,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data)
 		tnt_raise(IllegalParams, :"tuple count must be positive");
 
 	found = palloc(fiber->gc_pool, sizeof(*found));
-	txn->out->add_u32(found);
+	txn->port->add_u32(found);
 	*found = 0;
 
 	for (u32 i = 0; i < count; i++) {
@@ -1002,7 +989,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data)
 				continue;
 			}
 
-			txn->out->add_tuple(tuple);
+			txn->port->add_tuple(tuple);
 
 			if (limit == ++(*found))
 				break;
@@ -1039,10 +1026,10 @@ prepare_delete(struct box_txn *txn, struct tbuf *data)
 		tuples_affected = 1;
 	}
 
-	txn->out->dup_u32(tuples_affected);
+	txn->port->dup_u32(tuples_affected);
 
 	if (txn->old_tuple && (txn->flags & BOX_RETURN_TUPLE))
-		txn->out->add_tuple(txn->old_tuple);
+		txn->port->add_tuple(txn->old_tuple);
 }
 
 static void
@@ -1060,47 +1047,6 @@ op_is_select(u32 op)
 	return op == SELECT || op == CALL;
 }
 
-static void
-iov_add_u32(u32 *p_u32)
-{
-	iov_add(p_u32, sizeof(u32));
-}
-
-static void
-iov_dup_u32(u32 u32)
-{
-	iov_dup(&u32, sizeof(u32));
-}
-
-static void
-iov_add_tuple(struct box_tuple *tuple)
-{
-	size_t len = tuple_len(tuple);
-
-	if (len > BOX_REF_THRESHOLD) {
-		tuple_txn_ref(in_txn(), tuple);
-		iov_add(&tuple->bsize, len);
-	} else {
-		iov_dup(&tuple->bsize, len);
-	}
-}
-
-static struct box_out box_out_iproto = {
-	iov_add_u32,
-	iov_dup_u32,
-	iov_add_tuple
-};
-
-static void box_quiet_add_u32(u32 *p_u32 __attribute__((unused))) {}
-static void box_quiet_dup_u32(u32 u32 __attribute__((unused))) {}
-static void box_quiet_add_tuple(struct box_tuple *tuple __attribute__((unused))) {}
-
-struct box_out box_out_quiet = {
-	box_quiet_add_u32,
-	box_quiet_dup_u32,
-	box_quiet_add_tuple
-};
-
 struct box_txn *
 txn_begin()
 {
@@ -1409,7 +1355,7 @@ box_process_rw(u32 op, struct tbuf *request_data)
 	if (txn == NULL) {
 		txn = txn_begin();
 		txn->flags |= BOX_GC_TXN;
-		txn->out = &box_out_iproto;
+		txn->port = &port_iproto;
 	}
 
 	@try {
@@ -1478,7 +1424,7 @@ recover_row(struct recovery_state *r __attribute__((unused)), struct tbuf *t)
 
 	struct box_txn *txn = txn_begin();
 	txn->flags |= BOX_NOT_STORE;
-	txn->out = &box_out_quiet;
+	txn->port = &port_null;
 
 	@try {
 		box_process_rw(op, t);
@@ -1689,9 +1635,6 @@ mod_init(void)
 	/* build secondary indexes */
 	build_indexes();
 
-	/* enable secondary indexes now */
-	secondary_indexes_enabled = true;
-
 	title("orphan");
 
 	if (cfg.local_hot_standby) {
diff --git a/mod/box/box_lua.h b/mod/box/box_lua.h
index f837e3e472b060be1ab30764b2b23385c1c31632..c50c40ba8444b258a80e656c9dc3b698dd925338 100644
--- a/mod/box/box_lua.h
+++ b/mod/box/box_lua.h
@@ -32,6 +32,8 @@
  */
 struct tbuf;
 struct box_txn;
+struct box_tuple;
+struct lua_State;
 
 /**
  * Invoke a Lua stored procedure from the binary protocol
@@ -42,4 +44,6 @@ void box_lua_call(struct box_txn *txn, struct tbuf *req);
  * Create an instance of Lua interpreter in box.
  */
 void box_lua_init();
+
+struct box_tuple *lua_istuple(struct lua_State *L, int narg);
 #endif /* INCLUDES_TARANTOOL_MOD_BOX_LUA_H */
diff --git a/mod/box/box_lua.m b/mod/box/box_lua.m
index caa0a047e26e103bc044267f9ebfb295ff53f52b..f0ea443e88e4226aa738be3e716c2a9d7d802625 100644
--- a/mod/box/box_lua.m
+++ b/mod/box/box_lua.m
@@ -29,21 +29,17 @@
  * SUCH DAMAGE.
  */
 #include "box_lua.h"
-#include "tarantool.h"
+#include <tarantool_lua.h>
 #include "box.h"
 
 #include "lua.h"
 #include "lauxlib.h"
 #include "lualib.h"
 
-#include "lj_obj.h"
-#include "lj_ctype.h"
-#include "lj_cdata.h"
-#include "lj_cconv.h"
-
 #include "pickle.h"
 #include "tuple.h"
 #include "space.h"
+#include "port.h"
 
 /* contents of box.lua */
 extern const char box_lua[];
@@ -81,7 +77,7 @@ lua_checktuple(struct lua_State *L, int narg)
 	return *(void **) luaL_checkudata(L, narg, tuplelib_name);
 }
 
-static inline struct box_tuple *
+struct box_tuple *
 lua_istuple(struct lua_State *L, int narg)
 {
 	if (lua_getmetatable(L, narg) == 0)
@@ -549,161 +545,11 @@ static const struct luaL_reg lbox_iterator_meta[] = {
 /* }}} */
 
 /** {{{ Lua I/O: facilities to intercept box output
- * and push into Lua stack and the opposite: append Lua types
- * to fiber IOV.
+ * and push into Lua stack.
  */
 
-/* Add a Lua table to iov as if it was a tuple, with as little
- * overhead as possible. */
-
 static void
-iov_add_lua_table(struct lua_State *L, int index)
-{
-	u32 *field_count = palloc(fiber->gc_pool, sizeof(u32));
-	u32 *tuple_len = palloc(fiber->gc_pool, sizeof(u32));
-
-	*field_count = 0;
-	*tuple_len = 0;
-
-	iov_add(tuple_len, sizeof(u32));
-	iov_add(field_count, sizeof(u32));
-
-	u8 field_len_buf[5];
-	size_t field_len, field_len_len;
-	const char *field;
-
-	lua_pushnil(L);  /* first key */
-	while (lua_next(L, index) != 0) {
-		++*field_count;
-
-		switch (lua_type(L, -1)) {
-		case LUA_TNUMBER:
-		{
-			u32 field_num = lua_tonumber(L, -1);
-			field_len = sizeof(u32);
-			field_len_len =
-				save_varint32(field_len_buf,
-					      field_len) - field_len_buf;
-			iov_dup(field_len_buf, field_len_len);
-			iov_dup(&field_num, field_len);
-			*tuple_len += field_len_len + field_len;
-			break;
-		}
-		case LUA_TCDATA:
-		{
-			u64 field_num = tarantool_lua_tointeger64(L, -1);
-			field_len = sizeof(u64);
-			field_len_len =
-				save_varint32(field_len_buf,
-					      field_len) - field_len_buf;
-			iov_dup(field_len_buf, field_len_len);
-			iov_dup(&field_num, field_len);
-			*tuple_len += field_len_len + field_len;
-			break;
-		}
-		case LUA_TSTRING:
-		{
-			field = lua_tolstring(L, -1, &field_len);
-			field_len_len =
-				save_varint32(field_len_buf,
-					      field_len) - field_len_buf;
-			iov_dup(field_len_buf, field_len_len);
-			iov_dup(field, field_len);
-			*tuple_len += field_len_len + field_len;
-			break;
-		}
-		default:
-			tnt_raise(ClientError, :ER_PROC_RET,
-				  lua_typename(L, lua_type(L, -1)));
-			break;
-		}
-		lua_pop(L, 1);
-	}
-}
-
-void iov_add_ret(struct lua_State *L, int index)
-{
-	int type = lua_type(L, index);
-	struct box_tuple *tuple;
-	switch (type) {
-	case LUA_TTABLE:
-	{
-		iov_add_lua_table(L, index);
-		return;
-	}
-	case LUA_TNUMBER:
-	{
-		size_t len = sizeof(u32);
-		u32 num = lua_tointeger(L, index);
-		tuple = tuple_alloc(len + varint32_sizeof(len));
-		tuple->field_count = 1;
-		memcpy(save_varint32(tuple->data, len), &num, len);
-		break;
-	}
-	case LUA_TCDATA:
-	{
-		u64 num = tarantool_lua_tointeger64(L, index);
-		size_t len = sizeof(u64);
-		tuple = tuple_alloc(len + varint32_sizeof(len));
-		tuple->field_count = 1;
-		memcpy(save_varint32(tuple->data, len), &num, len);
-		break;
-	}
-	case LUA_TSTRING:
-	{
-		size_t len;
-		const char *str = lua_tolstring(L, index, &len);
-		tuple = tuple_alloc(len + varint32_sizeof(len));
-		tuple->field_count = 1;
-		memcpy(save_varint32(tuple->data, len), str, len);
-		break;
-	}
-	case LUA_TNIL:
-	case LUA_TBOOLEAN:
-	{
-		const char *str = tarantool_lua_tostring(L, index);
-		size_t len = strlen(str);
-		tuple = tuple_alloc(len + varint32_sizeof(len));
-		tuple->field_count = 1;
-		memcpy(save_varint32(tuple->data, len), str, len);
-		break;
-	}
-	case LUA_TUSERDATA:
-	{
-		tuple = lua_istuple(L, index);
-		if (tuple)
-			break;
-	}
-	default:
-		/*
-		 * LUA_TNONE, LUA_TTABLE, LUA_THREAD, LUA_TFUNCTION
-		 */
-		tnt_raise(ClientError, :ER_PROC_RET, lua_typename(L, type));
-		break;
-	}
-	tuple_txn_ref(in_txn(), tuple);
-	iov_add(&tuple->bsize, tuple_len(tuple));
-}
-
-/**
- * Add all elements from Lua stack to fiber iov.
- *
- * To allow clients to understand a complex return from
- * a procedure, we are compatible with SELECT protocol,
- * and return the number of return values first, and
- * then each return value as a tuple.
- */
-void
-iov_add_multret(struct lua_State *L)
-{
-	int nargs = lua_gettop(L);
-	iov_dup(&nargs, sizeof(u32));
-	for (int i = 1; i <= nargs; ++i)
-		iov_add_ret(L, i);
-}
-
-static void
-box_lua_dup_u32(u32 u32 __attribute__((unused)))
+port_lua_dup_u32(u32 u32 __attribute__((unused)))
 {
 	/*
 	 * Do nothing -- the only u32 Box can give us is
@@ -714,22 +560,35 @@ box_lua_dup_u32(u32 u32 __attribute__((unused)))
 }
 
 static void
-box_lua_add_u32(u32 *p_u32 __attribute__((unused)))
+port_lua_add_u32(u32 *p_u32 __attribute__((unused)))
 {
-	/* See the comment in box_lua_dup_u32. */
+	/* See the comment in port_lua_dup_u32. */
 }
 
 static void
-box_lua_add_tuple(struct box_tuple *tuple)
+port_lua_add_tuple(struct box_tuple *tuple)
 {
 	struct lua_State *L = in_txn()->L;
 	lbox_pushtuple(L, tuple);
 }
 
-static struct box_out box_out_lua = {
-	box_lua_add_u32,
-	box_lua_dup_u32,
-	box_lua_add_tuple
+static void
+port_lua_add_lua_multret(struct lua_State *L)
+{
+	/*
+	 * We cannot issue a CALL request from within a CALL
+	 * request. Instead users should call Lua procedures
+	 * directly.
+	 */
+	assert(false);
+	(void) L;
+}
+
+static struct port port_lua = {
+	port_lua_add_u32,
+	port_lua_dup_u32,
+	port_lua_add_tuple,
+	port_lua_add_lua_multret
 };
 
 /* }}} */
@@ -740,7 +599,7 @@ txn_enter_lua(lua_State *L)
 	struct box_txn *old_txn = in_txn();
 	fiber->mod_data.txn = NULL;
 	struct box_txn *txn = fiber->mod_data.txn = txn_begin();
-	txn->out = &box_out_lua;
+	txn->port = &port_lua;
 	txn->L = L;
 	return old_txn;
 }
@@ -836,8 +695,7 @@ box_lua_panic(struct lua_State *L)
  * Invoke a Lua stored procedure from the binary protocol
  * (implementation of 'CALL' command code).
  */
-void box_lua_call(struct box_txn *txn __attribute__((unused)),
-		  struct tbuf *data)
+void box_lua_call(struct box_txn *txn, struct tbuf *data)
 {
 	lua_State *L = lua_newthread(root_L);
 	int coro_ref = luaL_ref(root_L, LUA_REGISTRYINDEX);
@@ -856,7 +714,7 @@ void box_lua_call(struct box_txn *txn __attribute__((unused)),
 		}
 		lua_call(L, nargs, LUA_MULTRET);
 		/* Send results of the called procedure to the client. */
-		iov_add_multret(L);
+		txn->port->add_lua_multret(L);
 	} @finally {
 		/*
 		 * Allow the used coro to be garbage collected.
diff --git a/mod/box/index.h b/mod/box/index.h
index 430d31d4acc25651b50b2480574eef7ef982a9da..2c518ffa1f379c36740e77e8fba5cc5a34936daf 100644
--- a/mod/box/index.h
+++ b/mod/box/index.h
@@ -76,8 +76,6 @@ struct key_def {
 	bool is_unique;
 };
 
-@class Index;
-
 @interface Index: Object {
  @public
 	/* Index owner space */
diff --git a/mod/box/memcached-grammar.m b/mod/box/memcached-grammar.m
index 2b07325cb84394b7bee1929e4e61ab847aaaf5cc..d97e8038de51101dcc64bde2538cfbd677b4a091 100644
--- a/mod/box/memcached-grammar.m
+++ b/mod/box/memcached-grammar.m
@@ -1034,7 +1034,7 @@ tr195:
 	{
 			struct box_txn *txn = txn_begin();
 			txn->flags |= BOX_GC_TXN;
-			txn->out = &box_out_quiet;
+			txn->port = &port_null;
 			@try {
 				memcached_get(txn, keys_count, keys, show_cas);
 				txn_commit(txn);
diff --git a/mod/box/memcached-grammar.rl b/mod/box/memcached-grammar.rl
index 22ac49629ffc2bc7f9448d0d2697cd6857985a5c..b8c239a2dd389eccd5a0751a0a8e069981d0b1f7 100644
--- a/mod/box/memcached-grammar.rl
+++ b/mod/box/memcached-grammar.rl
@@ -192,7 +192,7 @@ memcached_dispatch()
 		action get {
 			struct box_txn *txn = txn_begin();
 			txn->flags |= BOX_GC_TXN;
-			txn->out = &box_out_quiet;
+			txn->port = &port_null;
 			@try {
 				memcached_get(txn, keys_count, keys, show_cas);
 				txn_commit(txn);
diff --git a/mod/box/memcached.m b/mod/box/memcached.m
index 1641d3241227923687b82500c3454558f2288982..c9d87090011f4da8244816fd8f7899db3915bf18 100644
--- a/mod/box/memcached.m
+++ b/mod/box/memcached.m
@@ -34,6 +34,7 @@
 #include "salloc.h"
 #include "pickle.h"
 #include "space.h"
+#include "port.h"
 
 #define STAT(_)					\
         _(MEMC_GET, 1)				\
@@ -103,7 +104,7 @@ store(void *key, u32 exptime, u32 flags, u32 bytes, u8 *data)
 		  key_len, key_len, (u8 *)key, exptime, flags, cas);
 
 	struct box_txn *txn = txn_begin();
-	txn->out = &box_out_quiet;
+	txn->port = &port_null;
 	/*
 	 * Use a box dispatch wrapper which handles correctly
 	 * read-only/read-write modes.
@@ -124,7 +125,7 @@ delete(void *key)
 	tbuf_append_field(req, key);
 
 	struct box_txn *txn = txn_begin();
-	txn->out = &box_out_quiet;
+	txn->port = &port_null;
 
 	rw_callback(DELETE, req);
 }
diff --git a/mod/box/port.h b/mod/box/port.h
new file mode 100644
index 0000000000000000000000000000000000000000..efe495c56d3de110fb4946884734a2339f563647
--- /dev/null
+++ b/mod/box/port.h
@@ -0,0 +1,46 @@
+#ifndef INCLUDES_TARANTOOL_BOX_PORT_H
+#define INCLUDES_TARANTOOL_BOX_PORT_H
+/*
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <util.h>
+
+struct box_tuple;
+struct lua_State;
+
+struct port {
+	void (*add_u32)(u32 *u32);
+	void (*dup_u32)(u32 u32);
+	void (*add_tuple)(struct box_tuple *tuple);
+	void (*add_lua_multret)(struct lua_State *L);
+};
+
+extern struct port port_null;
+extern struct port port_iproto;
+
+#endif /* INCLUDES_TARANTOOL_BOX_PORT_H */
diff --git a/mod/box/port.m b/mod/box/port.m
new file mode 100644
index 0000000000000000000000000000000000000000..0946a7bb2431c854e93d6bf5d92ea653eb005206
--- /dev/null
+++ b/mod/box/port.m
@@ -0,0 +1,249 @@
+/*
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "port.h"
+#include "box.h"
+#include <pickle.h>
+#include <tarantool_lua.h>
+#include "tuple.h"
+#include "box_lua.h"
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include "lj_obj.h"
+#include "lj_ctype.h"
+#include "lj_cdata.h"
+#include "lj_cconv.h"
+
+/*
+  For tuples of size below this threshold, when sending a tuple
+  to the client, make a deep copy of the tuple for the duration
+  of sending rather than increment a reference counter.
+  This is necessary to avoid excessive page splits when taking
+  a snapshot: many small tuples can be accessed by clients
+  immediately after the snapshot process has forked off,
+  thus incrementing tuple ref count, and causing the OS to
+  create a copy of the memory page for the forked
+  child.
+*/
+const int BOX_REF_THRESHOLD = 8196;
+
+
+static void
+iov_add_u32(u32 *p_u32)
+{
+	iov_add(p_u32, sizeof(u32));
+}
+
+static void
+iov_dup_u32(u32 u32)
+{
+	iov_dup(&u32, sizeof(u32));
+}
+
+static void
+iov_add_tuple(struct box_tuple *tuple)
+{
+	size_t len = tuple_len(tuple);
+
+	if (len > BOX_REF_THRESHOLD) {
+		tuple_txn_ref(in_txn(), tuple);
+		iov_add(&tuple->bsize, len);
+	} else {
+		iov_dup(&tuple->bsize, len);
+	}
+}
+
+/* Add a Lua table to iov as if it was a tuple, with as little
+ * overhead as possible. */
+
+static void
+iov_add_lua_table(struct lua_State *L, int index)
+{
+	u32 *field_count = palloc(fiber->gc_pool, sizeof(u32));
+	u32 *tuple_len = palloc(fiber->gc_pool, sizeof(u32));
+
+	*field_count = 0;
+	*tuple_len = 0;
+
+	iov_add(tuple_len, sizeof(u32));
+	iov_add(field_count, sizeof(u32));
+
+	u8 field_len_buf[5];
+	size_t field_len, field_len_len;
+	const char *field;
+
+	lua_pushnil(L);  /* first key */
+	while (lua_next(L, index) != 0) {
+		++*field_count;
+
+		switch (lua_type(L, -1)) {
+		case LUA_TNUMBER:
+		{
+			u32 field_num = lua_tonumber(L, -1);
+			field_len = sizeof(u32);
+			field_len_len =
+				save_varint32(field_len_buf,
+					      field_len) - field_len_buf;
+			iov_dup(field_len_buf, field_len_len);
+			iov_dup(&field_num, field_len);
+			*tuple_len += field_len_len + field_len;
+			break;
+		}
+		case LUA_TCDATA:
+		{
+			u64 field_num = tarantool_lua_tointeger64(L, -1);
+			field_len = sizeof(u64);
+			field_len_len =
+				save_varint32(field_len_buf,
+					      field_len) - field_len_buf;
+			iov_dup(field_len_buf, field_len_len);
+			iov_dup(&field_num, field_len);
+			*tuple_len += field_len_len + field_len;
+			break;
+		}
+		case LUA_TSTRING:
+		{
+			field = lua_tolstring(L, -1, &field_len);
+			field_len_len =
+				save_varint32(field_len_buf,
+					      field_len) - field_len_buf;
+			iov_dup(field_len_buf, field_len_len);
+			iov_dup(field, field_len);
+			*tuple_len += field_len_len + field_len;
+			break;
+		}
+		default:
+			tnt_raise(ClientError, :ER_PROC_RET,
+				  lua_typename(L, lua_type(L, -1)));
+			break;
+		}
+		lua_pop(L, 1);
+	}
+}
+
+void iov_add_ret(struct lua_State *L, int index)
+{
+	int type = lua_type(L, index);
+	struct box_tuple *tuple;
+	switch (type) {
+	case LUA_TTABLE:
+	{
+		iov_add_lua_table(L, index);
+		return;
+	}
+	case LUA_TNUMBER:
+	{
+		size_t len = sizeof(u32);
+		u32 num = lua_tointeger(L, index);
+		tuple = tuple_alloc(len + varint32_sizeof(len));
+		tuple->field_count = 1;
+		memcpy(save_varint32(tuple->data, len), &num, len);
+		break;
+	}
+	case LUA_TCDATA:
+	{
+		u64 num = tarantool_lua_tointeger64(L, index);
+		size_t len = sizeof(u64);
+		tuple = tuple_alloc(len + varint32_sizeof(len));
+		tuple->field_count = 1;
+		memcpy(save_varint32(tuple->data, len), &num, len);
+		break;
+	}
+	case LUA_TSTRING:
+	{
+		size_t len;
+		const char *str = lua_tolstring(L, index, &len);
+		tuple = tuple_alloc(len + varint32_sizeof(len));
+		tuple->field_count = 1;
+		memcpy(save_varint32(tuple->data, len), str, len);
+		break;
+	}
+	case LUA_TNIL:
+	case LUA_TBOOLEAN:
+	{
+		const char *str = tarantool_lua_tostring(L, index);
+		size_t len = strlen(str);
+		tuple = tuple_alloc(len + varint32_sizeof(len));
+		tuple->field_count = 1;
+		memcpy(save_varint32(tuple->data, len), str, len);
+		break;
+	}
+	case LUA_TUSERDATA:
+	{
+		tuple = lua_istuple(L, index);
+		if (tuple)
+			break;
+	}
+	default:
+		/*
+		 * LUA_TNONE, LUA_TTABLE, LUA_THREAD, LUA_TFUNCTION
+		 */
+		tnt_raise(ClientError, :ER_PROC_RET, lua_typename(L, type));
+		break;
+	}
+	tuple_txn_ref(in_txn(), tuple);
+	iov_add(&tuple->bsize, tuple_len(tuple));
+}
+
+/**
+ * Add all elements from Lua stack to fiber iov.
+ *
+ * To allow clients to understand a complex return from
+ * a procedure, we are compatible with SELECT protocol,
+ * and return the number of return values first, and
+ * then each return value as a tuple.
+ */
+void
+iov_add_multret(struct lua_State *L)
+{
+	int nargs = lua_gettop(L);
+	iov_dup(&nargs, sizeof(u32));
+	for (int i = 1; i <= nargs; ++i)
+		iov_add_ret(L, i);
+}
+
+struct port port_iproto = {
+	iov_add_u32,
+	iov_dup_u32,
+	iov_add_tuple,
+	iov_add_multret
+};
+
+static void port_null_add_u32(u32 *p_u32 __attribute__((unused))) {}
+static void port_null_dup_u32(u32 u32 __attribute__((unused))) {}
+static void port_null_add_tuple(struct box_tuple *tuple __attribute__((unused))) {}
+static void port_null_add_lua_multret(struct lua_State *L __attribute__((unused))) {}
+
+struct port port_null = {
+	port_null_add_u32,
+	port_null_dup_u32,
+	port_null_add_tuple,
+	port_null_add_lua_multret
+};
+
diff --git a/mod/box/space.h b/mod/box/space.h
index b23f6d27607de3140c2477a86d291a564f56a58d..8b7b46d08004238bc2afbcdec4f23717ba4ee69c 100644
--- a/mod/box/space.h
+++ b/mod/box/space.h
@@ -1,5 +1,5 @@
-#ifndef TARANTOOL_SPACE_H_INCLUDED
-#define TARANTOOL_SPACE_H_INCLUDED
+#ifndef TARANTOOL_BOX_SPACE_H_INCLUDED
+#define TARANTOOL_BOX_SPACE_H_INCLUDED
 /*
  * Redistribution and use in source and binary forms, with or
  * without modification, are permitted provided that the following
@@ -145,4 +145,4 @@ i32 check_spaces(struct tarantool_cfg *conf);
 /* Build secondary keys. */
 void build_indexes(void);
 
-#endif /* TARANTOOL_SPACE_H_INCLUDED */
+#endif /* TARANTOOL_BOX_SPACE_H_INCLUDED */
diff --git a/mod/box/space.m b/mod/box/space.m
index 7cf0e52742cd5fc83aeb6c197251ee49e313986f..a9bf0034bd7027689445870f190064dc88a450a7 100644
--- a/mod/box/space.m
+++ b/mod/box/space.m
@@ -300,6 +300,8 @@ space_init(void)
 void
 build_indexes(void)
 {
+	assert(secondary_indexes_enabled == false);
+
 	for (u32 n = 0; n < BOX_SPACE_MAX; ++n) {
 		if (space[n].enabled == false)
 			continue;
@@ -316,6 +318,8 @@ build_indexes(void)
 
 		say_info("Space %"PRIu32": done", n);
 	}
+	/* enable secondary indexes now */
+	secondary_indexes_enabled = true;
 }
 
 i32
diff --git a/mod/box/tree.m b/mod/box/tree.m
index 1546651ca07304cc7472edf7eceed3be2fe5434d..9ad7a70897308451c6d52cd932528ba5d9d0c77b 100644
--- a/mod/box/tree.m
+++ b/mod/box/tree.m
@@ -50,7 +50,7 @@ u64_cmp(u64 a, u64 b)
 }
 
 /**
- * Tuple addrress comparison.
+ * Tuple address comparison.
  */
 static inline int
 ta_cmp(struct box_tuple *tuple_a, struct box_tuple *tuple_b)
diff --git a/src/admin.m b/src/admin.m
index 4067c2ee64e3605a48f3bf3524d948d08037528f..bad711f261517e8bcac59ffbd255bef0cc4f9e7c 100644
--- a/src/admin.m
+++ b/src/admin.m
@@ -1,5 +1,5 @@
 
-#line 1 "core/admin.rl"
+#line 1 "src/admin.rl"
 /*
  * Copyright (C) 2010 Mail.RU
  * Copyright (C) 2010 Yuriy Vostrikov
@@ -38,6 +38,7 @@
 #include <say.h>
 #include <stat.h>
 #include <tarantool.h>
+#include <tarantool_lua.h>
 #include TARANTOOL_CONFIG
 #include <tbuf.h>
 #include <util.h>
@@ -67,7 +68,7 @@ static const char *help =
 static const char *unknown_command = "unknown command. try typing help." CRLF;
 
 
-#line 71 "core/admin.m"
+#line 72 "src/admin.m"
 static const int admin_start = 1;
 static const int admin_first_final = 135;
 static const int admin_error = 0;
@@ -75,7 +76,7 @@ static const int admin_error = 0;
 static const int admin_en_main = 1;
 
 
-#line 70 "core/admin.rl"
+#line 71 "src/admin.rl"
 
 
 
@@ -137,12 +138,12 @@ admin_dispatch(lua_State *L)
 	p = fiber->rbuf->data;
 
 	
-#line 141 "core/admin.m"
+#line 142 "src/admin.m"
 	{
 	cs = admin_start;
 	}
 
-#line 146 "core/admin.m"
+#line 147 "src/admin.m"
 	{
 	if ( p == pe )
 		goto _test_eof;
@@ -205,15 +206,15 @@ case 6:
 	}
 	goto st0;
 tr13:
-#line 240 "core/admin.rl"
+#line 241 "src/admin.rl"
 	{slab_validate(); ok(out);}
 	goto st135;
 tr20:
-#line 228 "core/admin.rl"
+#line 229 "src/admin.rl"
 	{return 0;}
 	goto st135;
 tr25:
-#line 155 "core/admin.rl"
+#line 156 "src/admin.rl"
 	{
 			start(out);
 			tbuf_append(out, help, strlen(help));
@@ -221,9 +222,9 @@ tr25:
 		}
 	goto st135;
 tr36:
-#line 214 "core/admin.rl"
+#line 215 "src/admin.rl"
 	{strend = p;}
-#line 161 "core/admin.rl"
+#line 162 "src/admin.rl"
 	{
 			strstart[strend-strstart]='\0';
 			start(out);
@@ -232,7 +233,7 @@ tr36:
 		}
 	goto st135;
 tr43:
-#line 168 "core/admin.rl"
+#line 169 "src/admin.rl"
 	{
 			if (reload_cfg(err))
 				fail(out, err);
@@ -241,11 +242,11 @@ tr43:
 		}
 	goto st135;
 tr67:
-#line 238 "core/admin.rl"
+#line 239 "src/admin.rl"
 	{coredump(60); ok(out);}
 	goto st135;
 tr76:
-#line 175 "core/admin.rl"
+#line 176 "src/admin.rl"
 	{
 			int ret = snapshot(NULL, 0);
 
@@ -260,9 +261,9 @@ tr76:
 		}
 	goto st135;
 tr98:
-#line 224 "core/admin.rl"
+#line 225 "src/admin.rl"
 	{ state = false; }
-#line 188 "core/admin.rl"
+#line 189 "src/admin.rl"
 	{
 			strstart[strend-strstart] = '\0';
 			if (errinj_set_byname(strstart, state)) {
@@ -274,9 +275,9 @@ tr98:
 		}
 	goto st135;
 tr101:
-#line 223 "core/admin.rl"
+#line 224 "src/admin.rl"
 	{ state = true; }
-#line 188 "core/admin.rl"
+#line 189 "src/admin.rl"
 	{
 			strstart[strend-strstart] = '\0';
 			if (errinj_set_byname(strstart, state)) {
@@ -288,7 +289,7 @@ tr101:
 		}
 	goto st135;
 tr117:
-#line 131 "core/admin.rl"
+#line 132 "src/admin.rl"
 	{
 			tarantool_cfg_iterator_t *i;
 			char *key, *value;
@@ -308,15 +309,15 @@ tr117:
 		}
 	goto st135;
 tr131:
-#line 231 "core/admin.rl"
+#line 232 "src/admin.rl"
 	{start(out); fiber_info(out); end(out);}
 	goto st135;
 tr137:
-#line 230 "core/admin.rl"
+#line 231 "src/admin.rl"
 	{start(out); tarantool_info(out); end(out);}
 	goto st135;
 tr146:
-#line 149 "core/admin.rl"
+#line 150 "src/admin.rl"
 	{
 			start(out);
 			errinj_info(out);
@@ -324,33 +325,33 @@ tr146:
 		}
 	goto st135;
 tr152:
-#line 234 "core/admin.rl"
+#line 235 "src/admin.rl"
 	{start(out); palloc_stat(out); end(out);}
 	goto st135;
 tr160:
-#line 233 "core/admin.rl"
+#line 234 "src/admin.rl"
 	{start(out); slab_stat(out); end(out);}
 	goto st135;
 tr164:
-#line 235 "core/admin.rl"
+#line 236 "src/admin.rl"
 	{start(out); stat_print(out);end(out);}
 	goto st135;
 st135:
 	if ( ++p == pe )
 		goto _test_eof135;
 case 135:
-#line 343 "core/admin.m"
+#line 344 "src/admin.m"
 	goto st0;
 tr14:
-#line 240 "core/admin.rl"
+#line 241 "src/admin.rl"
 	{slab_validate(); ok(out);}
 	goto st7;
 tr21:
-#line 228 "core/admin.rl"
+#line 229 "src/admin.rl"
 	{return 0;}
 	goto st7;
 tr26:
-#line 155 "core/admin.rl"
+#line 156 "src/admin.rl"
 	{
 			start(out);
 			tbuf_append(out, help, strlen(help));
@@ -358,9 +359,9 @@ tr26:
 		}
 	goto st7;
 tr37:
-#line 214 "core/admin.rl"
+#line 215 "src/admin.rl"
 	{strend = p;}
-#line 161 "core/admin.rl"
+#line 162 "src/admin.rl"
 	{
 			strstart[strend-strstart]='\0';
 			start(out);
@@ -369,7 +370,7 @@ tr37:
 		}
 	goto st7;
 tr44:
-#line 168 "core/admin.rl"
+#line 169 "src/admin.rl"
 	{
 			if (reload_cfg(err))
 				fail(out, err);
@@ -378,11 +379,11 @@ tr44:
 		}
 	goto st7;
 tr68:
-#line 238 "core/admin.rl"
+#line 239 "src/admin.rl"
 	{coredump(60); ok(out);}
 	goto st7;
 tr77:
-#line 175 "core/admin.rl"
+#line 176 "src/admin.rl"
 	{
 			int ret = snapshot(NULL, 0);
 
@@ -397,9 +398,9 @@ tr77:
 		}
 	goto st7;
 tr99:
-#line 224 "core/admin.rl"
+#line 225 "src/admin.rl"
 	{ state = false; }
-#line 188 "core/admin.rl"
+#line 189 "src/admin.rl"
 	{
 			strstart[strend-strstart] = '\0';
 			if (errinj_set_byname(strstart, state)) {
@@ -411,9 +412,9 @@ tr99:
 		}
 	goto st7;
 tr102:
-#line 223 "core/admin.rl"
+#line 224 "src/admin.rl"
 	{ state = true; }
-#line 188 "core/admin.rl"
+#line 189 "src/admin.rl"
 	{
 			strstart[strend-strstart] = '\0';
 			if (errinj_set_byname(strstart, state)) {
@@ -425,7 +426,7 @@ tr102:
 		}
 	goto st7;
 tr118:
-#line 131 "core/admin.rl"
+#line 132 "src/admin.rl"
 	{
 			tarantool_cfg_iterator_t *i;
 			char *key, *value;
@@ -445,15 +446,15 @@ tr118:
 		}
 	goto st7;
 tr132:
-#line 231 "core/admin.rl"
+#line 232 "src/admin.rl"
 	{start(out); fiber_info(out); end(out);}
 	goto st7;
 tr138:
-#line 230 "core/admin.rl"
+#line 231 "src/admin.rl"
 	{start(out); tarantool_info(out); end(out);}
 	goto st7;
 tr147:
-#line 149 "core/admin.rl"
+#line 150 "src/admin.rl"
 	{
 			start(out);
 			errinj_info(out);
@@ -461,22 +462,22 @@ tr147:
 		}
 	goto st7;
 tr153:
-#line 234 "core/admin.rl"
+#line 235 "src/admin.rl"
 	{start(out); palloc_stat(out); end(out);}
 	goto st7;
 tr161:
-#line 233 "core/admin.rl"
+#line 234 "src/admin.rl"
 	{start(out); slab_stat(out); end(out);}
 	goto st7;
 tr165:
-#line 235 "core/admin.rl"
+#line 236 "src/admin.rl"
 	{start(out); stat_print(out);end(out);}
 	goto st7;
 st7:
 	if ( ++p == pe )
 		goto _test_eof7;
 case 7:
-#line 480 "core/admin.m"
+#line 481 "src/admin.m"
 	if ( (*p) == 10 )
 		goto st135;
 	goto st0;
@@ -629,28 +630,28 @@ case 23:
 	}
 	goto tr33;
 tr33:
-#line 214 "core/admin.rl"
+#line 215 "src/admin.rl"
 	{strstart = p;}
 	goto st24;
 st24:
 	if ( ++p == pe )
 		goto _test_eof24;
 case 24:
-#line 640 "core/admin.m"
+#line 641 "src/admin.m"
 	switch( (*p) ) {
 		case 10: goto tr36;
 		case 13: goto tr37;
 	}
 	goto st24;
 tr34:
-#line 214 "core/admin.rl"
+#line 215 "src/admin.rl"
 	{strstart = p;}
 	goto st25;
 st25:
 	if ( ++p == pe )
 		goto _test_eof25;
 case 25:
-#line 654 "core/admin.m"
+#line 655 "src/admin.m"
 	switch( (*p) ) {
 		case 10: goto tr36;
 		case 13: goto tr37;
@@ -1100,28 +1101,28 @@ case 73:
 		goto tr91;
 	goto st0;
 tr91:
-#line 222 "core/admin.rl"
+#line 223 "src/admin.rl"
 	{ strstart = p; }
 	goto st74;
 st74:
 	if ( ++p == pe )
 		goto _test_eof74;
 case 74:
-#line 1111 "core/admin.m"
+#line 1112 "src/admin.m"
 	if ( (*p) == 32 )
 		goto tr92;
 	if ( 33 <= (*p) && (*p) <= 126 )
 		goto st74;
 	goto st0;
 tr92:
-#line 222 "core/admin.rl"
+#line 223 "src/admin.rl"
 	{ strend = p; }
 	goto st75;
 st75:
 	if ( ++p == pe )
 		goto _test_eof75;
 case 75:
-#line 1125 "core/admin.m"
+#line 1126 "src/admin.m"
 	switch( (*p) ) {
 		case 32: goto st75;
 		case 111: goto st76;
@@ -1813,7 +1814,7 @@ case 134:
 	_out: {}
 	}
 
-#line 246 "core/admin.rl"
+#line 247 "src/admin.rl"
 
 
 	tbuf_ltrim(fiber->rbuf, (void *)pe - (void *)fiber->rbuf->data);
diff --git a/src/admin.rl b/src/admin.rl
index 59d9573b93c72d80e3ce4b36abb5183010f5c26d..f79cb42291eb14f9a28a6e327e2a31e3c57e4fdf 100644
--- a/src/admin.rl
+++ b/src/admin.rl
@@ -36,6 +36,7 @@
 #include <say.h>
 #include <stat.h>
 #include <tarantool.h>
+#include <tarantool_lua.h>
 #include TARANTOOL_CONFIG
 #include <tbuf.h>
 #include <util.h>
diff --git a/src/tarantool.m b/src/tarantool.m
index d7ec42b88d0e775aa6290c4758474772b8d99389..cccf7859f03829b32ec3864e3edbbf43ab256a73 100644
--- a/src/tarantool.m
+++ b/src/tarantool.m
@@ -58,6 +58,7 @@
 #include <third_party/gopt/gopt.h>
 #include <cfg/warning.h>
 #include "tarantool_pthread.h"
+#include "tarantool_lua.h"
 
 
 static pid_t master_pid;
diff --git a/src/tarantool_lua.m b/src/tarantool_lua.m
index 7759f2045167a5f1698887037fdfa64dcbb9ab21..e4afd5b20c0a904b5f516129341da6f363096ab0 100644
--- a/src/tarantool_lua.m
+++ b/src/tarantool_lua.m
@@ -28,7 +28,8 @@
  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include "tarantool.h"
+#include <tarantool_lua.h>
+#include <tarantool.h>
 
 #include "lua.h"
 #include "lauxlib.h"