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