From bf911a3105edbc0f0c49b073fa7c168a61bd4569 Mon Sep 17 00:00:00 2001
From: knizhnik <knizhnik@garret.ru>
Date: Sat, 25 Oct 2014 16:28:23 +0400
Subject: [PATCH] Introduce BOX key type for R-Tree

---
 src/box/engine_memtx.cc           |  17 +--
 src/box/index.cc                  |  13 +-
 src/box/key_def.cc                |   9 +-
 src/box/key_def.h                 |   2 +-
 src/box/rtree_index.cc            | 185 ++++++++++++----------------
 test/box/rtree_array.result       |   4 +-
 test/box/rtree_array.test.lua     |   2 +-
 test/box/rtree_benchmark.result   |  12 +-
 test/box/rtree_benchmark.test.lua |   8 +-
 test/box/rtree_point.result       |  88 +++++++-------
 test/box/rtree_point.test.lua     |  20 ++--
 test/box/rtree_point_r2.result    |  88 +++++++-------
 test/box/rtree_point_r2.test.lua  |  20 ++--
 test/box/rtree_rect.result        |  51 ++++----
 test/box/rtree_rect.test.lua      |   8 +-
 test/box/suite.ini                |   2 +-
 third_party/rtree.cc              | 193 +++++++++++++++---------------
 third_party/rtree.h               |  74 ++++++------
 18 files changed, 366 insertions(+), 430 deletions(-)

diff --git a/src/box/engine_memtx.cc b/src/box/engine_memtx.cc
index 1ede5cbf32..fd47ba665d 100644
--- a/src/box/engine_memtx.cc
+++ b/src/box/engine_memtx.cc
@@ -142,22 +142,9 @@ MemtxFactory::keydefCheck(struct key_def *key_def)
 		/* TREE index has no limitations. */
 		break;
 	case RTREE:
-		if (key_def->part_count != 1 && key_def->part_count != 2 && key_def->part_count != 4) {
+		if (key_def->part_count != 1 || key_def->parts[0].type != BOX) {
 			tnt_raise(ClientError, ER_MODIFY_INDEX,
-				  "R-Tree index can be defied only for points (two parts) or rectangles (four parts)");
-		}
-		if (key_def->part_count == 1) {
-			if (key_def->parts[0].type != ARR) {
-				tnt_raise(ClientError, ER_MODIFY_INDEX,
-					  "R-Tree index can be defied only for points, rectangles and arrays");
-			}
-		} else {
-			for (int i = 0; i < key_def->part_count; i++) {
-				if (key_def->parts[i].type != NUM) {
-					tnt_raise(ClientError, ER_MODIFY_INDEX,
-						  "R-Tree index can be defied only for numeric fields");
-				}
-			}
+				  "R-Tree index can be defied only for BOX type");
 		}
 		break;
 	case BITSET:
