From 752fd27fbc02250a159e536045743ec8a8f5e69a Mon Sep 17 00:00:00 2001
From: Alexandr <a.lyapunov@corp.mail.ru>
Date: Tue, 31 Dec 2013 15:10:56 +0400
Subject: [PATCH] fixes, follows from discussion
 https://github.com/tarantool/tarantool/issues/79#issuecomment-29309533

---
 src/box/tree_index.cc           |  21 ++--
 test/big/tarantool.cfg          |   8 ++
 test/big/tree_alloc_fail.result | 176 ++++++++++++++++++++++++++++++++
 test/big/tree_alloc_fail.test   |  50 +++++++++
 test/box/errinj.result          |  35 -------
 test/box/errinj.test            |  14 ---
 6 files changed, 243 insertions(+), 61 deletions(-)
 create mode 100644 test/big/tree_alloc_fail.result
 create mode 100644 test/big/tree_alloc_fail.test

diff --git a/src/box/tree_index.cc b/src/box/tree_index.cc
index 5feba50828..1333c7f4d8 100644
--- a/src/box/tree_index.cc
+++ b/src/box/tree_index.cc
@@ -281,8 +281,8 @@ TreeIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple,
 		sptree_index_fold(&new_node, new_tuple);
 
 		/* Try to optimistically replace the new_tuple. */
-		int tree_res =  sptree_index_replace(&tree, &new_node,
-						     (void **) &p_dup_node);
+		int tree_res = sptree_index_replace(&tree, &new_node,
+						    (void **) &p_dup_node);
 
 		if (tree_res) {
 			tnt_raise(ClientError, ER_MEMORY_ISSUE, tree_res,
@@ -393,8 +393,7 @@ TreeIndex::beginBuild()
 	size_t sz = tree.max_size * sizeof(struct sptree_index_node);
 	tree.members = malloc(sz);
 	if (tree.members == NULL) {
-		tnt_raise(ClientError, ER_MEMORY_ISSUE,
-			  sz, "TreeIndex", "begin build");
+		panic("malloc(): failed to allocate %" PRI_SZ " bytes", sz);
 	}
 }
 
@@ -407,8 +406,8 @@ TreeIndex::buildNext(struct tuple *tuple)
 		size_t sz = tree.max_size * sizeof(struct sptree_index_node);
 		tree.members = realloc(tree.members, sz);
 		if (tree.members == NULL) {
-			tnt_raise(ClientError, ER_MEMORY_ISSUE,
-				  sz, "TreeIndex", "begin build");
+			panic("malloc(): failed to allocate %" PRI_SZ " bytes",
+			      sz);
 		}
 	}
 
@@ -434,8 +433,7 @@ TreeIndex::endBuild()
 			  sptree_index_node_compare,
 			  this);
 	if (tree_res) {
-		tnt_raise(ClientError, ER_MEMORY_ISSUE,
-			  tree_res, "TreeIndex", "init tree");
+		panic("tree_init: failed to allocate %d bytes", tree_res);
 	}
 }
 
@@ -455,8 +453,8 @@ TreeIndex::build(Index *pk)
 		size_t sz = estimated_tuples * sizeof(struct sptree_index_node);
 		nodes = malloc(sz);
 		if (nodes == NULL) {
-			tnt_raise(ClientError, ER_MEMORY_ISSUE,
-				  sz, "TreeIndex", "build");
+			panic("malloc(): failed to allocate %" PRI_SZ " bytes",
+			      sz);
 		}
 	}
 
@@ -485,7 +483,6 @@ TreeIndex::build(Index *pk)
 					     : sptree_index_node_compare_dup,
 			  this);
 	if (tree_res) {
-		tnt_raise(ClientError, ER_MEMORY_ISSUE,
-			  tree_res, "TreeIndex", "init tree");
+		panic("tree_init: failed to allocate %d bytes", tree_res);
 	}
 }
diff --git a/test/big/tarantool.cfg b/test/big/tarantool.cfg
index 58def14511..619d1396e7 100644
--- a/test/big/tarantool.cfg
+++ b/test/big/tarantool.cfg
@@ -394,3 +394,11 @@ space[27].index[1].key_field[0].fieldno = 2
 space[27].index[1].key_field[0].type = NUM
 space[27].index[1].key_field[1].fieldno = 4
 space[27].index[1].key_field[1].type = NUM
