diff --git a/src/box/index.cc b/src/box/index.cc
index eba9c8c0b60865ef7b8068e554dd5febca045dbf..02a6cc56a8165a26cc8c8259e43810a1802c6b7f 100644
--- a/src/box/index.cc
+++ b/src/box/index.cc
@@ -757,8 +757,8 @@ generic_index_create_iterator(struct index *base, enum iterator_type type,
 }
 
 
-struct snapshot_iterator *
-generic_index_create_snapshot_iterator(struct index *index)
+struct index_read_view *
+generic_index_create_read_view(struct index *index)
 {
 	diag_set(UnsupportedIndexFeature, index->def, "consistent read view");
 	return NULL;
diff --git a/src/box/index.h b/src/box/index.h
index 13a6fc757dbf185757c00b28577799c66e894fb9..6bb88d51ff1a63da081aab0fefed341598f48813 100644
--- a/src/box/index.h
+++ b/src/box/index.h
@@ -45,6 +45,8 @@ struct tuple;
 struct engine;
 struct space;
 struct index;
+struct index_read_view;
+struct index_read_view_iterator;
 struct index_def;
 struct key_def;
 struct info_handler;
@@ -359,24 +361,6 @@ iterator_next_internal(struct iterator *it, struct tuple **ret);
 void
 iterator_delete(struct iterator *it);
 
-/**
- * Snapshot iterator.
- * \sa index::create_snapshot_iterator().
- */
-struct snapshot_iterator {
-	/**
-	 * Iterate to the next tuple in the snapshot.
-	 * Returns a pointer to the tuple data and its
-	 * size or NULL if EOF.
-	 */
-	int (*next)(struct snapshot_iterator *,
-		    const char **data, uint32_t *size);
-	/**
-	 * Destroy the iterator.
-	 */
-	void (*free)(struct snapshot_iterator *);
-};
-
 /**
  * Check that the key has correct part count and correct part size
  * for use in an index iterator.
@@ -512,12 +496,8 @@ struct index_vtab {
 	struct iterator *(*create_iterator)(struct index *index,
 			enum iterator_type type,
 			const char *key, uint32_t part_count);
-	/**
-	 * Create an ALL iterator with personal read view so further
-	 * index modifications will not affect the iteration results.
-	 * Must be destroyed by iterator_delete() after usage.
-	 */
-	struct snapshot_iterator *(*create_snapshot_iterator)(struct index *);
+	/** Create an index read view. */
+	struct index_read_view *(*create_read_view)(struct index *index);
 	/** Introspection (index:stat()) */
 	void (*stat)(struct index *, struct info_handler *);
 	/**
@@ -567,6 +547,52 @@ struct index {
 	struct rlist full_scans;
 };
 
+/** Index read view virtual function table. */
+struct index_read_view_vtab {
+	/** Free an index read view instance. */
+	void
+	(*free)(struct index_read_view *rv);
+	/** Create an index read view iterator. */
+	struct index_read_view_iterator *
+	(*create_iterator)(struct index_read_view *rv, enum iterator_type type,
+			   const char *key, uint32_t part_count);
+};
+
+/**
+ * Index read view.
+ *
+ * An index read view is a frozen image of the index at the time of the read
+ * view creation. It only has read-only methods. The API is similar to the API
+ * of an index, but a read view returns raw data (not wrapped in struct tuple).
+ *
+ * Note about multi-threading: a read view may only be created and destroyed in
+ * the tx thread, but it may be used in any other thread.
+ */
+struct index_read_view {
+	/** Virtual function table. */
+	const struct index_read_view_vtab *vtab;
+};
+
+/** Iterator over an index read view. */
+struct index_read_view_iterator {
+	/** Free an index read view iterator instance. */
+	void
+	(*free)(struct index_read_view_iterator *iterator);
+	/**
+	 * Iterate to the next tuple in the read view.
+	 *
+	 * The tuple data and size are returned in the data and size arguments.
+	 * Note, the tuple may be allocated from the fiber region so one should
+	 * call region_truncate after using the data. On EOF the data is set to
+	 * NULL.
+	 *
+	 * Returns 0 on success. On error returns -1 and sets diag.
+	 */
+	int
+	(*next_raw)(struct index_read_view_iterator *iterator,
+		    const char **data, uint32_t *size);
+};
+
 /**
  * Check if replacement of an old tuple with a new one is
  * allowed.
@@ -747,10 +773,10 @@ index_create_iterator(struct index *index, enum iterator_type type,
 	return index->vtab->create_iterator(index, type, key, part_count);
 }
 
-static inline struct snapshot_iterator *
-index_create_snapshot_iterator(struct index *index)
+static inline struct index_read_view *
+index_create_read_view(struct index *index)
 {
-	return index->vtab->create_snapshot_iterator(index);
+	return index->vtab->create_read_view(index);
 }
 
 static inline void
@@ -795,6 +821,33 @@ index_end_build(struct index *index)
 	index->vtab->end_build(index);
 }
 
+static inline void
+index_read_view_delete(struct index_read_view *rv)
+{
+	rv->vtab->free(rv);
+}
+
+static inline struct index_read_view_iterator *
+index_read_view_create_iterator(struct index_read_view *rv,
+				enum iterator_type type,
+				const char *key, uint32_t part_count)
+{
+	return rv->vtab->create_iterator(rv, type, key, part_count);
+}
+
+static inline void
+index_read_view_iterator_delete(struct index_read_view_iterator *iterator)
+{
+	iterator->free(iterator);
+}
+
+static inline int
+index_read_view_iterator_next_raw(struct index_read_view_iterator *iterator,
+				  const char **data, uint32_t *size)
+{
+	return iterator->next_raw(iterator, data, size);
+}
+
 /*
  * Virtual method stubs.
  */
@@ -820,7 +873,8 @@ int generic_index_get(struct index *, const char *, uint32_t, struct tuple **);
 int generic_index_replace(struct index *, struct tuple *, struct tuple *,
 			  enum dup_replace_mode,
 			  struct tuple **, struct tuple **);
-struct snapshot_iterator *generic_index_create_snapshot_iterator(struct index *);
+struct index_read_view *
+generic_index_create_read_view(struct index *index);
 void generic_index_stat(struct index *, struct info_handler *);
 void generic_index_compact(struct index *);
 void generic_index_reset_stat(struct index *);
diff --git a/src/box/memtx_bitset.cc b/src/box/memtx_bitset.cc
index 654be6a20c488973238607a27294c07e43587834..c96316b0bcd37cdfc15ddb35347398f891c9f862 100644
--- a/src/box/memtx_bitset.cc
+++ b/src/box/memtx_bitset.cc
@@ -502,8 +502,7 @@ static const struct index_vtab memtx_bitset_index_vtab = {
 	/* .get = */ generic_index_get,
 	/* .replace = */ memtx_bitset_index_replace,
 	/* .create_iterator = */ memtx_bitset_index_create_iterator,
-	/* .create_snapshot_iterator = */
-		generic_index_create_snapshot_iterator,
+	/* .create_read_view = */ generic_index_create_read_view,
 	/* .stat = */ generic_index_stat,
 	/* .compact = */ generic_index_compact,
 	/* .reset_stat = */ generic_index_reset_stat,
diff --git a/src/box/memtx_engine.cc b/src/box/memtx_engine.cc
index 5a495ecf95c79f7dd8aec89e72ad196f19db11d8..ed29450cbe5ce6c5442b288f87540ba629e66165 100644
--- a/src/box/memtx_engine.cc
+++ b/src/box/memtx_engine.cc
@@ -654,7 +654,7 @@ checkpoint_write_tuple(struct xlog *l, uint32_t space_id, uint32_t group_id,
 struct checkpoint_entry {
 	uint32_t space_id;
 	uint32_t group_id;
-	struct snapshot_iterator *iterator;
+	struct index_read_view *rv;
 	struct rlist link;
 };
 
@@ -711,7 +711,7 @@ checkpoint_delete(struct checkpoint *ckpt)
 {
 	struct checkpoint_entry *entry, *tmp;
 	rlist_foreach_entry_safe(entry, &ckpt->entries, link, tmp) {
-		entry->iterator->free(entry->iterator);
+		index_read_view_delete(entry->rv);
 		free(entry);
 	}
 	memtx_allocators_close_read_view(ckpt->rv);
@@ -768,8 +768,8 @@ checkpoint_add_space(struct space *sp, void *data)
 
 	entry->space_id = space_id(sp);
 	entry->group_id = space_group_id(sp);
-	entry->iterator = index_create_snapshot_iterator(pk);
-	if (entry->iterator == NULL)
+	entry->rv = index_create_read_view(pk);
+	if (entry->rv == NULL)
 		return -1;
 
 	return 0;
@@ -827,13 +827,24 @@ checkpoint_f(va_list ap)
 		int rc;
 		uint32_t size;
 		const char *data;
-		struct snapshot_iterator *it = entry->iterator;
-		while ((rc = it->next(it, &data, &size)) == 0 && data != NULL) {
-			if (checkpoint_write_tuple(&snap, entry->space_id,
-					entry->group_id, data, size) != 0)
-				goto fail;
+		struct index_read_view_iterator *it =
+			index_read_view_create_iterator(entry->rv, ITER_ALL,
+							NULL, 0);
+		if (it == NULL)
+			goto fail;
+		while (true) {
+			rc = index_read_view_iterator_next_raw(it, &data,
+							       &size);
+			if (rc != 0 || data == NULL)
+				break;
+			rc = checkpoint_write_tuple(&snap, entry->space_id,
+						    entry->group_id,
+						    data, size);
+			if (rc != 0)
+				break;
 			fiber_gc();
 		}
+		index_read_view_iterator_delete(it);
 		if (rc != 0)
 			goto fail;
 	}
@@ -990,7 +1001,7 @@ memtx_engine_backup(struct engine *engine, const struct vclock *vclock,
 struct memtx_join_entry {
 	struct rlist in_ctx;
 	uint32_t space_id;
-	struct snapshot_iterator *iterator;
+	struct index_read_view *rv;
 };
 
 struct memtx_join_ctx {
@@ -1028,8 +1039,8 @@ memtx_join_add_space(struct space *space, void *arg)
 		return -1;
 	}
 	entry->space_id = space_id(space);
-	entry->iterator = index_create_snapshot_iterator(pk);
-	if (entry->iterator == NULL) {
+	entry->rv = index_create_read_view(pk);
+	if (entry->rv == NULL) {
 		free(entry);
 		return -1;
 	}
@@ -1084,16 +1095,26 @@ memtx_join_f(va_list ap)
 	struct memtx_join_ctx *ctx = va_arg(ap, struct memtx_join_ctx *);
 	struct memtx_join_entry *entry;
 	rlist_foreach_entry(entry, &ctx->entries, in_ctx) {
-		struct snapshot_iterator *it = entry->iterator;
+		struct index_read_view_iterator *it =
+			index_read_view_create_iterator(entry->rv, ITER_ALL,
+							NULL, 0);
+		if (it == NULL)
+			return -1;
 		int rc;
 		uint32_t size;
 		const char *data;
-		while ((rc = it->next(it, &data, &size)) == 0 && data != NULL) {
-			if (memtx_join_send_tuple(ctx->stream, entry->space_id,
-						  data, size) != 0)
-				return -1;
+		while (true) {
+			rc = index_read_view_iterator_next_raw(it, &data,
+							       &size);
+			if (rc != 0 || data == NULL)
+				break;
+			rc = memtx_join_send_tuple(ctx->stream, entry->space_id,
+						   data, size);
+			if (rc != 0)
+				break;
 			fiber_gc();
 		}
+		index_read_view_iterator_delete(it);
 		if (rc != 0)
 			return -1;
 	}
@@ -1129,7 +1150,7 @@ memtx_engine_complete_join(struct engine *engine, void *arg)
 	struct memtx_join_ctx *ctx = (struct memtx_join_ctx *)arg;
 	struct memtx_join_entry *entry, *next;
 	rlist_foreach_entry_safe(entry, &ctx->entries, in_ctx, next) {
-		entry->iterator->free(entry->iterator);
+		index_read_view_delete(entry->rv);
 		free(entry);
 	}
 	memtx_allocators_close_read_view(ctx->rv);
diff --git a/src/box/memtx_hash.cc b/src/box/memtx_hash.cc
index f38535d086528071d608a4ea81bfd4eab9b61f93..c6ab4756544446d31dcc93354e438c87a33dac5c 100644
--- a/src/box/memtx_hash.cc
+++ b/src/box/memtx_hash.cc
@@ -465,54 +465,66 @@ memtx_hash_index_create_iterator(struct index *base, enum iterator_type type,
 	return (struct iterator *)it;
 }
 
-struct hash_snapshot_iterator {
-	struct snapshot_iterator base;
+/** Read view implementation. */
+struct hash_read_view {
+	/** Base class. */
+	struct index_read_view base;
+	/** Read view index. Ref counter incremented. */
 	struct memtx_hash_index *index;
+	/** Light read view. */
 	struct light_index_view view;
-	struct light_index_iterator iterator;
+	/** Used for clarifying read view tuples. */
 	struct memtx_tx_snapshot_cleaner cleaner;
 };
 
-/**
- * Destroy read view and free snapshot iterator.
- * Virtual method of snapshot iterator.
- * @sa index_vtab::create_snapshot_iterator.
- */
+/** Read view iterator implementation. */
+struct hash_read_view_iterator {
+	/** Base class. */
+	struct index_read_view_iterator base;
+	/** Read view. */
+	struct hash_read_view *rv;
+	/** Light iterator. */
+	struct light_index_iterator iterator;
+};
+
 static void
-hash_snapshot_iterator_free(struct snapshot_iterator *iterator)
+hash_read_view_free(struct index_read_view *base)
 {
-	assert(iterator->free == hash_snapshot_iterator_free);
-	struct hash_snapshot_iterator *it =
-		(struct hash_snapshot_iterator *) iterator;
-	light_index_view_destroy(&it->view);
-	index_unref(&it->index->base);
-	memtx_tx_snapshot_cleaner_destroy(&it->cleaner);
+	struct hash_read_view *rv = (struct hash_read_view *)base;
+	light_index_view_destroy(&rv->view);
+	index_unref(&rv->index->base);
+	memtx_tx_snapshot_cleaner_destroy(&rv->cleaner);
+	TRASH(rv);
+	free(rv);
+}
+
+static void
+hash_read_view_iterator_free(struct index_read_view_iterator *iterator)
+{
+	assert(iterator->free == hash_read_view_iterator_free);
+	TRASH(iterator);
 	free(iterator);
 }
 
-/**
- * Get next tuple from snapshot iterator.
- * Virtual method of snapshot iterator.
- * @sa index_vtab::create_snapshot_iterator.
- */
+/** Implementation of next_raw index_read_view_iterator callback. */
 static int
-hash_snapshot_iterator_next(struct snapshot_iterator *iterator,
-			    const char **data, uint32_t *size)
+hash_read_view_iterator_next_raw(struct index_read_view_iterator *iterator,
+				 const char **data, uint32_t *size)
 {
-	assert(iterator->free == hash_snapshot_iterator_free);
-	struct hash_snapshot_iterator *it =
-		(struct hash_snapshot_iterator *) iterator;
+	assert(iterator->free == hash_read_view_iterator_free);
+	struct hash_read_view_iterator *it =
+		(struct hash_read_view_iterator *)iterator;
 
 	while (true) {
 		struct tuple **res = light_index_view_iterator_get_and_next(
-			&it->view, &it->iterator);
+			&it->rv->view, &it->iterator);
 		if (res == NULL) {
 			*data = NULL;
 			return 0;
 		}
 
 		struct tuple *tuple = *res;
-		tuple = memtx_tx_snapshot_clarify(&it->cleaner, tuple);
+		tuple = memtx_tx_snapshot_clarify(&it->rv->cleaner, tuple);
 
 		if (tuple != NULL) {
 			*data = tuple_data_range(tuple, size);
@@ -524,33 +536,46 @@ hash_snapshot_iterator_next(struct snapshot_iterator *iterator,
 	return 0;
 }
 
-/**
- * Create an ALL iterator with personal read view so further
- * index modifications will not affect the iteration results.
- * Must be destroyed by iterator->free after usage.
- */
-static struct snapshot_iterator *
-memtx_hash_index_create_snapshot_iterator(struct index *base)
+/** Implementation of create_iterator index_read_view callback. */
+static struct index_read_view_iterator *
+hash_read_view_create_iterator(struct index_read_view *base,
+			       enum iterator_type type,
+			       const char *key, uint32_t part_count)
 {
-	struct memtx_hash_index *index = (struct memtx_hash_index *)base;
-	struct hash_snapshot_iterator *it = (struct hash_snapshot_iterator *)
-		calloc(1, sizeof(*it));
-	if (it == NULL) {
-		diag_set(OutOfMemory, sizeof(struct hash_snapshot_iterator),
-			 "memtx_hash_index", "iterator");
-		return NULL;
-	}
+	assert(type == ITER_ALL);
+	assert(key == NULL);
+	assert(part_count == 0);
+	(void)type;
+	(void)key;
+	(void)part_count;
+	struct hash_read_view *rv = (struct hash_read_view *)base;
+	struct hash_read_view_iterator *it =
+		(struct hash_read_view_iterator *)xmalloc(sizeof(*it));
+	it->base.next_raw = hash_read_view_iterator_next_raw;
+	it->base.free = hash_read_view_iterator_free;
+	it->rv = rv;
+	light_index_view_iterator_begin(&rv->view, &it->iterator);
+	return (struct index_read_view_iterator *)it;
+}
 
+/** Implementation of create_read_view index callback. */
+static struct index_read_view *
+memtx_hash_index_create_read_view(struct index *base)
+{
+	static const struct index_read_view_vtab vtab = {
+		.free = hash_read_view_free,
+		.create_iterator = hash_read_view_create_iterator,
+	};
+	struct memtx_hash_index *index = (struct memtx_hash_index *)base;
+	struct hash_read_view *rv =
+		(struct hash_read_view *)xmalloc(sizeof(*rv));
 	struct space *space = space_cache_find(base->def->space_id);
-	memtx_tx_snapshot_cleaner_create(&it->cleaner, space);
-
-	it->base.next = hash_snapshot_iterator_next;
-	it->base.free = hash_snapshot_iterator_free;
-	it->index = index;
+	memtx_tx_snapshot_cleaner_create(&rv->cleaner, space);
+	rv->base.vtab = &vtab;
+	rv->index = index;
 	index_ref(base);
-	light_index_view_create(&it->view, &index->hash_table);
-	light_index_view_iterator_begin(&it->view, &it->iterator);
-	return (struct snapshot_iterator *) it;
+	light_index_view_create(&rv->view, &index->hash_table);
+	return (struct index_read_view *)rv;
 }
 
 static const struct index_vtab memtx_hash_index_vtab = {
@@ -573,8 +598,7 @@ static const struct index_vtab memtx_hash_index_vtab = {
 	/* .get = */ memtx_index_get,
 	/* .replace = */ memtx_hash_index_replace,
 	/* .create_iterator = */ memtx_hash_index_create_iterator,
-	/* .create_snapshot_iterator = */
-		memtx_hash_index_create_snapshot_iterator,
+	/* .create_read_view = */ memtx_hash_index_create_read_view,
 	/* .stat = */ generic_index_stat,
 	/* .compact = */ generic_index_compact,
 	/* .reset_stat = */ generic_index_reset_stat,
diff --git a/src/box/memtx_rtree.cc b/src/box/memtx_rtree.cc
index 77308aaec558ca63f8b36e5e2f6a6ee38dd9db63..1b52952306f06b5573d43c4d3a1046e0329d2e01 100644
--- a/src/box/memtx_rtree.cc
+++ b/src/box/memtx_rtree.cc
@@ -386,8 +386,7 @@ static const struct index_vtab memtx_rtree_index_vtab = {
 	/* .get = */ memtx_index_get,
 	/* .replace = */ memtx_rtree_index_replace,
 	/* .create_iterator = */ memtx_rtree_index_create_iterator,
-	/* .create_snapshot_iterator = */
-		generic_index_create_snapshot_iterator,
+	/* .create_read_view = */ generic_index_create_read_view,
 	/* .stat = */ generic_index_stat,
 	/* .compact = */ generic_index_compact,
 	/* .reset_stat = */ generic_index_reset_stat,
diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c
index c329d5ace4134a6a039dfa04a17d0f70ae27d589..858b74defdbaddf3466d8a387792dfd18f1ff509 100644
--- a/src/box/memtx_space.c
+++ b/src/box/memtx_space.c
@@ -835,13 +835,6 @@ memtx_space_check_index_def(struct space *space, struct index_def *index_def)
 	return 0;
 }
 
-static struct snapshot_iterator *
-sequence_data_index_create_snapshot_iterator(struct index *index)
-{
-	(void)index;
-	return sequence_data_iterator_create();
-}
-
 static struct index *
 sequence_data_index_new(struct memtx_engine *memtx, struct index_def *def)
 {
@@ -853,8 +846,7 @@ sequence_data_index_new(struct memtx_engine *memtx, struct index_def *def)
 	static bool vtab_initialized;
 	if (!vtab_initialized) {
 		vtab = *index->vtab;
-		vtab.create_snapshot_iterator =
-			sequence_data_index_create_snapshot_iterator;
+		vtab.create_read_view = sequence_data_read_view_create;
 		vtab_initialized = true;
 	}
 
diff --git a/src/box/memtx_tree.cc b/src/box/memtx_tree.cc
index fcca15158366c46895f75e73f5890fdfef813e46..b66e7c340bb658f4340312139dc53b2b4b7f0523 100644
--- a/src/box/memtx_tree.cc
+++ b/src/box/memtx_tree.cc
@@ -1668,40 +1668,65 @@ memtx_tree_index_end_build(struct index *base)
 	index->build_array_alloc_size = 0;
 }
 
+/** Read view implementation. */
 template <bool USE_HINT>
-struct tree_snapshot_iterator {
-	struct snapshot_iterator base;
+struct tree_read_view {
+	/** Base class. */
+	struct index_read_view base;
+	/** Read view index. Ref counter incremented. */
 	struct memtx_tree_index<USE_HINT> *index;
+	/** BPS tree read view. */
 	memtx_tree_view_t<USE_HINT> tree_view;
-	memtx_tree_iterator_t<USE_HINT> tree_iterator;
+	/** Used for clarifying read view tuples. */
 	struct memtx_tx_snapshot_cleaner cleaner;
 };
 
+/** Read view iterator implementation. */
+template <bool USE_HINT>
+struct tree_read_view_iterator {
+	/** Base class. */
+	struct index_read_view_iterator base;
+	/** Read view. */
+	struct tree_read_view<USE_HINT> *rv;
+	/** BPS tree iterator. */
+	memtx_tree_iterator_t<USE_HINT> tree_iterator;
+};
+
+template <bool USE_HINT>
+static void
+tree_read_view_free(struct index_read_view *base)
+{
+	struct tree_read_view<USE_HINT> *rv =
+		(struct tree_read_view<USE_HINT> *)base;
+	memtx_tree_view_destroy(&rv->tree_view);
+	index_unref(&rv->index->base);
+	memtx_tx_snapshot_cleaner_destroy(&rv->cleaner);
+	TRASH(rv);
+	free(rv);
+}
+
 template <bool USE_HINT>
 static void
-tree_snapshot_iterator_free(struct snapshot_iterator *iterator)
+tree_read_view_iterator_free(struct index_read_view_iterator *iterator)
 {
-	assert(iterator->free == &tree_snapshot_iterator_free<USE_HINT>);
-	struct tree_snapshot_iterator<USE_HINT> *it =
-		(struct tree_snapshot_iterator<USE_HINT> *)iterator;
-	memtx_tree_view_destroy(&it->tree_view);
-	index_unref(&it->index->base);
-	memtx_tx_snapshot_cleaner_destroy(&it->cleaner);
+	assert(iterator->free == &tree_read_view_iterator_free<USE_HINT>);
+	TRASH(iterator);
 	free(iterator);
 }
 
+/** Implementation of next_raw index_read_view_iterator callback. */
 template <bool USE_HINT>
 static int
-tree_snapshot_iterator_next(struct snapshot_iterator *iterator,
-			    const char **data, uint32_t *size)
+tree_read_view_iterator_next_raw(struct index_read_view_iterator *iterator,
+				 const char **data, uint32_t *size)
 {
-	assert(iterator->free == &tree_snapshot_iterator_free<USE_HINT>);
-	struct tree_snapshot_iterator<USE_HINT> *it =
-		(struct tree_snapshot_iterator<USE_HINT> *)iterator;
+	assert(iterator->free == &tree_read_view_iterator_free<USE_HINT>);
+	struct tree_read_view_iterator<USE_HINT> *it =
+		(struct tree_read_view_iterator<USE_HINT> *)iterator;
 
 	while (true) {
 		struct memtx_tree_data<USE_HINT> *res =
-			memtx_tree_view_iterator_get_elem(&it->tree_view,
+			memtx_tree_view_iterator_get_elem(&it->rv->tree_view,
 							  &it->tree_iterator);
 
 		if (res == NULL) {
@@ -1709,11 +1734,11 @@ tree_snapshot_iterator_next(struct snapshot_iterator *iterator,
 			return 0;
 		}
 
-		memtx_tree_view_iterator_next(&it->tree_view,
+		memtx_tree_view_iterator_next(&it->rv->tree_view,
 					      &it->tree_iterator);
 
 		struct tuple *tuple = res->tuple;
-		tuple = memtx_tx_snapshot_clarify(&it->cleaner, tuple);
+		tuple = memtx_tx_snapshot_clarify(&it->rv->cleaner, tuple);
 
 		if (tuple != NULL) {
 			*data = tuple_data_range(tuple, size);
@@ -1726,37 +1751,51 @@ tree_snapshot_iterator_next(struct snapshot_iterator *iterator,
 	return 0;
 }
 
-/**
- * Create an ALL iterator with personal read view so further
- * index modifications will not affect the iteration results.
- * Must be destroyed by iterator->free after usage.
- */
+/** Implementation of create_iterator index_read_view callback. */
 template <bool USE_HINT>
-static struct snapshot_iterator *
-memtx_tree_index_create_snapshot_iterator(struct index *base)
+static struct index_read_view_iterator *
+tree_read_view_create_iterator(struct index_read_view *base,
+			       enum iterator_type type,
+			       const char *key, uint32_t part_count)
 {
+	assert(type == ITER_ALL);
+	assert(key == NULL);
+	assert(part_count == 0);
+	(void)type;
+	(void)key;
+	(void)part_count;
+	struct tree_read_view<USE_HINT> *rv =
+		(struct tree_read_view<USE_HINT> *)base;
+	struct tree_read_view_iterator<USE_HINT> *it =
+		(struct tree_read_view_iterator<USE_HINT> *)
+		xmalloc(sizeof(*it));
+	it->base.free = tree_read_view_iterator_free<USE_HINT>;
+	it->base.next_raw = tree_read_view_iterator_next_raw<USE_HINT>;
+	it->rv = rv;
+	it->tree_iterator = memtx_tree_view_first(&rv->tree_view);
+	return (struct index_read_view_iterator *)it;
+}
+
+/** Implementation of create_read_view index callback. */
+template <bool USE_HINT>
+static struct index_read_view *
+memtx_tree_index_create_read_view(struct index *base)
+{
+	static const struct index_read_view_vtab vtab = {
+		.free = tree_read_view_free<USE_HINT>,
+		.create_iterator = tree_read_view_create_iterator<USE_HINT>,
+	};
 	struct memtx_tree_index<USE_HINT> *index =
 		(struct memtx_tree_index<USE_HINT> *)base;
-	struct tree_snapshot_iterator<USE_HINT> *it =
-		(struct tree_snapshot_iterator<USE_HINT> *)
-		calloc(1, sizeof(*it));
-	if (it == NULL) {
-		diag_set(OutOfMemory,
-			 sizeof(struct tree_snapshot_iterator<USE_HINT>),
-			 "memtx_tree_index", "create_snapshot_iterator");
-		return NULL;
-	}
-
+	struct tree_read_view<USE_HINT> *rv =
+		(struct tree_read_view<USE_HINT> *)xmalloc(sizeof(*rv));
 	struct space *space = space_cache_find(base->def->space_id);
-	memtx_tx_snapshot_cleaner_create(&it->cleaner, space);
-
-	it->base.free = tree_snapshot_iterator_free<USE_HINT>;
-	it->base.next = tree_snapshot_iterator_next<USE_HINT>;
-	it->index = index;
+	memtx_tx_snapshot_cleaner_create(&rv->cleaner, space);
+	rv->base.vtab = &vtab;
+	rv->index = index;
 	index_ref(base);
-	memtx_tree_view_create(&it->tree_view, &index->tree);
-	it->tree_iterator = memtx_tree_view_first(&it->tree_view);
-	return (struct snapshot_iterator *) it;
+	memtx_tree_view_create(&rv->tree_view, &index->tree);
+	return (struct index_read_view *)rv;
 }
 
 /**
@@ -1785,8 +1824,7 @@ static const struct index_vtab memtx_tree_disabled_index_vtab = {
 	/* .get = */ generic_index_get,
 	/* .replace = */ disabled_index_replace,
 	/* .create_iterator = */ generic_index_create_iterator,
-	/* .create_snapshot_iterator = */
-		generic_index_create_snapshot_iterator,
+	/* .create_read_view = */ generic_index_create_read_view,
 	/* .stat = */ generic_index_stat,
 	/* .compact = */ generic_index_compact,
 	/* .reset_stat = */ generic_index_reset_stat,
@@ -1849,8 +1887,8 @@ get_memtx_tree_index_vtab(void)
 				 memtx_tree_index_replace<USE_HINT>,
 		/* .create_iterator = */
 			memtx_tree_index_create_iterator<USE_HINT>,
-		/* .create_snapshot_iterator = */
-			memtx_tree_index_create_snapshot_iterator<USE_HINT>,
+		/* .create_read_view = */
+			memtx_tree_index_create_read_view<USE_HINT>,
 		/* .stat = */ generic_index_stat,
 		/* .compact = */ generic_index_compact,
 		/* .reset_stat = */ generic_index_reset_stat,
diff --git a/src/box/sequence.c b/src/box/sequence.c
index 1cd68980dcbb68fddcc2c7fde4c2fe5e35f379f5..f6eefd4bc1bafc571fc2bad412e0fd4e49d7b5f7 100644
--- a/src/box/sequence.c
+++ b/src/box/sequence.c
@@ -300,23 +300,34 @@ access_check_sequence(struct sequence *seq)
 	return 0;
 }
 
-struct sequence_data_iterator {
-	struct snapshot_iterator base;
+/** Read view implementation. */
+struct sequence_data_read_view {
+	/** Base class. */
+	struct index_read_view base;
 	/** Frozen view of the data index. */
 	struct light_sequence_view view;
+};
+
+/** Read view iterator implementation. */
+struct sequence_data_iterator {
+	/** Base class. */
+	struct index_read_view_iterator base;
+	/** Read view. */
+	struct sequence_data_read_view *rv;
 	/** Iterator over the data index. */
 	struct light_sequence_iterator iter;
 };
 
+/** Implementation of next_raw index_read_view_iterator callback. */
 static int
-sequence_data_iterator_next(struct snapshot_iterator *base,
-			    const char **data, uint32_t *size)
+sequence_data_iterator_next_raw(struct index_read_view_iterator *base,
+				const char **data, uint32_t *size)
 {
 	struct sequence_data_iterator *iter =
 		(struct sequence_data_iterator *)base;
 
 	struct sequence_data *sd = light_sequence_view_iterator_get_and_next(
-		&iter->view, &iter->iter);
+		&iter->rv->view, &iter->iter);
 	if (sd == NULL) {
 		*data = NULL;
 		return 0;
@@ -338,26 +349,56 @@ sequence_data_iterator_next(struct snapshot_iterator *base,
 }
 
 static void
-sequence_data_iterator_free(struct snapshot_iterator *base)
+sequence_data_iterator_free(struct index_read_view_iterator *iter)
 {
-	struct sequence_data_iterator *iter =
-		(struct sequence_data_iterator *)base;
-	light_sequence_view_destroy(&iter->view);
 	TRASH(iter);
 	free(iter);
 }
 
-struct snapshot_iterator *
-sequence_data_iterator_create(void)
+/** Implementation of create_iterator index_read_view callback. */
+static struct index_read_view_iterator *
+sequence_data_iterator_create(struct index_read_view *base,
+			      enum iterator_type type,
+			      const char *key, uint32_t part_count)
 {
-	struct sequence_data_iterator *iter = xcalloc(1, sizeof(*iter));
-
+	assert(type == ITER_ALL);
+	assert(key == NULL);
+	assert(part_count == 0);
+	(void)type;
+	(void)key;
+	(void)part_count;
+	struct sequence_data_read_view *rv =
+		(struct sequence_data_read_view *)base;
+	struct sequence_data_iterator *iter = xmalloc(sizeof(*iter));
+	iter->base.next_raw = sequence_data_iterator_next_raw;
 	iter->base.free = sequence_data_iterator_free;
-	iter->base.next = sequence_data_iterator_next;
+	iter->rv = rv;
+	light_sequence_view_iterator_begin(&rv->view, &iter->iter);
+	return (struct index_read_view_iterator *)iter;
+}
+
+static void
+sequence_data_read_view_free(struct index_read_view *base)
+{
+	struct sequence_data_read_view *rv =
+		(struct sequence_data_read_view *)base;
+	light_sequence_view_destroy(&rv->view);
+	TRASH(rv);
+	free(rv);
+}
 
-	light_sequence_view_create(&iter->view, &sequence_data_index);
-	light_sequence_view_iterator_begin(&iter->view, &iter->iter);
-	return &iter->base;
+struct index_read_view *
+sequence_data_read_view_create(struct index *index)
+{
+	(void)index;
+	static const struct index_read_view_vtab vtab = {
+		.free = sequence_data_read_view_free,
+		.create_iterator = sequence_data_iterator_create,
+	};
+	struct sequence_data_read_view *rv = xmalloc(sizeof(*rv));
+	rv->base.vtab = &vtab;
+	light_sequence_view_create(&rv->view, &sequence_data_index);
+	return (struct index_read_view *)rv;
 }
 
 int
diff --git a/src/box/sequence.h b/src/box/sequence.h
index 400bdc6f994828c5b28bef5fd8faa4538baeb200..e4968557ae52908ecef6477fa7907f8e0aaf844f 100644
--- a/src/box/sequence.h
+++ b/src/box/sequence.h
@@ -43,8 +43,8 @@
 extern "C" {
 #endif /* defined(__cplusplus) */
 
-struct iterator;
-struct Vdbe;
+struct index;
+struct index_read_view;
 
 /** Sequence metadata. */
 struct sequence_def {
@@ -158,14 +158,14 @@ int
 access_check_sequence(struct sequence *seq);
 
 /**
- * Create an iterator over sequence data.
+ * Create a read view of sequence data.
  *
- * The iterator creates a snapshot of sequence data and walks
- * over it, i.e. updates done after the iterator was open are
- * invisible. Used to make a snapshot of _sequence_data space.
+ * This function creates a snapshot of sequence data such that updates done
+ * after the read view was created are invisible. Used to make a snapshot of
+ * _sequence_data space.
  */
-struct snapshot_iterator *
-sequence_data_iterator_create(void);
+struct index_read_view *
+sequence_data_read_view_create(struct index *index);
 
 /**
  * Get last element of given sequence.
diff --git a/src/box/session_settings.c b/src/box/session_settings.c
index c3233c95d80da5bbe6ef3f5f650343d0c0621d5a..aa79dbcec539cd356570e19966ef4c011d15ebfd 100644
--- a/src/box/session_settings.c
+++ b/src/box/session_settings.c
@@ -275,8 +275,7 @@ static const struct index_vtab session_settings_index_vtab = {
 	/* .get = */ session_settings_index_get,
 	/* .replace = */ generic_index_replace,
 	/* .create_iterator = */ session_settings_index_create_iterator,
-	/* .create_snapshot_iterator = */
-		generic_index_create_snapshot_iterator,
+	/* .create_read_view = */ generic_index_create_read_view,
 	/* .stat = */ generic_index_stat,
 	/* .compact = */ generic_index_compact,
 	/* .reset_stat = */ generic_index_reset_stat,
diff --git a/src/box/sysview.c b/src/box/sysview.c
index 6f37e5fa968458361e8349219d568f34de0c49bf..6b04c45e579dd8ec226a888892b88661288cbaee 100644
--- a/src/box/sysview.c
+++ b/src/box/sysview.c
@@ -196,8 +196,7 @@ static const struct index_vtab sysview_index_vtab = {
 	/* .get = */ sysview_index_get,
 	/* .replace = */ generic_index_replace,
 	/* .create_iterator = */ sysview_index_create_iterator,
-	/* .create_snapshot_iterator = */
-		generic_index_create_snapshot_iterator,
+	/* .create_read_view = */ generic_index_create_read_view,
 	/* .stat = */ generic_index_stat,
 	/* .compact = */ generic_index_compact,
 	/* .reset_stat = */ generic_index_reset_stat,
diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 403b7c49d0025d4f2a5adb98c3f0ed7633b369f4..89168a32d6c9303d954583e45dec0a04809476a9 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -4589,8 +4589,7 @@ static const struct index_vtab vinyl_index_vtab = {
 	/* .get = */ vinyl_index_get,
 	/* .replace = */ generic_index_replace,
 	/* .create_iterator = */ vinyl_index_create_iterator,
-	/* .create_snapshot_iterator = */
-		generic_index_create_snapshot_iterator,
+	/* .create_read_view = */ generic_index_create_read_view,
 	/* .stat = */ vinyl_index_stat,
 	/* .compact = */ vinyl_index_compact,
 	/* .reset_stat = */ vinyl_index_reset_stat,