Home | History | Annotate | Line # | Download | only in unit
rtree.c revision 1.1.1.2
      1      1.1  christos #include "test/jemalloc_test.h"
      2      1.1  christos 
      3      1.1  christos #include "jemalloc/internal/rtree.h"
      4      1.1  christos 
      5  1.1.1.2  christos #define INVALID_ARENA_IND ((1U << MALLOCX_ARENA_BITS) - 1)
      6      1.1  christos 
      7      1.1  christos /* Potentially too large to safely place on the stack. */
      8      1.1  christos rtree_t test_rtree;
      9      1.1  christos 
     10      1.1  christos TEST_BEGIN(test_rtree_read_empty) {
     11      1.1  christos 	tsdn_t *tsdn;
     12      1.1  christos 
     13      1.1  christos 	tsdn = tsdn_fetch();
     14      1.1  christos 
     15  1.1.1.2  christos 	base_t *base = base_new(tsdn, 0, &ehooks_default_extent_hooks,
     16  1.1.1.2  christos 	    /* metadata_use_hooks */ true);
     17  1.1.1.2  christos 	expect_ptr_not_null(base, "Unexpected base_new failure");
     18  1.1.1.2  christos 
     19      1.1  christos 	rtree_t *rtree = &test_rtree;
     20      1.1  christos 	rtree_ctx_t rtree_ctx;
     21      1.1  christos 	rtree_ctx_data_init(&rtree_ctx);
     22  1.1.1.2  christos 	expect_false(rtree_new(rtree, base, false),
     23  1.1.1.2  christos 	    "Unexpected rtree_new() failure");
     24  1.1.1.2  christos 	rtree_contents_t contents;
     25  1.1.1.2  christos 	expect_true(rtree_read_independent(tsdn, rtree, &rtree_ctx, PAGE,
     26  1.1.1.2  christos 	    &contents), "rtree_read_independent() should fail on empty rtree.");
     27  1.1.1.2  christos 
     28  1.1.1.2  christos 	base_delete(tsdn, base);
     29      1.1  christos }
     30      1.1  christos TEST_END
     31      1.1  christos 
     32      1.1  christos #undef NTHREADS
     33      1.1  christos #undef NITERS
     34      1.1  christos #undef SEED
     35      1.1  christos 
     36  1.1.1.2  christos static edata_t *
     37  1.1.1.2  christos alloc_edata(void) {
     38  1.1.1.2  christos 	void *ret = mallocx(sizeof(edata_t), MALLOCX_ALIGN(EDATA_ALIGNMENT));
     39  1.1.1.2  christos 	assert_ptr_not_null(ret, "Unexpected mallocx() failure");
     40  1.1.1.2  christos 
     41  1.1.1.2  christos 	return ret;
     42  1.1.1.2  christos }
     43  1.1.1.2  christos 
     44      1.1  christos TEST_BEGIN(test_rtree_extrema) {
     45  1.1.1.2  christos 	edata_t *edata_a, *edata_b;
     46  1.1.1.2  christos 	edata_a = alloc_edata();
     47  1.1.1.2  christos 	edata_b = alloc_edata();
     48  1.1.1.2  christos 	edata_init(edata_a, INVALID_ARENA_IND, NULL, SC_LARGE_MINCLASS,
     49  1.1.1.2  christos 	    false, sz_size2index(SC_LARGE_MINCLASS), 0,
     50  1.1.1.2  christos 	    extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
     51  1.1.1.2  christos 	edata_init(edata_b, INVALID_ARENA_IND, NULL, 0, false, SC_NSIZES, 0,
     52  1.1.1.2  christos 	    extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
     53      1.1  christos 
     54      1.1  christos 	tsdn_t *tsdn = tsdn_fetch();
     55      1.1  christos 
     56  1.1.1.2  christos 	base_t *base = base_new(tsdn, 0, &ehooks_default_extent_hooks,
     57  1.1.1.2  christos 	    /* metadata_use_hooks */ true);
     58  1.1.1.2  christos 	expect_ptr_not_null(base, "Unexpected base_new failure");
     59  1.1.1.2  christos 
     60      1.1  christos 	rtree_t *rtree = &test_rtree;
     61      1.1  christos 	rtree_ctx_t rtree_ctx;
     62      1.1  christos 	rtree_ctx_data_init(&rtree_ctx);
     63  1.1.1.2  christos 	expect_false(rtree_new(rtree, base, false),
     64  1.1.1.2  christos 	    "Unexpected rtree_new() failure");
     65      1.1  christos 
     66  1.1.1.2  christos 	rtree_contents_t contents_a;
     67  1.1.1.2  christos 	contents_a.edata = edata_a;
     68  1.1.1.2  christos 	contents_a.metadata.szind = edata_szind_get(edata_a);
     69  1.1.1.2  christos 	contents_a.metadata.slab = edata_slab_get(edata_a);
     70  1.1.1.2  christos 	contents_a.metadata.is_head = edata_is_head_get(edata_a);
     71  1.1.1.2  christos 	contents_a.metadata.state = edata_state_get(edata_a);
     72  1.1.1.2  christos 	expect_false(rtree_write(tsdn, rtree, &rtree_ctx, PAGE, contents_a),
     73  1.1.1.2  christos 	    "Unexpected rtree_write() failure");
     74  1.1.1.2  christos 	expect_false(rtree_write(tsdn, rtree, &rtree_ctx, PAGE, contents_a),
     75      1.1  christos 	    "Unexpected rtree_write() failure");
     76  1.1.1.2  christos 	rtree_contents_t read_contents_a = rtree_read(tsdn, rtree, &rtree_ctx,
     77  1.1.1.2  christos 	    PAGE);
     78  1.1.1.2  christos 	expect_true(contents_a.edata == read_contents_a.edata
     79  1.1.1.2  christos 	    && contents_a.metadata.szind == read_contents_a.metadata.szind
     80  1.1.1.2  christos 	    && contents_a.metadata.slab == read_contents_a.metadata.slab
     81  1.1.1.2  christos 	    && contents_a.metadata.is_head == read_contents_a.metadata.is_head
     82  1.1.1.2  christos 	    && contents_a.metadata.state == read_contents_a.metadata.state,
     83  1.1.1.2  christos 	    "rtree_read() should return previously set value");
     84  1.1.1.2  christos 
     85  1.1.1.2  christos 	rtree_contents_t contents_b;
     86  1.1.1.2  christos 	contents_b.edata = edata_b;
     87  1.1.1.2  christos 	contents_b.metadata.szind = edata_szind_get_maybe_invalid(edata_b);
     88  1.1.1.2  christos 	contents_b.metadata.slab = edata_slab_get(edata_b);
     89  1.1.1.2  christos 	contents_b.metadata.is_head = edata_is_head_get(edata_b);
     90  1.1.1.2  christos 	contents_b.metadata.state = edata_state_get(edata_b);
     91  1.1.1.2  christos 	expect_false(rtree_write(tsdn, rtree, &rtree_ctx, ~((uintptr_t)0),
     92  1.1.1.2  christos 	    contents_b), "Unexpected rtree_write() failure");
     93  1.1.1.2  christos 	rtree_contents_t read_contents_b = rtree_read(tsdn, rtree, &rtree_ctx,
     94  1.1.1.2  christos 	    ~((uintptr_t)0));
     95  1.1.1.2  christos 	assert_true(contents_b.edata == read_contents_b.edata
     96  1.1.1.2  christos 	    && contents_b.metadata.szind == read_contents_b.metadata.szind
     97  1.1.1.2  christos 	    && contents_b.metadata.slab == read_contents_b.metadata.slab
     98  1.1.1.2  christos 	    && contents_b.metadata.is_head == read_contents_b.metadata.is_head
     99  1.1.1.2  christos 	    && contents_b.metadata.state == read_contents_b.metadata.state,
    100  1.1.1.2  christos 	    "rtree_read() should return previously set value");
    101      1.1  christos 
    102  1.1.1.2  christos 	base_delete(tsdn, base);
    103      1.1  christos }
    104      1.1  christos TEST_END
    105      1.1  christos 
    106      1.1  christos TEST_BEGIN(test_rtree_bits) {
    107      1.1  christos 	tsdn_t *tsdn = tsdn_fetch();
    108  1.1.1.2  christos 	base_t *base = base_new(tsdn, 0, &ehooks_default_extent_hooks,
    109  1.1.1.2  christos 	    /* metadata_use_hooks */ true);
    110  1.1.1.2  christos 	expect_ptr_not_null(base, "Unexpected base_new failure");
    111      1.1  christos 
    112      1.1  christos 	uintptr_t keys[] = {PAGE, PAGE + 1,
    113      1.1  christos 	    PAGE + (((uintptr_t)1) << LG_PAGE) - 1};
    114  1.1.1.2  christos 	edata_t *edata_c = alloc_edata();
    115  1.1.1.2  christos 	edata_init(edata_c, INVALID_ARENA_IND, NULL, 0, false, SC_NSIZES, 0,
    116  1.1.1.2  christos 	    extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
    117      1.1  christos 
    118      1.1  christos 	rtree_t *rtree = &test_rtree;
    119      1.1  christos 	rtree_ctx_t rtree_ctx;
    120      1.1  christos 	rtree_ctx_data_init(&rtree_ctx);
    121  1.1.1.2  christos 	expect_false(rtree_new(rtree, base, false),
    122  1.1.1.2  christos 	    "Unexpected rtree_new() failure");
    123      1.1  christos 
    124      1.1  christos 	for (unsigned i = 0; i < sizeof(keys)/sizeof(uintptr_t); i++) {
    125  1.1.1.2  christos 		rtree_contents_t contents;
    126  1.1.1.2  christos 		contents.edata = edata_c;
    127  1.1.1.2  christos 		contents.metadata.szind = SC_NSIZES;
    128  1.1.1.2  christos 		contents.metadata.slab = false;
    129  1.1.1.2  christos 		contents.metadata.is_head = false;
    130  1.1.1.2  christos 		contents.metadata.state = extent_state_active;
    131  1.1.1.2  christos 
    132  1.1.1.2  christos 		expect_false(rtree_write(tsdn, rtree, &rtree_ctx, keys[i],
    133  1.1.1.2  christos 		    contents), "Unexpected rtree_write() failure");
    134      1.1  christos 		for (unsigned j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) {
    135  1.1.1.2  christos 			expect_ptr_eq(rtree_read(tsdn, rtree, &rtree_ctx,
    136  1.1.1.2  christos 			    keys[j]).edata, edata_c,
    137  1.1.1.2  christos 			    "rtree_edata_read() should return previously set "
    138      1.1  christos 			    "value and ignore insignificant key bits; i=%u, "
    139      1.1  christos 			    "j=%u, set key=%#"FMTxPTR", get key=%#"FMTxPTR, i,
    140      1.1  christos 			    j, keys[i], keys[j]);
    141      1.1  christos 		}
    142  1.1.1.2  christos 		expect_ptr_null(rtree_read(tsdn, rtree, &rtree_ctx,
    143  1.1.1.2  christos 		    (((uintptr_t)2) << LG_PAGE)).edata,
    144      1.1  christos 		    "Only leftmost rtree leaf should be set; i=%u", i);
    145      1.1  christos 		rtree_clear(tsdn, rtree, &rtree_ctx, keys[i]);
    146      1.1  christos 	}
    147      1.1  christos 
    148  1.1.1.2  christos 	base_delete(tsdn, base);
    149      1.1  christos }
    150      1.1  christos TEST_END
    151      1.1  christos 
    152      1.1  christos TEST_BEGIN(test_rtree_random) {
    153      1.1  christos #define NSET 16
    154      1.1  christos #define SEED 42
    155      1.1  christos 	sfmt_t *sfmt = init_gen_rand(SEED);
    156      1.1  christos 	tsdn_t *tsdn = tsdn_fetch();
    157  1.1.1.2  christos 
    158  1.1.1.2  christos 	base_t *base = base_new(tsdn, 0, &ehooks_default_extent_hooks,
    159  1.1.1.2  christos 	    /* metadata_use_hooks */ true);
    160  1.1.1.2  christos 	expect_ptr_not_null(base, "Unexpected base_new failure");
    161  1.1.1.2  christos 
    162      1.1  christos 	uintptr_t keys[NSET];
    163      1.1  christos 	rtree_t *rtree = &test_rtree;
    164      1.1  christos 	rtree_ctx_t rtree_ctx;
    165      1.1  christos 	rtree_ctx_data_init(&rtree_ctx);
    166      1.1  christos 
    167  1.1.1.2  christos 	edata_t *edata_d = alloc_edata();
    168  1.1.1.2  christos 	edata_init(edata_d, INVALID_ARENA_IND, NULL, 0, false, SC_NSIZES, 0,
    169  1.1.1.2  christos 	    extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
    170      1.1  christos 
    171  1.1.1.2  christos 	expect_false(rtree_new(rtree, base, false),
    172  1.1.1.2  christos 	    "Unexpected rtree_new() failure");
    173      1.1  christos 
    174      1.1  christos 	for (unsigned i = 0; i < NSET; i++) {
    175      1.1  christos 		keys[i] = (uintptr_t)gen_rand64(sfmt);
    176      1.1  christos 		rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree,
    177      1.1  christos 		    &rtree_ctx, keys[i], false, true);
    178  1.1.1.2  christos 		expect_ptr_not_null(elm,
    179      1.1  christos 		    "Unexpected rtree_leaf_elm_lookup() failure");
    180  1.1.1.2  christos 		rtree_contents_t contents;
    181  1.1.1.2  christos 		contents.edata = edata_d;
    182  1.1.1.2  christos 		contents.metadata.szind = SC_NSIZES;
    183  1.1.1.2  christos 		contents.metadata.slab = false;
    184  1.1.1.2  christos 		contents.metadata.is_head = false;
    185  1.1.1.2  christos 		contents.metadata.state = edata_state_get(edata_d);
    186  1.1.1.2  christos 		rtree_leaf_elm_write(tsdn, rtree, elm, contents);
    187  1.1.1.2  christos 		expect_ptr_eq(rtree_read(tsdn, rtree, &rtree_ctx,
    188  1.1.1.2  christos 		    keys[i]).edata, edata_d,
    189  1.1.1.2  christos 		    "rtree_edata_read() should return previously set value");
    190      1.1  christos 	}
    191      1.1  christos 	for (unsigned i = 0; i < NSET; i++) {
    192  1.1.1.2  christos 		expect_ptr_eq(rtree_read(tsdn, rtree, &rtree_ctx,
    193  1.1.1.2  christos 		    keys[i]).edata, edata_d,
    194  1.1.1.2  christos 		    "rtree_edata_read() should return previously set value, "
    195      1.1  christos 		    "i=%u", i);
    196      1.1  christos 	}
    197      1.1  christos 
    198      1.1  christos 	for (unsigned i = 0; i < NSET; i++) {
    199      1.1  christos 		rtree_clear(tsdn, rtree, &rtree_ctx, keys[i]);
    200  1.1.1.2  christos 		expect_ptr_null(rtree_read(tsdn, rtree, &rtree_ctx,
    201  1.1.1.2  christos 		    keys[i]).edata,
    202  1.1.1.2  christos 		   "rtree_edata_read() should return previously set value");
    203      1.1  christos 	}
    204      1.1  christos 	for (unsigned i = 0; i < NSET; i++) {
    205  1.1.1.2  christos 		expect_ptr_null(rtree_read(tsdn, rtree, &rtree_ctx,
    206  1.1.1.2  christos 		    keys[i]).edata,
    207  1.1.1.2  christos 		    "rtree_edata_read() should return previously set value");
    208      1.1  christos 	}
    209      1.1  christos 
    210  1.1.1.2  christos 	base_delete(tsdn, base);
    211      1.1  christos 	fini_gen_rand(sfmt);
    212      1.1  christos #undef NSET
    213      1.1  christos #undef SEED
    214      1.1  christos }
    215      1.1  christos TEST_END
    216      1.1  christos 
    217  1.1.1.2  christos static void
    218  1.1.1.2  christos test_rtree_range_write(tsdn_t *tsdn, rtree_t *rtree, uintptr_t start,
    219  1.1.1.2  christos     uintptr_t end) {
    220  1.1.1.2  christos 	rtree_ctx_t rtree_ctx;
    221  1.1.1.2  christos 	rtree_ctx_data_init(&rtree_ctx);
    222  1.1.1.2  christos 
    223  1.1.1.2  christos 	edata_t *edata_e = alloc_edata();
    224  1.1.1.2  christos 	edata_init(edata_e, INVALID_ARENA_IND, NULL, 0, false, SC_NSIZES, 0,
    225  1.1.1.2  christos 	    extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
    226  1.1.1.2  christos 	rtree_contents_t contents;
    227  1.1.1.2  christos 	contents.edata = edata_e;
    228  1.1.1.2  christos 	contents.metadata.szind = SC_NSIZES;
    229  1.1.1.2  christos 	contents.metadata.slab = false;
    230  1.1.1.2  christos 	contents.metadata.is_head = false;
    231  1.1.1.2  christos 	contents.metadata.state = extent_state_active;
    232  1.1.1.2  christos 
    233  1.1.1.2  christos 	expect_false(rtree_write(tsdn, rtree, &rtree_ctx, start,
    234  1.1.1.2  christos 	    contents), "Unexpected rtree_write() failure");
    235  1.1.1.2  christos 	expect_false(rtree_write(tsdn, rtree, &rtree_ctx, end,
    236  1.1.1.2  christos 	    contents), "Unexpected rtree_write() failure");
    237  1.1.1.2  christos 
    238  1.1.1.2  christos 	rtree_write_range(tsdn, rtree, &rtree_ctx, start, end, contents);
    239  1.1.1.2  christos 	for (uintptr_t i = 0; i < ((end - start) >> LG_PAGE); i++) {
    240  1.1.1.2  christos 		expect_ptr_eq(rtree_read(tsdn, rtree, &rtree_ctx,
    241  1.1.1.2  christos 		    start + (i << LG_PAGE)).edata, edata_e,
    242  1.1.1.2  christos 		    "rtree_edata_read() should return previously set value");
    243  1.1.1.2  christos 	}
    244  1.1.1.2  christos 	rtree_clear_range(tsdn, rtree, &rtree_ctx, start, end);
    245  1.1.1.2  christos 	rtree_leaf_elm_t *elm;
    246  1.1.1.2  christos 	for (uintptr_t i = 0; i < ((end - start) >> LG_PAGE); i++) {
    247  1.1.1.2  christos 		elm = rtree_leaf_elm_lookup(tsdn, rtree, &rtree_ctx,
    248  1.1.1.2  christos 		    start + (i << LG_PAGE), false, false);
    249  1.1.1.2  christos 		expect_ptr_not_null(elm, "Should have been initialized.");
    250  1.1.1.2  christos 		expect_ptr_null(rtree_leaf_elm_read(tsdn, rtree, elm,
    251  1.1.1.2  christos 		    false).edata, "Should have been cleared.");
    252  1.1.1.2  christos 	}
    253  1.1.1.2  christos }
    254  1.1.1.2  christos 
    255  1.1.1.2  christos TEST_BEGIN(test_rtree_range) {
    256  1.1.1.2  christos 	tsdn_t *tsdn = tsdn_fetch();
    257  1.1.1.2  christos 	base_t *base = base_new(tsdn, 0, &ehooks_default_extent_hooks,
    258  1.1.1.2  christos 	    /* metadata_use_hooks */ true);
    259  1.1.1.2  christos 	expect_ptr_not_null(base, "Unexpected base_new failure");
    260  1.1.1.2  christos 
    261  1.1.1.2  christos 	rtree_t *rtree = &test_rtree;
    262  1.1.1.2  christos 	expect_false(rtree_new(rtree, base, false),
    263  1.1.1.2  christos 	    "Unexpected rtree_new() failure");
    264  1.1.1.2  christos 
    265  1.1.1.2  christos 	/* Not crossing rtree node boundary first. */
    266  1.1.1.2  christos 	uintptr_t start = ZU(1) << rtree_leaf_maskbits();
    267  1.1.1.2  christos 	uintptr_t end = start + (ZU(100) << LG_PAGE);
    268  1.1.1.2  christos 	test_rtree_range_write(tsdn, rtree, start, end);
    269  1.1.1.2  christos 
    270  1.1.1.2  christos 	/* Crossing rtree node boundary. */
    271  1.1.1.2  christos 	start = (ZU(1) << rtree_leaf_maskbits()) - (ZU(10) << LG_PAGE);
    272  1.1.1.2  christos 	end = start + (ZU(100) << LG_PAGE);
    273  1.1.1.2  christos 	assert_ptr_ne((void *)rtree_leafkey(start), (void *)rtree_leafkey(end),
    274  1.1.1.2  christos 	    "The range should span across two rtree nodes");
    275  1.1.1.2  christos 	test_rtree_range_write(tsdn, rtree, start, end);
    276  1.1.1.2  christos 
    277  1.1.1.2  christos 	base_delete(tsdn, base);
    278  1.1.1.2  christos }
    279  1.1.1.2  christos TEST_END
    280  1.1.1.2  christos 
    281      1.1  christos int
    282      1.1  christos main(void) {
    283      1.1  christos 	return test(
    284      1.1  christos 	    test_rtree_read_empty,
    285      1.1  christos 	    test_rtree_extrema,
    286      1.1  christos 	    test_rtree_bits,
    287  1.1.1.2  christos 	    test_rtree_random,
    288  1.1.1.2  christos 	    test_rtree_range);
    289      1.1  christos }
    290