From 59705b82a8044118e3ecd379113004682c8d8e24 Mon Sep 17 00:00:00 2001
From: Roman Tsisyk <roman@tsisyk.com>
Date: Fri, 21 Feb 2014 12:55:21 +0400
Subject: [PATCH] Reimplement iterators using FFI

This patch replaces Lua/C bindings to iterator by FFI.
---
 src/box/bitset_index.cc          |   2 +-
 src/box/hash_index.cc            |   2 +-
 src/box/lua/index.cc             | 215 ++++---------------------------
 src/box/lua/index.h              |  16 +++
 src/box/lua/schema.lua           |  71 +++++++---
 src/box/lua/tuple.lua            |  18 ++-
 src/box/tree_index.cc            |   5 +-
 src/box/tuple.h                  |   2 +-
 src/ffisyms.cc                   |   5 +-
 src/lua/msgpackffi.lua           |  10 +-
 test/big/hash_multipart.result   |   2 +-
 test/big/hash_multipart.test.lua |   2 +-
 test/big/iterator.result         |   5 +-
 test/big/lua.result              |   5 +-
 test/big/sql.result              |   2 +-
 test/big/sql.test.py             |   2 +-
 test/big/tree_pk.result          |   4 +-
 test/big/tree_pk.test.lua        |   4 +-
 test/box/crossjoin.result        |   4 +-
 test/box/crossjoin.test.lua      |   4 +-
 test/box/errinj_index.result     |   8 +-
 test/box/errinj_index.test.lua   |   8 +-
 test/box/tuple.result            |  10 +-
 test/wal/lua.result              |   2 +-
 test/wal/lua.test.lua            |   2 +-
 test/wal/oom.result              |   2 +-
 test/wal/oom.test.lua            |   2 +-
 27 files changed, 164 insertions(+), 250 deletions(-)

