rtree.c 9.8 KB

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