diff --git a/src/box/index.cc b/src/box/index.cc
index 54880ff19e..4f717db46d 100644
--- a/src/box/index.cc
+++ b/src/box/index.cc
@@ -75,19 +75,12 @@ key_validate(struct key_def *key_def, enum iterator_type type, const char *key,
 
         if (key_def->type == RTREE) {
                 if (part_count != 1 && part_count != 2 && part_count != 4) {
-                        tnt_raise(ClientError, ER_KEY_PART_COUNT,
-                                  "R-Tree key should be point (two integer coordinates) or rectangles (four integer coordinates)");
+                        tnt_raise(ClientError, ER_KEY_PART_COUNT, 4, part_count);
                 }
-		if (part_count == 1) {
+		for (uint32_t part = 0; part < part_count; part++) {
 			enum mp_type mp_type = mp_typeof(*key);
 			mp_next(&key);
-			key_mp_type_validate(ARR, mp_type, ER_KEY_PART_TYPE, 0);
-		} else {
-			for (uint32_t part = 0; part < part_count; part++) {
-				enum mp_type mp_type = mp_typeof(*key);
-				mp_next(&key);
-				key_mp_type_validate(NUM, mp_type, ER_KEY_PART_TYPE, part);
-			}
+			key_mp_type_validate(BOX, mp_type, ER_KEY_PART_TYPE, part);
 		}
         } else {
                 if (part_count > key_def->part_count)
diff --git a/src/box/key_def.cc b/src/box/key_def.cc
index 3f70f12d2a..8dbc59afc4 100644
--- a/src/box/key_def.cc
+++ b/src/box/key_def.cc
@@ -33,14 +33,15 @@
 #include <stdio.h>
 #include "exception.h"
 
-const char *field_type_strs[] = {"UNKNOWN", "NUM", "STR", "ARR", "\0"};
+const char *field_type_strs[] = {"UNKNOWN", "NUM", "STR", "ARR", "BOX", "\0"};
 STRS(index_type, ENUM_INDEX_TYPE);
 
 const uint32_t key_mp_type[] = {
 	/* [UNKNOWN] = */ UINT32_MAX,
-	/* [NUM]     = */ (1U << MP_UINT)|(1U << MP_INT)|(1U << MP_FLOAT)|(1U << MP_DOUBLE),
-	/* [STR]    = */  1U << MP_STR,
-	/* [ARR]    = */  1U << MP_ARRAY
+	/* [NUM]     = */  1U << MP_UINT,
+	/* [STR]    =  */  1U << MP_STR,
+	/* [ARR]    =  */  1U << MP_ARRAY,
+	/* [BOX]     = */ (1U << MP_UINT)|(1U << MP_INT)|(1U << MP_FLOAT)|(1U << MP_DOUBLE)|(1U << MP_ARRAY)
 };
 
 enum schema_object_type
diff --git a/src/box/key_def.h b/src/box/key_def.h
index b5df2bc553..b1340fd955 100644
--- a/src/box/key_def.h
+++ b/src/box/key_def.h
@@ -75,7 +75,7 @@ schema_object_type(const char *name);
  * since there is a mismatch between enum name (STRING) and type
  * name literal ("STR"). STR is already used as Objective C type.
  */
-enum field_type { UNKNOWN = 0, NUM, STRING, ARR, field_type_MAX };
+enum field_type { UNKNOWN = 0, NUM, STRING, ARR, BOX, field_type_MAX };
 extern const char *field_type_strs[];
 
 static inline uint32_t
diff --git a/src/box/rtree_index.cc b/src/box/rtree_index.cc
index bc3e74cbf6..edfd38129c 100644
--- a/src/box/rtree_index.cc
+++ b/src/box/rtree_index.cc
@@ -34,12 +34,20 @@
 #include "fiber.h"
 #include "small/small.h"
 
+/** For all memory used by all rtree indexes. */
+static struct mempool rtree_page_pool;
+/** Number of allocated pages. */
+static int rtree_page_pool_initialized = 0;
+
 /* {{{ Utilities. *************************************************/
 
 inline void extract_rectangle(rectangle_t& r, struct tuple const* tuple, struct key_def* kd)
 {
-        switch (kd->part_count) {
-	case 1: // vector
+	const char* elems = tuple_field(tuple, kd->parts[0].fieldno);
+	uint32_t size = mp_decode_array(&elems);
+        assert (kd->part_count == 1);
+	switch (size) {
+	case 1: // array
 	{
 		const char* elems = tuple_field(tuple, kd->parts[0].fieldno);
 		uint32_t size = mp_decode_array(&elems);
@@ -55,23 +63,26 @@ inline void extract_rectangle(rectangle_t& r, struct tuple const* tuple, struct
 			break;
 		default:
 			tnt_raise(ClientError, ER_UNSUPPORTED,
-				  "R-Tree field should be array with size 2 point) or 4 (rectangle)");
+				  "R-Tree index", "Field should be array with "
+				  "size 2 (point) or 4 (rectangle)");
 
 		}
 		break;
 	}
-        case 2: // point
-                r.boundary[0] = r.boundary[2] = tuple_field_num(tuple, kd->parts[0].fieldno);
-                r.boundary[1] = r.boundary[3] = tuple_field_num(tuple, kd->parts[1].fieldno);
-                break;
-        case 4: // rectangle
-                for (int i = 0; i < 4; i++) {
-                        r.boundary[i] = tuple_field_num(tuple, kd->parts[i].fieldno);
-                }
-                break;
-        default:
-                assert(false);
-        }
+	case 2: // point
+		r.boundary[0] = r.boundary[2] = mp_decode_num(&elems, 0);
+		r.boundary[1] = r.boundary[3] = mp_decode_num(&elems, 1);
+		break;
+	case 4:
+		for (int i = 0; i < 4; i++) {
+			r.boundary[i] = mp_decode_num(&elems, i);
+		}
+		break;
+	default:
+		tnt_raise(ClientError, ER_UNSUPPORTED,
+			  "R-Tree index", "Key should contain 2 (point) or 4 (rectangle) coordinates");
+
+	}
 }
 /* {{{ TreeIndex Iterators ****************************************/
 
@@ -96,54 +107,18 @@ rtree_iterator_next(struct iterator *i)
 
 /* {{{ TreeIndex  **********************************************************/
 
-class MemPoolAllocatorFactory : public FixedSizeAllocator::Factory
+static void *
+rtree_page_alloc()
 {
-	class Allocator : public FixedSizeAllocator
-	{
-	private:
-		struct mempool pool;
-		size_t size;
-	public:
-		Allocator(size_t obj_size)
-		{
-			size = obj_size;
-			mempool_create(&pool, &cord()->slabc, obj_size);
-		}
-
-		virtual void* alloc()
-		{
-			return mempool_alloc(&pool);
-		}
-
-		virtual void free(void* ptr)
-		{
-			mempool_free(&pool, ptr);
-		}
-
-		virtual size_t used_size()
-		{
-			return mempool_used(&pool);
-		}
-
-		virtual ~Allocator()
-		{
-			mempool_destroy(&pool);
-		}
-	};
-public:
-	virtual FixedSizeAllocator* create(size_t obj_size)
-	{
-		return new Allocator(obj_size);
-	}
-
-	virtual void destroy(FixedSizeAllocator* allocator)
-	{
-		delete allocator;
-	}
-};
-
-static MemPoolAllocatorFactory rtree_allocator_factory;
+	ERROR_INJECT(ERRINJ_INDEX_ALLOC, return 0);
+	return mempool_alloc(&rtree_page_pool);
+}
 
+static void
+rtree_page_free(void *page)
+{
+	return mempool_free(&rtree_page_pool, page);
+}
 RTreeIndex::~RTreeIndex()
 {
 	// Iterator has to be destroye prior to tree
@@ -154,24 +129,16 @@ RTreeIndex::~RTreeIndex()
 }
 
 RTreeIndex::RTreeIndex(struct key_def *key_def)
-: Index(key_def), tree(&rtree_allocator_factory)
+  : Index(key_def), tree(rtree_page_alloc, rtree_page_free)
 {
-        if (key_def->part_count != 1 && key_def->part_count != 2 && key_def->part_count != 4) {
+	if (rtree_page_pool_initialized == 0) {
+		mempool_create(&rtree_page_pool, &cord()->slabc,
+			       RTREE_PAGE_SIZE);
+		rtree_page_pool_initialized = 1;
+	}
+        if (key_def->part_count != 1 || key_def->parts[0].type != BOX) {
                 tnt_raise(ClientError, ER_UNSUPPORTED,
-                          "R-Tree index can be defied only for points (two parts) or rectangles (four parts)");
-        }
-	if (key_def->part_count == 1) {
-		if (key_def->parts[0].type != ARR) {
-			tnt_raise(ClientError, ER_UNSUPPORTED,
-				  "R-Tree index can be defied only for arrays, points and rectangles");
-		}
-	} else {
-		for (int i = 0; i < key_def->part_count; i++) {
-			if (key_def->parts[i].type != NUM) {
-				tnt_raise(ClientError, ER_UNSUPPORTED,
-					  "R-Tree index can be defied only for numeric fields");
-			}
-		}
+                          "R-Tree index", "Key should have BOX type");
         }
 }
 
@@ -208,23 +175,25 @@ RTreeIndex::findByKey(const char *key, uint32_t part_count) const
 			break;
 		default:
 			tnt_raise(ClientError, ER_UNSUPPORTED,
-				  "R-Tree key should be array of 2 (point ) or 4 (rectangle) numeric coordinates");
+				  "R-Tree key", "Key should be array of 2 (point) "
+				  "or 4 (rectangle) numeric coordinates");
 		}
 		break;
 	}
-        case 2:
-                r.boundary[0] = r.boundary[2] = mp_decode_num(&key, 0);
-                r.boundary[1] = r.boundary[3] = mp_decode_num(&key, 1);
-                break;
-        case 4:
-                for (int i = 0; i < 4; i++) {
-                        r.boundary[i] = mp_decode_num(&key, i);
-                }
-                break;
-        default:
-                tnt_raise(ClientError, ER_UNSUPPORTED,
-                          "R-Tree key should be point (two numeric coordinates) or rectangle (four numeric coordinates)");
-        }
+	case 2:
+		r.boundary[0] = r.boundary[2] = mp_decode_num(&key, 0);
+		r.boundary[1] = r.boundary[3] = mp_decode_num(&key, 1);
+		break;
+	case 4:
+		for (int i = 0; i < 4; i++) {
+			r.boundary[i] = mp_decode_num(&key, i);
+		}
+		break;
+	default:
+		tnt_raise(ClientError, ER_UNSUPPORTED,
+			  "R-Tree key", "Key should contain 2 (point) "
+			  "or 4 (rectangle) numeric coordinates");
+	}
         if (tree.search(r, SOP_OVERLAPS, iterator)) {
                 return (struct tuple*)iterator.next();
         }
@@ -273,7 +242,7 @@ RTreeIndex::initIterator(struct iterator *iterator, enum iterator_type type,
         case 0:
                 if (type != ITER_ALL) {
                         tnt_raise(ClientError, ER_UNSUPPORTED,
-				  "It is possible to omit key only for ITER_ALL");
+				  "R-Tree index", "It is possible to omit key only for ITER_ALL");
                 }
                 break;
 	case 1:
@@ -291,23 +260,25 @@ RTreeIndex::initIterator(struct iterator *iterator, enum iterator_type type,
 			break;
 		default:
 			tnt_raise(ClientError, ER_UNSUPPORTED,
-				  "R-Tree key should be array of 2 (point ) or 4 (rectangle) numeric coordinates");
+				  "R-Tree index", "Key should be array of 2 (point) "
+				  "or 4 (rectangle) numeric coordinates");
 		}
 		break;
 	}
