diff --git a/src/box/memtx_engine.cc b/src/box/memtx_engine.cc
index 36de2cb686911540fccad8ac04f7cb9dbfbb438f..3425df634082cd95039b7c765a965e3f5f7a32b6 100644
--- a/src/box/memtx_engine.cc
+++ b/src/box/memtx_engine.cc
@@ -54,6 +54,26 @@ static bool memtx_index_arena_initialized = false;
 static struct slab_arena memtx_index_arena;
 static struct slab_cache memtx_index_arena_slab_cache;
 static struct mempool memtx_index_extent_pool;
+/**
+ * To ensure proper statement-level rollback in case
+ * of out of memory conditions, we maintain a number
+ * of slack memory extents reserved before a statement
+ * is begun. If there isn't enough slack memory,
+ * we don't begin the statement.
+ */
+static int memtx_index_num_reserved_extents;
+static void *memtx_index_reserved_extents;
+
+enum {
+	/**
+	 * This number is calculated based on the
+	 * max (realistic) number of insertions
+	 * a deletion from a B-tree or an R-tree
+	 * can lead to, and, as a result, the max
+	 * number of new block allocations.
+	 */
+	RESERVE_EXTENTS_BEFORE_REPLACE = 16
+};
 
 /**
  * A version of space_replace for a space which has
@@ -154,6 +174,11 @@ memtx_replace_all_keys(struct txn *txn, struct space *space,
 		       struct tuple *old_tuple, struct tuple *new_tuple,
 		       enum dup_replace_mode mode)
 {
+	/*
+	 * Ensure we have enough slack memory to guarantee
+	 * successful statement-level rollback.
+	 */
+	memtx_index_extent_reserve(RESERVE_EXTENTS_BEFORE_REPLACE);
 	uint32_t i = 0;
 	try {
 		/* Update the primary key */
@@ -873,6 +898,9 @@ memtx_index_arena_init()
 	mempool_create(&memtx_index_extent_pool,
 		       &memtx_index_arena_slab_cache,
 		       MEMTX_EXTENT_SIZE);
+	/* Empty reserved list */
+	memtx_index_num_reserved_extents = 0;
+	memtx_index_reserved_extents = 0;
 	/* Done */
 	memtx_index_arena_initialized = true;
 }
@@ -883,7 +911,19 @@ memtx_index_arena_init()
 void *
 memtx_index_extent_alloc()
 {
-	ERROR_INJECT(ERRINJ_INDEX_ALLOC, return 0);
+	if (memtx_index_reserved_extents) {
+		assert(memtx_index_num_reserved_extents > 0);
+		memtx_index_num_reserved_extents--;
+		void *result = memtx_index_reserved_extents;
+		memtx_index_reserved_extents = *(void **)
+			memtx_index_reserved_extents;
+		return result;
+	}
+	ERROR_INJECT(ERRINJ_INDEX_ALLOC,
+		     /* same error as in mempool_alloc */
+		     tnt_raise(OutOfMemory, MEMTX_EXTENT_SIZE,
+			       "mempool", "new slab")
+	);
 	return mempool_alloc(&memtx_index_extent_pool);
 }
 
@@ -895,3 +935,23 @@ memtx_index_extent_free(void *extent)
 {
 	return mempool_free(&memtx_index_extent_pool, extent);
 }
+
+/**
+ * Reserve num extents in pool.
+ * Ensure that next num extent_alloc will succeed w/o an error
+ */
+void
+memtx_index_extent_reserve(int num)
+{
+	ERROR_INJECT(ERRINJ_INDEX_ALLOC,
+	/* same error as in mempool_alloc */
+		     tnt_raise(OutOfMemory, MEMTX_EXTENT_SIZE,
+			       "mempool", "new slab")
+	);
+	while (memtx_index_num_reserved_extents < num) {
+		void *ext = mempool_alloc(&memtx_index_extent_pool);
+		*(void **)ext = memtx_index_reserved_extents;
+		memtx_index_reserved_extents = ext;
+		memtx_index_num_reserved_extents++;
+	}
+}
diff --git a/src/box/memtx_engine.h b/src/box/memtx_engine.h
index ae1a685177645024f0194373e2583e63576a2c82..7d823881500ab3efa6418a7893a7f88bf1ff3d15 100644
--- a/src/box/memtx_engine.h
+++ b/src/box/memtx_engine.h
@@ -92,4 +92,11 @@ memtx_index_extent_alloc();
 void
 memtx_index_extent_free(void *extent);
 
