rtree.c revision 1.1 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 christos rtree_node_alloc_t *rtree_node_alloc_orig;
6 1.1 christos rtree_node_dalloc_t *rtree_node_dalloc_orig;
7 1.1 christos rtree_leaf_alloc_t *rtree_leaf_alloc_orig;
8 1.1 christos rtree_leaf_dalloc_t *rtree_leaf_dalloc_orig;
9 1.1 christos
10 1.1 christos /* Potentially too large to safely place on the stack. */
11 1.1 christos rtree_t test_rtree;
12 1.1 christos
13 1.1 christos static rtree_node_elm_t *
14 1.1 christos rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) {
15 1.1 christos rtree_node_elm_t *node;
16 1.1 christos
17 1.1 christos if (rtree != &test_rtree) {
18 1.1 christos return rtree_node_alloc_orig(tsdn, rtree, nelms);
19 1.1 christos }
20 1.1 christos
21 1.1 christos malloc_mutex_unlock(tsdn, &rtree->init_lock);
22 1.1 christos node = (rtree_node_elm_t *)calloc(nelms, sizeof(rtree_node_elm_t));
23 1.1 christos assert_ptr_not_null(node, "Unexpected calloc() failure");
24 1.1 christos malloc_mutex_lock(tsdn, &rtree->init_lock);
25 1.1 christos
26 1.1 christos return node;
27 1.1 christos }
28 1.1 christos
29 1.1 christos static void
30 1.1 christos rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree,
31 1.1 christos rtree_node_elm_t *node) {
32 1.1 christos if (rtree != &test_rtree) {
33 1.1 christos rtree_node_dalloc_orig(tsdn, rtree, node);
34 1.1 christos return;
35 1.1 christos }
36 1.1 christos
37 1.1 christos free(node);
38 1.1 christos }
39 1.1 christos
40 1.1 christos static rtree_leaf_elm_t *
41 1.1 christos rtree_leaf_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) {
42 1.1 christos rtree_leaf_elm_t *leaf;
43 1.1 christos
44 1.1 christos if (rtree != &test_rtree) {
45 1.1 christos return rtree_leaf_alloc_orig(tsdn, rtree, nelms);
46 1.1 christos }
47 1.1 christos
48 1.1 christos malloc_mutex_unlock(tsdn, &rtree->init_lock);
49 1.1 christos leaf = (rtree_leaf_elm_t *)calloc(nelms, sizeof(rtree_leaf_elm_t));
50 1.1 christos assert_ptr_not_null(leaf, "Unexpected calloc() failure");
51 1.1 christos malloc_mutex_lock(tsdn, &rtree->init_lock);
52 1.1 christos
53 1.1 christos return leaf;
54 1.1 christos }
55 1.1 christos
56 1.1 christos static void
57 1.1 christos rtree_leaf_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree,
58 1.1 christos rtree_leaf_elm_t *leaf) {
59 1.1 christos if (rtree != &test_rtree) {
60 1.1 christos rtree_leaf_dalloc_orig(tsdn, rtree, leaf);
61 1.1 christos return;
62 1.1 christos }
63 1.1 christos
64 1.1 christos free(leaf);
65 1.1 christos }
66 1.1 christos
67 1.1 christos TEST_BEGIN(test_rtree_read_empty) {
68 1.1 christos tsdn_t *tsdn;
69 1.1 christos
70 1.1 christos tsdn = tsdn_fetch();
71 1.1 christos
72 1.1 christos rtree_t *rtree = &test_rtree;
73 1.1 christos rtree_ctx_t rtree_ctx;
74 1.1 christos rtree_ctx_data_init(&rtree_ctx);
75 1.1 christos assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure");
76 1.1 christos assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx, PAGE,
77 1.1 christos false), "rtree_extent_read() should return NULL for empty tree");
78 1.1 christos rtree_delete(tsdn, rtree);
79 1.1 christos }
80 1.1 christos TEST_END
81 1.1 christos
82 1.1 christos #undef NTHREADS
83 1.1 christos #undef NITERS
84 1.1 christos #undef SEED
85 1.1 christos
86 1.1 christos TEST_BEGIN(test_rtree_extrema) {
87 1.1 christos extent_t extent_a, extent_b;
88 1.1 christos extent_init(&extent_a, NULL, NULL, LARGE_MINCLASS, false,
89 1.1 christos sz_size2index(LARGE_MINCLASS), 0, extent_state_active, false,
90 1.1 christos false, true);
91 1.1 christos extent_init(&extent_b, NULL, NULL, 0, false, NSIZES, 0,
92 1.1 christos extent_state_active, false, false, true);
93 1.1 christos
94 1.1 christos tsdn_t *tsdn = tsdn_fetch();
95 1.1 christos
96 1.1 christos rtree_t *rtree = &test_rtree;
97 1.1 christos rtree_ctx_t rtree_ctx;
98 1.1 christos rtree_ctx_data_init(&rtree_ctx);
99 1.1 christos assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure");
100 1.1 christos
101 1.1 christos assert_false(rtree_write(tsdn, rtree, &rtree_ctx, PAGE, &extent_a,
102 1.1 christos extent_szind_get(&extent_a), extent_slab_get(&extent_a)),
103 1.1 christos "Unexpected rtree_write() failure");
104 1.1 christos rtree_szind_slab_update(tsdn, rtree, &rtree_ctx, PAGE,
105 1.1 christos extent_szind_get(&extent_a), extent_slab_get(&extent_a));
106 1.1 christos assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, PAGE, true),
107 1.1 christos &extent_a,
108 1.1 christos "rtree_extent_read() should return previously set value");
109 1.1 christos
110 1.1 christos assert_false(rtree_write(tsdn, rtree, &rtree_ctx, ~((uintptr_t)0),
111 1.1 christos &extent_b, extent_szind_get_maybe_invalid(&extent_b),
112 1.1 christos extent_slab_get(&extent_b)), "Unexpected rtree_write() failure");
113 1.1 christos assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx,
114 1.1 christos ~((uintptr_t)0), true), &extent_b,
115 1.1 christos "rtree_extent_read() should return previously set value");
116 1.1 christos
117 1.1 christos rtree_delete(tsdn, rtree);
118 1.1 christos }
119 1.1 christos TEST_END
120 1.1 christos
121 1.1 christos TEST_BEGIN(test_rtree_bits) {
122 1.1 christos tsdn_t *tsdn = tsdn_fetch();
123 1.1 christos
124 1.1 christos uintptr_t keys[] = {PAGE, PAGE + 1,
125 1.1 christos PAGE + (((uintptr_t)1) << LG_PAGE) - 1};
126 1.1 christos
127 1.1 christos extent_t extent;
128 1.1 christos extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0,
129 1.1 christos extent_state_active, false, false, true);
130 1.1 christos
131 1.1 christos rtree_t *rtree = &test_rtree;
132 1.1 christos rtree_ctx_t rtree_ctx;
133 1.1 christos rtree_ctx_data_init(&rtree_ctx);
134 1.1 christos assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure");
135 1.1 christos
136 1.1 christos for (unsigned i = 0; i < sizeof(keys)/sizeof(uintptr_t); i++) {
137 1.1 christos assert_false(rtree_write(tsdn, rtree, &rtree_ctx, keys[i],
138 1.1 christos &extent, NSIZES, false),
139 1.1 christos "Unexpected rtree_write() failure");
140 1.1 christos for (unsigned j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) {
141 1.1 christos assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx,
142 1.1 christos keys[j], true), &extent,
143 1.1 christos "rtree_extent_read() should return previously set "
144 1.1 christos "value and ignore insignificant key bits; i=%u, "
145 1.1 christos "j=%u, set key=%#"FMTxPTR", get key=%#"FMTxPTR, i,
146 1.1 christos j, keys[i], keys[j]);
147 1.1 christos }
148 1.1 christos assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx,
149 1.1 christos (((uintptr_t)2) << LG_PAGE), false),
150 1.1 christos "Only leftmost rtree leaf should be set; i=%u", i);
151 1.1 christos rtree_clear(tsdn, rtree, &rtree_ctx, keys[i]);
152 1.1 christos }
153 1.1 christos
154 1.1 christos rtree_delete(tsdn, rtree);
155 1.1 christos }
156 1.1 christos TEST_END
157 1.1 christos
158 1.1 christos TEST_BEGIN(test_rtree_random) {
159 1.1 christos #define NSET 16
160 1.1 christos #define SEED 42
161 1.1 christos sfmt_t *sfmt = init_gen_rand(SEED);
162 1.1 christos tsdn_t *tsdn = tsdn_fetch();
163 1.1 christos uintptr_t keys[NSET];
164 1.1 christos rtree_t *rtree = &test_rtree;
165 1.1 christos rtree_ctx_t rtree_ctx;
166 1.1 christos rtree_ctx_data_init(&rtree_ctx);
167 1.1 christos
168 1.1 christos extent_t extent;
169 1.1 christos extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0,
170 1.1 christos extent_state_active, false, false, true);
171 1.1 christos
172 1.1 christos assert_false(rtree_new(rtree, false), "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 christos assert_ptr_not_null(elm,
179 1.1 christos "Unexpected rtree_leaf_elm_lookup() failure");
180 1.1 christos rtree_leaf_elm_write(tsdn, rtree, elm, &extent, NSIZES, false);
181 1.1 christos assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx,
182 1.1 christos keys[i], true), &extent,
183 1.1 christos "rtree_extent_read() should return previously set value");
184 1.1 christos }
185 1.1 christos for (unsigned i = 0; i < NSET; i++) {
186 1.1 christos assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx,
187 1.1 christos keys[i], true), &extent,
188 1.1 christos "rtree_extent_read() should return previously set value, "
189 1.1 christos "i=%u", i);
190 1.1 christos }
191 1.1 christos
192 1.1 christos for (unsigned i = 0; i < NSET; i++) {
193 1.1 christos rtree_clear(tsdn, rtree, &rtree_ctx, keys[i]);
194 1.1 christos assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx,
195 1.1 christos keys[i], true),
196 1.1 christos "rtree_extent_read() should return previously set value");
197 1.1 christos }
198 1.1 christos for (unsigned i = 0; i < NSET; i++) {
199 1.1 christos assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx,
200 1.1 christos keys[i], true),
201 1.1 christos "rtree_extent_read() should return previously set value");
202 1.1 christos }
203 1.1 christos
204 1.1 christos rtree_delete(tsdn, rtree);
205 1.1 christos fini_gen_rand(sfmt);
206 1.1 christos #undef NSET
207 1.1 christos #undef SEED
208 1.1 christos }
209 1.1 christos TEST_END
210 1.1 christos
211 1.1 christos int
212 1.1 christos main(void) {
213 1.1 christos rtree_node_alloc_orig = rtree_node_alloc;
214 1.1 christos rtree_node_alloc = rtree_node_alloc_intercept;
215 1.1 christos rtree_node_dalloc_orig = rtree_node_dalloc;
216 1.1 christos rtree_node_dalloc = rtree_node_dalloc_intercept;
217 1.1 christos rtree_leaf_alloc_orig = rtree_leaf_alloc;
218 1.1 christos rtree_leaf_alloc = rtree_leaf_alloc_intercept;
219 1.1 christos rtree_leaf_dalloc_orig = rtree_leaf_dalloc;
220 1.1 christos rtree_leaf_dalloc = rtree_leaf_dalloc_intercept;
221 1.1 christos
222 1.1 christos return test(
223 1.1 christos test_rtree_read_empty,
224 1.1 christos test_rtree_extrema,
225 1.1 christos test_rtree_bits,
226 1.1 christos test_rtree_random);
227 1.1 christos }
228