-        case 2:
-                r.boundary[0] = r.boundary[2] = mp_decode_num(&key, 0);
-                r.boundary[1] = r.boundary[3] = mp_decode_num(&key, 1);
-                break;
-        case 4:
-                for (int i = 0; i < 4; i++) {
-                        r.boundary[i] = mp_decode_num(&key, i);
-                }
-                break;
-        default:
-                tnt_raise(ClientError, ER_UNSUPPORTED,
-                          "R-Tree key should be point (two numeric coordinates) or rectangle (four numeric coordinates)");
-        }
+	case 2:
+		r.boundary[0] = r.boundary[2] = mp_decode_num(&key, 0);
+		r.boundary[1] = r.boundary[3] = mp_decode_num(&key, 1);
+		break;
+	case 4:
+		for (int i = 0; i < 4; i++) {
+			r.boundary[i] = mp_decode_num(&key, i);
+		}
+		break;
+	default:
+		tnt_raise(ClientError, ER_UNSUPPORTED,
+			  "R-Tree index", "Key contain 2 (point) "
+			  "or 4 (rectangle) numeric coordinates");
+	}
         Spatial_search_op op;
         switch (type) {
         case ITER_ALL:
@@ -336,7 +307,7 @@ RTreeIndex::initIterator(struct iterator *iterator, enum iterator_type type,
                 break;
         default:
                 tnt_raise(ClientError, ER_UNSUPPORTED,
-                          "Unsupported search operation %d for R-Tree", type);
+                          "R-Tree index", "Unsupported search operation for R-Tree");
         }
         tree.search(r, op, it->impl);
 }
diff --git a/test/box/rtree_array.result b/test/box/rtree_array.result
index d983ed9a77..c4b09d00d5 100644
--- a/test/box/rtree_array.result
+++ b/test/box/rtree_array.result
@@ -12,11 +12,11 @@ s:create_index('primary')
   name: primary
   type: TREE
 ...
-s:create_index('spatial', { type = 'rtree', parts = {2, 'arr'}})
+s:create_index('spatial', { type = 'rtree', parts = {2, 'box'}})
 ---
 - unique: true
   parts:
-  - type: ARR
+  - type: BOX
     fieldno: 2
   id: 1
   space_id: 512
diff --git a/test/box/rtree_array.test.lua b/test/box/rtree_array.test.lua
index 2221cb88ca..511208bce1 100644
--- a/test/box/rtree_array.test.lua
+++ b/test/box/rtree_array.test.lua
@@ -1,6 +1,6 @@
 s = box.schema.create_space('spatial')
 s:create_index('primary')
-s:create_index('spatial', { type = 'rtree', parts = {2, 'arr'}})
+s:create_index('spatial', { type = 'rtree', parts = {2, 'box'}})
 
 s:insert{1,{0.0,0.0}}
 s:insert{2,{0.0,10.0}}
diff --git a/test/box/rtree_benchmark.result b/test/box/rtree_benchmark.result
index 02bfad52f4..2042d6d355 100644
--- a/test/box/rtree_benchmark.result
+++ b/test/box/rtree_benchmark.result
@@ -12,23 +12,21 @@ s:create_index('primary')
   name: primary
   type: TREE
 ...
-s:create_index('spatial', { type = 'rtree', parts = {2, 'num', 3, 'num'}})
+s:create_index('spatial', { type = 'rtree', parts = {2, 'box'}})
 ---
 - unique: true
   parts:
-  - type: NUM
+  - type: BOX
     fieldno: 2
-  - type: NUM
-    fieldno: 3
   id: 1
   space_id: 512
   name: spatial
   type: RTREE
 ...
-n_records = 1000000
+n_records = 100000
 ---
 ...
-n_iterations = 100000
+n_iterations = 10000
 ---
 ...
 n_neighbors = 10
@@ -42,7 +40,7 @@ start = os.clock()
 ...
 --# setopt delimiter ';'
 for i = 1, n_records do
-   s:insert{i,180*math.random(),180*math.random()}
+   s:insert{i,{180*math.random(),180*math.random()}}
 end;
 ---
 ...
diff --git a/test/box/rtree_benchmark.test.lua b/test/box/rtree_benchmark.test.lua
index 103cc4f2e3..08aa631851 100644
--- a/test/box/rtree_benchmark.test.lua
+++ b/test/box/rtree_benchmark.test.lua
@@ -1,9 +1,9 @@
 s = box.schema.create_space('rtreebench')
 s:create_index('primary')
-s:create_index('spatial', { type = 'rtree', parts = {2, 'num', 3, 'num'}})
+s:create_index('spatial', { type = 'rtree', parts = {2, 'box'}})
 
-n_records = 1000000
-n_iterations = 100000
+n_records = 100000
+n_iterations = 10000
 n_neighbors = 10
 
 file = io.open("rtree_benchmark.res", "w")
@@ -11,7 +11,7 @@ start = os.clock()
 
 --# setopt delimiter ';'
 for i = 1, n_records do
-   s:insert{i,180*math.random(),180*math.random()}
+   s:insert{i,{180*math.random(),180*math.random()}}
 end;
 
 file:write(string.format("Elapsed time for inserting %d records: %d\n", n_records, os.clock() - start));
diff --git a/test/box/rtree_point.result b/test/box/rtree_point.result
index aa86973a8f..db76b0b112 100644
--- a/test/box/rtree_point.result
+++ b/test/box/rtree_point.result
@@ -12,93 +12,91 @@ s:create_index('primary')
   name: primary
   type: TREE
 ...
-s:create_index('spatial', { type = 'rtree', parts = {2, 'num', 3, 'num'}})
+s:create_index('spatial', { type = 'rtree', parts = {2, 'box'}})
 ---
 - unique: true
   parts:
-  - type: NUM
+  - type: BOX
     fieldno: 2
-  - type: NUM
-    fieldno: 3
   id: 1
   space_id: 512
   name: spatial
   type: RTREE
 ...
-s:insert{1,0,0}
+s:insert{1,{0,0}}
 ---
-- [1, 0, 0]
+- [1, [0, 0]]
 ...
-s:insert{2,0,10}
+s:insert{2,{0,10}}
 ---
-- [2, 0, 10]
+- [2, [0, 10]]
 ...
-s:insert{3,0,50}
+s:insert{3,{0,50}}
 ---
-- [3, 0, 50]
+- [3, [0, 50]]
 ...
-s:insert{4,10,0}
+s:insert{4,{10,0}}
 ---
-- [4, 10, 0]
+- [4, [10, 0]]
 ...
-s:insert{5,50,0}
+s:insert{5,{50,0}}
 ---
-- [5, 50, 0]
+- [5, [50, 0]]
 ...
-s:insert{6,10,10}
+s:insert{6,{10,10}}
 ---
-- [6, 10, 10]
+- [6, [10, 10]]
 ...
-s:insert{7,10,50}
+s:insert{7,{10,50}}
 ---
-- [7, 10, 50]
+- [7, [10, 50]]
 ...
-s:insert{8,50,10}
+s:insert{8,{50,10}}
 ---
-- [8, 50, 10]
+- [8, [50, 10]]
 ...
-s:insert{9,50,50}
+s:insert{9,{50,50}}
 ---
-- [9, 50, 50]
+- [9, [50, 50]]
 ...
 -- select all records
 s.index.spatial:select({iterator = 'ALL'})
 ---
-- - [1, 0, 0]
-  - [2, 0, 10]
-  - [3, 0, 50]
-  - [4, 10, 0]
-  - [5, 50, 0]
-  - [6, 10, 10]
-  - [7, 10, 50]
-  - [8, 50, 10]
-  - [9, 50, 50]
+- - [1, [0, 0]]
+  - [2, [0, 10]]
+  - [3, [0, 50]]
+  - [4, [10, 0]]
+  - [5, [50, 0]]
+  - [6, [10, 10]]
+  - [7, [10, 50]]
+  - [8, [50, 10]]
+  - [9, [50, 50]]
 ...
 -- select records belonging to rectangle (0,0,10,10)
 s.index.spatial:select({0,0,10,10}, {iterator = 'LE'})
 ---
