Motr  M0
btree.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2013-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_UT
24 #include "lib/trace.h"
25 
26 #include "be/tx_group_fom.h"
27 #include "be/btree.h"
28 #include "lib/types.h" /* m0_uint128_eq */
29 #include "lib/misc.h" /* M0_BITS, M0_IN */
30 #include "lib/memory.h" /* M0_ALLOC_PTR */
31 #include "lib/errno.h" /* ENOENT */
32 #include "be/ut/helper.h"
33 #include "ut/ut.h"
34 #ifndef __KERNEL__
35 #include <stdio.h> /* sscanf */
36 #endif
37 
38 static struct m0_be_ut_backend *ut_be;
39 static struct m0_be_ut_seg *ut_seg;
40 static struct m0_be_seg *seg;
41 
42 extern void btree_dbg_print(struct m0_be_btree *tree);
43 
44 static int tree_cmp(const void *key0, const void *key1)
45 {
46  return strcmp(key0, key1);
47 }
48 
49 static m0_bcount_t tree_kv_size(const void *kv)
50 {
51  return kv != NULL ? strlen(kv) + 1 : 0;
52 }
53 
54 static const struct m0_be_btree_kv_ops kv_ops = {
56  .ko_ksize = tree_kv_size,
57  .ko_vsize = tree_kv_size,
58  .ko_compare = tree_cmp
59 };
60 
61 enum {
66 };
67 
68 static void check(struct m0_be_btree *tree);
69 
70 static struct m0_be_btree *create_tree(void);
71 
72 static void destroy_tree(struct m0_be_btree *tree);
73 static void truncate_tree(struct m0_be_btree *tree);
74 
75 
77 {
78  struct m0_be_btree *tree0;
79 
80  M0_ENTRY();
83 
86  /* Init BE */
88  m0_be_ut_seg_init(ut_seg, ut_be, 1ULL << 24);
89  seg = ut_seg->bus_seg;
90 
91  /* create btree */
92  tree0 = create_tree();
93 
95  check(tree0);
96 
97  /* truncate btree */
98  truncate_tree(tree0);
99 
103  m0_free(ut_seg);
104  m0_free(ut_be);
105 
106  M0_LEAVE();
107 }
108 
110 {
111  struct m0_be_btree *tree0;
112 
113  M0_ENTRY();
115  M0_UT_ASSERT(ut_be != NULL);
116 
119  /* Init BE */
121  m0_be_ut_seg_init(ut_seg, ut_be, 1ULL << 24);
122  seg = ut_seg->bus_seg;
123 
124  /* create btrees */
125  tree0 = create_tree();
126 
128 
129  check(tree0);
130  destroy_tree(tree0);
131 
135  m0_free(ut_seg);
136  m0_free(ut_be);
137 
138  M0_LEAVE();
139 }
140 
141 static int
142 btree_insert(struct m0_be_btree *t, struct m0_buf *k, struct m0_buf *v,
143  int nr_left)
144 {
145  struct m0_be_tx_credit cred = {};
146  static struct m0_be_tx *tx = NULL;
147  static int nr;
148  struct m0_be_op op = {};
149  int rc;
150 
151  M0_ENTRY();
152 
153  if (tx == NULL) {
154  nr = TXN_OPS_NR;
155  M0_ALLOC_PTR(tx);
156  M0_ASSERT(tx != NULL);
158  INSERT_VSIZE*2 + 1, &cred);
159  m0_be_ut_tx_init(tx, ut_be);
160  m0_be_tx_prep(tx, &cred);
161 
162  rc = m0_be_tx_open_sync(tx);
163  M0_UT_ASSERT(rc == 0);
164  }
165 
167  bo_u.u_btree.t_rc);
168 
169  if (--nr == 0 || nr_left == 0) {
171  m0_be_tx_fini(tx);
172  m0_free(tx);
173  tx = NULL;
174  }
175 
176  return M0_RC(rc);
177 }
178 
179 static int
180 btree_insert_inplace(struct m0_be_btree *t, struct m0_buf *k, int v,
181  int nr_left)
182 {
183  struct m0_be_tx_credit cred = {};
184  static struct m0_be_tx *tx = NULL;
185  static int nr;
186  struct m0_be_op op = {};
187  struct m0_be_btree_anchor anchor;
188  int rc;
189 
190  M0_ENTRY();
191 
192  if (tx == NULL) {
193  nr = TXN_OPS_NR;
194  M0_ALLOC_PTR(tx);
195  M0_UT_ASSERT(tx != NULL);
197  INSERT_VSIZE*2 + 1, &cred);
198  m0_be_ut_tx_init(tx, ut_be);
199  m0_be_tx_prep(tx, &cred);
200 
201  rc = m0_be_tx_open_sync(tx);
202  M0_UT_ASSERT(rc == 0);
203  }
204 
205  if ((v & 1) == 0)
206  anchor.ba_value.b_nob = INSERT_VSIZE;
207  else
208  anchor.ba_value.b_nob = INSERT_VSIZE*2;
210  k, &anchor, M0_BITS(M0_BAP_NORMAL)),
211  bo_u.u_btree.t_rc);
212  /* update value */
213  if ((v & 1) == 0)
214  sprintf(anchor.ba_value.b_addr, "%0*d", INSERT_VSIZE - 1, v);
215  else
216  sprintf(anchor.ba_value.b_addr, "%0*d", INSERT_VSIZE*2 - 1, v);
217  m0_be_btree_release(tx, &anchor);
218 
219  if (--nr == 0 || nr_left == 0) {
221  m0_be_tx_fini(tx);
222  m0_free(tx);
223  tx = NULL;
224  }
225 
226  return M0_RC(rc);
227 }
228 
229 static int
230 btree_delete(struct m0_be_btree *t, struct m0_buf *k, int nr_left)
231 {
232  struct m0_be_tx_credit cred = {};
233  static struct m0_be_tx *tx = NULL;
234  static int nr;
235  struct m0_be_op op = {};
236  int rc;
237 
238  M0_ENTRY();
239 
240  if (tx == NULL) {
241  nr = TXN_OPS_NR;
242  M0_ALLOC_PTR(tx);
243  M0_UT_ASSERT(tx != NULL);
245  INSERT_VSIZE*2 + 1, &cred);
246  m0_be_ut_tx_init(tx, ut_be);
247  m0_be_tx_prep(tx, &cred);
248 
249  rc = m0_be_tx_open_sync(tx);
250  M0_UT_ASSERT(rc == 0);
251  }
252 
254  bo_u.u_btree.t_rc);
255 
256  if (--nr == 0 || nr_left == 0) {
258  m0_be_tx_fini(tx);
259  m0_free(tx);
260  tx = NULL;
261  }
262 
263  return M0_RC(rc);
264 }
265 
266 static void shuffle_array(int a[], size_t n)
267 {
268  if (n > 1) {
269  int i;
270  uint64_t seed;
271 
272  seed = 123;
273  for (i = 0; i < n - 1; ++i)
274  M0_SWAP(a[i], a[m0_rnd(n, &seed)]);
275  }
276 }
277 
278 static void btree_delete_test(struct m0_be_btree *tree, struct m0_be_tx *tx)
279 {
280  struct m0_buf key;
281  struct m0_buf val;
282  char k[INSERT_KSIZE];
283  char v[INSERT_VSIZE*2];
284  int *rand_keys;
285  int rc;
286  int i;
287 
290 
291  M0_LOG(M0_INFO, "Check error code...");
292  sprintf(k, "%0*d", INSERT_KSIZE-1, INSERT_COUNT);
293 
294  rc = btree_delete(tree, &key, 0);
295  M0_UT_ASSERT(rc == -ENOENT);
296 
297  btree_dbg_print(tree);
298 
299  M0_LOG(M0_INFO, "Delete random keys...");
300  M0_ALLOC_ARR(rand_keys, INSERT_COUNT);
301  M0_UT_ASSERT(rand_keys != NULL);
302  for (i = 0; i < INSERT_COUNT; ++i)
303  rand_keys[i] = i;
304  shuffle_array(rand_keys, INSERT_COUNT);
305  for (i = 0; i < INSERT_COUNT; i+=2) {
306  sprintf(k, "%0*d", INSERT_KSIZE-1, rand_keys[i]);
307  M0_LOG(M0_DEBUG, "%04d: delete key=%s", i, (char*)k);
308  rc = btree_delete(tree, &key, INSERT_COUNT - i - 2);
309  M0_UT_ASSERT(rc == 0);
310  }
311 
312  M0_LOG(M0_INFO, "Make sure nothing deleted is left...");
313  for (i = 0; i < INSERT_COUNT; i+=2) {
314  sprintf(k, "%0*d", INSERT_KSIZE-1, rand_keys[i]);
315  rc = btree_delete(tree, &key, INSERT_COUNT - i - 2);
316  M0_UT_ASSERT(rc == -ENOENT);
317  }
318 
319  M0_LOG(M0_INFO, "Insert back all deleted stuff...");
320  for (i = 0; i < INSERT_COUNT; i+=2) {
321  sprintf(k, "%0*d", INSERT_KSIZE-1, rand_keys[i]);
322  if ((rand_keys[i] & 1) == 0) {
324  sprintf(v, "%0*d", INSERT_VSIZE-1, rand_keys[i]);
325  } else {
326  m0_buf_init(&val, v, INSERT_VSIZE*2);
327  sprintf(v, "%0*d", INSERT_VSIZE*2 - 1, rand_keys[i]);
328  }
329  rc = btree_insert(tree, &key, &val, INSERT_COUNT - i - 2);
330  M0_UT_ASSERT(rc == 0);
331  }
332 
333  M0_LOG(M0_INFO, "Delete everything in random order...");
334  for (i = 0; i < INSERT_COUNT; i++) {
335  sprintf(k, "%0*d", INSERT_KSIZE-1, rand_keys[i]);
336  M0_LOG(M0_DEBUG, "%04d: delete key=%s", i, (char*)k);
337  rc = btree_delete(tree, &key, INSERT_COUNT - i - 1);
338  M0_UT_ASSERT(rc == 0);
339  }
340 
341  M0_LOG(M0_INFO, "Make sure nothing is left...");
342  for (i = 0; i < INSERT_COUNT; i++) {
343  sprintf(k, "%0*d", INSERT_KSIZE-1, i);
344  rc = btree_delete(tree, &key, INSERT_COUNT - i - 1);
345  M0_UT_ASSERT(rc == -ENOENT);
346  }
347 
348  M0_LOG(M0_INFO, "Insert everything back...");
349  for (i = 0; i < INSERT_COUNT; i++) {
350  sprintf(k, "%0*d", INSERT_KSIZE-1, rand_keys[i]);
351  if ((rand_keys[i] & 1) == 0) {
353  sprintf(v, "%0*d", INSERT_VSIZE-1, rand_keys[i]);
354  } else {
355  m0_buf_init(&val, v, INSERT_VSIZE*2);
356  sprintf(v, "%0*d", INSERT_VSIZE*2 - 1, rand_keys[i]);
357  }
358  rc = btree_insert(tree, &key, &val, INSERT_COUNT - i - 1);
359  M0_UT_ASSERT(rc == 0);
360  }
361  m0_free(rand_keys);
362 
363  M0_LOG(M0_INFO, "Deleting [%04d, %04d)...", INSERT_COUNT/4,
364  INSERT_COUNT*3/4);
365  for (i = INSERT_COUNT/4; i < INSERT_COUNT*3/4; ++i) {
366  sprintf(k, "%0*d", INSERT_KSIZE-1, i);
367  M0_LOG(M0_DEBUG, "delete key=%04d", i);
368  rc = btree_delete(tree, &key, INSERT_COUNT*3/4 - i - 1);
369  M0_UT_ASSERT(rc == 0);
370  }
371 
372  M0_LOG(M0_INFO, "Check double delete in-the-middle...");
373  sprintf(k, "%0*d", INSERT_KSIZE-1, INSERT_COUNT/5 & ~1);
374  M0_LOG(M0_DEBUG, "delete key=%s", (char*)k);
375  rc = btree_delete(tree, &key, 0);
376  M0_UT_ASSERT(rc == 0);
377  M0_LOG(M0_DEBUG, "delete key=%s", (char*)k);
378  rc = btree_delete(tree, &key, 0);
379  M0_UT_ASSERT(rc == -ENOENT);
380  M0_LOG(M0_INFO, "Insert it back.");
382  sprintf(v, "%0*d", INSERT_VSIZE-1, INSERT_COUNT/5 & ~1);
383  btree_insert(tree, &key, &val, 0);
384 }
385 
386 static int btree_save(struct m0_be_btree *tree, struct m0_buf *k,
387  struct m0_buf *v, bool overwrite)
388 {
389  struct m0_be_tx *tx;
390  struct m0_be_tx_credit cred = {};
391  struct m0_be_op op = {};
392  int rc;
393 
394  M0_ALLOC_PTR(tx);
395  M0_UT_ASSERT(tx != NULL);
397  if (overwrite)
399  &cred);
400  m0_be_ut_tx_init(tx, ut_be);
401  m0_be_tx_prep(tx, &cred);
402 
403  rc = m0_be_tx_open_sync(tx);
404  M0_UT_ASSERT(rc == 0);
406  m0_be_btree_save(tree, tx, &op, k, v, overwrite),
407  bo_u.u_btree.t_rc);
409  m0_be_tx_fini(tx);
410  m0_free(tx);
411  return rc;
412 }
413 
414 static void btree_save_test(struct m0_be_btree *tree)
415 {
416  struct m0_buf key;
417  struct m0_buf val;
418  struct m0_buf ret_val;
419  struct m0_be_op *op;
420  char k[INSERT_KSIZE];
421  char v[INSERT_VSIZE];
422  char r[INSERT_VSIZE];
423  int rc;
424 
425  M0_ALLOC_PTR(op);
426  M0_ASSERT(op != NULL);
427 
428  m0_buf_init(&key, k, sizeof k);
429  m0_buf_init(&val, v, sizeof v);
430  m0_buf_init(&ret_val, r, sizeof r);
431 
432  /* Hope that a0a0 is not in the tree. */
433  sprintf(k, "%0*x", INSERT_KSIZE-1, 0xa0a0);
434  sprintf(v, "%0*x", INSERT_VSIZE-1, 0xa0a0);
435 
436  /* Check that key is not already inserted. */
438  op, m0_be_btree_lookup(tree, op, &key, &ret_val),
439  bo_u.u_btree.t_rc);
440  M0_UT_ASSERT(rc == -ENOENT);
441 
442  M0_LOG(M0_INFO, "Save new key...");
443  rc = btree_save(tree, &key, &val, false);
444  M0_UT_ASSERT(rc == 0);
445  btree_dbg_print(tree);
446  M0_SET0(op);
448  op, m0_be_btree_lookup(tree, op, &key, &ret_val),
449  bo_u.u_btree.t_rc);
450  M0_UT_ASSERT(rc == 0);
451  M0_UT_ASSERT(strcmp(ret_val.b_addr, v) == 0);
452 
453  M0_LOG(M0_INFO, "Save existing key without overwrite flag...");
454  rc = btree_save(tree, &key, &val, false);
455  M0_UT_ASSERT(rc == -EEXIST);
456 
457  M0_LOG(M0_INFO, "Save existing key with overwrite flag...");
458  sprintf(v, "%0*x", INSERT_VSIZE-1, 0xb0b0);
459  rc = btree_save(tree, &key, &val, true);
460  M0_UT_ASSERT(rc == 0);
461  btree_dbg_print(tree);
462  M0_SET0(op);
464  op, m0_be_btree_lookup(tree, op, &key, &ret_val),
465  bo_u.u_btree.t_rc);
466  M0_UT_ASSERT(rc == 0);
467  M0_UT_ASSERT(strcmp(ret_val.b_addr, v) == 0);
468 
469  M0_LOG(M0_INFO, "Cleanup the key...");
470  btree_delete(tree, &key, 0);
471 }
472 
473 static struct m0_be_btree *create_tree(void)
474 {
475  struct m0_be_tx_credit *cred;
476  struct m0_be_btree *tree;
477  struct m0_be_tx *tx;
478  struct m0_buf key;
479  struct m0_buf val;
480  char k[INSERT_KSIZE];
481  char v[INSERT_VSIZE * 2];
482  char v2[INSERT_VSIZE * 3];
483  struct m0_be_op *op;
484  int rc;
485  int i;
486 
487  M0_ENTRY();
488 
489  M0_ALLOC_PTR(cred);
490  M0_UT_ASSERT(cred != NULL);
491 
492  { /* XXX: should calculate these credits not for dummy tree,
493  but for allocated below. This needs at least two transactions. */
494  struct m0_be_btree *t = M0_ALLOC_PTR(t);
495  M0_UT_ASSERT(t != NULL);
496  *t = (struct m0_be_btree) { .bb_seg = seg };
497  m0_be_btree_create_credit(t, 1, cred);
498  m0_free(t);
499  }
500  M0_BE_ALLOC_CREDIT_PTR(tree, seg, cred);
501 
502  M0_ALLOC_PTR(op);
503  M0_UT_ASSERT(op != NULL);
504  M0_ALLOC_PTR(tx);
505  M0_UT_ASSERT(tx != NULL);
506  m0_be_ut_tx_init(tx, ut_be);
507  m0_be_tx_prep(tx, cred);
508  rc = m0_be_tx_open_sync(tx);
509  M0_UT_ASSERT(rc == 0);
510 
511  /* start */
512  M0_BE_ALLOC_PTR_SYNC(tree, seg, tx);
513  m0_be_btree_init(tree, seg, &kv_ops);
514 
516  m0_be_btree_create(tree, tx, op, &M0_FID_TINIT('b', 0, 1)));
518  &M0_FID_TINIT('b', 0, 1)));
520  m0_be_tx_close_sync(tx); /* Make things persistent. */
521  m0_be_tx_fini(tx);
522 
523  M0_SET0(op);
525  bo_u.u_btree.t_rc);
526  M0_UT_ASSERT(rc == -ENOENT && key.b_addr == NULL && key.b_nob == 0);
527 
528  M0_SET0(op);
530  bo_u.u_btree.t_rc);
531  M0_UT_ASSERT(rc == -ENOENT && key.b_addr == NULL && key.b_nob == 0);
532 
534  M0_LOG(M0_INFO, "Inserting...");
535  /* insert */
536  for (i = 0; i < INSERT_COUNT/2; ++i) {
537  sprintf(k, "%0*d", INSERT_KSIZE-1, i);
538  if ((i & 1) == 0) {
540  sprintf(v, "%0*d", INSERT_VSIZE - 1, i);
541  } else {
542  m0_buf_init(&val, v, INSERT_VSIZE*2);
543  sprintf(v, "%0*d", INSERT_VSIZE*2 - 1, i);
544  }
545  btree_insert(tree, &key, &val, INSERT_COUNT/2 - i - 1);
546  }
548 
549  M0_LOG(M0_INFO, "Inserting inplace...");
550  /* insert inplace */
551  for (i = INSERT_COUNT/2; i < INSERT_COUNT; ++i) {
552  sprintf(k, "%0*d", INSERT_KSIZE-1, i);
553  btree_insert_inplace(tree, &key, i, INSERT_COUNT - i - 1);
554  }
555  btree_dbg_print(tree);
556 
557  btree_delete_test(tree, tx);
558  btree_save_test(tree);
559  M0_LOG(M0_INFO, "Updating...");
560  m0_be_ut_tx_init(tx, ut_be);
561  *cred = M0_BE_TX_CREDIT(0, 0);
562  m0_be_btree_update_credit(tree, 1, INSERT_VSIZE, cred);
563  m0_be_tx_prep(tx, cred);
564  rc = m0_be_tx_open_sync(tx);
565  M0_UT_ASSERT(rc == 0);
566 
567  sprintf(k, "%0*d", INSERT_KSIZE-1, INSERT_COUNT - 1);
568  sprintf(v, "XYZ");
569  val.b_nob = 4;
570  M0_SET0(op);
572 
573  m0_be_tx_close_sync(tx); /* Make things persistent. */
574  m0_be_tx_fini(tx);
575 
576  btree_dbg_print(tree);
577 
578  M0_LOG(M0_INFO, "Updating with longer value...");
579  m0_be_ut_tx_init(tx, ut_be);
580  *cred = M0_BE_TX_CREDIT(0, 0);
582  cred);
583  m0_be_tx_prep(tx, cred);
584  rc = m0_be_tx_open_sync(tx);
585  M0_UT_ASSERT(rc == 0);
586 
587  sprintf(k, "%0*d", INSERT_KSIZE-1, INSERT_COUNT - 2);
588  snprintf(v2, sizeof v2, "%s", "ABCDEFGHI");
589  m0_buf_init(&val, v2, strlen(v2)+1);
590  M0_SET0(op);
592 
593  m0_be_tx_close_sync(tx); /* Make things persistent. */
594  m0_be_tx_fini(tx);
595  m0_free(tx);
596  m0_free(op);
597  m0_free(cred);
598 
599  btree_dbg_print(tree);
600 
601  M0_LEAVE();
602  return tree;
603 }
604 
605 static void truncate_tree(struct m0_be_btree *tree)
606 {
607  struct m0_be_tx_credit cred = {};
608  struct m0_be_tx *tx;
609  struct m0_be_op *op;
610  struct m0_buf key;
611  char k[INSERT_KSIZE];
612  int rc;
613  int i;
614 
615  M0_ENTRY();
616 
617  m0_buf_init(&key, k, sizeof k);
618  m0_be_btree_destroy_credit(tree, &cred);
619  M0_BE_FREE_CREDIT_PTR(tree, seg, &cred);
620 
621  M0_ALLOC_PTR(tx);
622  M0_UT_ASSERT(tx != NULL);
623  M0_ALLOC_PTR(op);
624  M0_ASSERT(op != NULL);
625  m0_be_ut_tx_init(tx, ut_be);
626  m0_be_tx_prep(tx, &cred);
627 
628  rc = m0_be_tx_open_sync(tx);
629  M0_UT_ASSERT(rc == 0);
630  btree_dbg_print(tree);
631  M0_ASSERT(INSERT_COUNT % 5 == 0);
632  for (i = 0; i < INSERT_COUNT; i+=5) {
633  M0_SET0(op);
635  op, 5));
636  }
638  M0_BE_FREE_PTR_SYNC(tree, seg, tx);
639  m0_be_tx_close_sync(tx); /* Make things persistent. */
640  m0_be_tx_fini(tx);
641  m0_free(op);
642  m0_free(tx);
643  M0_LEAVE();
644 }
645 
646 static void destroy_tree(struct m0_be_btree *tree)
647 {
648  struct m0_be_tx_credit cred = {};
649  struct m0_be_tx *tx;
650  struct m0_be_op *op;
651  struct m0_buf key;
652  char k[INSERT_KSIZE];
653  int rc;
654  int i;
655 
656  M0_ENTRY();
657 
658  m0_buf_init(&key, k, sizeof k);
659 
660  M0_LOG(M0_INFO, "Delete everything...");
661  for (i = 0; i < INSERT_COUNT; i++) {
662  sprintf(k, "%0*d", INSERT_KSIZE-1, i);
663  btree_delete(tree, &key, INSERT_COUNT - i - 1);
664  }
665 
666  m0_be_btree_destroy_credit(tree, &cred);
667  M0_BE_FREE_CREDIT_PTR(tree, seg, &cred);
668 
669  M0_ALLOC_PTR(tx);
670  M0_UT_ASSERT(tx != NULL);
671  M0_ALLOC_PTR(op);
672  M0_ASSERT(op != NULL);
673  m0_be_ut_tx_init(tx, ut_be);
674  m0_be_tx_prep(tx, &cred);
675 
676  rc = m0_be_tx_open_sync(tx);
677  M0_UT_ASSERT(rc == 0);
678 
679  M0_LOG(M0_INFO, "Btree %p destroy...", tree);
681  btree_dbg_print(tree);
682  M0_BE_FREE_PTR_SYNC(tree, seg, tx);
683  m0_be_tx_close_sync(tx); /* Make things persistent. */
684  m0_be_tx_fini(tx);
685  m0_free(op);
686  m0_free(tx);
687  M0_LEAVE();
688 }
689 
690 static void cursor_test(struct m0_be_btree *tree)
691 {
692  /* the structure is too large for kernel stack to be local */
693  static struct m0_be_btree_cursor *cursor;
694  struct m0_buf key;
695  struct m0_buf val;
696  char sbuf[INSERT_KSIZE+INSERT_VSIZE];
697  struct m0_buf start = M0_BUF_INIT(sizeof sbuf, sbuf);
698  int v;
699  int i;
700  int rc;
701 
702  M0_ALLOC_PTR(cursor);
703  M0_UT_ASSERT(cursor != NULL);
704 
705  m0_be_btree_cursor_init(cursor, tree);
706 
707  sprintf(sbuf, "%0*d", INSERT_KSIZE-1, INSERT_COUNT/2);
708  rc = m0_be_btree_cursor_get_sync(cursor, &start, true);
709  M0_UT_ASSERT(rc == 0);
710 
711  m0_be_btree_cursor_kv_get(cursor, &key, &val);
712 
713  for (i = 0; i < INSERT_COUNT/4; ++i) {
714  sscanf(key.b_addr, "%d", &v);
715  M0_LOG(M0_DEBUG, "i=%i k=%d", i, v);
716  M0_UT_ASSERT(v == i + INSERT_COUNT*3/4);
717 
718  M0_SET0(&cursor->bc_op);
719  m0_be_op_init(&cursor->bc_op);
720  m0_be_btree_cursor_next(cursor);
721  m0_be_op_wait(&cursor->bc_op);
722  rc = cursor->bc_op.bo_u.u_btree.t_rc;
723  m0_be_op_fini(&cursor->bc_op);
724  if (i < INSERT_COUNT/4 - 1)
725  M0_UT_ASSERT(rc == 0);
726 
727  m0_be_btree_cursor_kv_get(cursor, &key, &val);
728  }
729 
730  M0_UT_ASSERT(key.b_addr == NULL);
731  M0_UT_ASSERT(rc == -ENOENT);
732 
733  sprintf(sbuf, "%0*d", INSERT_KSIZE-1, INSERT_COUNT/4 - 1);
734  rc = m0_be_btree_cursor_get_sync(cursor, &start, false);
735  M0_UT_ASSERT(rc == 0);
736 
737  m0_be_btree_cursor_kv_get(cursor, &key, &val);
738 
739  for (i = INSERT_COUNT/4 - 1; i >= 0; --i) {
740  sscanf(key.b_addr, "%d", &v);
741  M0_LOG(M0_DEBUG, "i=%i k=%d", i, v);
742  M0_UT_ASSERT(v == i);
743 
744  M0_SET0(&cursor->bc_op);
745  m0_be_op_init(&cursor->bc_op);
746  m0_be_btree_cursor_prev(cursor);
747  m0_be_op_wait(&cursor->bc_op);
748  rc = cursor->bc_op.bo_u.u_btree.t_rc;
749  m0_be_op_fini(&cursor->bc_op);
750  if (i > 0)
751  M0_UT_ASSERT(rc == 0);
752 
753  m0_be_btree_cursor_kv_get(cursor, &key, &val);
754  }
755 
756  M0_UT_ASSERT(key.b_addr == NULL);
757  M0_UT_ASSERT(rc == -ENOENT);
758 
759  sprintf(sbuf, "%0*d", INSERT_KSIZE-1, INSERT_COUNT);
760  /* just to avoid CppCheck warning about changing unused sbuf below */
761  start = M0_BUF_INIT(sizeof sbuf, sbuf);
762  rc = m0_be_btree_cursor_get_sync(cursor, &start, true);
763  M0_UT_ASSERT(rc == -ENOENT);
764 
766  M0_UT_ASSERT(rc == 0);
768  sprintf(sbuf, "%0*d", INSERT_KSIZE-1, INSERT_COUNT -1);
769  M0_UT_ASSERT(strcmp(key.b_addr, sbuf) == 0);
770 
772  M0_UT_ASSERT(rc == 0);
773  m0_be_btree_cursor_kv_get(cursor, &key, &val);
774  sprintf(sbuf, "%0*d", INSERT_KSIZE-1, 0);
775  M0_UT_ASSERT(strcmp(key.b_addr, sbuf) == 0);
776  sprintf(sbuf, "%0*d", INSERT_VSIZE-1, 0);
777  M0_UT_ASSERT(strcmp(val.b_addr, sbuf) == 0);
778 
779  m0_be_btree_cursor_fini(cursor);
780  m0_free(cursor);
781 }
782 
783 static void check(struct m0_be_btree *tree)
784 {
785  struct m0_be_op *op;
786  struct m0_buf key;
787  struct m0_buf val;
788  char k[INSERT_KSIZE];
789  char v[INSERT_VSIZE * 2];
790  char v2[INSERT_VSIZE * 3];
791  char s[INSERT_VSIZE * 2];
792  int i;
793  int rc;
794 
795  M0_ALLOC_PTR(op);
796  M0_ASSERT(op != NULL);
797 
798  m0_be_btree_init(tree, seg, &kv_ops);
799 
801 
802  /* lookup */
803  for (i = 0; i < INSERT_COUNT; ++i) {
804  sprintf(k, "%0*d", INSERT_KSIZE-1, i);
805  M0_SET0(op);
806 
807  if (i == INSERT_COUNT - 2)
808  m0_buf_init(&val, v2, ARRAY_SIZE(v2));
809  else
810  m0_buf_init(&val, v, INSERT_VSIZE*2);
811 
813  op, m0_be_btree_lookup(tree, op, &key, &val),
814  bo_u.u_btree.t_rc);
815 
816  if (INSERT_COUNT/4 <= i && i < INSERT_COUNT*3/4)
817  M0_UT_ASSERT(rc == -ENOENT);
818  else if (i == INSERT_COUNT - 1)
819  M0_UT_ASSERT(strcmp(v, "XYZ") == 0);
820  else if (i == INSERT_COUNT - 2)
821  M0_UT_ASSERT(strcmp(v2, "ABCDEFGHI") == 0);
822  else {
823  if ((i & 1) == 0) {
824  sprintf(s, "%0*d", INSERT_VSIZE-1, i);
825  M0_UT_ASSERT(strcmp(v, s) == 0);
826  } else {
827  sprintf(s, "%0*d", INSERT_VSIZE*2 - 1, i);
828  M0_UT_ASSERT(strcmp(v, s) == 0);
829  }
830  }
831  }
832 
833  /* lookup inplace */
834  for (i = 0; i < INSERT_COUNT; ++i) {
835  struct m0_be_btree_anchor anchor;
836 
837  sprintf(k, "%0*d", INSERT_KSIZE-1, i);
838  M0_SET0(op);
840  op,
841  m0_be_btree_lookup_inplace(tree, op, &key, &anchor),
842  bo_u.u_btree.t_rc);
843  val = anchor.ba_value;
844 
845  if (INSERT_COUNT/4 <= i && i < INSERT_COUNT*3/4)
846  M0_UT_ASSERT(rc == -ENOENT);
847  else if (i == INSERT_COUNT - 1)
848  M0_UT_ASSERT(strcmp(val.b_addr, "XYZ") == 0);
849  else if (i == INSERT_COUNT - 2)
850  M0_UT_ASSERT(strcmp(val.b_addr, "ABCDEFGHI") == 0);
851  else {
852  if ((i & 1) == 0) {
853  sprintf(s, "%0*d", INSERT_VSIZE-1, i);
854  M0_UT_ASSERT(strcmp(val.b_addr, s) == 0);
855  } else {
856  sprintf(s, "%0*d", INSERT_VSIZE*2 - 1, i);
857  M0_UT_ASSERT(strcmp(val.b_addr, s) == 0);
858  }
859  }
860 
861  m0_be_btree_release(NULL, &anchor);
862  }
863 
864  M0_SET0(op);
866  bo_u.u_btree.t_rc);
867  M0_UT_ASSERT(rc == 0);
868  sprintf(s, "%0*d", INSERT_KSIZE-1, 0);
869  M0_UT_ASSERT(strcmp(key.b_addr, s) == 0);
870 
871  sprintf(k, "%0*d", INSERT_KSIZE-1, INSERT_COUNT - 1);
872  M0_SET0(op);
874  bo_u.u_btree.t_rc);
875  M0_UT_ASSERT(rc == 0);
876  M0_UT_ASSERT(strcmp(key.b_addr, k) == 0);
877 
878  cursor_test(tree);
879  btree_dbg_print(tree);
880  m0_be_btree_fini(tree);
881  m0_free(op);
882 }
883 
884 #undef M0_TRACE_SUBSYSTEM
885 
886 /*
887  * Local variables:
888  * c-indentation-style: "K&R"
889  * c-basic-offset: 8
890  * tab-width: 8
891  * fill-column: 80
892  * scroll-step: 1
893  * End:
894  */
895 /*
896  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
897  */
M0_INTERNAL void m0_be_btree_insert_inplace(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key, struct m0_be_btree_anchor *anchor, uint64_t zonemask)
Definition: btree.c:2126
void m0_be_ut_seg_fini(struct m0_be_ut_seg *ut_seg)
Definition: stubs.c:267
#define M0_BE_ALLOC_CREDIT_PTR(ptr, seg, accum)
Definition: alloc.h:355
static int btree_insert(struct m0_be_btree *t, struct m0_buf *k, struct m0_buf *v, int nr_left)
Definition: btree.c:142
M0_INTERNAL void m0_be_btree_cursor_next(struct m0_be_btree_cursor *cur)
Definition: btree.c:2358
static size_t nr
Definition: dump.c:1505
struct m0_be_op::@39::m0_be_op__btree u_btree
#define M0_BE_ALLOC_PTR_SYNC(ptr, seg, tx)
Definition: alloc.h:339
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
M0_INTERNAL void m0_be_btree_delete_credit(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t ksize, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1740
uint64_t ko_type
Definition: btree.h:97
void m0_be_ut_seg_reload(struct m0_be_ut_seg *ut_seg)
Definition: stubs.c:272
#define NULL
Definition: misc.h:38
static m0_bcount_t tree_kv_size(const void *kv)
Definition: btree.c:49
static struct m0_be_btree * create_tree(void)
Definition: btree.c:473
Definition: idx_mock.c:52
void * b_addr
Definition: buf.h:39
M0_INTERNAL void m0_be_btree_lookup(struct m0_be_btree *tree, struct m0_be_op *op, const struct m0_buf *key, struct m0_buf *value)
Definition: btree.c:2033
#define M0_LOG(level,...)
Definition: trace.h:167
M0_LEAVE()
struct m0_be_seg * bus_seg
Definition: helper.h:119
M0_INTERNAL void m0_be_tx_fini(struct m0_be_tx *tx)
Definition: stubs.c:163
M0_INTERNAL void m0_buf_init(struct m0_buf *buf, void *data, uint32_t nob)
Definition: buf.c:37
M0_INTERNAL void m0_be_tx_prep(struct m0_be_tx *tx, const struct m0_be_tx_credit *credit)
Definition: stubs.c:175
void m0_be_ut_seg_init(struct m0_be_ut_seg *ut_seg, struct m0_be_ut_backend *ut_be, m0_bcount_t size)
Definition: stubs.c:256
M0_INTERNAL void m0_be_btree_maxkey(struct m0_be_btree *tree, struct m0_be_op *op, struct m0_buf *out)
Definition: btree.c:2049
M0_INTERNAL bool m0_be_btree_is_empty(struct m0_be_btree *tree)
Definition: btree.c:2499
#define M0_BITS(...)
Definition: misc.h:236
uint64_t m0_bcount_t
Definition: types.h:77
static void btree_delete_test(struct m0_be_btree *tree, struct m0_be_tx *tx)
Definition: btree.c:278
M0_INTERNAL void m0_be_btree_create(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_fid *btree_fid)
Definition: btree.c:1512
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL void m0_be_btree_destroy_credit(struct m0_be_btree *tree, struct m0_be_tx_credit *accum)
Definition: btree.c:1831
#define M0_SWAP(v0, v1)
Definition: arith.h:207
struct m0_be_btree_backlink bb_backlink
Definition: btree.h:66
M0_INTERNAL void m0_be_btree_delete(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key)
Definition: btree.c:1958
M0_INTERNAL void m0_be_btree_cursor_fini(struct m0_be_btree_cursor *cursor)
Definition: btree.c:2290
return M0_RC(rc)
op
Definition: libdemo.c:64
#define M0_BE_TX_CREDIT(nr, size)
Definition: tx_credit.h:94
#define M0_ENTRY(...)
Definition: trace.h:170
Definition: buf.h:37
static void truncate_tree(struct m0_be_btree *tree)
Definition: btree.c:605
int i
Definition: dir.c:1033
M0_INTERNAL void m0_be_btree_update_credit(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1750
M0_INTERNAL void m0_be_btree_insert_credit2(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t ksize, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1730
M0_INTERNAL uint64_t m0_rnd(uint64_t max, uint64_t *seed)
Definition: misc.c:115
Definition: trace.h:482
M0_INTERNAL void m0_be_btree_create_credit(const struct m0_be_btree *tree, m0_bcount_t nr, struct m0_be_tx_credit *accum)
Definition: btree.c:1783
M0_INTERNAL void m0_be_btree_insert(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key, const struct m0_buf *val)
Definition: btree.c:1932
#define M0_FID_TINIT(type, container, key)
Definition: fid.h:90
M0_INTERNAL void m0_be_btree_save(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key, const struct m0_buf *val, bool overwrite)
Definition: btree.c:1912
M0_INTERNAL void m0_be_btree_lookup_inplace(struct m0_be_btree *tree, struct m0_be_op *op, const struct m0_buf *key, struct m0_be_btree_anchor *anchor)
Definition: btree.c:2152
M0_INTERNAL void m0_be_btree_insert_credit(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t ksize, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1720
m0_bcount_t b_nob
Definition: buf.h:38
#define M0_ASSERT(cond)
M0_INTERNAL void m0_be_btree_destroy(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op)
Definition: btree.c:1538
M0_INTERNAL void btree_dbg_print(struct m0_be_btree *tree)
Definition: btree.c:2505
M0_INTERNAL void m0_be_btree_release(struct m0_be_tx *tx, struct m0_be_btree_anchor *anchor)
Definition: btree.c:2180
static struct m0_thread t[8]
Definition: service_ut.c:1230
static int key0
Definition: locality.c:282
static struct m0_be_ut_backend * ut_be
Definition: btree.c:38
M0_INTERNAL int m0_be_tx_open_sync(struct m0_be_tx *tx)
Definition: stubs.c:199
void m0_be_ut_backend_init(struct m0_be_ut_backend *ut_be)
Definition: stubs.c:238
M0_INTERNAL void m0_be_btree_fini(struct m0_be_btree *tree)
Definition: btree.c:1503
M0_INTERNAL void m0_be_btree_minkey(struct m0_be_btree *tree, struct m0_be_op *op, struct m0_buf *out)
Definition: btree.c:2070
M0_INTERNAL void m0_be_btree_update_credit2(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t ksize, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1772
M0_INTERNAL int m0_be_btree_cursor_first_sync(struct m0_be_btree_cursor *cur)
Definition: btree.c:2348
static const struct m0_be_btree_kv_ops kv_ops
Definition: btree.c:54
#define M0_BE_FREE_PTR_SYNC(ptr, seg, tx)
Definition: alloc.h:345
Definition: seg.h:66
M0_INTERNAL void m0_be_btree_cursor_kv_get(struct m0_be_btree_cursor *cur, struct m0_buf *key, struct m0_buf *val)
Definition: btree.c:2485
M0_INTERNAL bool m0_fid_eq(const struct m0_fid *fid0, const struct m0_fid *fid1)
Definition: fid.c:164
M0_INTERNAL void m0_be_btree_update(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key, const struct m0_buf *val)
Definition: btree.c:1941
void m0_be_ut_btree_create_truncate(void)
Definition: btree.c:76
uint64_t n
Definition: fops.h:107
static void check(struct m0_be_btree *tree)
Definition: btree.c:783
static int tree_cmp(const void *key0, const void *key1)
Definition: btree.c:44
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
struct m0_buf ba_value
Definition: btree.h:469
static int r[NR]
Definition: thread.c:46
static int btree_insert_inplace(struct m0_be_btree *t, struct m0_buf *k, int v, int nr_left)
Definition: btree.c:180
M0_INTERNAL void m0_be_btree_cursor_prev(struct m0_be_btree_cursor *cur)
Definition: btree.c:2411
#define M0_BE_OP_SYNC_WITH(op, action)
Definition: op.h:207
void m0_be_ut_tx_init(struct m0_be_tx *tx, struct m0_be_ut_backend *ut_be)
Definition: stubs.c:286
struct m0_be_op bc_op
Definition: btree.h:589
M0_INTERNAL void m0_be_op_fini(struct m0_be_op *op)
Definition: stubs.c:92
static int start(struct m0_fom *fom)
Definition: trigger_fom.c:321
void m0_be_ut_backend_fini(struct m0_be_ut_backend *ut_be)
Definition: stubs.c:242
M0_INTERNAL void m0_be_btree_init(struct m0_be_btree *tree, struct m0_be_seg *seg, const struct m0_be_btree_kv_ops *ops)
Definition: btree.c:1487
M0_INTERNAL void m0_be_btree_cursor_init(struct m0_be_btree_cursor *cur, struct m0_be_btree *btree)
Definition: btree.c:2281
static struct m0_be_seg * seg
Definition: btree.c:40
M0_INTERNAL int m0_be_btree_cursor_get_sync(struct m0_be_btree_cursor *cur, const struct m0_buf *key, bool slant)
Definition: btree.c:2331
union m0_be_op::@39 bo_u
void m0_be_ut_btree_create_destroy(void)
Definition: btree.c:109
static int btree_delete(struct m0_be_btree *t, struct m0_buf *k, int nr_left)
Definition: btree.c:230
Definition: op.h:74
static int btree_save(struct m0_be_btree *tree, struct m0_buf *k, struct m0_buf *v, bool overwrite)
Definition: btree.c:386
static struct m0_be_ut_seg * ut_seg
Definition: btree.c:39
static void btree_save_test(struct m0_be_btree *tree)
Definition: btree.c:414
M0_INTERNAL void m0_be_op_init(struct m0_be_op *op)
Definition: stubs.c:87
void m0_free(void *data)
Definition: memory.c:146
static struct m0_addb2_source * s
Definition: consumer.c:39
M0_INTERNAL int m0_be_btree_cursor_last_sync(struct m0_be_btree_cursor *cur)
Definition: btree.c:2353
#define M0_BUF_INIT(size, data)
Definition: buf.h:64
static void destroy_tree(struct m0_be_btree *tree)
Definition: btree.c:646
M0_INTERNAL void m0_be_btree_truncate(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, m0_bcount_t limit)
Definition: btree.c:1564
static void shuffle_array(int a[], size_t n)
Definition: btree.c:266
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
#define M0_UT_ASSERT(a)
Definition: ut.h:46
#define M0_BE_OP_SYNC_RET_WITH(op, action, member)
Definition: op.h:253
#define M0_BE_FREE_CREDIT_PTR(ptr, seg, accum)
Definition: alloc.h:359
M0_INTERNAL void m0_be_op_wait(struct m0_be_op *op)
Definition: stubs.c:96
static void cursor_test(struct m0_be_btree *tree)
Definition: btree.c:690
M0_INTERNAL void m0_be_tx_close_sync(struct m0_be_tx *tx)
Definition: stubs.c:205
Definition: tx.h:280
Definition: idx_mock.c:47