+/**
+ * Reserve num extents in pool.
+ * Ensure that next num extent_alloc will succeed w/o an error
+ */
+void
+memtx_index_extent_reserve(int num);
+
 #endif /* TARANTOOL_BOX_MEMTX_ENGINE_H_INCLUDED */
diff --git a/src/box/memtx_rtree.cc b/src/box/memtx_rtree.cc
index 7106aa0f7cf7dae1a83d5fe0a0125962605fb522..4f5e414951d7c3eda5d2467d690e58227d1ce1ee 100644
--- a/src/box/memtx_rtree.cc
+++ b/src/box/memtx_rtree.cc
@@ -34,11 +34,6 @@
 #include "fiber.h"
 #include "small/small.h"
 
-/**
- * Single-linked list of free rtree pages
- */
-static void *rtree_free_pages = 0;
-
 /* {{{ Utilities. *************************************************/
 
 inline void extract_rectangle(struct rtree_rect *rect,
@@ -122,41 +117,6 @@ index_rtree_iterator_next(struct iterator *i)
 
 /* {{{ MemtxRTree  **********************************************************/
 
-static void *
-rtree_page_alloc()
-{
-	ERROR_INJECT(ERRINJ_INDEX_ALLOC, return 0);
-	if (!rtree_free_pages) {
-		/**
-		 * No free pages in list - let's allocate new extent, split it
-		 * into pages and add them to the list.
-		 */
-		char *extent = (char *)memtx_index_extent_alloc();
-		if (!extent) {
-			panic("%s", "Memory allocation failed in rtree");
-			return 0;
-		}
-		assert(MEMTX_EXTENT_SIZE % RTREE_PAGE_SIZE == 0);
-		assert(RTREE_PAGE_SIZE >= sizeof(void *));
-		for (size_t i = 0; i < MEMTX_EXTENT_SIZE; i += RTREE_PAGE_SIZE) {
-			*(void **)(extent + i) = rtree_free_pages;
-			rtree_free_pages = (void *)(extent + i);
-		}
-	}
-	/* Now we surely have a free page in free list */
-	void *res = rtree_free_pages;
-	rtree_free_pages = *(void **)rtree_free_pages;
-	return res;
-}
-
-static void
-rtree_page_free(void *page)
-{
-	/* Just add to free list. */
-	*(void **)page = rtree_free_pages;
-	rtree_free_pages = page;
-}
-
 MemtxRTree::~MemtxRTree()
 {
 	// Iterator has to be destroyed prior to tree
@@ -175,7 +135,8 @@ MemtxRTree::MemtxRTree(struct key_def *key_def)
 	assert(key_def->is_unique == false);
 
 	memtx_index_arena_init();
-	rtree_init(&tree, rtree_page_alloc, rtree_page_free);
+	rtree_init(&tree, MEMTX_EXTENT_SIZE,
+		   memtx_index_extent_alloc, memtx_index_extent_free);
 }
 
 size_t
diff --git a/src/lib/salad/rtree.c b/src/lib/salad/rtree.c
index a14f89134ee1ff5555b177baadab3cb0a7e1fcc9..70a43d410c1eeff74ae6bed723f595f3a50eb3d0 100644
--- a/src/lib/salad/rtree.c
+++ b/src/lib/salad/rtree.c
@@ -249,13 +249,23 @@ rtree_always_true(const struct rtree_rect *rt1,
 static struct rtree_page *
 rtree_alloc_page(struct rtree *tree)
 {
-	return (struct rtree_page *)tree->page_alloc();
+	if (tree->free_pages) {
+		struct rtree_page *result =
+			(struct rtree_page *)tree->free_pages;
+		tree->free_pages = *(void **)tree->free_pages;
+		return result;
+	} else {
+		uint32_t unused_id;
+		return (struct rtree_page *)
+			matras_alloc(&tree->mtab, &unused_id);
+	}
 }
 
 static void
 rtree_free_page(struct rtree *tree, struct rtree_page *page)
 {
-	tree->page_free(page);
+	*(void **)page = tree->free_pages;
+	tree->free_pages = (void *)page;
 }
 
 static void
@@ -558,7 +568,7 @@ rtree_page_purge(struct rtree *tree, struct rtree_page *page, int level)
 		for (int i = 0; i < page->n; i++)
 			rtree_page_purge(tree, page->b[i].data.page, level);
 	}
-	tree->page_free(page);
+	rtree_free_page(tree, page);
 }
 
 /*------------------------------------------------------------------------- */