-- - [1, 0, 0]
-  - [2, 0, 10]
-  - [4, 10, 0]
-  - [6, 10, 10]
+- - [1, [0, 0]]
+  - [2, [0, 10]]
+  - [4, [10, 0]]
+  - [6, [10, 10]]
 ...
 -- select records with coodinates (10,10)
 s.index.spatial:select({10,10}, {iterator = 'EQ'})
 ---
-- - [6, 10, 10]
+- - [6, [10, 10]]
 ...
 -- select neigbors of point (5,5)
 s.index.spatial:select({5,5}, {iterator = 'NEIGHBOR'})
 ---
-- - [6, 10, 10]
-  - [4, 10, 0]
-  - [2, 0, 10]
-  - [1, 0, 0]
-  - [8, 50, 10]
-  - [7, 10, 50]
-  - [5, 50, 0]
-  - [3, 0, 50]
-  - [9, 50, 50]
+- - [6, [10, 10]]
+  - [4, [10, 0]]
+  - [2, [0, 10]]
+  - [1, [0, 0]]
+  - [8, [50, 10]]
+  - [7, [10, 50]]
+  - [5, [50, 0]]
+  - [3, [0, 50]]
+  - [9, [50, 50]]
 ...
 s:drop()
 ---
diff --git a/test/box/rtree_point.test.lua b/test/box/rtree_point.test.lua
index cc36e1e400..ec2abc66be 100644
--- a/test/box/rtree_point.test.lua
+++ b/test/box/rtree_point.test.lua
@@ -1,16 +1,16 @@
 s = box.schema.create_space('spatial')
 s:create_index('primary')
-s:create_index('spatial', { type = 'rtree', parts = {2, 'num', 3, 'num'}})
+s:create_index('spatial', { type = 'rtree', parts = {2, 'box'}})
 
-s:insert{1,0,0}
-s:insert{2,0,10}
-s:insert{3,0,50}
-s:insert{4,10,0}
-s:insert{5,50,0}
-s:insert{6,10,10}
-s:insert{7,10,50}
-s:insert{8,50,10}
-s:insert{9,50,50}
+s:insert{1,{0,0}}
+s:insert{2,{0,10}}
+s:insert{3,{0,50}}
+s:insert{4,{10,0}}
+s:insert{5,{50,0}}
+s:insert{6,{10,10}}
+s:insert{7,{10,50}}
+s:insert{8,{50,10}}
+s:insert{9,{50,50}}
 
 -- select all records
 s.index.spatial:select({iterator = 'ALL'})
diff --git a/test/box/rtree_point_r2.result b/test/box/rtree_point_r2.result
index 89ac9cdb19..c4b09d00d5 100644
--- a/test/box/rtree_point_r2.result
+++ b/test/box/rtree_point_r2.result
@@ -12,93 +12,91 @@ s:create_index('primary')
   name: primary
   type: TREE
 ...
-s:create_index('spatial', { type = 'rtree', parts = {2, 'num', 3, 'num'}})
+s:create_index('spatial', { type = 'rtree', parts = {2, 'box'}})
 ---
 - unique: true
   parts:
-  - type: NUM
+  - type: BOX
     fieldno: 2
-  - type: NUM
-    fieldno: 3
   id: 1
   space_id: 512
   name: spatial
   type: RTREE
 ...
-s:insert{1,0.0,0.0}
+s:insert{1,{0.0,0.0}}
 ---
-- [1, 0, 0]
+- [1, [0, 0]]
 ...
-s:insert{2,0.0,10.0}
+s:insert{2,{0.0,10.0}}
 ---
-- [2, 0, 10]
+- [2, [0, 10]]
 ...
-s:insert{3,0.0,50.0}
+s:insert{3,{0.0,50.0}}
 ---
-- [3, 0, 50]
+- [3, [0, 50]]
 ...
-s:insert{4,10.0,0.0}
+s:insert{4,{10.0,0.0}}
 ---
-- [4, 10, 0]
+- [4, [10, 0]]
 ...
-s:insert{5,50.0,0.0}
+s:insert{5,{50.0,0.0}}
 ---
-- [5, 50, 0]
+- [5, [50, 0]]
 ...
-s:insert{6,10.0,10.0}
+s:insert{6,{10.0,10.0}}
 ---
-- [6, 10, 10]
+- [6, [10, 10]]
 ...
-s:insert{7,10.0,50.0}
+s:insert{7,{10.0,50.0}}
 ---
-- [7, 10, 50]
+- [7, [10, 50]]
 ...
-s:insert{8,50.0,10.0}
+s:insert{8,{50.0,10.0}}
 ---
-- [8, 50, 10]
+- [8, [50, 10]]
 ...
-s:insert{9,50.0,50.0}
+s:insert{9,{50.0,50.0}}
 ---
-- [9, 50, 50]
+- [9, [50, 50]]
 ...
 -- select all records
 s.index.spatial:select({iterator = 'ALL'})
 ---
-- - [1, 0, 0]
-  - [2, 0, 10]
-  - [3, 0, 50]
-  - [4, 10, 0]
-  - [5, 50, 0]
-  - [6, 10, 10]
-  - [7, 10, 50]
-  - [8, 50, 10]
-  - [9, 50, 50]
+- - [1, [0, 0]]
+  - [2, [0, 10]]
+  - [3, [0, 50]]
+  - [4, [10, 0]]
+  - [5, [50, 0]]
+  - [6, [10, 10]]
+  - [7, [10, 50]]
+  - [8, [50, 10]]
+  - [9, [50, 50]]
 ...
 -- select records belonging to rectangle (0,0,10,10)
 s.index.spatial:select({0.0,0.0,10.0,10.0}, {iterator = 'LE'})
 ---
-- - [1, 0, 0]
-  - [2, 0, 10]
-  - [4, 10, 0]
-  - [6, 10, 10]
+- - [1, [0, 0]]
+  - [2, [0, 10]]
+  - [4, [10, 0]]
+  - [6, [10, 10]]
 ...
 -- select records with coodinates (10,10)
 s.index.spatial:select({10.0,10.0}, {iterator = 'EQ'})
 ---
-- - [6, 10, 10]
+- - [6, [10, 10]]
 ...
 -- select neigbors of point (5,5)
 s.index.spatial:select({5.0,5.0}, {iterator = 'NEIGHBOR'})
 ---
-- - [6, 10, 10]
-  - [4, 10, 0]
-  - [2, 0, 10]
-  - [1, 0, 0]
-  - [8, 50, 10]
-  - [7, 10, 50]
-  - [5, 50, 0]
-  - [3, 0, 50]
-  - [9, 50, 50]
+- - [6, [10, 10]]
+  - [4, [10, 0]]
+  - [2, [0, 10]]
+  - [1, [0, 0]]
+  - [8, [50, 10]]
+  - [7, [10, 50]]
+  - [5, [50, 0]]
+  - [3, [0, 50]]
+  - [9, [50, 50]]
 ...
 s:drop()
 ---
diff --git a/test/box/rtree_point_r2.test.lua b/test/box/rtree_point_r2.test.lua
index 9fb63dcda3..511208bce1 100644
--- a/test/box/rtree_point_r2.test.lua
+++ b/test/box/rtree_point_r2.test.lua
@@ -1,16 +1,16 @@
 s = box.schema.create_space('spatial')
 s:create_index('primary')
