Motr  M0
tx.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 
32 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_UT
33 #include "lib/trace.h"
34 
35 #include "lib/types.h" /* m0_uint128_eq */
36 #include "lib/arith.h" /* m0_rnd64 */
37 #include "lib/misc.h" /* M0_BITS */
38 #include "lib/memory.h" /* M0_ALLOC_PTR */
39 
40 #include "ut/ut.h"
41 
42 #include "be/ut/helper.h" /* m0_be_ut_backend */
43 
45 {
46  struct m0_be_ut_backend ut_be;
47  struct m0_be_ut_seg ut_seg;
48  struct m0_be_seg *seg;
49  struct m0_be_tx_credit credit = M0_BE_TX_CREDIT_TYPE(uint64_t);
50  struct m0_be_tx tx;
51  uint64_t *data;
52  int rc;
53 
54  M0_SET0(&ut_be);
56  m0_be_ut_seg_init(&ut_seg, NULL, 1 << 20);
57  seg = ut_seg.bus_seg;
58 
59  m0_be_ut_tx_init(&tx, &ut_be);
60 
61  m0_be_tx_prep(&tx, &credit);
62 
63  /* m0_be_tx_open_sync() can be used in UT */
64  m0_be_tx_open(&tx);
67  M0_UT_ASSERT(rc == 0);
68 
69  data = (uint64_t *) (seg->bs_addr + seg->bs_reserved);
70  *data = 0x101;
72 
73  /* m0_be_tx_close_sync() can be used in UT */
74  m0_be_tx_close(&tx);
76  M0_UT_ASSERT(rc == 0);
77  m0_be_tx_fini(&tx);
78 
81 }
82 
84 {
85  struct m0_be_ut_backend ut_be;
86  struct m0_be_tx tx;
87  int rc;
88 
89  M0_SET0(&ut_be);
91 
92  m0_be_ut_tx_init(&tx, &ut_be);
93 
95 
96  m0_be_tx_open(&tx);
99  M0_UT_ASSERT(rc != 0);
100 
101  m0_be_tx_fini(&tx);
102 
104 }
105 
106 static void be_ut_tx_test(size_t nr);
107 
108 static void be_ut_tx_alloc_init(void **alloc, struct m0_be_seg *seg)
109 {
111 }
112 
113 static void be_ut_tx_alloc_fini(void **alloc)
114 {
115  *alloc = NULL;
116 }
117 
118 static void *be_ut_tx_alloc(void **alloc, m0_bcount_t size)
119 {
120  void *ptr = *alloc;
121 
122  *alloc += size;
123  return ptr;
124 }
125 
127 {
128  struct m0_be_ut_backend ut_be;
129  struct m0_be_tx_credit credit = M0_BE_TX_CREDIT_TYPE(uint64_t);
130  struct m0_be_ut_seg ut_seg;
131  struct m0_be_seg *seg;
132  struct m0_be_tx tx;
133  uint64_t *data;
134  int rc;
135 
136  M0_SET0(&ut_be);
138  m0_be_ut_seg_init(&ut_seg, NULL, 1 << 20);
139  seg = ut_seg.bus_seg;
140 
141  /* test success path */
142  m0_be_ut_tx_init(&tx, &ut_be);
143  M0_UT_ASSERT(tx.t_sm.sm_rc == 0);
145 
146  m0_be_tx_prep(&tx, &credit);
147  M0_UT_ASSERT(tx.t_sm.sm_rc == 0);
149 
150  /* to check M0_BTS_PLACED state */
151  m0_be_tx_get(&tx);
152 
153  rc = m0_be_tx_open_sync(&tx);
154  M0_UT_ASSERT(rc == 0);
156 
157  data = (uint64_t *) (seg->bs_addr + seg->bs_reserved);
158  *data = 0x101;
160 
161  m0_be_tx_close(&tx);
163  M0_UT_ASSERT(rc == 0);
165 
166  m0_be_tx_put(&tx);
168  M0_UT_ASSERT(rc == 0);
170 
171  m0_be_tx_fini(&tx);
172 
173  /* test failure path */
174  m0_be_ut_tx_init(&tx, &ut_be);
175  M0_UT_ASSERT(tx.t_sm.sm_rc == 0);
177 
179  M0_UT_ASSERT(tx.t_sm.sm_rc == 0);
181 
182  m0_be_tx_get(&tx);
183 
184  rc = m0_be_tx_open_sync(&tx);
185  M0_UT_ASSERT(rc != 0);
187 
188  m0_be_tx_put(&tx);
189 
190  m0_be_tx_fini(&tx);
191 
194 }
195 
197 {
198  struct m0_be_ut_backend ut_be;
199  struct m0_be_tx tx;
200  int rc;
201  int i;
202  struct m0_be_tx_credit credit[] = {
203  M0_BE_TX_CREDIT(0, 0),
204  M0_BE_TX_CREDIT(1, sizeof(void *)),
205  };
206 
207  M0_SET0(&ut_be);
209 
210  for (i = 0; i < ARRAY_SIZE(credit); ++i) {
211  m0_be_ut_tx_init(&tx, &ut_be);
212 
213  m0_be_tx_prep(&tx, &credit[i]);
214 
215  rc = m0_be_tx_open_sync(&tx);
216  M0_UT_ASSERT(rc == 0);
217 
218  m0_be_tx_close_sync(&tx);
219  m0_be_tx_fini(&tx);
220  }
221 
223 }
224 
226 {
227  be_ut_tx_test(1);
228 }
229 
231 {
232  be_ut_tx_test(2);
233 }
234 
236  uint32_t real;
237  uint32_t imag;
238 };
239 
240 struct be_ut_tx_x {
241  struct m0_be_tx tx;
244  void *data;
245  const union {
246  struct m0_uint128 u128;
248  } captured;
249 };
250 
251 enum { SHIFT = 0 };
252 
253 static void
254 be_ut_transact(struct be_ut_tx_x *x, struct m0_be_seg *seg, void **alloc)
255 {
256  int rc;
257 
258  m0_be_tx_prep(&x->tx, &x->cred);
259 
260  rc = m0_be_tx_open_sync(&x->tx);
261  M0_UT_ASSERT(rc == 0);
262 
263  x->data = be_ut_tx_alloc(alloc, x->size);
264 
265  /* Dirty the memory. */
266  M0_CASSERT(sizeof(struct m0_uint128) != sizeof(int));
267  M0_CASSERT(sizeof(struct m0_uint128) != sizeof(struct be_ut_complex));
268  M0_ASSERT(M0_IN(x->size, (sizeof(struct m0_uint128),
269  sizeof(struct be_ut_complex))));
270  memcpy(x->data, &x->captured, x->size);
271 
272  /* Capture dirty memory. */
273  m0_be_tx_capture(&x->tx, &M0_BE_REG(seg, x->size, x->data));
274 
275  m0_be_tx_close(&x->tx);
276 }
277 
281 static void be_ut_tx_test(size_t nr)
282 {
283  struct m0_be_ut_backend ut_be;
284  struct m0_be_ut_seg ut_seg;
285  void *alloc;
286  struct be_ut_tx_x *x;
287  struct be_ut_tx_x xs[] = {
288  {
289  .size = sizeof(struct m0_uint128),
290  .captured.u128 = M0_UINT128(0xdeadd00d8badf00d,
291  0x5ca1ab1e7e1eca57)
292  },
293  {
294  .size = sizeof(struct be_ut_complex),
295  .captured.complex = { .real = 18, .imag = 4 }
296  },
297  { .size = 0 } /* terminator */
298  };
299 
300  M0_PRE(0 < nr && nr < ARRAY_SIZE(xs));
301  xs[nr].size = 0;
302 
303  M0_SET0(&ut_be);
305  m0_be_ut_seg_init(&ut_seg, NULL, 1 << 20);
307 
308  for (x = xs; x->size != 0; ++x) {
309  m0_be_ut_tx_init(&x->tx, &ut_be);
310  m0_be_tx_get(&x->tx);
311  x->cred = M0_BE_TX_CREDIT(1, x->size);
312  }
313 
314  for (x = xs; x->size != 0; ++x)
316 
317  /* Wait for transactions to become persistent. */
318  for (x = xs; x->size != 0; ++x) {
320  M0_TIME_NEVER);
321  M0_UT_ASSERT(rc == 0);
322  m0_be_tx_put(&x->tx);
323  }
324  for (x = xs; x->size != 0; ++x) {
326  M0_TIME_NEVER);
327  M0_UT_ASSERT(rc == 0);
328  m0_be_tx_fini(&x->tx);
329  }
330 
334 
335 }
336 
337 static void be_ut_tx_do_force (struct be_ut_tx_x *xs, size_t nr)
338 {
339  int i;
340  int nr_grps;
341  struct be_ut_tx_x *x;
342  struct m0_be_tx_group **grps;
343 
344  M0_ALLOC_ARR(grps, nr);
345  M0_UT_ASSERT(grps != NULL);
346 
347  /*
348  * Find all tx groups.
349  *
350  * Note: only 1 tx group is supported at this moment.
351  */
352  nr_grps = 0;
353  for (x = xs; x->size != 0; ++x) {
354  for (i = 0; i < nr_grps; i++) {
355  if (x->tx.t_group == grps[i]) break;
356  }
357 
358  if (i == nr_grps) {
359  grps[i] = x->tx.t_group;
360  nr_grps ++;
361  }
362  }
363 
364  /*
365  * Note: we will force only one tx per group.
366  */
367  for (i = 0, x = xs; x->size != 0; ) {
368  m0_be_tx_force(&x->tx);
369  i++;
370 
371  /* Skip those txs belong to the same group. */
372  while (x->tx.t_group != grps[i] && x->size != 0)
373  x++;
374  }
375 
376  m0_free(grps);
377 }
378 
383 static void be_ut_tx_force(size_t nr)
384 {
385  struct m0_be_ut_backend ut_be;
386  struct m0_be_ut_seg ut_seg;
387  void *alloc;
388  struct be_ut_tx_x *x;
389  struct be_ut_tx_x xs[] = {
390  {
391  .size = sizeof(struct m0_uint128),
392  .captured.u128 = M0_UINT128(0xdeadd00d8badf00d,
393  0x5ca1ab1e7e1eca57)
394  },
395  {
396  .size = sizeof(struct be_ut_complex),
397  .captured.complex = { .real = 18, .imag = 4 }
398  },
399  { .size = 0 } /* terminator */
400  };
401 
402  M0_PRE(0 < nr && nr < ARRAY_SIZE(xs));
403  xs[nr].size = 0;
404 
405  M0_SET0(&ut_be);
407  m0_be_ut_seg_init(&ut_seg, NULL, 1 << 20);
409 
410  for (x = xs; x->size != 0; ++x) {
411  m0_be_ut_tx_init(&x->tx, &ut_be);
412  m0_be_tx_get(&x->tx);
413  x->cred = M0_BE_TX_CREDIT(1, x->size);
414  }
415 
416  for (x = xs; x->size != 0; ++x)
418 
419 #if 0 /* XXX */
420  /* Wait for transactions to become GROUPED. */
421  for (x = xs; x->size != 0; ++x) {
422  int rc = m0_be_tx_timedwait(&x->tx, M0_BITS(M0_BTS_GROUPED),
423  M0_TIME_NEVER);
424  M0_UT_ASSERT(rc == 0);
425  }
426 #endif
427 
428  /* Force all txs to be persistent */
429  be_ut_tx_do_force(xs, nr);
430 
431  /* Wait for transactions to become persistent. */
432  for (x = xs; x->size != 0; ++x) {
434  M0_TIME_NEVER);
435  M0_UT_ASSERT(rc == 0);
436  m0_be_tx_put(&x->tx);
437  }
438 
439  for (x = xs; x->size != 0; ++x) {
441  M0_TIME_NEVER);
442  M0_UT_ASSERT(rc == 0);
443  m0_be_tx_fini(&x->tx);
444  }
445 
449 
450 }
451 
453 {
454  be_ut_tx_force(2);
455 }
456 
457 
459 enum {
464 };
465 
466 static void be_ut_tx_reg_rand(struct m0_be_reg *reg,
467  struct m0_be_seg *seg,
468  uint64_t *seed)
469 {
470  uintptr_t addr;
471 
472  reg->br_seg = seg;
474  addr = m0_rnd64(seed) %
475  (seg->bs_size - reg->br_size - seg->bs_reserved);
476  reg->br_addr = seg->bs_addr + seg->bs_reserved + addr;
477 }
478 
479 static void be_ut_tx_reg_rand_fill(struct m0_be_reg *reg, uint64_t *seed)
480 {
481  int i;
482 
483  for (i = 0; i < reg->br_size; ++i)
484  ((char *) reg->br_addr)[i] = m0_rnd64(seed) & 0xFF;
485 }
486 
488 {
489  static struct m0_be_reg regs[BE_UT_TX_P_REG_NR];
490  struct m0_be_ut_backend ut_be;
491  struct m0_be_tx_credit credit;
492  struct m0_be_ut_seg ut_seg;
493  struct m0_be_seg *seg;
494  struct m0_be_tx tx;
495  uint64_t seed = 0;
496  int i;
497  int j;
498  int rc;
499 
500  M0_SET0(&ut_be);
503  seg = ut_seg.bus_seg;
504 
505  for (j = 0; j < BE_UT_TX_P_TX_NR; ++j) {
506  M0_SET0(&tx);
507  m0_be_ut_tx_init(&tx, &ut_be);
508 
509  for (i = 0; i < ARRAY_SIZE(regs); ++i)
510  be_ut_tx_reg_rand(&regs[i], seg, &seed);
511 
512  M0_SET0(&credit);
513  for (i = 0; i < ARRAY_SIZE(regs); ++i) {
515  1, regs[i].br_size));
516  }
517 
518  m0_be_tx_prep(&tx, &credit);
519 
520  rc = m0_be_tx_open_sync(&tx);
521  M0_UT_ASSERT(rc == 0);
522 
523  for (i = 0; i < ARRAY_SIZE(regs); ++i) {
524  be_ut_tx_reg_rand_fill(&regs[i], &seed);
525  m0_be_tx_capture(&tx, &regs[i]);
526  }
527 
528  m0_be_tx_get(&tx);
529  m0_be_tx_close(&tx);
531  M0_TIME_NEVER);
532  M0_UT_ASSERT(rc == 0);
533 
534  m0_be_tx_put(&tx);
536  M0_TIME_NEVER);
537  M0_UT_ASSERT(rc == 0);
538  m0_be_tx_fini(&tx);
539  }
540 
543 }
544 
545 enum {
551 };
552 
554  struct m0_be_tx txf_tx;
559 };
560 
561 static bool be_ut_tx_fast_cb(struct m0_clink *clink)
562 {
563  struct be_ut_tx_fast *txf;
564 
565  txf = container_of(clink, struct be_ut_tx_fast, txf_clink);
567  if (m0_be_tx_state(&txf->txf_tx) == M0_BTS_ACTIVE) {
570  m0_semaphore_up(&txf->txf_sem);
572  }
573  return false;
574 }
575 
576 static void be_ut_tx_fast_gc_free(struct m0_be_tx *tx, void *param)
577 {
578  struct be_ut_tx_fast *txf = param;
579 
580  txf->txf_state = BE_UT_TX_F_INIT;
581  m0_semaphore_up(&txf->txf_sem);
583 }
584 
586 {
587  struct m0_be_ut_backend ut_be;
588  struct be_ut_tx_fast *txf;
589  struct m0_semaphore global_sem;
590  struct m0_be_ut_seg ut_seg;
591  struct m0_sm_group *grp = NULL;
592  struct m0_be_seg *seg;
593  struct m0_be_reg reg;
594  struct m0_be_tx *tx;
595  int nr_init;
596  int nr_closed;
597  int i;
598 
599  M0_SET0(&ut_be);
602  seg = ut_seg.bus_seg;
605  for (i = 0; i < BE_UT_TX_F_TX_CONCUR; ++i) {
606  m0_semaphore_init(&txf[i].txf_sem, 1);
607  m0_clink_init(&txf[i].txf_clink, &be_ut_tx_fast_cb);
608  txf[i].txf_state = BE_UT_TX_F_INIT;
609  txf[i].txf_global_sem = &global_sem;
610  }
611  reg = M0_BE_REG(seg, 1, seg->bs_addr + seg->bs_reserved);
612  nr_init = 0;
613  nr_closed = 0;
614  while (!(nr_closed == BE_UT_TX_F_TX_NR &&
615  nr_init == BE_UT_TX_F_TX_NR + BE_UT_TX_F_TX_CONCUR)) {
616  if (grp != NULL)
618  m0_semaphore_down(&global_sem);
619  if (grp != NULL)
621  for (i = 0; i < BE_UT_TX_F_TX_CONCUR; ++i) {
622  if (m0_semaphore_trydown(&txf[i].txf_sem))
623  break;
624  }
626  tx = &txf[i].txf_tx;
627  switch (txf[i].txf_state) {
628  case BE_UT_TX_F_INIT:
629  if (nr_init++ >= BE_UT_TX_F_TX_NR)
630  break;
631  M0_SET0(tx);
632  m0_be_ut_tx_init(tx, &ut_be);
633  grp = tx->t_sm.sm_grp;
635  m0_clink_add(&tx->t_sm.sm_chan, &txf[i].txf_clink);
636  m0_be_tx_prep(tx, &M0_BE_TX_CREDIT(1, reg.br_size));
637  m0_be_tx_open(tx);
638  break;
639  case BE_UT_TX_F_CAPTURE:
640  m0_be_tx_capture(tx, &reg);
641  ++reg.br_addr;
642  m0_be_tx_close(tx);
643  ++nr_closed;
644  break;
645  default:
646  M0_IMPOSSIBLE("invalid state %d", txf[i].txf_state);
647  }
648  }
649  for (i = 0; i < BE_UT_TX_F_TX_CONCUR; ++i) {
650  m0_clink_fini(&txf[i].txf_clink);
651  m0_semaphore_fini(&txf[i].txf_sem);
652  }
653  m0_semaphore_fini(&global_sem);
654  m0_free(txf);
657 }
658 
659 enum {
662 };
663 
668 };
669 
671  struct m0_be_tx *tx,
672  bool exclusive)
673 {
674  M0_SET0(tx);
675  m0_be_ut_tx_init(tx, state->tts_ut_be);
676 
677  if (exclusive)
679  else
680  m0_be_tx_open_sync(tx);
681 
683  m0_be_tx_fini(tx);
684 }
685 
686 static void be_ut_tx_thread(struct be_ut_tx_thread_state *state)
687 {
688  struct m0_be_tx tx;
689  int i;
690 
691  if (state->tts_exclusive)
692  be_ut_tx_run_tx_helper(state, &tx, true);
693  else
694  for (i = 0; i < BE_UT_TX_C_TX_PER_THREAD; ++i)
695  be_ut_tx_run_tx_helper(state, &tx, false);
696 
698 }
699 
700 void m0_be_ut_tx_concurrent_helper(bool exclusive)
701 {
702  static struct be_ut_tx_thread_state threads[BE_UT_TX_C_THREAD_NR];
703  struct m0_be_ut_backend ut_be;
704  int i;
705  int rc;
706 
707  M0_SET0(&ut_be);
709 
710  for (i = 0; i < ARRAY_SIZE(threads); ++i) {
711  threads[i].tts_ut_be = &ut_be;
712  threads[i].tts_exclusive = !exclusive ? false :
713  (i == ARRAY_SIZE(threads) / 2 ||
714  i == ARRAY_SIZE(threads) / 4 ||
715  i == ARRAY_SIZE(threads) * 3 / 4);
716  rc = M0_THREAD_INIT(&threads[i].tts_thread,
717  struct be_ut_tx_thread_state *, NULL,
718  &be_ut_tx_thread, &threads[i],
719  "#%dbe_ut_tx", i);
720  M0_UT_ASSERT(rc == 0);
721  }
722  for (i = 0; i < ARRAY_SIZE(threads); ++i) {
723  rc = m0_thread_join(&threads[i].tts_thread);
724  M0_UT_ASSERT(rc == 0);
725  m0_thread_fini(&threads[i].tts_thread);
726  }
727 
729 }
730 
732 {
734 }
735 
737 {
739 }
740 
741 enum {
746 };
747 
748 M0_BASSERT(BE_UT_TX_CAPTURING_RANGE >= sizeof(uint64_t));
749 
751 {
752  struct m0_be_ut_backend ut_be;
753  struct m0_be_tx_credit cred = M0_BE_TX_CREDIT_TYPE(uint64_t);
754  struct m0_be_ut_seg ut_seg;
755  struct m0_be_seg *seg;
756  struct m0_be_tx tx;
757  uint64_t seed = 0;
758  uint64_t *ptr;
759  int i;
760  int j;
761  int rc;
762 
763  M0_SET0(&ut_be);
766  seg = ut_seg.bus_seg;
767 
769  for (i = 0; i < BE_UT_TX_CAPTURING_TX_NR; ++i) {
770  m0_be_ut_tx_init(&tx, &ut_be);
771  m0_be_tx_prep(&tx, &cred);
772  rc = m0_be_tx_open_sync(&tx);
773  M0_UT_ASSERT(rc == 0);
774 
775  for (j = 0; j < BE_UT_TX_CAPTURING_NR; ++j) {
777  m0_rnd64(&seed) %
778  (BE_UT_TX_CAPTURING_RANGE - sizeof *ptr);
779  *ptr = m0_rnd64(&seed);
781  }
782 
783  m0_be_tx_close_sync(&tx);
784  m0_be_tx_fini(&tx);
785  }
788 }
789 
790 enum {
794 };
795 
797  struct m0_be_tx *bugc_tx;
806 };
807 
809 
810 static bool be_ut_tx_gc_cb(struct m0_clink *clink)
811 {
812  struct be_ut_gc_test *test;
813 
816  if (m0_be_tx_state(test->bugc_tx) == M0_BTS_ACTIVE) {
818  m0_mutex_lock(test->bugc_rb_lock);
819  test->bugc_ringbuf[*test->bugc_rb_pos] = test->bugc_index;
820  ++*test->bugc_rb_pos;
821  m0_semaphore_up(test->bugc_rb_ready);
822  m0_mutex_unlock(test->bugc_rb_lock);
823  }
824  return false;
825 }
826 
827 static void be_ut_tx_gc_free(struct m0_be_tx *tx, void *param)
828 {
829  int i;
830  int index = -1;
831 
832  for (i = 0; i < BE_UT_TX_GC_TX_NR; ++i) {
833  if (be_ut_gc_tests[i].bugc_tx == tx) {
834  M0_UT_ASSERT(index == -1);
835  index = i;
836  }
837  }
841  m0_free(tx);
844 }
845 
846 static void be_ut_tx_gc_free_tx_failed(struct m0_be_tx *tx, void *param)
847 {
848  M0_UT_ASSERT(false);
849 }
850 
851 void m0_be_ut_tx_gc(void)
852 {
853  struct m0_be_ut_backend ut_be;
854  struct be_ut_gc_test *test;
855  struct m0_semaphore rb_ready;
856  struct m0_semaphore gc_done;
857  struct m0_be_ut_seg ut_seg;
858  struct m0_sm_group *grp;
859  struct m0_be_seg *seg;
860  struct m0_mutex rb_lock;
861  struct m0_be_tx *tx;
862  uint64_t seed = 0;
863  long *array;
864  long *ringbuf;
865  bool gc_enabled;
866  int gc_enabled_nr = 0;
867  int rb_pos = 0;
868  int i;
869  int rc;
870 
871  M0_SET0(&ut_be);
874  seg = ut_seg.bus_seg;
875  array = seg->bs_addr + m0_be_seg_reserved(seg);
877  M0_UT_ASSERT(ringbuf != NULL);
878  m0_semaphore_init(&rb_ready, 0);
879  m0_semaphore_init(&gc_done, 0);
880  m0_mutex_init(&rb_lock);
881 
882  for (i = 0; i < BE_UT_TX_GC_TX_NR; ++i) {
883  M0_ALLOC_PTR(tx);
884  M0_UT_ASSERT(tx != NULL);
885 
886  be_ut_gc_tests[i] = (struct be_ut_gc_test){
887  .bugc_tx = tx,
888  .bugc_gc_enabled = false,
889  .bugc_ringbuf = ringbuf,
890  .bugc_rb_pos = &rb_pos,
891  .bugc_rb_ready = &rb_ready,
892  .bugc_rb_lock = &rb_lock,
893  .bugc_index = i,
894  .bugc_gc_done = &gc_done,
895  };
897 
898  gc_enabled = m0_rnd64(&seed) % BE_UT_TX_GC_RAND_DENOMINATOR;
899  be_ut_gc_tests[i].bugc_gc_enabled = gc_enabled;
900  tx = be_ut_gc_tests[i].bugc_tx;
901  gc_enabled_nr += gc_enabled;
902 
903  m0_be_ut_tx_init(tx, &ut_be);
904  m0_be_tx_prep(tx, &M0_BE_TX_CREDIT_PTR(&array[i]));
906  m0_be_tx_open(tx);
907  grp = tx->t_sm.sm_grp;
908 
909  if (gc_enabled) {
911  &be_ut_gc_tests[i]);
912  }
913  }
914  /*
915  * Check that at least one transaction has gc enabled
916  * and at least one doesn't.
917  */
918  M0_UT_ASSERT(gc_enabled_nr > 0);
919  M0_UT_ASSERT(gc_enabled_nr < BE_UT_TX_GC_TX_NR);
920 
921  for (i = 0; i < BE_UT_TX_GC_TX_NR; ++i) {
923  m0_semaphore_down(&rb_ready);
925 
926  m0_mutex_lock(&rb_lock);
927  test = &be_ut_gc_tests[ringbuf[i]];
928  tx = test->bugc_tx;
929  m0_mutex_unlock(&rb_lock);
930 
932  m0_be_tx_capture(tx, &M0_BE_REG_PTR(seg, &array[i]));
933  m0_be_tx_close(tx);
934  }
936  for (i = 0; i < gc_enabled_nr; ++i)
937  m0_semaphore_down(&gc_done);
939  /*
940  * Finalise and free all tx that weren't GCed.
941  */
942  for (i = 0; i < BE_UT_TX_GC_TX_NR; ++i) {
943  test = &be_ut_gc_tests[i];
944  tx = test->bugc_tx;
945  M0_UT_ASSERT(equi(test->bugc_gc_enabled, tx == NULL));
946  if (tx != NULL) {
948  M0_TIME_NEVER);
949  m0_be_tx_fini(tx);
950  m0_free(tx);
951  }
952  }
953  M0_UT_ASSERT(!m0_semaphore_trydown(&rb_ready));
955  /*
956  * Check "m0_be_tx_open() failed with gc enabled" case.
957  */
958  M0_ALLOC_PTR(tx);
959  M0_UT_ASSERT(tx != NULL);
960  m0_be_ut_tx_init(tx, &ut_be);
963  rc = m0_be_tx_open_sync(tx);
964  M0_UT_ASSERT(rc != 0);
965  m0_be_tx_fini(tx);
966  m0_free(tx);
967 
968  m0_mutex_fini(&rb_lock);
969  m0_semaphore_fini(&gc_done);
970  m0_semaphore_fini(&rb_ready);
971  m0_free(ringbuf);
974 }
975 
976 enum {
980 };
981 
983  /* tx to test */
984  struct m0_be_tx tpt_tx;
985  /* tx payload credit */
987  /* how many bytes to fill in the test */
989  /* segment for capturing */
991  /* number of bytes to capture */
993  /* offset for capturing in seg (starting with bs_reserved) */
995 };
996 
997 #define TX_PAYLOAD_TEST(credit, fill, capture, offset) { \
998  .tpt_credit = (credit), \
999  .tpt_fill = (fill), \
1000  .tpt_capture = (capture), \
1001  .tpt_offset = (offset), \
1002 }
1003 
1004 static uint64_t be_ut_tx_payload_seed;
1005 
1007 {
1008  int i;
1009 
1010  for (i = 0; i < size; ++i)
1011  data[i] = m0_rnd64(&be_ut_tx_payload_seed) & 0xFF;
1012 }
1013 
1015  struct be_ut_tx_payload_test *test,
1016  size_t nr)
1017 {
1018  struct m0_be_tx_credit cred;
1019  struct m0_be_seg *seg;
1020  struct m0_be_reg reg;
1021  int rc;
1022  int i;
1023 
1024  for (i = 0; i < nr; ++i) {
1025  m0_be_ut_tx_init(&test[i].tpt_tx, ut_be);
1026  if (test[i].tpt_capture > 0) {
1027  cred = M0_BE_TX_CREDIT(1, test[i].tpt_capture);
1028  m0_be_tx_prep(&test[i].tpt_tx, &cred);
1029  }
1030  m0_be_tx_payload_prep(&test[i].tpt_tx, test[i].tpt_credit);
1031  /*
1032  * If test hangs here - try to increase BE log size
1033  * or decrease BE_UT_TX_PAYLOAD_TX_NR.
1034  */
1035  rc = m0_be_tx_open_sync(&test[i].tpt_tx);
1036  M0_UT_ASSERT(rc == 0);
1037  M0_ASSERT(test[i].tpt_fill <= test[i].tpt_credit);
1038  M0_ASSERT(test[i].tpt_fill <= test[i].tpt_tx.t_payload.b_nob);
1039  be_ut_tx_buf_fill_random(test[i].tpt_tx.t_payload.b_addr,
1040  test[i].tpt_fill);
1041  test[i].tpt_tx.t_payload.b_nob = test[i].tpt_fill;
1042  if (test[i].tpt_capture > 0) {
1043  seg = test[i].tpt_seg;
1044  reg = M0_BE_REG(seg, test[i].tpt_capture,
1045  seg->bs_addr + seg->bs_reserved +
1046  test[i].tpt_offset);
1047  m0_be_tx_capture(&test[i].tpt_tx, &reg);
1048  }
1049  m0_be_tx_close_sync(&test[i].tpt_tx);
1050  m0_be_tx_fini(&test[i].tpt_tx);
1051  }
1052 }
1053 
1055 {
1056  enum {
1057  PAYLOAD_SIZE = BE_UT_TX_PAYLOAD_SIZE_MAX,
1058  };
1059  struct be_ut_tx_payload_test *tests;
1060  struct be_ut_tx_payload_test special_cases[] = {
1061  /* payload credit, payload fill, capture credit, capture fill */
1062  TX_PAYLOAD_TEST(0, 0, 0, 0),
1063  TX_PAYLOAD_TEST(0, 0, 0x100, 0),
1064  TX_PAYLOAD_TEST(0, 0, 0x100, 0x100),
1065  TX_PAYLOAD_TEST(1, 0, 0, 0),
1066  TX_PAYLOAD_TEST(1, 1, 0, 0),
1067  TX_PAYLOAD_TEST(PAYLOAD_SIZE, 0, 0, 0),
1068  TX_PAYLOAD_TEST(PAYLOAD_SIZE, 0, 0x100, 0),
1069  TX_PAYLOAD_TEST(PAYLOAD_SIZE, 0, 0x100, 0x100),
1070  TX_PAYLOAD_TEST(PAYLOAD_SIZE, PAYLOAD_SIZE, 0x100, 0x100),
1071  TX_PAYLOAD_TEST(PAYLOAD_SIZE, PAYLOAD_SIZE / 2, 0x100, 0),
1072  };
1073  struct m0_be_ut_backend ut_be = {};
1074  struct m0_be_ut_seg ut_seg = {};
1075  struct m0_be_seg *seg;
1076  m0_bcount_t size;
1077  int i;
1078 
1079  be_ut_tx_payload_seed = 42; /* always works like magic */
1080 
1083  seg = ut_seg.bus_seg;
1084 
1085  for (i = 0; i < ARRAY_SIZE(special_cases); ++i)
1086  special_cases[i].tpt_seg = seg;
1087  be_ut_tx_payload_test_nr(&ut_be, &special_cases[0],
1088  ARRAY_SIZE(special_cases));
1089 
1091  for (i = 0; i < BE_UT_TX_PAYLOAD_TEST_NR; ++i) {
1092  tests[i].tpt_seg = seg;
1093  size = seg->bs_size - seg->bs_reserved;
1094 
1095  tests[i].tpt_credit = m0_rnd64(&be_ut_tx_payload_seed) %
1097  tests[i].tpt_fill = m0_rnd64(&be_ut_tx_payload_seed) %
1098  tests[i].tpt_credit;
1099  tests[i].tpt_capture = m0_rnd64(&be_ut_tx_payload_seed) % size;
1100  tests[i].tpt_offset = m0_rnd64(&be_ut_tx_payload_seed) %
1101  (size - tests[i].tpt_capture);
1102  }
1104  m0_free(tests);
1105 
1108 }
1109 
1110 #undef TX_PAYLOAD_TEST
1111 
1112 #undef M0_TRACE_SUBSYSTEM
1113 
1116 /*
1117  * Local variables:
1118  * c-indentation-style: "K&R"
1119  * c-basic-offset: 8
1120  * tab-width: 8
1121  * fill-column: 80
1122  * scroll-step: 1
1123  * End:
1124  */
1125 /*
1126  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
1127  */
struct m0_be_tx tpt_tx
Definition: tx.c:984
void * bs_addr
Definition: seg.h:71
void m0_be_ut_seg_fini(struct m0_be_ut_seg *ut_seg)
Definition: stubs.c:267
static void ptr(struct m0_addb2__context *ctx, const uint64_t *v, char *buf)
Definition: dump.c:440
#define M0_BE_TX_CREDIT_PTR(ptr)
Definition: tx_credit.h:98
static size_t nr
Definition: dump.c:1505
M0_INTERNAL void m0_be_tx_close_sync(struct m0_be_tx *tx)
Definition: tx.c:604
#define M0_PRE(cond)
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
static void be_ut_tx_reg_rand(struct m0_be_reg *reg, struct m0_be_seg *seg, uint64_t *seed)
Definition: tx.c:466
#define NULL
Definition: misc.h:38
M0_INTERNAL void m0_clink_init(struct m0_clink *link, m0_chan_cb_t cb)
Definition: chan.c:201
M0_INTERNAL void m0_clink_del(struct m0_clink *link)
Definition: chan.c:267
int t_payload
Definition: list.c:45
M0_INTERNAL bool m0_semaphore_trydown(struct m0_semaphore *semaphore)
Definition: semaphore.c:60
int m0_thread_join(struct m0_thread *q)
Definition: kthread.c:169
void m0_be_ut_tx_payload(void)
Definition: tx.c:1054
static bool x
Definition: sm.c:168
const m0_time_t M0_TIME_NEVER
Definition: time.c:108
static struct m0_sm_group * grp
Definition: bytecount.c:38
void m0_be_ut_tx_concurrent_excl(void)
Definition: tx.c:736
m0_bcount_t tpt_fill
Definition: tx.c:988
#define M0_CASSERT(cond)
struct m0_be_seg * bus_seg
Definition: helper.h:119
#define M0_BE_REG_PTR(seg, ptr)
Definition: seg.h:154
static void * be_ut_tx_alloc(void **alloc, m0_bcount_t size)
Definition: tx.c:118
struct m0_semaphore * bugc_rb_ready
Definition: tx.c:802
static char * tests
Definition: st_kmain.c:52
m0_bcount_t bs_size
Definition: seg.h:69
const struct m0_be_tx_credit m0_be_tx_credit_invalid
Definition: tx_credit.c:41
void m0_be_ut_tx_usecase_failure(void)
Definition: tx.c:83
struct m0_semaphore * txf_global_sem
Definition: tx.c:557
struct m0_bufvec data
Definition: di.c:40
void m0_be_ut_tx_capturing(void)
Definition: tx.c:750
long bugc_index
Definition: tx.c:804
Definition: tx.c:240
m0_bcount_t br_size
Definition: seg.h:144
void m0_be_ut_tx_states(void)
Definition: tx.c:126
struct m0_be_ut_seg ut_seg
Definition: ad.c:73
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
#define M0_BITS(...)
Definition: misc.h:236
uint64_t m0_bcount_t
Definition: types.h:77
#define M0_THREAD_INIT(thread, TYPE, init, func, arg, namefmt,...)
Definition: thread.h:139
struct m0_be_seg * tpt_seg
Definition: tx.c:990
struct m0_semaphore * bugc_gc_done
Definition: tx.c:805
#define container_of(ptr, type, member)
Definition: misc.h:33
#define M0_SET0(obj)
Definition: misc.h:64
#define M0_BE_TX_CREDIT_TYPE(type)
Definition: tx_credit.h:97
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
M0_INTERNAL int m0_be_tx_open_sync(struct m0_be_tx *tx)
Definition: tx.c:571
M0_INTERNAL void m0_be_tx_prep(struct m0_be_tx *tx, const struct m0_be_tx_credit *credit)
Definition: tx.c:260
void m0_be_ut_tx_usecase_success(void)
Definition: tx.c:44
M0_INTERNAL void m0_be_tx_put(struct m0_be_tx *tx)
Definition: tx.c:383
#define M0_BE_REG(seg, size, addr)
Definition: seg.h:148
void m0_be_ut_tx_fast(void)
Definition: tx.c:585
long * bugc_ringbuf
Definition: tx.c:800
struct tpool_test test[]
Definition: thread_pool.c:45
static uint64_t be_ut_tx_payload_seed
Definition: tx.c:1004
struct m0_be_tx * bugc_tx
Definition: tx.c:797
struct m0_be_tx tx
Definition: tx.c:241
m0_bcount_t bs_reserved
Definition: seg.h:74
static void be_ut_tx_thread(struct be_ut_tx_thread_state *state)
Definition: tx.c:686
struct m0_be_tx_credit cred
Definition: tx.c:242
#define equi(a, b)
Definition: misc.h:297
void m0_be_ut_tx_empty(void)
Definition: tx.c:196
#define M0_BE_TX_CREDIT(nr, size)
Definition: tx_credit.h:94
static void be_ut_tx_buf_fill_random(char *data, m0_bcount_t size)
Definition: tx.c:1006
m0_bcount_t size
Definition: tx.c:243
M0_INTERNAL void m0_sm_group_unlock(struct m0_sm_group *grp)
Definition: sm.c:96
static char * addr
Definition: node_k.c:37
M0_INTERNAL m0_bcount_t m0_be_seg_reserved(const struct m0_be_seg *seg)
Definition: seg.c:430
int i
Definition: dir.c:1033
struct m0_be_ut_backend ut_be
Definition: ad.c:72
uint32_t imag
Definition: tx.c:237
struct m0_semaphore txf_sem
Definition: tx.c:556
static void be_ut_tx_alloc_fini(void **alloc)
Definition: tx.c:113
void m0_be_ut_tx_persistence(void)
Definition: tx.c:487
void m0_be_ut_tx_concurrent(void)
Definition: tx.c:731
#define M0_ASSERT(cond)
static bool be_ut_tx_fast_cb(struct m0_clink *clink)
Definition: tx.c:561
static void be_ut_tx_fast_gc_free(struct m0_be_tx *tx, void *param)
Definition: tx.c:576
M0_INTERNAL void m0_be_tx_credit_mul(struct m0_be_tx_credit *c, m0_bcount_t k)
Definition: tx_credit.c:73
Definition: tx.c:251
M0_INTERNAL void m0_be_tx_credit_add(struct m0_be_tx_credit *c0, const struct m0_be_tx_credit *c1)
Definition: tx_credit.c:44
static void be_ut_tx_test(size_t nr)
Definition: tx.c:281
struct m0_be_tx txf_tx
Definition: tx.c:554
M0_INTERNAL void m0_be_tx_open(struct m0_be_tx *tx)
Definition: tx.c:281
void m0_thread_fini(struct m0_thread *q)
Definition: thread.c:92
static void be_ut_tx_reg_rand_fill(struct m0_be_reg *reg, uint64_t *seed)
Definition: tx.c:479
void m0_be_ut_backend_init(struct m0_be_ut_backend *ut_be)
Definition: stubs.c:238
static struct ff2c_term * alloc(void)
Definition: parser.c:37
M0_INTERNAL int m0_semaphore_init(struct m0_semaphore *semaphore, unsigned value)
Definition: semaphore.c:38
const union be_ut_tx_x::@85 captured
struct m0_sm_group * sm_grp
Definition: sm.h:321
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
static void be_ut_transact(struct be_ut_tx_x *x, struct m0_be_seg *seg, void **alloc)
Definition: tx.c:254
M0_INTERNAL int m0_be_tx_exclusive_open_sync(struct m0_be_tx *tx)
Definition: tx.c:594
static struct be_ut_gc_test be_ut_gc_tests[BE_UT_TX_GC_TX_NR]
Definition: tx.c:808
Definition: xcode.h:73
int32_t sm_rc
Definition: sm.h:336
uint32_t real
Definition: tx.c:236
bool tts_exclusive
Definition: tx.c:667
struct m0_thread tts_thread
Definition: tx.c:665
void m0_be_ut_tx_concurrent_helper(bool exclusive)
Definition: tx.c:700
static struct m0_clink clink[RDWR_REQUEST_MAX]
static void be_ut_tx_force(size_t nr)
Definition: tx.c:383
struct m0_sm t_sm
Definition: tx.h:281
Definition: seg.h:66
Definition: seg.h:142
static void be_ut_tx_gc_free(struct m0_be_tx *tx, void *param)
Definition: tx.c:827
M0_INTERNAL void m0_be_tx_close(struct m0_be_tx *tx)
Definition: tx.c:362
static void be_ut_tx_gc_free_tx_failed(struct m0_be_tx *tx, void *param)
Definition: tx.c:846
M0_BASSERT(BE_UT_TX_CAPTURING_RANGE >=sizeof(uint64_t))
static void be_ut_tx_payload_test_nr(struct m0_be_ut_backend *ut_be, struct be_ut_tx_payload_test *test, size_t nr)
Definition: tx.c:1014
M0_INTERNAL enum m0_be_tx_state m0_be_tx_state(const struct m0_be_tx *tx)
Definition: tx.c:412
void m0_be_ut_tx_single(void)
Definition: tx.c:225
M0_INTERNAL int m0_be_tx_timedwait(struct m0_be_tx *tx, uint64_t states, m0_time_t deadline)
Definition: tx.c:394
M0_INTERNAL uint64_t m0_rnd64(uint64_t *seed)
Definition: misc.c:100
static void be_ut_tx_alloc_init(void **alloc, struct m0_be_seg *seg)
Definition: tx.c:108
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
struct m0_chan sm_chan
Definition: sm.h:331
M0_INTERNAL void m0_clink_add(struct m0_chan *chan, struct m0_clink *link)
Definition: chan.c:228
M0_INTERNAL void m0_semaphore_fini(struct m0_semaphore *semaphore)
Definition: semaphore.c:45
Definition: list.c:42
struct m0_uint128 u128
Definition: tx.c:246
M0_INTERNAL void m0_be_tx_get(struct m0_be_tx *tx)
Definition: tx.c:373
M0_INTERNAL void m0_be_tx_fini(struct m0_be_tx *tx)
Definition: tx.c:237
struct m0_mutex * bugc_rb_lock
Definition: tx.c:803
struct be_ut_complex complex
Definition: tx.c:247
void m0_be_ut_tx_init(struct m0_be_tx *tx, struct m0_be_ut_backend *ut_be)
Definition: stubs.c:286
m0_bcount_t size
Definition: di.c:39
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
M0_INTERNAL void m0_clink_fini(struct m0_clink *link)
Definition: chan.c:208
void m0_be_ut_backend_fini(struct m0_be_ut_backend *ut_be)
Definition: stubs.c:242
void m0_be_ut_tx_several(void)
Definition: tx.c:230
M0_INTERNAL void m0_sm_group_lock(struct m0_sm_group *grp)
Definition: sm.c:83
m0_bcount_t tpt_capture
Definition: tx.c:992
M0_INTERNAL void m0_be_tx_gc_enable(struct m0_be_tx *tx, void(*gc_free)(struct m0_be_tx *, void *param), void *param)
Definition: tx.c:728
static struct m0_be_seg * seg
Definition: btree.c:40
#define M0_UINT128(hi, lo)
Definition: types.h:40
int * bugc_rb_pos
Definition: tx.c:801
m0_bcount_t tpt_offset
Definition: tx.c:994
m0_bcount_t tpt_credit
Definition: tx.c:986
int txf_state
Definition: tx.c:558
M0_INTERNAL void m0_be_tx_payload_prep(struct m0_be_tx *tx, m0_bcount_t size)
Definition: tx.c:271
M0_INTERNAL void m0_semaphore_down(struct m0_semaphore *semaphore)
Definition: semaphore.c:49
#define TX_PAYLOAD_TEST(credit, fill, capture, offset)
Definition: tx.c:997
M0_INTERNAL void m0_semaphore_up(struct m0_semaphore *semaphore)
Definition: semaphore.c:65
M0_INTERNAL void m0_be_tx_capture(struct m0_be_tx *tx, const struct m0_be_reg *reg)
Definition: tx.c:312
void * data
Definition: tx.c:244
void m0_free(void *data)
Definition: memory.c:146
Definition: mutex.h:47
struct m0_be_seg * br_seg
Definition: seg.h:143
static void be_ut_tx_run_tx_helper(struct be_ut_tx_thread_state *state, struct m0_be_tx *tx, bool exclusive)
Definition: tx.c:670
void * br_addr
Definition: seg.h:145
struct m0_clink bugc_clink
Definition: tx.c:799
struct m0_clink txf_clink
Definition: tx.c:555
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
void m0_be_ut_tx_force(void)
Definition: tx.c:452
#define M0_UT_ASSERT(a)
Definition: ut.h:46
void m0_be_ut_tx_gc(void)
Definition: tx.c:851
M0_INTERNAL void m0_be_tx_force(struct m0_be_tx *tx)
Definition: tx.c:638
void m0_be_ut_backend_thread_exit(struct m0_be_ut_backend *ut_be)
Definition: stubs.c:282
static void be_ut_tx_do_force(struct be_ut_tx_x *xs, size_t nr)
Definition: tx.c:337
Definition: tx.h:280
static bool be_ut_tx_gc_cb(struct m0_clink *clink)
Definition: tx.c:810
#define M0_IMPOSSIBLE(fmt,...)
struct m0_be_ut_backend * tts_ut_be
Definition: tx.c:666
bool bugc_gc_enabled
Definition: tx.c:798