+
+# Test alloc fail in tree
+space[28].enabled = 1
+
+space[28].index[0].type = TREE
+space[28].index[0].unique = true
+space[28].index[0].key_field[0].fieldno = 0
+space[28].index[0].key_field[0].type = NUM
diff --git a/test/big/tree_alloc_fail.result b/test/big/tree_alloc_fail.result
new file mode 100644
index 0000000000..843173a8b7
--- /dev/null
+++ b/test/big/tree_alloc_fail.result
@@ -0,0 +1,176 @@
+lua s = box.space[28]
+---
+...
+lua for i = 1,10 do s:insert(i, i, 'test' .. i) end
+---
+...
+lua for i = 1,10 do print(s:select(0, i)) end
+---
+1: {1, 'test1'}
+2: {2, 'test2'}
+3: {3, 'test3'}
+4: {4, 'test4'}
+5: {5, 'test5'}
+6: {6, 'test6'}
+7: {7, 'test7'}
+8: {8, 'test8'}
+9: {9, 'test9'}
+10: {10, 'test10'}
+...
+lua for t in s.index[0]:iterator(box.index.ALL) do print(t); end
+---
+1: {1, 'test1'}
+2: {2, 'test2'}
+3: {3, 'test3'}
+4: {4, 'test4'}
+5: {5, 'test5'}
+6: {6, 'test6'}
+7: {7, 'test7'}
+8: {8, 'test8'}
+9: {9, 'test9'}
+10: {10, 'test10'}
+...
+set injection ERRINJ_TREE_ALLOC on
+---
+ok
+...
+lua for i = 1,10 do print(s:select(0, i)) end
+---
+1: {1, 'test1'}
+2: {2, 'test2'}
+3: {3, 'test3'}
+4: {4, 'test4'}
+5: {5, 'test5'}
+6: {6, 'test6'}
+7: {7, 'test7'}
+8: {8, 'test8'}
+9: {9, 'test9'}
+10: {10, 'test10'}
+...
+lua for i = 501,1000 do s:insert(i, i) end
+---
+error: 'Failed to allocate 1024 bytes in TreeIndex for replace'
+...
+lua s:delete(1)
+---
+ - 1: {1, 'test1'}
+...
+lua for t in s.index[0]:iterator(box.index.ALL) do print(t) end
+---
+error: 'Failed to allocate 196 bytes in TreeIndex for init iterator'
+...
+set injection ERRINJ_TREE_ALLOC off
+---
+ok
+...
+lua s:select(0, 1)
+---
+...
+set injection ERRINJ_TREE_ALLOC on
+---
+ok
+...
+lua for i = 1,10 do print(s:select(0, i)) end
+---
+2: {2, 'test2'}
+3: {3, 'test3'}
+4: {4, 'test4'}
+5: {5, 'test5'}
+6: {6, 'test6'}
+7: {7, 'test7'}
+8: {8, 'test8'}
+9: {9, 'test9'}
+10: {10, 'test10'}
+...
+lua for i = 1001,1500 do s:insert(i, i) end
+---
+error: 'Failed to allocate 1024 bytes in TreeIndex for replace'
+...
+lua s:delete(2)
+---
+ - 2: {2, 'test2'}
+...
+lua s.index[0]:iterator(box.index.ALL)
+---
+error: 'Failed to allocate 200 bytes in TreeIndex for init iterator'
+...
+set injection ERRINJ_TREE_ALLOC off
+---
+ok
+...
+lua s:select(0, 1)
+---
+...
+set injection ERRINJ_TREE_ALLOC on
+---
+ok
+...
+lua for i = 1,10 do print(s:select(0, i)) end
+---
+3: {3, 'test3'}
+4: {4, 'test4'}
+5: {5, 'test5'}
+6: {6, 'test6'}
+7: {7, 'test7'}
+8: {8, 'test8'}
+9: {9, 'test9'}
+10: {10, 'test10'}
+...
+lua for i = 1501,2000 do s:insert(i, i) end
+---
+error: 'Failed to allocate 1024 bytes in TreeIndex for replace'
+...
+lua s:delete(3)
+---
+ - 3: {3, 'test3'}
+...
+lua s.index[0]:iterator(box.index.ALL)
+---
+error: 'Failed to allocate 200 bytes in TreeIndex for init iterator'
+...
+set injection ERRINJ_TREE_ALLOC off
+---
+ok
+...
+lua for i = 2001,2500 do s:insert(i, i) end
+---
+...
+lua for i = 1,10 do print(s:select(0, i)) end
+---
+4: {4, 'test4'}
+5: {5, 'test5'}
+6: {6, 'test6'}
+7: {7, 'test7'}
+8: {8, 'test8'}
+9: {9, 'test9'}
+10: {10, 'test10'}
+...
+lua s:delete(8)
+---
+ - 8: {8, 'test8'}
+...
+lua for i = 1,10 do print(s:select(0, i)) end
+---
+4: {4, 'test4'}
+5: {5, 'test5'}
+6: {6, 'test6'}
+7: {7, 'test7'}
+9: {9, 'test9'}
+10: {10, 'test10'}
+...
+lua for i = 2001,2010 do print(s:select(0, i)) end
+---
+2001: {2001}
+2002: {2002}
+2003: {2003}
+2004: {2004}
+2005: {2005}
+2006: {2006}
+2007: {2007}
+2008: {2008}
+2009: {2009}
+2010: {2010}
+...
+lua s:truncate()
+---
+...
diff --git a/test/big/tree_alloc_fail.test b/test/big/tree_alloc_fail.test
new file mode 100644
index 0000000000..ef7de11a7d
--- /dev/null
+++ b/test/big/tree_alloc_fail.test
@@ -0,0 +1,50 @@
+# encoding: tarantool
+#
+import sys
+
+# Check a failed realloc in tree.
+exec admin "lua s = box.space[28]"
+
+exec admin "lua for i = 1,10 do s:insert(i, i, 'test' .. i) end"
+exec admin "lua for i = 1,10 do print(s:select(0, i)) end"
+exec admin "lua for t in s.index[0]:iterator(box.index.ALL) do print(t); end"
+
+exec admin "set injection ERRINJ_TREE_ALLOC on"
+
+exec admin "lua for i = 1,10 do print(s:select(0, i)) end"
+exec admin "lua for i = 501,1000 do s:insert(i, i) end"
+exec admin "lua s:delete(1)"
+exec admin "lua for t in s.index[0]:iterator(box.index.ALL) do print(t) end"
+
+# reserve memory for iterator in index. last insert may increase tree depth
+exec admin "set injection ERRINJ_TREE_ALLOC off"
+exec admin "lua s:select(0, 1)"
+exec admin "set injection ERRINJ_TREE_ALLOC on"
+
+exec admin "lua for i = 1,10 do print(s:select(0, i)) end"
+
+exec admin "lua for i = 1001,1500 do s:insert(i, i) end"
+exec admin "lua s:delete(2)"
+exec admin "lua s.index[0]:iterator(box.index.ALL)"
+
+# reserve memory for iterator in index. last insert may increase tree depth
+#  (if rebalance was not initiated)
+exec admin "set injection ERRINJ_TREE_ALLOC off"
+exec admin "lua s:select(0, 1)"
+exec admin "set injection ERRINJ_TREE_ALLOC on"
+
+exec admin "lua for i = 1,10 do print(s:select(0, i)) end"
+exec admin "lua for i = 1501,2000 do s:insert(i, i) end"
+exec admin "lua s:delete(3)"
+exec admin "lua s.index[0]:iterator(box.index.ALL)"
+
+exec admin "set injection ERRINJ_TREE_ALLOC off"
+
+exec admin "lua for i = 2001,2500 do s:insert(i, i) end"
+exec admin "lua for i = 1,10 do print(s:select(0, i)) end"
+exec admin "lua s:delete(8)"
+exec admin "lua for i = 1,10 do print(s:select(0, i)) end"
+exec admin "lua for i = 2001,2010 do print(s:select(0, i)) end"
+exec admin "lua s:truncate()"
+
+# vim: syntax=python
diff --git a/test/box/errinj.result b/test/box/errinj.result
index eef7c12f29..e6bb917253 100644
--- a/test/box/errinj.result
+++ b/test/box/errinj.result
@@ -111,38 +111,3 @@ ok
 lua box.space[0]:truncate()
 ---
 ...