-s:create_index('spatial', { type = 'rtree', parts = {2, 'num', 3, 'num'}})
+s:create_index('spatial', { type = 'rtree', parts = {2, 'box'}})
 
-s:insert{1,0.0,0.0}
-s:insert{2,0.0,10.0}
-s:insert{3,0.0,50.0}
-s:insert{4,10.0,0.0}
-s:insert{5,50.0,0.0}
-s:insert{6,10.0,10.0}
-s:insert{7,10.0,50.0}
-s:insert{8,50.0,10.0}
-s:insert{9,50.0,50.0}
+s:insert{1,{0.0,0.0}}
+s:insert{2,{0.0,10.0}}
+s:insert{3,{0.0,50.0}}
+s:insert{4,{10.0,0.0}}
+s:insert{5,{50.0,0.0}}
+s:insert{6,{10.0,10.0}}
+s:insert{7,{10.0,50.0}}
+s:insert{8,{50.0,10.0}}
+s:insert{9,{50.0,50.0}}
 
 -- select all records
 s.index.spatial:select({iterator = 'ALL'})
diff --git a/test/box/rtree_rect.result b/test/box/rtree_rect.result
index f0feac3aa2..ca8e4dd34e 100644
--- a/test/box/rtree_rect.result
+++ b/test/box/rtree_rect.result
@@ -12,46 +12,39 @@ s:create_index('primary')
   name: primary
   type: TREE
 ...
-s:create_index('spatial', { type = 'rtree', parts = {2, 'num', 3, 'num', 4, 'num', 5, 'num'}})
+s:create_index('spatial', { type = 'rtree', parts = {2, 'box'}})
 ---
 - unique: true
   parts:
-  - type: NUM
+  - type: BOX
     fieldno: 2
-  - type: NUM
-    fieldno: 3
-  - type: NUM
-    fieldno: 4
-  - type: NUM
-    fieldno: 5
   id: 1
   space_id: 512
   name: spatial
   type: RTREE
 ...