@@ -624,7 +634,8 @@ rtree_iterator_destroy(struct rtree_iterator *itr)
 	struct rtree_neighbor_page *curr, *next;
 	for (curr = itr->page_list; curr != NULL; curr = next) {
 		next = curr->next;
-		itr->tree->page_free(curr);
+		rtree_free_page((struct rtree *) itr->tree,
+				(struct rtree_page *) curr);
 	}
 	itr->page_list = NULL;
 	itr->page_pos = RTREE_NEIGHBORS_IN_PAGE;
@@ -648,7 +659,8 @@ rtree_iterator_allocate_neighbour(struct rtree_iterator *itr)
 {
 	if (itr->page_pos >= RTREE_NEIGHBORS_IN_PAGE) {
 		struct rtree_neighbor_page *new_page =
-			(struct rtree_neighbor_page *)itr->tree->page_alloc();
+			(struct rtree_neighbor_page *)
+			rtree_alloc_page((struct rtree*)itr->tree);
 		new_page->next = itr->page_list;
 		itr->page_list = new_page;
 		itr->page_pos = 0;
@@ -683,6 +695,7 @@ rtree_iterator_free_neighbor(struct rtree_iterator *itr,
 void
 rtree_iterator_init(struct rtree_iterator *itr)
 {
+	itr->tree = 0;
 	itr->neigh_list = NULL;
 	itr->neigh_free_list = NULL;
 	itr->page_list = NULL;
@@ -764,22 +777,24 @@ rtree_iterator_next(struct rtree_iterator *itr)
 /*------------------------------------------------------------------------- */
 
 void
-rtree_init(struct rtree *tree,
-	   rtree_page_alloc_t page_alloc, rtree_page_free_t page_free)
+rtree_init(struct rtree *tree, uint32_t extent_size,
+	   rtree_extent_alloc_t extent_alloc, rtree_extent_free_t extent_free)
 {
 	tree->n_records = 0;
 	tree->height = 0;
 	tree->root = NULL;
 	tree->version = 0;
 	tree->n_pages = 0;
-	tree->page_alloc = page_alloc;
-	tree->page_free = page_free;
+	matras_create(&tree->mtab, extent_size, RTREE_PAGE_SIZE,
+		      extent_alloc, extent_free);
+	tree->free_pages = 0;
 }
 
 void
 rtree_destroy(struct rtree *tree)
 {
 	rtree_purge(tree);
+	matras_destroy(&tree->mtab);
 }
 
 void
@@ -859,6 +874,7 @@ rtree_search(const struct rtree *tree, const struct rtree_rect *rect,
 	     enum spatial_search_op op, struct rtree_iterator *itr)
 {
 	rtree_iterator_reset(itr);
+	assert(itr->tree == 0 || itr->tree == tree);
 	itr->tree = tree;
 	itr->version = tree->version;
 	itr->rect = *rect;
diff --git a/src/lib/salad/rtree.h b/src/lib/salad/rtree.h
index f3e62085009023b2ee4aeb4af23375898295baf8..4d1f4c2e2864810d17ee7a6f99adb82ff0e86f4c 100644
--- a/src/lib/salad/rtree.h
+++ b/src/lib/salad/rtree.h
@@ -30,6 +30,7 @@
  */
 #include <stddef.h>
 #include <stdbool.h>
+#include "small/matras.h"
 
 /**
  * In-memory Guttman's R-tree
@@ -56,6 +57,7 @@ enum {
 	/**
 	 * R-Tree uses linear search for elements on a page,
 	 * so a larger page size can hurt performance.
+	 * must be power of 2
 	 */
 	RTREE_PAGE_SIZE = 1024
 };
@@ -88,8 +90,8 @@ enum spatial_search_op
 };
 
 /* pointers to page allocation and deallocations functions */
-typedef void *(*rtree_page_alloc_t)();
-typedef void (*rtree_page_free_t)(void *);
+typedef void *(*rtree_extent_alloc_t)();
+typedef void (*rtree_extent_free_t)(void *);
 
 /* A point in RTREE_DIMENSION space */
 struct rtree_point
@@ -124,10 +126,10 @@ struct rtree
 	unsigned version;
 	/* Number of allocated (used) pages */
 	unsigned n_pages;
-	/* Function for allocation new pages */
-	rtree_page_alloc_t page_alloc;
-	/* Function for deallocation new pages */
-	rtree_page_free_t page_free;
+	/* Matras for allocating new page */
+	struct matras mtab;
+	/* List of free pages */
+	void *free_pages;
 };
 
 /* Struct for iteration and retrieving rtree values */
@@ -196,12 +198,13 @@ rtree_set2d(struct rtree_rect *rect,
 /**
  * @brief Initialize a tree
  * @param tree - pointer to a tree
- * @param page_alloc - page allocation function
- * @param page_free - page deallocation function
+ * @param extent_size - size of extents allocated by extent_alloc (see next)
+ * @param extent_alloc - extent allocation function
+ * @param extent_free - extent deallocation function
  */
 void
-rtree_init(struct rtree *tree,
-	   rtree_page_alloc_t page_alloc, rtree_page_free_t page_free);
+rtree_init(struct rtree *tree, uint32_t extent_size,
+	   rtree_extent_alloc_t extent_alloc, rtree_extent_free_t extent_free);
 
 /**
  * @brief Destroy a tree
diff --git a/test/box/errinj_index.result b/test/box/errinj_index.result
index dc640cc3d8025199364585ded2b197a0b43c77c2..f3943dccac9fafc18e97b34e11a62221ef17ce3b 100644
--- a/test/box/errinj_index.result
+++ b/test/box/errinj_index.result
@@ -93,11 +93,11 @@ res
 ...
 for i = 501,2500 do s:insert{i, i} end
 ---
-- error: Failed to allocate 16384 bytes in MemtxTree for replace
+- error: Failed to allocate 16384 bytes in mempool for new slab
 ...
 s:delete{1}
 ---
-- [1, 1, 'test1']
+- error: Failed to allocate 16384 bytes in mempool for new slab
 ...
 res = {}
 ---
@@ -107,7 +107,8 @@ for i = 1,10 do table.insert(res, (s:get{i})) end
 ...
 res
 ---
-- - [2, 2, 'test2']
+- - [1, 1, 'test1']
+  - [2, 2, 'test2']
   - [3, 3, 'test3']
   - [4, 4, 'test4']
   - [5, 5, 'test5']
@@ -125,29 +126,10 @@ for i = 501,510 do table.insert(res, (s:get{i})) end
 ...
 res
 ---
-- - [501, 501]
-  - [502, 502]
-  - [503, 503]
-  - [504, 504]
-  - [505, 505]
-  - [506, 506]
-  - [507, 507]
-  - [508, 508]
-  - [509, 509]
-  - [510, 510]
-...
-res = {}
----
-...
-for i = 2001,2010 do table.insert(res, (s:get{i})) end
----
-...
-res
----
 - []
 ...
---count must be greater that 1000 but less than 2000
-function check_iter_and_size() local count = 0 for _, t in s.index[0]:pairs() do count = count + 1 end return count <= 1000 and "fail 1" or count >= 2000 and "fail 2" or "ok" end
+--count must be exactly 10
+function check_iter_and_size() local count = 0 for _, t in s.index[0]:pairs() do count = count + 1 end return count == 10 and "ok" or "fail" end
 ---
 ...
 check_iter_and_size()
@@ -156,11 +138,11 @@ check_iter_and_size()
 ...
 for i = 2501,3500 do s:insert{i, i} end
 ---
-- error: Failed to allocate 16384 bytes in MemtxTree for replace
+- error: Failed to allocate 16384 bytes in mempool for new slab
 ...
 s:delete{2}
 ---
-- [2, 2, 'test2']
+- error: Failed to allocate 16384 bytes in mempool for new slab
 ...
 check_iter_and_size()
 ---
@@ -174,7 +156,9 @@ for i = 1,10 do table.insert(res, (s:get{i})) end
 ...
 res
 ---
-- - [3, 3, 'test3']
+- - [1, 1, 'test1']
+  - [2, 2, 'test2']
+  - [3, 3, 'test3']
   - [4, 4, 'test4']
   - [5, 5, 'test5']
   - [6, 6, 'test6']
@@ -183,18 +167,6 @@ res
   - [9, 9, 'test9']
   - [10, 10, 'test10']
 ...
-for i = 3501,4500 do s:insert{i, i} end
----
-- error: Failed to allocate 16384 bytes in MemtxTree for replace
-...
-s:delete{3}
----
-- [3, 3, 'test3']
-...
-check_iter_and_size()
----
-- ok
-...
 errinj.set("ERRINJ_INDEX_ALLOC", false)
 ---
 - ok
@@ -210,7 +182,10 @@ for i = 1,10 do table.insert(res, (s:get{i})) end
 ...
 res
 ---
-- - [4, 4, 'test4']
+- - [1, 1, 'test1']
+  - [2, 2, 'test2']
+  - [3, 3, 'test3']
+  - [4, 4, 'test4']
   - [5, 5, 'test5']
   - [6, 6, 'test6']
   - [7, 7, 'test7']
@@ -230,7 +205,10 @@ for i = 1,10 do table.insert(res, (s:get{i})) end
 ...
 res
 ---
-- - [4, 4, 'test4']
+- - [1, 1, 'test1']
+  - [2, 2, 'test2']
+  - [3, 3, 'test3']
+  - [4, 4, 'test4']
   - [5, 5, 'test5']
   - [6, 6, 'test6']
   - [7, 7, 'test7']
@@ -352,11 +330,11 @@ res
 ...
 for i = 501,2500 do s:insert{i, i} end
 ---
-- error: Failed to allocate 10 bytes in hash_table for key
+- error: Failed to allocate 16384 bytes in mempool for new slab
 ...
 s:delete{1}
 ---
-- [1, 1, 'test1']
+- error: Failed to allocate 16384 bytes in mempool for new slab
 ...
 res = {}
 ---
@@ -366,7 +344,8 @@ for i = 1,10 do table.insert(res, (s:get{i})) end
 ...
 res
 ---
-- - [2, 2, 'test2']
+- - [1, 1, 'test1']
+  - [2, 2, 'test2']
   - [3, 3, 'test3']
   - [4, 4, 'test4']
   - [5, 5, 'test5']
@@ -396,23 +375,19 @@ res
 ---
 - []
 ...
---since every insertion is rejected, count must be (10 - number of deletions)
-function check_iter_and_size(size_must_be) local count = 0 for _, t in s.index[0]:pairs() do count = count + 1 end print (count) return count ~= size_must_be and "fail 1" or "ok" end
----
-...
-check_iter_and_size(9)
+check_iter_and_size()
 ---
 - ok
 ...
 for i = 2501,3500 do s:insert{i, i} end
 ---
-- error: Failed to allocate 9 bytes in hash_table for key
+- error: Failed to allocate 16384 bytes in mempool for new slab
 ...
 s:delete{2}
 ---
-- [2, 2, 'test2']
+- error: Failed to allocate 16384 bytes in mempool for new slab
 ...
-check_iter_and_size(8)
+check_iter_and_size()
 ---
 - ok
 ...
@@ -424,7 +399,9 @@ for i = 1,10 do table.insert(res, (s:get{i})) end
 ...
 res
 ---
-- - [3, 3, 'test3']
+- - [1, 1, 'test1']
+  - [2, 2, 'test2']
+  - [3, 3, 'test3']
   - [4, 4, 'test4']
   - [5, 5, 'test5']
   - [6, 6, 'test6']
@@ -435,13 +412,13 @@ res
 ...
 for i = 3501,4500 do s:insert{i, i} end
 ---
-- error: Failed to allocate 8 bytes in hash_table for key
+- error: Failed to allocate 16384 bytes in mempool for new slab
 ...
 s:delete{3}
 ---
-- [3, 3, 'test3']
+- error: Failed to allocate 16384 bytes in mempool for new slab
 ...
-check_iter_and_size(7)
+check_iter_and_size()
 ---
 - ok
 ...
@@ -460,7 +437,10 @@ for i = 1,10 do table.insert(res, (s:get{i})) end
 ...
 res
 ---
-- - [4, 4, 'test4']
+- - [1, 1, 'test1']
+  - [2, 2, 'test2']
+  - [3, 3, 'test3']
+  - [4, 4, 'test4']
   - [5, 5, 'test5']
   - [6, 6, 'test6']
   - [7, 7, 'test7']
@@ -480,7 +460,10 @@ for i = 1,10 do table.insert(res, (s:get{i})) end
 ...
 res
 ---
-- - [4, 4, 'test4']
+- - [1, 1, 'test1']
+  - [2, 2, 'test2']
+  - [3, 3, 'test3']
+  - [4, 4, 'test4']
   - [5, 5, 'test5']
   - [6, 6, 'test6']
   - [7, 7, 'test7']
diff --git a/test/box/errinj_index.test.lua b/test/box/errinj_index.test.lua
index c725b490fe1f757a87c5e5ee222f684acd29b741..6068965ee2b81012e967031d2adf5d77e5a00eec 100644
--- a/test/box/errinj_index.test.lua
+++ b/test/box/errinj_index.test.lua
@@ -31,12 +31,9 @@ res
 res = {}
 for i = 501,510 do table.insert(res, (s:get{i})) end
 res
-res = {}
-for i = 2001,2010 do table.insert(res, (s:get{i})) end
-res
 
---count must be greater that 1000 but less than 2000
-function check_iter_and_size() local count = 0 for _, t in s.index[0]:pairs() do count = count + 1 end return count <= 1000 and "fail 1" or count >= 2000 and "fail 2" or "ok" end
+--count must be exactly 10
+function check_iter_and_size() local count = 0 for _, t in s.index[0]:pairs() do count = count + 1 end return count == 10 and "ok" or "fail" end
 check_iter_and_size()
 
 for i = 2501,3500 do s:insert{i, i} end
@@ -46,10 +43,6 @@ res = {}
 for i = 1,10 do table.insert(res, (s:get{i})) end
 res
 
-for i = 3501,4500 do s:insert{i, i} end
-s:delete{3}
-check_iter_and_size()
-
 errinj.set("ERRINJ_INDEX_ALLOC", false)
 
 for i = 4501,5500 do s:insert{i, i} end
@@ -102,20 +95,18 @@ res = {}
 for i = 2001,2010 do table.insert(res, (s:get{i})) end
 res
 
---since every insertion is rejected, count must be (10 - number of deletions)
-function check_iter_and_size(size_must_be) local count = 0 for _, t in s.index[0]:pairs() do count = count + 1 end print (count) return count ~= size_must_be and "fail 1" or "ok" end
-check_iter_and_size(9)
+check_iter_and_size()
 
 for i = 2501,3500 do s:insert{i, i} end
 s:delete{2}
-check_iter_and_size(8)
+check_iter_and_size()
 res = {}
 for i = 1,10 do table.insert(res, (s:get{i})) end
 res
 
 for i = 3501,4500 do s:insert{i, i} end
 s:delete{3}
-check_iter_and_size(7)
+check_iter_and_size()
 
 errinj.set("ERRINJ_INDEX_ALLOC", false)
 
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 11374bb225919bd7d05785ca914fdea3c375a4e3..6136e80c216479bc05f4ef55915e072352ebb306 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -48,9 +48,9 @@ target_link_libraries(bps_tree.test small)
 add_executable(bps_tree_itr.test bps_tree_itr.cc ${CMAKE_SOURCE_DIR}/third_party/qsort_arg.c)
 target_link_libraries(bps_tree_itr.test small)
 add_executable(rtree.test rtree.cc ${CMAKE_SOURCE_DIR}/src/lib/salad/rtree.c)
-target_link_libraries(rtree.test)
+target_link_libraries(rtree.test small)
 add_executable(rtree_itr.test rtree_itr.cc ${CMAKE_SOURCE_DIR}/src/lib/salad/rtree.c)
-target_link_libraries(rtree_itr.test)
+target_link_libraries(rtree_itr.test small)
 add_executable(matras.test matras.cc)
 target_link_libraries(matras.test small)
 add_executable(light.test light.cc)
diff --git a/test/unit/rtree.cc b/test/unit/rtree.cc
index 9e4960c862b0a49f901150f994eb98212e11396e..e8836deb9d5c81722f0e45d55e4c8de1d7373ccf 100644
--- a/test/unit/rtree.cc
+++ b/test/unit/rtree.cc
@@ -9,15 +9,17 @@
 
 static int page_count = 0;
 
+const uint32_t extent_size = RTREE_PAGE_SIZE * 8;
+
 static void *
-page_alloc()
+extent_alloc()
 {
 	page_count++;
-	return malloc(RTREE_PAGE_SIZE);
+	return malloc(extent_size);
 }
 
 static void
-page_free(void *page)
+extent_free(void *page)
 {
 	page_count--;
 	free(page);
@@ -34,7 +36,7 @@ simple_check()
 	header();
 
 	struct rtree tree;
-	rtree_init(&tree, page_alloc, page_free);
+	rtree_init(&tree, extent_size, extent_alloc, extent_free);
 
 	printf("Insert 1..X, remove 1..X\n");
 	for (size_t i = 1; i <= rounds; i++) {
@@ -241,8 +243,6 @@ neighbor_test()
 	header();
 
 	const int test_count = 1000;
-	struct rtree_iterator iterator;
-	rtree_iterator_init(&iterator);
 	struct rtree_rect arr[test_count];
 	static struct rtree_rect basis;
 
@@ -255,10 +255,12 @@ neighbor_test()
 
 	for (size_t i = 0; i <= test_count; i++) {
 		struct rtree tree;
-		rtree_init(&tree, page_alloc, page_free);
+		rtree_init(&tree, extent_size, extent_alloc, extent_free);
 
 		rtree_test_build(&tree, arr, i);
 
+		struct rtree_iterator iterator;
+		rtree_iterator_init(&iterator);
 		if (!rtree_search(&tree, &basis, SOP_NEIGHBOR, &iterator) && i != 0) {
 			fail("search is successful", "true");
 		}
@@ -269,10 +271,10 @@ neighbor_test()
 				fail("wrong search result", "true");
 			}
 		}
+		rtree_iterator_destroy(&iterator);
 		rtree_destroy(&tree);
 	}
 
-	rtree_iterator_destroy(&iterator);
 
 	footer();
 }
diff --git a/test/unit/rtree_itr.cc b/test/unit/rtree_itr.cc
index fae7c431108f5346f2cdcdcd1126d6337794bf1e..08bc959aec8ec7efc0c194ba0aeadea47b822ce2 100644
--- a/test/unit/rtree_itr.cc
+++ b/test/unit/rtree_itr.cc
@@ -6,19 +6,21 @@
 #include "unit.h"
 #include "salad/rtree.h"
 
-static int page_count = 0;
+static int extent_count = 0;
+
+const uint32_t extent_size = RTREE_PAGE_SIZE * 8;
 
 static void *
-page_alloc()
+extent_alloc()
 {
-	page_count++;
-	return malloc(RTREE_PAGE_SIZE);
+	extent_count++;
+	return malloc(extent_size);
 }
 
 static void
-page_free(void *page)
+extent_free(void *page)
 {
-	page_count--;
+	extent_count--;
 	free(page);
 }
 
@@ -28,7 +30,7 @@ itr_check()
 	header();
 
 	struct rtree tree;
-	rtree_init(&tree, page_alloc, page_free);
+	rtree_init(&tree, extent_size, extent_alloc, extent_free);
 
 	/* Filling tree */
 	const size_t count1 = 10000;
@@ -182,8 +184,8 @@ itr_check()
 	}
 
 	rtree_purge(&tree);
-	rtree_destroy(&tree);
 	rtree_iterator_destroy(&iterator);
+	rtree_destroy(&tree);
 
 	footer();
 }
@@ -197,9 +199,6 @@ itr_invalidate_check()
 	const size_t max_delete_count = 100;
 	const size_t max_insert_count = 200;
 	const size_t attempt_count = 100;
-	struct rtree_iterator iterators[test_size];
-	for (size_t i = 0; i < test_size; i++)
-		rtree_iterator_init(iterators + i);
 
 	struct rtree_rect rect;
 
@@ -212,7 +211,10 @@ itr_invalidate_check()
 			del_cnt = test_size - del_pos;
 		}
 		struct rtree tree;