-lua for i = 1,10 do box.space[0]:insert(i, i, 'testtesttest') end
----
-...
-set injection ERRINJ_TREE_ALLOC on
----
-ok
-...
-lua for i = 11,1000 do box.space[0]:insert(i, i) end
----
-error: 'Failed to allocate 1024 bytes in TreeIndex for replace'
-...
-lua box.space[0].index[0]:iterator(box.index.ALL)
----
-error: 'Failed to allocate 196 bytes in TreeIndex for init iterator'
-...
-set injection ERRINJ_TREE_ALLOC off
----
-ok
-...
-lua for i = 1,10 do print(box.space[0]:select(0, i)) end
----
-1: {1, 'testtesttest'}
-2: {2, 'testtesttest'}
-3: {3, 'testtesttest'}
-4: {4, 'testtesttest'}
-5: {5, 'testtesttest'}
-6: {6, 'testtesttest'}
-7: {7, 'testtesttest'}
-8: {8, 'testtesttest'}
-9: {9, 'testtesttest'}
-10: {10, 'testtesttest'}
-...
-lua box.space[0]:truncate()
----
-...
diff --git a/test/box/errinj.test b/test/box/errinj.test
index 7f692e2ebe..63d1a04ce6 100644
--- a/test/box/errinj.test
+++ b/test/box/errinj.test
@@ -43,18 +43,4 @@ exec admin "set injection ERRINJ_WAL_ROTATE on"
 exec admin "lua box.space[0]:truncate()"
 exec admin "set injection ERRINJ_WAL_ROTATE off"
 exec admin "lua box.space[0]:truncate()"
-
-# Check a failed realloc in tree.
-server.stop()
-server.deploy("box/tarantool_tree_alloc.cfg")
-exec admin "lua for i = 1,10 do box.space[0]:insert(i, i, 'testtesttest') end"
-exec admin "set injection ERRINJ_TREE_ALLOC on"
-exec admin "lua for i = 11,1000 do box.space[0]:insert(i, i) end"
-exec admin "lua box.space[0].index[0]:iterator(box.index.ALL)"
-exec admin "set injection ERRINJ_TREE_ALLOC off"
-exec admin "lua for i = 1,10 do print(box.space[0]:select(0, i)) end"
-exec admin "lua box.space[0]:truncate()"
-server.stop()
-server.deploy(self.suite_ini["config"])
-
 # vim: syntax=python
-- 
GitLab