-s:insert{1,0,0,10,10}
+s:insert{1,{0,0,10,10}{
 ---
-- [1, 0, 0, 10, 10]
+- error: '[string "s:insert{1,{0,0,10,10}{ "]:1: ''}'' expected near ''{'''
 ...
-s:insert{2,5,5,10,10}
+s:insert{2,{5,5,10,10}}
 ---
-- [2, 5, 5, 10, 10]
+- [2, [5, 5, 10, 10]]
 ...
-s:insert{3,0,0,5,5}
+s:insert{3,{0,0,5,5}}
 ---
-- [3, 0, 0, 5, 5]
+- [3, [0, 0, 5, 5]]
 ...
 -- select all records
 s.index.spatial:select({}, {iterator = 'ALL'})
 ---
-- - [1, 0, 0, 10, 10]
-  - [2, 5, 5, 10, 10]
-  - [3, 0, 0, 5, 5]
+- - [2, [5, 5, 10, 10]]
+  - [3, [0, 0, 5, 5]]
 ...
 -- select records belonging to rectangle (0,0,5,5)
 s.index.spatial:select({0,0,5,5}, {iterator = 'LE'})
 ---
-- - [3, 0, 0, 5, 5]
+- - [3, [0, 0, 5, 5]]
 ...
 -- select records strict belonging to rectangle (0,0,5,5)
 s.index.spatial:select({0,0,5,5}, {iterator = 'LT'})
@@ -61,43 +54,39 @@ s.index.spatial:select({0,0,5,5}, {iterator = 'LT'})
 -- select records strict belonging to rectangle (4,4,10,10)
 s.index.spatial:select({4,4,10,10}, {iterator = 'LT'})
 ---
-- - [2, 5, 5, 10, 10]
+- - [2, [5, 5, 10, 10]]
 ...
 -- select records containing point (5,5)
 s.index.spatial:select({5,5}, {iterator = 'GE'})
 ---
-- - [1, 0, 0, 10, 10]
-  - [2, 5, 5, 10, 10]
-  - [3, 0, 0, 5, 5]
+- - [2, [5, 5, 10, 10]]
+  - [3, [0, 0, 5, 5]]
 ...
 -- select records containing rectangle (1,1,2,2)
 s.index.spatial:select({1,1,2,2}, {iterator = 'GE'})
 ---
-- - [1, 0, 0, 10, 10]
-  - [3, 0, 0, 5, 5]
+- - [3, [0, 0, 5, 5]]
 ...
 -- select records strict containing rectangle (0,0,5,5)
 s.index.spatial:select({0,0,5,5}, {iterator = 'GT'})
 ---
-- - [1, 0, 0, 10, 10]
+- []
 ...
 -- select records overlapping rectangle (9,4,11,6)
 s.index.spatial:select({9,4,11,6}, {iterator = 'OVERLAPS'})
 ---
-- - [1, 0, 0, 10, 10]
-  - [2, 5, 5, 10, 10]
+- - [2, [5, 5, 10, 10]]
 ...
 -- select records with coordinates (0,0,5,5)
 s.index.spatial:select({0,0,5,5}, {iterator = 'EQ'})
 ---
-- - [3, 0, 0, 5, 5]
+- - [3, [0, 0, 5, 5]]
 ...
 -- select neigbors of point (1,1)
 s.index.spatial:select({1,1}, {iterator = 'NEIGHBOR'})
 ---
-- - [3, 0, 0, 5, 5]
-  - [1, 0, 0, 10, 10]
-  - [2, 5, 5, 10, 10]
+- - [3, [0, 0, 5, 5]]
+  - [2, [5, 5, 10, 10]]
 ...
 s:drop()
 ---
diff --git a/test/box/rtree_rect.test.lua b/test/box/rtree_rect.test.lua
index 9ffdaa7ae8..a22da55323 100644
--- a/test/box/rtree_rect.test.lua
+++ b/test/box/rtree_rect.test.lua
@@ -1,10 +1,10 @@
 s = box.schema.create_space('spatial')
 s:create_index('primary')
-s:create_index('spatial', { type = 'rtree', parts = {2, 'num', 3, 'num', 4, 'num', 5, 'num'}})
+s:create_index('spatial', { type = 'rtree', parts = {2, 'box'}})
 
-s:insert{1,0,0,10,10}
-s:insert{2,5,5,10,10}
-s:insert{3,0,0,5,5}
+s:insert{1,{0,0,10,10}{
+s:insert{2,{5,5,10,10}}
+s:insert{3,{0,0,5,5}}
 
 -- select all records
 s.index.spatial:select({}, {iterator = 'ALL'})
diff --git a/test/box/suite.ini b/test/box/suite.ini
index 6f9a00fec0..8074221235 100644
--- a/test/box/suite.ini
+++ b/test/box/suite.ini
@@ -2,7 +2,7 @@
 core = tarantool
 description = tarantool/box, minimal configuration
 script = box.lua
-disabled = rtree_benchmark.test.lua
+disabled =
 valgrind_disabled = admin_coredump.test.lua
 release_disabled = errinj.test.lua errinj_index.test.lua cmdline.test.lua
 lua_libs = lua/fiber.lua lua/fifo.lua
diff --git a/third_party/rtree.cc b/third_party/rtree.cc
index 016f0842d1..2308176016 100644
--- a/third_party/rtree.cc
+++ b/third_party/rtree.cc
@@ -1,11 +1,8 @@
+#include <new>
 #include <string.h>
 #include <assert.h>
 #include "rtree.h"
 
-inline void* operator new(size_t, void* at)
-{
-	return at;
-}
 
 class R_page {
 public:
@@ -15,8 +12,10 @@ class R_page {
 	};
 
 	enum {
-		card = (RTREE_PAGE_SIZE-4)/sizeof(branch), // maximal number of branches at page
-		min_fill = card/2        // minimal number of branches at non-root page
+		/* maximal number of branches at page */
+		CARD = (RTREE_PAGE_SIZE-4)/sizeof(branch),
+		/* minimal number of branches at non-root page */
+		MIN_FILL = CARD/2
 	};
 
 	struct reinsert_list {
@@ -34,7 +33,7 @@ class R_page {
 	R_page* split_page(R_tree* tree, branch const& br);
 
 	R_page* add_branch(R_tree* tree, branch const& br) {
-		if (n < card) {
+		if (n < CARD) {
 			b[n++] = br;
 			return NULL;
 		} else {
@@ -45,44 +44,44 @@ class R_page {
 
 	void purge(R_tree* tree, int level);
 
-	R_page* next_reinsert_page() const { return (R_page*)b[card-1].p; }
+	R_page* next_reinsert_page() const { return (R_page*)b[CARD-1].p; }
 
 	R_page(rectangle_t const& rect, record_t obj);
 	R_page(R_page* old_root, R_page* new_page);
 
-	int    n; // number of branches at page
-	branch b[card];
+	int    n; /* number of branches at page */
+	branch b[CARD];
 };
 
-R_tree::R_tree(FixedSizeAllocator::Factory* factory)
+R_tree::R_tree(page_alloc_t pg_alloc, page_free_t pg_free)
 {
 	n_records = 0;
 	height = 0;
 	root = NULL;
 	update_count = 0;
-	page_allocator = factory->create(sizeof(R_page));
-	neighbor_allocator = factory->create(sizeof(R_tree_iterator::Neighbor));
-	allocator_factory = factory;
+	n_pages = 0;
+	page_alloc = pg_alloc;
+	page_free = pg_free;
 }
 
 R_tree::~R_tree()
 {
 	purge();
-	allocator_factory->destroy(page_allocator);
-	allocator_factory->destroy(neighbor_allocator);
 }
 
 void R_tree::insert(rectangle_t const& r, record_t obj)
 {
 	if (root == NULL) {
-		root = new (page_allocator->alloc()) R_page(r, obj);
+		root = new (page_alloc()) R_page(r, obj);
 		height = 1;
+		n_pages += 1;
 	} else {
 		R_page* p = root->insert(this, r, obj, height);
 		if (p != NULL) {
-			// root splitted
-			root = new (page_allocator->alloc()) R_page(root, p);
+			/* root splitted */
+			root = new (page_alloc()) R_page(root, p);
 			height += 1;
+			n_pages += 1;
 		}
 	}
 	update_count += 1;
@@ -102,21 +101,24 @@ bool R_tree::remove(rectangle_t const& r, record_t obj)
 					R_page* p = root->insert(this, pg->b[i].r,
 								 pg->b[i].p, height-level);
 					if (p != NULL) {
-						// root splitted
-						root = new (page_allocator->alloc()) R_page(root, p);
+						/* root splitted */
+						root = new (page_alloc()) R_page(root, p);
 						height += 1;
+						n_pages += 1;
 					}
 				}
 				level -= 1;
 				R_page* next = pg->next_reinsert_page();
-				page_allocator->free(pg);
+				page_free(pg);
+				n_pages -= 1;
 				pg = next;
 			}
 			if (root->n == 1 && height > 1) {
 				R_page* new_root = root->b[0].p;
-				page_allocator->free(root);
+				page_free(root);
 				root = new_root;
 				height -= 1;
+				n_pages -= 1;
 			}
 			n_records -= 1;
 			update_count += 1;
@@ -184,7 +186,7 @@ R_tree_iterator::~R_tree_iterator()
 	reset();
 	for (curr = free; curr != NULL; curr = next) {
 		next = curr->next;
-		tree->neighbor_allocator->free(curr);
+		delete curr;
 	}
 }
 
@@ -236,7 +238,9 @@ bool R_tree_iterator::init(R_tree const* tree, rectangle_t const& r, Spatial_sea
 		break;
 	case SOP_NEIGHBOR:
 		if (tree->root) {
-			list = new_neighbor(tree->root, tree->root->cover().distance2(r.boundary), tree->height);
+			list = new_neighbor(tree->root,
+					    tree->root->cover().distance2(r.boundary),
+					    tree->height);
 			return true;
 		} else {
 			list = NULL;
@@ -244,7 +248,7 @@ bool R_tree_iterator::init(R_tree const* tree, rectangle_t const& r, Spatial_sea
 		}
 	}
 	if (tree->root && goto_first(0, tree->root)) {
-		stack[tree->height-1].pos -= 1; // will be incremented by goto_next
+		stack[tree->height-1].pos -= 1; /* will be incremented by goto_next */
 		eof = false;
 		return true;
 	} else {
@@ -273,7 +277,7 @@ R_tree_iterator::Neighbor* R_tree_iterator::new_neighbor(void* child, area_t dis
 {
 	Neighbor* n = free;
 	if (n == NULL) {
-		n = new (tree->neighbor_allocator->alloc()) Neighbor();
+		n = new Neighbor();
 	} else {
 		free = n->next;
 	}
@@ -293,20 +297,22 @@ void R_tree_iterator::free_neighbor(Neighbor* n)
 record_t R_tree_iterator::next()
 {
 	if (update_count != tree->update_count) {
-		// Index was updated since cursor initialziation
+		/* Index was updated since cursor initialziation */
 		return NULL;
 	}
 	if (op == SOP_NEIGHBOR) {
-		// To return element in order of increasing distance from specified point,
-		// we build sorted list of R-Tree items
-		// (ordered by distance from specified point) starting from root page.
-		// Algorithm is the following:
-		//
-		// insert root R-Tree page in the sorted list
-		// while sorted list is not empty:
-		//      get top element from the sorted list
-		//      if it is tree leaf (record) then return it as current element
-		//      otherwise (R-Tree page) get siblings of this R-Tree page and insert them in sorted list
+		/* To return element in order of increasing distance from specified point,
+		 * we build sorted list of R-Tree items
+		 * (ordered by distance from specified point) starting from root page.
+		 * Algorithm is the following:
+		 *
+		 * insert root R-Tree page in the sorted list
+		 * while sorted list is not empty:
+		 *      get top element from the sorted list
+		 *      if it is tree leaf (record) then return it as current element
+		 *      otherwise (R-Tree page) get siblings of this R-Tree page and
+		 *      insert them in sorted list
+		 */
 		while (true) {
 			Neighbor* neighbor = list;
 			if (neighbor == NULL) {
@@ -320,7 +326,9 @@ record_t R_tree_iterator::next()
 				return (record_t*)pg;
 			}
 			for (int i = 0, n = pg->n; i < n; i++) {
-				insert(new_neighbor(pg->b[i].p, pg->b[i].r.distance2(r.boundary), level-1));
+				insert(new_neighbor(pg->b[i].p,
+						    pg->b[i].r.distance2(r.boundary),
+						    level-1));
 			}
 		}
 	}
@@ -343,17 +351,17 @@ void R_tree::purge()
 		root->purge(this, height);
 		root = NULL;
 		n_records = 0;
+		n_pages = 0;
 		height = 0;
 	}
 }
 
-//-------------------------------------------------------------------------
-// R-tree page methods
-//-------------------------------------------------------------------------
+/*------------------------------------------------------------------------- */
+/* R-tree page methods */
+/*------------------------------------------------------------------------- */
+
 
-//
-// Create root page
-//
+/* Create root page */
 R_page::R_page(rectangle_t const& r, record_t obj)
 {
 	n = 1;
@@ -361,9 +369,7 @@ R_page::R_page(rectangle_t const& r, record_t obj)
 	b[0].p = (R_page*)obj;
 }
 
-//
-// Create new root page (root splitting)
-//
+/* Create new root page (root splitting) */
 R_page::R_page(R_page* old_root, R_page* new_page)
 {
 	n = 2;
@@ -373,9 +379,7 @@ R_page::R_page(R_page* old_root, R_page* new_page)
 	b[1].p = new_page;
 }
 
-//
-// Calculate cover of all rectangles at page
-//
+/* Calculate cover of all rectangles at page */
 rectangle_t R_page::cover() const
 {
 	rectangle_t r = b[0].r;
@@ -388,18 +392,18 @@ rectangle_t R_page::cover() const
 R_page* R_page::split_page(R_tree* tree, branch const& br)
 {
 	int i, j, seed[2] = {0,0};
-	area_t rect_area[card+1], waste, worst_waste = AREA_MIN;
-	//
-	// As the seeds for the two groups, find two rectangles which waste
-	// the most area if covered by a single rectangle.
-	//
+	area_t rect_area[CARD+1], waste, worst_waste = AREA_MIN;
+	/*
+	 * As the seeds for the two groups, find two rectangles which waste
+	 * the most area if covered by a single rectangle.
+	 */
 	rect_area[0] = area(br.r);
-	for (i = 0; i < card; i++) {
+	for (i = 0; i < CARD; i++) {
 		rect_area[i+1] = area(b[i].r);
 	}
 	branch const* bp = &br;
-	for (i = 0; i < card; i++) {
-		for (j = i+1; j <= card; j++) {
+	for (i = 0; i < CARD; i++) {
+		for (j = i+1; j <= CARD; j++) {
 			waste = area(bp->r + b[j-1].r) - rect_area[i] - rect_area[j];
 			if (waste > worst_waste) {
 				worst_waste = waste;
@@ -409,10 +413,10 @@ R_page* R_page::split_page(R_tree* tree, branch const& br)
 		}
 		bp = &b[i];
 	}
-	char taken[card];
+	char taken[CARD];
 	rectangle_t group[2];
 	area_t group_area[2];
-	int group_card[2];
+	int group_CARD[2];
 	R_page* p;
 
 	memset(taken, 0, sizeof taken);
@@ -421,28 +425,29 @@ R_page* R_page::split_page(R_tree* tree, branch const& br)
 
 	if (seed[0] == 0) {
 		group[0] = br.r;
-		p = new (tree->page_allocator->alloc()) R_page(br.r, br.p);
+		p = new (tree->page_alloc()) R_page(br.r, br.p);
 	} else {
 		group[0] = b[seed[0]-1].r;
-		p = new (tree->page_allocator->alloc()) R_page(group[0], b[seed[0]-1].p);
+		p = new (tree->page_alloc()) R_page(group[0], b[seed[0]-1].p);
 		b[seed[0]-1] = br;
 	}
-	group_card[0] = group_card[1] = 1;
+	tree->n_pages += 1;
+	group_CARD[0] = group_CARD[1] = 1;
 	group_area[0] = rect_area[seed[0]];
 	group_area[1] = rect_area[seed[1]];
-	//
-	// Split remaining rectangles between two groups.
-	// The one chosen is the one with the greatest difference in area
-	// expansion depending on which group - the rect most strongly
-	// attracted to one group and repelled from the other.
-	//
-	while (group_card[0] + group_card[1] < card + 1
-	       && group_card[0] < card + 1 - min_fill
-	       && group_card[1] < card + 1 - min_fill)
+	/*
+	 * Split remaining rectangles between two groups.
+	 * The one chosen is the one with the greatest difference in area
+	 * expansion depending on which group - the rect most strongly
+	 * attracted to one group and repelled from the other.
+	 */
+	while (group_CARD[0] + group_CARD[1] < CARD + 1
+	       && group_CARD[0] < CARD + 1 - MIN_FILL
+	       && group_CARD[1] < CARD + 1 - MIN_FILL)
 	{
 		int better_group = -1, chosen = -1;
 		area_t biggest_diff = -1;
-		for (i = 0; i < card; i++) {
+		for (i = 0; i < CARD; i++) {
 			if (!taken[i]) {
 				area_t diff = (area(group[0] + b[i].r) - group_area[0])
 					- (area(group[1] + b[i].r) - group_area[1]);
@@ -459,33 +464,33 @@ R_page* R_page::split_page(R_tree* tree, branch const& br)
 			}
 		}
 		assert(chosen >= 0);
-		group_card[better_group] += 1;
+		group_CARD[better_group] += 1;
 		group[better_group] += b[chosen].r;
 		group_area[better_group] = area(group[better_group]);
 		taken[chosen] = better_group+1;
 		if (better_group == 0) {
-			p->b[group_card[0]-1] = b[chosen];
+			p->b[group_CARD[0]-1] = b[chosen];
 		}
 	}
-	//
-	// If one group gets too full, then remaining rectangle are
-	// split between two groups in such way to balance cards of two groups.
-	//
-	if (group_card[0] + group_card[1] < card + 1) {
-		for (i = 0; i < card; i++) {
+	/*
+	 * If one group gets too full, then remaining rectangle are
+	 * split between two groups in such way to balance CARDs of two groups.
+	 */
+	if (group_CARD[0] + group_CARD[1] < CARD + 1) {
+		for (i = 0; i < CARD; i++) {
 			if (!taken[i]) {
-				if (group_card[0] >= group_card[1]) {
+				if (group_CARD[0] >= group_CARD[1]) {
 					taken[i] = 2;
-					group_card[1] += 1;
+					group_CARD[1] += 1;
 				} else {
 					taken[i] = 1;
-					p->b[group_card[0]++] = b[i];
+					p->b[group_CARD[0]++] = b[i];
 				}
 			}
 		}
 	}
-	p->n = group_card[0];
-	n = group_card[1];
+	p->n = group_CARD[0];
+	n = group_CARD[1];
 	for (i = 0, j = 0; i < n; j++) {
 		if (taken[j] == 2) {
 			b[i++] = b[j];
@@ -504,7 +509,7 @@ R_page* R_page::insert(R_tree* tree, rectangle_t const& r, record_t obj, int lev
 {
 	branch br;
 	if (--level != 0) {
-		// not leaf page
+		/* not leaf page */
 		int i, mini = 0;
 		area_t min_incr = AREA_MAX;
 		area_t best_area = AREA_MAX;
@@ -523,11 +528,11 @@ R_page* R_page::insert(R_tree* tree, rectangle_t const& r, record_t obj, int lev
 		R_page* p = b[mini].p;
 		R_page* q = p->insert(tree, r, obj, level);
 		if (q == NULL) {
-			// child was not split
+			/* child was not split */
 			b[mini].r += r;
 			return NULL;
 		} else {
-			// child was split
+			/* child was split */
 			b[mini].r = p->cover();
 			br.p = q;
 			br.r = q->cover();
@@ -548,11 +553,11 @@ bool R_page::remove(R_tree* tree, rectangle_t const& r, record_t rec,
 			if (b[i].r & r) {
 				R_page* p = b[i].p;
 				if (p->remove(tree, r, rec, level, rlist)) {
-					if (p->n >= min_fill) {
+					if (p->n >= MIN_FILL) {
 						b[i].r = p->cover();
 					} else {
-						// not enough entries in child
-						p->b[card-1].p = rlist.chain;
+						/* not enough entries in child */
+						p->b[CARD-1].p = rlist.chain;
 						rlist.chain = p;
 						rlist.level = level - 1;
 						remove_branch(i);
@@ -579,7 +584,7 @@ void R_page::purge(R_tree* tree, int level)
 			b[i].p->purge(tree, level);
 		}
 	}
-	tree->page_allocator->free(this);
+	tree->page_free(this);
 }
 
 
diff --git a/third_party/rtree.h b/third_party/rtree.h
index 48406c9823..9d90dbd985 100644
--- a/third_party/rtree.h
+++ b/third_party/rtree.h
@@ -21,7 +21,11 @@ typedef void*   record_t;
 #define AREA_MAX DBL_MAX
 #define AREA_MIN DBL_MIN
 
-#define RTREE_PAGE_SIZE 1024 /* R-Tree use linear search within element on the page, so larger page cause worse performance */
+enum {
+	RTREE_DIMENSION = 2,
+	RTREE_PAGE_SIZE = 1024 /* R-Tree use linear search within element on the page,
+				  so larger page cause worse performance */
+};
 
 class R_tree;
 class R_page;
@@ -30,18 +34,18 @@ class R_tree_iterator;
 class rectangle_t
 {
 public:
-	enum { dim = 2 };
-	coord_t boundary[dim*2];
+	coord_t boundary[RTREE_DIMENSION*2];
 
 	// Squarer of distance
 	area_t distance2(coord_t const* point) const
 	{
 		area_t d = 0;
-		for (int i = 0; i < dim; i++) {
+		for (int i = 0; i < RTREE_DIMENSION; i++) {
 			if (point[i] < boundary[i]) {
 				d += (boundary[i] - point[i]) * (boundary[i] - point[i]);
-			} else if (point[i] > boundary[dim + i]) {
-				d += (boundary[dim + i] - point[i]) * (boundary[dim + i] - point[i]);
+			} else if (point[i] > boundary[RTREE_DIMENSION + i]) {
+				d += (boundary[RTREE_DIMENSION + i] - point[i])
+				   * (boundary[RTREE_DIMENSION + i] - point[i]);
 			}
 		}
 		return d;
@@ -50,35 +54,39 @@ class rectangle_t
 
 	friend area_t area(rectangle_t const& r) {
 		area_t area = 1;
-		for (int i = dim; --i >= 0; area *= r.boundary[i+dim] - r.boundary[i]);
+		for (int i = RTREE_DIMENSION;
+		     --i >= 0;
+		     area *= r.boundary[i+RTREE_DIMENSION] - r.boundary[i]);
 		return area;
 	}
 
 	void operator +=(rectangle_t const& r) {
-		int i = dim;
+		int i = RTREE_DIMENSION;
 		while (--i >= 0) {
 			boundary[i] = (boundary[i] <= r.boundary[i])
 				? boundary[i] : r.boundary[i];
-			boundary[i+dim] = (boundary[i+dim] >= r.boundary[i+dim])
-				? boundary[i+dim] : r.boundary[i+dim];
+			boundary[i+RTREE_DIMENSION] =
+				(boundary[i+RTREE_DIMENSION] >= r.boundary[i+RTREE_DIMENSION])
+				? boundary[i+RTREE_DIMENSION] : r.boundary[i+RTREE_DIMENSION];
 		}
 	}
 	rectangle_t operator + (rectangle_t const& r) const {
 		rectangle_t res;
-		int i = dim;
+		int i = RTREE_DIMENSION;
 		while (--i >= 0) {
 			res.boundary[i] = (boundary[i] <= r.boundary[i])
 				? boundary[i] : r.boundary[i];
-			res.boundary[i+dim] = (boundary[i+dim] >= r.boundary[i+dim])
-				? boundary[i+dim] : r.boundary[i+dim];
+			res.boundary[i+RTREE_DIMENSION] =
+				(boundary[i+RTREE_DIMENSION] >= r.boundary[i+RTREE_DIMENSION])
+				? boundary[i+RTREE_DIMENSION] : r.boundary[i+RTREE_DIMENSION];
 		}
 		return res;
 	}
 	bool operator& (rectangle_t const& r) const {
-		int i = dim;
+		int i = RTREE_DIMENSION;
 		while (--i >= 0) {
-			if (boundary[i] > r.boundary[i+dim] ||
-			    r.boundary[i] > boundary[i+dim])
+			if (boundary[i] > r.boundary[i+RTREE_DIMENSION] ||
+			    r.boundary[i] > boundary[i+RTREE_DIMENSION])
 			{
 				return false;
 			}
@@ -86,10 +94,10 @@ class rectangle_t
 		return true;
 	}
 	bool operator <= (rectangle_t const& r) const {
-		int i = dim;
+		int i = RTREE_DIMENSION;
 		while (--i >= 0) {
 			if (boundary[i] < r.boundary[i] ||
-			    boundary[i+dim] > r.boundary[i+dim])
+			    boundary[i+RTREE_DIMENSION] > r.boundary[i+RTREE_DIMENSION])
 			{
 				return false;
 			}
@@ -108,7 +116,7 @@ class rectangle_t
 	}
 
 	bool operator == (rectangle_t const& r) const {
-		int i = dim*2;
+		int i = RTREE_DIMENSION*2;
 		while (--i >= 0) {
 			if (boundary[i] != r.boundary[i]) {
 				return false;
@@ -179,28 +187,16 @@ class R_tree_iterator
 	~R_tree_iterator();
 };
 
-class FixedSizeAllocator {
-public:
-	class Factory {
-	public:
-		virtual FixedSizeAllocator* create(size_t obj_size) = 0;
-		virtual void destroy(FixedSizeAllocator* allocator) = 0;
-		virtual ~Factory() {}
-	};
-
-	virtual void*  alloc() = 0;
-	virtual void   free(void* ptr) = 0;
-	virtual size_t used_size() = 0;
-	virtual ~FixedSizeAllocator() {}
-};
-
 class R_tree
 {
 	friend class R_tree_iterator;
 	friend class R_page;
+
+	typedef void* (*page_alloc_t)();
+	typedef void (*page_free_t)(void*);
 public:
 	size_t used_size() const {
-		return page_allocator->used_size();
+		return n_pages * RTREE_PAGE_SIZE;
 	}
 
 	unsigned number_of_records() const {
@@ -210,7 +206,7 @@ class R_tree
 	void insert(rectangle_t const& r, record_t obj);
 	bool remove(rectangle_t const& r, record_t obj);
 	void purge();
-	R_tree(FixedSizeAllocator::Factory* allocator_factory);
+	R_tree(page_alloc_t page_alloc, page_free_t page_free);
 	~R_tree();
 
 protected:
@@ -218,9 +214,9 @@ class R_tree
 	unsigned height;
 	R_page*  root;
 	int update_count;
-	FixedSizeAllocator* page_allocator;
-	FixedSizeAllocator* neighbor_allocator;
-	FixedSizeAllocator::Factory* allocator_factory;
+	int n_pages;
+	page_alloc_t page_alloc;
+	page_free_t page_free;
 };
 
 #endif
-- 
GitLab