diff --git a/src/box/bitset_index.cc b/src/box/bitset_index.cc
index 0b9f9b2be5..8523aa48fb 100644
--- a/src/box/bitset_index.cc
+++ b/src/box/bitset_index.cc
@@ -204,7 +204,7 @@ BitsetIndex::initIterator(struct iterator *iterator, enum iterator_type type,
 			  const char *key, uint32_t part_count) const
 {
 	assert(iterator->free == bitset_index_iterator_free);
-	assert(part_count != 0 || key == NULL);
+	assert(part_count == 0 || key != NULL);
 	(void) part_count;
 
 	struct bitset_index_iterator *it = bitset_index_iterator(iterator);
diff --git a/src/box/hash_index.cc b/src/box/hash_index.cc
index b4aa976d52..3a270e28c8 100644
--- a/src/box/hash_index.cc
+++ b/src/box/hash_index.cc
@@ -291,7 +291,7 @@ void
 HashIndex::initIterator(struct iterator *ptr, enum iterator_type type,
 			const char *key, uint32_t part_count) const
 {
-	assert(key != NULL || part_count == 0);
+	assert(part_count == 0 || key != NULL);
 	(void) part_count;
 	assert(ptr->free == hash_iterator_free);
 
diff --git a/src/box/lua/index.cc b/src/box/lua/index.cc
index cf1b2cbe4b..782dbf9eda 100644
--- a/src/box/lua/index.cc
+++ b/src/box/lua/index.cc
@@ -39,7 +39,6 @@
  */
 
 static const char *indexlib_name = "box.index";
-static const char *iteratorlib_name = "box.index.iterator";
 
 /* Index userdata. */
 struct lbox_index
@@ -53,47 +52,6 @@ struct lbox_index
 	int sc_version;
 };
 
-static struct iterator *
-lbox_checkiterator(struct lua_State *L, int i)
-{
-	struct iterator **it = (struct iterator **)
-			luaL_checkudata(L, i, iteratorlib_name);
-	assert(it != NULL);
-	return *it;
-}
-
-static void
-lbox_pushiterator(struct lua_State *L, Index *index,
-		  struct iterator *it, enum iterator_type type,
-		  const char *key, size_t key_size, uint32_t part_count)
-{
-	struct lbox_iterator_udata {
-		struct iterator *it;
-		char key[];
-	};
-
-	struct lbox_iterator_udata *udata = (struct lbox_iterator_udata *)
-		lua_newuserdata(L, sizeof(*udata) + key_size);
-	luaL_getmetatable(L, iteratorlib_name);
-	lua_setmetatable(L, -2);
-
-	udata->it = it;
-	if (key) {
-		memcpy(udata->key, key, key_size);
-		key = udata->key;
-	}
-	key_validate(index->key_def, type, key, part_count);
-	index->initIterator(it, type, key, part_count);
-}
-
-static int
-lbox_iterator_gc(struct lua_State *L)
-{
-	struct iterator *it = lbox_checkiterator(L, -1);
-	it->free(it);
-	return 0;
-}
-
 static Index *
 lua_checkindex(struct lua_State *L, int i)
 {
@@ -166,144 +124,6 @@ lbox_index_random(struct lua_State *L)
 	return 1;
 }
 
-
-/*
- * Lua iterator over a Taratnool/Box index.
- *
- *	(iteration_state, tuple) = index.next(index, [params])
- *
- * When [params] are absent or nil
- * returns a pointer to a new ALL iterator and
- * to the first tuple (or nil, if the index is
- * empty).
- *
- * When [params] is a userdata,
- * i.e. we're inside an iteration loop, retrieves
- * the next tuple from the iterator.
- *
- * Otherwise, [params] can be used to seed
- * a new iterator with iterator type and
- * type-specific arguments. For exaple,
- * for GE iterator, a list of Lua scalars
- * cann follow the box.index.GE: this will
- * start iteration from the offset specified by
- * the given (multipart) key.
- *
- * @return Returns an iterator object, either created
- *         or taken from Lua stack.
- */
-
-static inline struct iterator *
-lbox_create_iterator(struct lua_State *L)
-{
-	Index *index = lua_checkindex(L, 1);
-	int top = lua_gettop(L);
-
-	/* Create a new iterator. */
-	enum iterator_type type = ITER_ALL;
-	uint32_t key_part_count = 0;
-	const char *key = NULL;
-	size_t key_size = 0;
-
-
-	if (top > 2 && !lua_isnil(L, 3)) {
-		if (!lua_istable(L, 3))
-			luaL_error(L, "usage: index:iterator(key[, opts ])");
-		lua_pushliteral(L, "iterator");
-		lua_gettable(L, 3);
-
-		if (!lua_isnil(L, -1)) {
-			type = (enum iterator_type) luaL_checkint(L, -1);
-			if (type < ITER_ALL || type >= iterator_type_MAX)
-				luaL_error(L, "unknown iterator type: %d", type);
-		}
-		lua_pop(L, 1);
-	}
-
-
-	RegionGuard region_guard(&fiber()->gc);
-
-	if (top > 1 && !lua_isnil(L, 2)) {
-		if (lua_istable(L, 2) && luaL_getn(L, 2) == 0)
-			goto create;
-
-		struct tbuf *b = tbuf_new(&fiber()->gc);
-		luamp_encodestack(L, b, 2, 2);
-		key = b->data;
-		assert(b->size > 0);
-		if (unlikely(mp_typeof(*key) != MP_ARRAY))
-			tnt_raise(ClientError, ER_TUPLE_NOT_ARRAY);
-		key_part_count = mp_decode_array(&key);
-		key_size = b->data + b->size - key;
-	}
-
-	create:
-
-	struct iterator *it = index->allocIterator();
-	lbox_pushiterator(L, index, it, type, key, key_size, key_part_count);
-	return it;
-}
-
-/**
- * Lua-style next() function, for use in pairs().
- * @example:
- * for k, v in box.space[0].index[0].idx.next, box.space[0].index[0].idx, nil do
- *	print(v)
- * end
- */
-static int
-lbox_index_next(struct lua_State *L)
-{
-	int argc = lua_gettop(L);
-	struct iterator *it = NULL;
-	if (argc == 2 && lua_type(L, 2) == LUA_TUSERDATA) {
-		/*
-		 * Apart from the index itself, we have only one
-		 * other argument, and it's a userdata: must be
-		 * iteration state created before.
-		 */
-		it = lbox_checkiterator(L, 2);
-	} else {
-		it = lbox_create_iterator(L);
-	}
-	struct tuple *tuple = it->next(it);
-	/* If tuple is NULL, pushes nil as end indicator. */
-	lbox_pushtuple(L, tuple);
-	return tuple ? 2 : 1;
-}
-
-/** iterator() closure function. */
-static int
-lbox_index_iterator_closure(struct lua_State *L)
-{
-	/* Extract closure arguments. */
-	struct iterator *it = lbox_checkiterator(L, lua_upvalueindex(1));
-
-	struct tuple *tuple = it->next(it);
-
-	/* If tuple is NULL, push nil as end indicator. */
-	lbox_pushtuple(L, tuple);
-	return 1;
-}
-
-/**
- * @brief Create iterator closure over a Taratnool/Box index.
- * @example lua it = box.space[0].index[0]:iterator(box.index.GE, 1);
- *   print(it(), it()).
- * @param L lua stack
- * @see http://www.lua.org/pil/7.1.html
- * @return number of return values put on the stack
- */
-static int
-lbox_index_iterator(struct lua_State *L)
-{
-	/* Create iterator and push it onto the stack. */
-	(void) lbox_create_iterator(L);
-	lua_pushcclosure(L, &lbox_index_iterator_closure, 1);
-	return 1;
-}
-
-
 static void
 box_index_init_iterator_types(struct lua_State *L, int idx)
 {
@@ -317,6 +137,33 @@ box_index_init_iterator_types(struct lua_State *L, int idx)
 
 /* }}} */
 
+/* {{{ box.index.iterator Lua library: index iterators */
+
+struct iterator *
+boxffi_index_iterator(uint32_t space_id, uint32_t index_id, int type,
+		      const char *key)
+{
+	struct iterator *it = NULL;
+	enum iterator_type itype = (enum iterator_type) type;
+	try {
+		struct space *space = space_find(space_id);
+		Index *index = index_find(space, index_id);
+		assert(mp_typeof(*key) == MP_ARRAY); /* checked by Lua */
+		uint32_t part_count = mp_decode_array(&key);
+		key_validate(index->key_def, itype, key, part_count);
+		it = index->allocIterator();
+		index->initIterator(it, itype, key, part_count);
+		return it;
+	} catch(Exception *) {
+		if (it)
+			it->free(it);
+		/* will be hanled by box.raise() in Lua */
+		return NULL;
+	}
+}
+
+/* }}} */
+
 void
 box_lua_index_init(struct lua_State *L)
 {
@@ -325,13 +172,6 @@ box_lua_index_init(struct lua_State *L)
 		{"__len", lbox_index_len},
 		{"part_count", lbox_index_part_count},
 		{"random", lbox_index_random},
-		{"next", lbox_index_next},
-		{"iterator", lbox_index_iterator},
-		{NULL, NULL}
-	};
-
-	static const struct luaL_reg lbox_iterator_meta[] = {
-		{"__gc", lbox_iterator_gc},
 		{NULL, NULL}
 	};
 
@@ -346,5 +186,4 @@ box_lua_index_init(struct lua_State *L)
 	luaL_register(L, "box.index", indexlib);
 	box_index_init_iterator_types(L, -2);
 	lua_pop(L, 1);
-	luaL_register_type(L, iteratorlib_name, lbox_iterator_meta);
 }
diff --git a/src/box/lua/index.h b/src/box/lua/index.h
index a16fba724a..757ed9e4d5 100644
--- a/src/box/lua/index.h
+++ b/src/box/lua/index.h
@@ -28,9 +28,25 @@
  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
+#include <stdint.h>
+
 struct lua_State;
+struct iterator;
 
 void
 box_lua_index_init(struct lua_State *L);
 
+#if defined(__cplusplus)
+extern "C" {
+#endif /* defined(__cplusplus) */
+
+struct iterator *
+boxffi_index_iterator(uint32_t space_id, uint32_t index_id, int type,
+		      const char *key);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif /* defined(__cplusplus) */
+
 #endif /* INCLUDES_TARANTOOL_BOX_LUA_INDEX_H */
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index 63297f3456..fe90f5b0cc 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -4,7 +4,17 @@ local ffi = require('ffi')
 ffi.cdef[[
     struct space *space_by_id(uint32_t id);
     void space_run_triggers(struct space *space, bool yesno);
+
+    struct iterator {
+        struct tuple *(*next)(struct iterator *);
+        void (*free)(struct iterator *);
+    };
+    struct iterator *
+    boxffi_index_iterator(uint32_t space_id, uint32_t index_id, int type,
+                  const char *key);
 ]]
+local builtin = ffi.C
+local msgpackffi = require('msgpackffi')
 
 box.schema.space = {}
 box.schema.space.create = function(name, options)
@@ -174,6 +184,25 @@ local function keify(key)
     return {key}
 end
 
+local iterator_mt = {
+    __call = function(iterator)
+        local tuple = iterator.cdata.next(iterator.cdata)
+        if tuple ~= nil then
+            return box.tuple.bless(tuple)
+        else
+            return nil
+        end
+    end;
+    __tostring = function(iterator)
+        return string.format("iterator on space %d index %d",
+            iterator.index.n, iterator.index.id)
+    end;
+}
+
+local iterator_cdata_gc = function(iterator_cdata)
+    return iterator_cdata.free(iterator_cdata)
+end
+
 function box.schema.space.bless(space)
     local index_mt = {}
     -- __len and __index
@@ -207,25 +236,31 @@ function box.schema.space.bless(space)
     index_mt.random = function(index, rnd) return index.idx:random(rnd) end
     -- iteration
     index_mt.iterator = function(index, key, opts)
-        if opts == nil then
-            opts = {}
-        elseif type(opts) ~= 'table' then
-            error("usage: index:iterator(key[, { option = value, ... })")
+        local pkey, pkey_end = msgpackffi.encode_tuple(key)
+        -- Use ALL for {} and nil keys and EQ for other keys
+        local itype = pkey + 1 < pkey_end and box.index.EQ or box.index.ALL
+        if opts then
+            if type(opts.iterator) == "number" then
+                itype = opts.iterator
+            elseif box.index[opts.iterator] then
+                itype = box.index[opts.iterator]
+            elseif opts.iterator ~= nil then
+                error("Wrong iterator type: "..tostring(opts.iterator))
+            end
         end
 
-        if type(opts.iterator) == 'string' then
-            if box.index[ opts.iterator ] == nil then
-                error("Wrong iterator type: " .. opts.iterator)
-            end
-            opts.iterator = box.index[ opts.iterator ]
+        local keybuf = ffi.string(pkey, pkey_end - pkey)
+        local cdata = builtin.boxffi_index_iterator(index.n, index.id,
+            itype, keybuf);
+        if cdata == nil then
+            box.raise()
         end
 
-        return index.idx:iterator(key, opts)
-    end
-    --
-    -- pairs
-    index_mt.pairs = function(index)
-        return index.idx.next, index.idx, nil
+        return setmetatable({
+            cdata = ffi.gc(cdata, iterator_cdata_gc);
+            keybuf = keybuf;
+            index = index;
+        }, iterator_mt)
     end
     -- index subtree size
     index_mt.count = function(index, key, opts)
@@ -382,7 +417,10 @@ function box.schema.space.bless(space)
         table.insert(tuple, 1, max + 1)
         return space:insert(tuple)
     end
-
+    space_mt.iterator = function(space, key)
+        check_index(space, 0)
+        return space.index[0]:iterator(key)
+    end
     space_mt.truncate = function(space)
         check_index(space, 0)
         local pk = space.index[0]
@@ -397,7 +435,6 @@ function box.schema.space.bless(space)
             end
         end
     end
-    space_mt.pairs = function(space) return space.index[0]:pairs() end
     space_mt.drop = function(space)
         return box.schema.space.drop(space.n)
     end
diff --git a/src/box/lua/tuple.lua b/src/box/lua/tuple.lua
index fe86828db3..501e2a7735 100644
--- a/src/box/lua/tuple.lua
+++ b/src/box/lua/tuple.lua
@@ -14,6 +14,8 @@ struct tuple
     char data[0];
 } __attribute__((packed));
 
+void
+tuple_ref(struct tuple *tuple, int count);
 uint32_t
 tuple_arity(const struct tuple *tuple);
 const char *
@@ -122,8 +124,18 @@ local methods = {
     end
 }
 
-local tuple_gc = cfuncs.__gc;
 local const_struct_tuple_ref_t = ffi.typeof('const struct tuple&')
+
+local tuple_gc = function(tuple)
+    builtin.tuple_ref(tuple, -1)
+end
+
+local tuple_bless = function(tuple)
+    -- update in-place, do not spent time calling tuple_ref
+    tuple._refs = tuple._refs + 1
+    return ffi.gc(ffi.cast(const_struct_tuple_ref_t, tuple), tuple_gc)
+end
+
 local tuple_field = function(tuple, field_n)
     local field = builtin.tuple_field(tuple, field_n)
     if field == nil then
@@ -165,5 +177,5 @@ ffi.metatype(tuple_iterator_t, {
 -- Remove the global variable
 cfuncs = nil
 
--- export tuple_gc  */
-box.tuple._gc = tuple_gc;
+-- internal api for box.select and iterators
+box.tuple.bless = tuple_bless
diff --git a/src/box/tree_index.cc b/src/box/tree_index.cc
index 0e6a24ace6..cfa95d93b4 100644
--- a/src/box/tree_index.cc
+++ b/src/box/tree_index.cc
@@ -294,7 +294,7 @@ void
 TreeIndex::initIterator(struct iterator *iterator, enum iterator_type type,
 			const char *key, uint32_t part_count) const
 {
-	assert(key != NULL || part_count == 0);
+	assert(part_count == 0 || key != NULL);
 	struct tree_iterator *it = tree_iterator(iterator);
 
 	if (part_count == 0) {
@@ -302,6 +302,9 @@ TreeIndex::initIterator(struct iterator *iterator, enum iterator_type type,
 		 * If no key is specified, downgrade equality
 		 * iterators to a full range.
 		 */
+		if (type < 0 || type > ITER_GT)
+			tnt_raise(ClientError, ER_UNSUPPORTED,
+				  "Tree index", "requested iterator type");
 		type = iterator_type_is_reverse(type) ? ITER_LE : ITER_GE;
 		key = NULL;
 	}
diff --git a/src/box/tuple.h b/src/box/tuple.h
index 0ea1555e5e..b608c0b435 100644
--- a/src/box/tuple.h
+++ b/src/box/tuple.h
@@ -175,7 +175,7 @@ tuple_new(struct tuple_format *format, const char *data, const char *end);
  *
  * @pre tuple->refs + count >= 0
  */
-void
+extern "C" void
 tuple_ref(struct tuple *tuple, int count);
 
 void
diff --git a/src/ffisyms.cc b/src/ffisyms.cc
index 887bda605d..8ac28fb7fb 100644
--- a/src/ffisyms.cc
+++ b/src/ffisyms.cc
@@ -1,6 +1,7 @@
 #include <bit/bit.h>
 #include <lib/msgpuck/msgpuck.h>
 #include <box/tuple.h>
+#include <box/lua/index.h>
 
 /*
  * A special hack to cc/ld to keep symbols in an optimized binary.
@@ -15,5 +16,7 @@ void *ffi_symbols[] = {
 	(void *) tuple_field,
 	(void *) tuple_rewind,
 	(void *) tuple_seek,
-	(void *) tuple_next
+	(void *) tuple_next,
+	(void *) tuple_ref,
+	(void *) boxffi_index_iterator
 };
diff --git a/src/lua/msgpackffi.lua b/src/lua/msgpackffi.lua
index db264974e3..bd45236fad 100644
--- a/src/lua/msgpackffi.lua
+++ b/src/lua/msgpackffi.lua
@@ -255,10 +255,10 @@ local function encode_r(buf, obj, level)
         if fun ~= nil then
             fun(buf, obj)
         else
-            error('unsupported FFI type: '..ffi.typeof(obj))
+            error("can not encode FFI type: '"..ffi.typeof(obj).."'")
         end
     else
-        error("Unsupported Lua type: "..type(obj))
+        error("can not encode Lua type: '"..type(obj).."'")
     end
 end
 
@@ -488,11 +488,13 @@ end
 
 local function encode_tuple(obj)
     tmpbuf:reset()
-    if type(obj) == "table" then
+    if obj == nil then
+        encode_fix(tmpbuf, 0x90, 0)  -- empty array
+    elseif type(obj) == "table" then
         encode_array(tmpbuf, #obj)
         local i
         for i=1,#obj,1 do
-            encode_r(tmpbuf, tuple[i], 1)
+            encode_r(tmpbuf, obj[i], 1)
         end
     else
         encode_fix(tmpbuf, 0x90, 1)  -- array of one element
diff --git a/test/big/hash_multipart.result b/test/big/hash_multipart.result
index 68520055ae..4eedee3310 100644
--- a/test/big/hash_multipart.result
+++ b/test/big/hash_multipart.result
@@ -52,7 +52,7 @@ hash:insert{1, 'bar', 1, '', 5}
 --# setopt delimiter ';'
 function box.select_all()
     local result = {}
-    for k, v in hash:pairs() do
+    for v in hash:iterator() do
         table.insert(result, v)
     end
     return result
diff --git a/test/big/hash_multipart.test.lua b/test/big/hash_multipart.test.lua
index b0ad415d98..23b32bb600 100644
--- a/test/big/hash_multipart.test.lua
+++ b/test/big/hash_multipart.test.lua
@@ -22,7 +22,7 @@ hash:insert{1, 'bar', 1, '', 5}
 --# setopt delimiter ';'
 function box.select_all()
     local result = {}
-    for k, v in hash:pairs() do
+    for v in hash:iterator() do
         table.insert(result, v)
     end
     return result
diff --git a/test/big/iterator.result b/test/big/iterator.result
index 47dc0d0b80..86c43987a1 100644
--- a/test/big/iterator.result
+++ b/test/big/iterator.result
@@ -886,12 +886,13 @@ iterate('tweedledum', 'i5', 1, 3, box.index.EQ, 'sid_005', 'tid_995', 'a')
 -------------------------------------------------------------------------------
 space.index['primary']:iterator({}, {iterator = -666 })
 ---
-- error: 'unknown iterator type: -666'
+- error: Tree index does not support requested iterator type
 ...
 -- Test cases for #123: box.index.count does not check arguments properly
 space.index['primary']:iterator(function() end, { iterator = box.index.EQ })
 ---
-- error: 'msgpack.encode: can not encode Lua type ''function'''
+- error: '[string "-- msgpackffi.lua (internal file)..."]:261: can not encode Lua
+    type: ''function'''
 ...
 space:drop()
 ---
diff --git a/test/big/lua.result b/test/big/lua.result
index 5eb4456fa4..0f93ba12f8 100644
--- a/test/big/lua.result
+++ b/test/big/lua.result
@@ -466,7 +466,7 @@ t = {}
 ...
 index:iterator('sid_t', { iterator = 'wrong_iterator_type' })
 ---
-- error: '[string "-- schema.lua (internal file)..."]:218: Wrong iterator type: wrong_iterator_type'
+- error: '[string "-- schema.lua (internal file)..."]:248: Wrong iterator type: wrong_iterator_type'
 ...
 index = nil
 ---
@@ -568,7 +568,8 @@ space.index['i1']:count()
 -- Test cases for #123: box.index.count does not check arguments properly
 space.index['i1']:count(function() end)
 ---
-- error: 'msgpack.encode: can not encode Lua type ''function'''
+- error: '[string "-- msgpackffi.lua (internal file)..."]:261: can not encode Lua
+    type: ''function'''
 ...
 space:drop()
 ---
diff --git a/test/big/sql.result b/test/big/sql.result
index c232a4b78b..8e358ad5d9 100644
--- a/test/big/sql.result
+++ b/test/big/sql.result
@@ -228,7 +228,7 @@ insert into t0 values (41234567, 'part1_a', 'part2_a')
 l = {}
 ---
 ...
-for k, v in s:pairs() do table.insert(l, v) end
+for v in s:iterator() do table.insert(l, v) end
 ---
 ...
 return l
diff --git a/test/big/sql.test.py b/test/big/sql.test.py
index 09a10002c7..b3d2f65da7 100644
--- a/test/big/sql.test.py
+++ b/test/big/sql.test.py
@@ -90,7 +90,7 @@ sql("insert into t0 values (21234567, 'part1', 'part2_a')")
 sql("insert into t0 values (31234567, 'part1_a', 'part2')")
 sql("insert into t0 values (41234567, 'part1_a', 'part2_a')")
 admin("l = {}")
-admin("for k, v in s:pairs() do table.insert(l, v) end")
+admin("for v in s:iterator() do table.insert(l, v) end")
 admin("return l")
 sql("select * from t0 where k0=01234567")
 sql("select * from t0 where k0=11234567")
diff --git a/test/big/tree_pk.result b/test/big/tree_pk.result
index 30c3038652..65296a7b60 100644
--- a/test/big/tree_pk.result
+++ b/test/big/tree_pk.result
@@ -137,8 +137,8 @@ s1:delete{'third'}
 --# setopt delimiter ';'
 function crossjoin(space0, space1, limit)
     local result = {}
-    for k0, v0 in space0:pairs() do
-        for k1, v1 in space1:pairs() do
+    for v0 in space0:iterator() do
+        for v1 in space1:iterator() do
             if limit <= 0 then
                 return result
             end
diff --git a/test/big/tree_pk.test.lua b/test/big/tree_pk.test.lua
index 4cb76faebd..9c600a6ef6 100644
--- a/test/big/tree_pk.test.lua
+++ b/test/big/tree_pk.test.lua
@@ -52,8 +52,8 @@ s1:delete{'third'}
 --# setopt delimiter ';'
 function crossjoin(space0, space1, limit)
     local result = {}
-    for k0, v0 in space0:pairs() do
-        for k1, v1 in space1:pairs() do
+    for v0 in space0:iterator() do
+        for v1 in space1:iterator() do
             if limit <= 0 then
                 return result
             end
diff --git a/test/box/crossjoin.result b/test/box/crossjoin.result
index d3f7e7de9c..b3c9739ae9 100644
--- a/test/box/crossjoin.result
+++ b/test/box/crossjoin.result
@@ -7,8 +7,8 @@ space:create_index('primary', { type = 'tree' })
 --# setopt delimiter ';'
 function crossjoin(space0, space1, limit)
   local result = {}
-  for k0, v0 in space0:pairs() do
-    for k1, v1 in space1:pairs() do
+  for v0 in space0:iterator() do
+    for v1 in space1:iterator() do
       if limit <= 0 then
         return result
       end
diff --git a/test/box/crossjoin.test.lua b/test/box/crossjoin.test.lua
index 5d3c4e58a7..b7839c1f4e 100644
--- a/test/box/crossjoin.test.lua
+++ b/test/box/crossjoin.test.lua
@@ -3,8 +3,8 @@ space:create_index('primary', { type = 'tree' })
 --# setopt delimiter ';'
 function crossjoin(space0, space1, limit)
   local result = {}
-  for k0, v0 in space0:pairs() do
-    for k1, v1 in space1:pairs() do
+  for v0 in space0:iterator() do
+    for v1 in space1:iterator() do
       if limit <= 0 then
         return result
       end
diff --git a/test/box/errinj_index.result b/test/box/errinj_index.result
index 86b05a62aa..3c936cfacc 100644
--- a/test/box/errinj_index.result
+++ b/test/box/errinj_index.result
@@ -30,7 +30,7 @@ res
 res = {}
 ---
 ...
-for t in s.index[0]:iterator(box.index.ALL) do table.insert(res, t) end
+for t in s.index[0]:iterator() do table.insert(res, t) end
 ---
 ...
 res
@@ -80,7 +80,7 @@ s:delete{1}
 res = {}
 ---
 ...
-for t in s.index[0]:iterator(box.index.ALL) do table.insert(res, t) end
+for t in s.index[0]:iterator() do table.insert(res, t) end
 ---
 - error: Failed to allocate 196 bytes in TreeIndex for init iterator
 ...
@@ -126,7 +126,7 @@ s:delete{2}
 ---
 - [2, 2, 'test2']
 ...
-s.index[0]:iterator(box.index.ALL)
+s.index[0]:iterator()
 ---
 - error: Failed to allocate 200 bytes in TreeIndex for init iterator
 ...
@@ -168,7 +168,7 @@ s:delete{3}
 ---
 - [3, 3, 'test3']
 ...
-s.index[0]:iterator(box.index.ALL)
+s.index[0]:iterator()
 ---
 - error: Failed to allocate 200 bytes in TreeIndex for init iterator
 ...
diff --git a/test/box/errinj_index.test.lua b/test/box/errinj_index.test.lua
index 3ef07a4ad0..1341c396f2 100644
--- a/test/box/errinj_index.test.lua
+++ b/test/box/errinj_index.test.lua
@@ -8,7 +8,7 @@ res = {}
 for i = 1,10 do table.insert(res, s:select{i}) end
 res
 res = {}
-for t in s.index[0]:iterator(box.index.ALL) do table.insert(res, t) end
+for t in s.index[0]:iterator() do table.insert(res, t) end
 res
 
 box.errinj.set("ERRINJ_TREE_ALLOC", true)
@@ -19,7 +19,7 @@ res
 for i = 501,1000 do s:insert{i, i} end
 s:delete{1}
 res = {}
-for t in s.index[0]:iterator(box.index.ALL) do table.insert(res, t) end
+for t in s.index[0]:iterator() do table.insert(res, t) end
 res
 
 -- reserve memory for iterator in index. last insert may increase tree depth
@@ -33,7 +33,7 @@ res
 
 for i = 1001,1500 do s:insert{i, i} end
 s:delete{2}
-s.index[0]:iterator(box.index.ALL)
+s.index[0]:iterator()
 
 -- reserve memory for iterator in index. last insert may increase tree depth
 -- (if rebalance was not initiated)
@@ -46,7 +46,7 @@ for i = 1,10 do table.insert(res, (s:select{i})) end
 res
 for i = 1501,2000 do s:insert{i, i} end
 s:delete{3}
-s.index[0]:iterator(box.index.ALL)
+s.index[0]:iterator()
 
 box.errinj.set("ERRINJ_TREE_ALLOC", false)
 
diff --git a/test/box/tuple.result b/test/box/tuple.result
index 097b52e9cd..c4d6442694 100644
--- a/test/box/tuple.result
+++ b/test/box/tuple.result
@@ -377,15 +377,15 @@ t:next(3)
 ...
 t:next(4)
 ---
-- error: '[string "-- tuple.lua (internal file)..."]:63: error: invalid key to ''next'''
+- error: '[string "-- tuple.lua (internal file)..."]:65: error: invalid key to ''next'''
 ...
 t:next(-1)
 ---
-- error: '[string "-- tuple.lua (internal file)..."]:63: error: invalid key to ''next'''
+- error: '[string "-- tuple.lua (internal file)..."]:65: error: invalid key to ''next'''
 ...
 t:next("fdsaf")
 ---
-- error: '[string "-- tuple.lua (internal file)..."]:46: error: invalid key to ''next'''
+- error: '[string "-- tuple.lua (internal file)..."]:48: error: invalid key to ''next'''
 ...
 box.tuple.new({'x', 'y', 'z'}):next()
 ---
@@ -397,7 +397,7 @@ t=space:insert{1953719668}
 ...
 t:next(1684234849)
 ---
-- error: '[string "-- tuple.lua (internal file)..."]:63: error: invalid key to ''next'''
+- error: '[string "-- tuple.lua (internal file)..."]:65: error: invalid key to ''next'''
 ...
 t:next(1)
 ---
@@ -552,7 +552,7 @@ r = {}
 ...
 for _state, val in t:pairs(10) do table.insert(r, val) end
 ---
-- error: '[string "-- tuple.lua (internal file)..."]:63: error: invalid key to ''next'''
+- error: '[string "-- tuple.lua (internal file)..."]:65: error: invalid key to ''next'''
 ...
 r
 ---
diff --git a/test/wal/lua.result b/test/wal/lua.result
index f9dfd7508d..46aa6065ab 100644
--- a/test/wal/lua.result
+++ b/test/wal/lua.result
@@ -17,7 +17,7 @@ for i = 1, 1000 do
         space:insert{tostring(j), os.time(), 1}
     end
     count = 0
-    for v in space.index[1]:iterator(box.index.ALL) do
+    for v in space.index[1]:iterator() do
         count = count + 1
     end
     if count ~= 30 then
diff --git a/test/wal/lua.test.lua b/test/wal/lua.test.lua
index ca3250aed2..6c29dba3b3 100644
--- a/test/wal/lua.test.lua
+++ b/test/wal/lua.test.lua
@@ -12,7 +12,7 @@ for i = 1, 1000 do
         space:insert{tostring(j), os.time(), 1}
     end
     count = 0
-    for v in space.index[1]:iterator(box.index.ALL) do
+    for v in space.index[1]:iterator() do
         count = count + 1
     end
     if count ~= 30 then
diff --git a/test/wal/oom.result b/test/wal/oom.result
index f78306e991..54f21b9a0c 100644
--- a/test/wal/oom.result
+++ b/test/wal/oom.result
@@ -78,7 +78,7 @@ t = {}
 ---
 ...
 --# setopt delimiter ';'
-for k,v in space:pairs() do
+for v in space:iterator() do
     table.insert(t, v)
     i = i + 1
     if i == 50 then
diff --git a/test/wal/oom.test.lua b/test/wal/oom.test.lua
index 2fccb28cd8..6b30d09d21 100644
--- a/test/wal/oom.test.lua
+++ b/test/wal/oom.test.lua
@@ -31,7 +31,7 @@ space.index['primary']:select{15}
 i = 0
 t = {}
 --# setopt delimiter ';'
-for k,v in space:pairs() do
+for v in space:iterator() do
     table.insert(t, v)
     i = i + 1
     if i == 50 then
-- 
GitLab