-		rtree_init(&tree, page_alloc, page_free);
+		rtree_init(&tree, extent_size, extent_alloc, extent_free);
+		struct rtree_iterator iterators[test_size];
+		for (size_t i = 0; i < test_size; i++)
+			rtree_iterator_init(iterators + i);
 
 		for (size_t i = 0; i < test_size; i++) {
 			rtree_set2d(&rect, i, i, i, i);
@@ -240,6 +242,9 @@ itr_invalidate_check()
 				fail("Iterator was not invalidated (18)", "true");
 			}
 		}
+
+		for (size_t i = 0; i < test_size; i++)
+			rtree_iterator_destroy(iterators + i);
 		rtree_destroy(&tree);
 	}
 
@@ -250,7 +255,10 @@ itr_invalidate_check()
 		size_t ins_cnt = rand() % max_insert_count + 1;
 
 		struct rtree tree;
-		rtree_init(&tree, page_alloc, page_free);
+		rtree_init(&tree, extent_size, extent_alloc, extent_free);
+		struct rtree_iterator iterators[test_size];
+		for (size_t i = 0; i < test_size; i++)
+			rtree_iterator_init(iterators + i);
 
 		for (size_t i = 0; i < test_size; i++) {
 			rtree_set2d(&rect, i, i, i, i);
@@ -276,12 +284,12 @@ itr_invalidate_check()
 				fail("Iterator was not invalidated (22)", "true");
 			}
 		}
+
+		for (size_t i = 0; i < test_size; i++)
+			rtree_iterator_destroy(iterators + i);
 		rtree_destroy(&tree);
 	}
 
-	for (size_t i = 0; i < test_size; i++)
-		rtree_iterator_destroy(iterators + i);
-
 	footer();
 }
 
@@ -290,7 +298,7 @@ main(void)
 {
 	itr_check();
 	itr_invalidate_check();
-	if (page_count != 0) {
+	if (extent_count != 0) {
 		fail("memory leak!", "false");
 	}
 }