diff --git a/src/box/engine_memtx.cc b/src/box/engine_memtx.cc index 1ede5cbf3247ab367ae79f0763a5f9f0d24bbdae..fd47ba665d69a31d21fe55dfc5b4fca84d37a991 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 54880ff19ea5a4859b14eebbe35c30c75e2d18fa..4f717db46df909bc95d743eb29d36dd9f80163c8 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 3f70f12d2a06c012f3ad5230e90ff2762c19edf7..8dbc59afc4a099deb8dbd48b8d93d96c5c0d546b 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 b5df2bc55300a529f96252d879a09df1cdf4ec3f..b1340fd955dfffc7105e54ab57ad6725c0a87220 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 bc3e74cbf66be8607e87e3cdc0eae57537b01b67..edfd38129cee277b3403aa5979c6cb48ae81f1cd 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 d983ed9a779411dbd662024807898b64aa3dbb8f..c4b09d00d5dbc214a7842ea09f2bcfcf7ce392e6 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 2221cb88cae8dc1e5b00d8739133347cdcf97f07..511208bce1087ca0b578ce36903a476ff9d341ad 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 02bfad52f4f31356a7baacb1350174ea26b56f6b..2042d6d355e0ab3ce9cde350b80360992f4fd870 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 103cc4f2e367018d17369cebef1e36aced883bab..08aa63185168bb734e916d9cfe1d698d36a7a629 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 aa86973a8f831cd32065bbc035ecaa5a909537ec..db76b0b1121191644296a314e64ae5e96ebe1cd7 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 cc36e1e40020b854cf05b9250fa94650342e3cdf..ec2abc66be894c0b594fb934062dc038fd58c648 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 89ac9cdb19b69d199bc48c7f0f5d459089a79980..c4b09d00d5dbc214a7842ea09f2bcfcf7ce392e6 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 9fb63dcda3b0ada230633f646001f1faa11d8a09..511208bce1087ca0b578ce36903a476ff9d341ad 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 f0feac3aa2fb1167eb2ae106a0ad35ad909e018d..ca8e4dd34e6a7067b333330060d8a0695210d536 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 9ffdaa7ae80d318c313623b315601bef5c452160..a22da55323b05fdbe31a5fa53d3c3968ad9f9733 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 6f9a00fec05deb820394d6f41fe181b0d7470979..807422123594320de65c110e9f2e8bebdbc5291e 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 016f0842d12eb7f4e5f43180b25ac5b0b3fd01a7..2308176016c2fd7627213abbbd69ee50e77fb284 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 48406c98234ad96c023b33429f489e9c7b37e08f..9d90dbd9857b6c1337abb77002317e30f1f6025b 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