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 #include <stddef.h> /* ptrdiff_t */
24 
25 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_BE
26 #include "lib/trace.h"
27 
28 #include "be/tx.h"
29 #include "be/tx_group.h"
30 #include "be/tx_internal.h"
31 
32 #include "lib/errno.h" /* ENOMEM */
33 #include "lib/misc.h" /* M0_BITS */
34 #include "lib/arith.h" /* M0_CNT_INC */
35 #include "lib/memory.h" /* m0_alloc_nz */
36 #include "fol/fol.h" /* m0_fol_rec_encode() */
37 
38 #include "be/op.h" /* m0_be_op */
39 #include "be/domain.h" /* m0_be_domain_engine */
40 #include "be/engine.h" /* m0_be_engine__tx_state_set */
41 #include "be/addb2.h" /* M0_AVI_BE_TX_STATE, M0_AVI_BE_TX_COUNTER */
42 #include "be/fmt.h" /* m0_be_fmt_tx */
43 
50 static bool be_tx_state_invariant(const struct m0_sm *mach)
51 {
52  return m0_be_tx__invariant(
53  container_of(mach, const struct m0_be_tx, t_sm));
54 }
55 
56 static bool be_tx_is_locked(const struct m0_be_tx *tx);
57 
58 #define BE_TX_LOCKED_AT_STATE(tx, states) \
59 ({ \
60  const struct m0_be_tx *__tx = (tx); \
61  \
62  _0C(be_tx_is_locked(__tx)) && m0_be_tx__invariant(__tx) && \
63  _0C(M0_IN(m0_be_tx_state(__tx), states)); \
64 })
65 
82 static const ptrdiff_t be_tx_ast_offset[M0_BTS_NR + 1] = {
83  [M0_BTS_GROUPING] = offsetof(struct m0_be_tx, t_ast_grouping),
84  [M0_BTS_ACTIVE] = offsetof(struct m0_be_tx, t_ast_active),
85  [M0_BTS_FAILED] = offsetof(struct m0_be_tx, t_ast_failed),
86  [M0_BTS_LOGGED] = offsetof(struct m0_be_tx, t_ast_logged),
87  [M0_BTS_PLACED] = offsetof(struct m0_be_tx, t_ast_placed),
88  [M0_BTS_DONE] = offsetof(struct m0_be_tx, t_ast_done)
89 };
90 
91 static void be_tx_state_move_ast(struct m0_be_tx *tx,
92  enum m0_be_tx_state state);
93 
94 static void be_tx_ast_cb(struct m0_sm_group *sm_group, struct m0_sm_ast *ast)
95 {
96  enum m0_be_tx_state state = (enum m0_be_tx_state)ast->sa_datum;
97  struct m0_be_tx *tx = ((void *)ast) - be_tx_ast_offset[state];
98 
100  M0_PRE(be_tx_ast_offset[state] != 0);
101  be_tx_state_move_ast(tx, state);
102 }
103 
104 static struct m0_sm_ast *
105 be_tx_ast(struct m0_be_tx *tx, enum m0_be_tx_state state)
106 {
108  M0_PRE(be_tx_ast_offset[state] != 0);
109  return ((void *)tx) + be_tx_ast_offset[state];
110 }
111 
112 /* be sure to change be_tx_state_move_ast if change be_tx_states */
114  [M0_BTS_PREPARE] = {
116  .sd_name = "prepare",
117  .sd_invariant = be_tx_state_invariant,
118  .sd_allowed = M0_BITS(M0_BTS_OPENING, M0_BTS_FAILED),
119  },
120  [M0_BTS_OPENING] = {
121  .sd_name = "opening",
122  .sd_invariant = be_tx_state_invariant,
123  .sd_allowed = M0_BITS(M0_BTS_GROUPING, M0_BTS_FAILED),
124  },
125  [M0_BTS_GROUPING] = {
126  .sd_name = "grouping",
127  .sd_invariant = be_tx_state_invariant,
128  .sd_allowed = M0_BITS(M0_BTS_ACTIVE),
129  },
130  [M0_BTS_FAILED] = {
131  .sd_flags = M0_SDF_TERMINAL | M0_SDF_FAILURE,
132  .sd_name = "failed",
133  .sd_invariant = be_tx_state_invariant,
134  .sd_allowed = 0,
135  },
136  [M0_BTS_ACTIVE] = {
137  .sd_name = "active",
138  .sd_invariant = be_tx_state_invariant,
139  .sd_allowed = M0_BITS(M0_BTS_CLOSED),
140  },
141  [M0_BTS_CLOSED] = {
142  .sd_name = "closed",
143  .sd_invariant = be_tx_state_invariant,
144  .sd_allowed = M0_BITS(M0_BTS_LOGGED),
145  },
146  [M0_BTS_LOGGED] = {
147  .sd_name = "logged",
148  .sd_invariant = be_tx_state_invariant,
149  .sd_allowed = M0_BITS(M0_BTS_PLACED),
150  },
151  [M0_BTS_PLACED] = {
152  .sd_name = "placed",
153  .sd_invariant = be_tx_state_invariant,
154  .sd_allowed = M0_BITS(M0_BTS_DONE),
155  },
156  [M0_BTS_DONE] = {
157  .sd_flags = M0_SDF_TERMINAL,
158  .sd_name = "done",
159  .sd_invariant = be_tx_state_invariant,
160  .sd_allowed = 0,
161  },
162 };
163 
165  { "opening", M0_BTS_PREPARE, M0_BTS_OPENING },
166  { "prepare-failed", M0_BTS_PREPARE, M0_BTS_FAILED },
167  { "grouping", M0_BTS_OPENING, M0_BTS_GROUPING },
168  { "open-failed", M0_BTS_OPENING, M0_BTS_FAILED },
169  { "activated", M0_BTS_GROUPING, M0_BTS_ACTIVE },
170  { "closed", M0_BTS_ACTIVE, M0_BTS_CLOSED },
171  { "logged", M0_BTS_CLOSED, M0_BTS_LOGGED },
172  { "placed", M0_BTS_LOGGED, M0_BTS_PLACED },
173  { "done", M0_BTS_PLACED, M0_BTS_DONE }
174 };
175 
177  .scf_name = "m0_be_tx::t_sm",
178  .scf_nr_states = ARRAY_SIZE(be_tx_states),
179  .scf_state = be_tx_states,
180  .scf_trans_nr = ARRAY_SIZE(be_tx_sm_trans),
181  .scf_trans = be_tx_sm_trans
182 };
183 
184 static void be_tx_state_move(struct m0_be_tx *tx,
185  enum m0_be_tx_state state,
186  int rc);
187 
188 M0_INTERNAL void m0_be_tx_init(struct m0_be_tx *tx,
189  uint64_t tid,
190  struct m0_be_domain *dom,
191  struct m0_sm_group *sm_group,
192  m0_be_tx_cb_t persistent,
193  m0_be_tx_cb_t discarded,
194  void (*filler)(struct m0_be_tx *tx,
195  void *payload),
196  void *datum)
197 {
198  enum m0_be_tx_state state;
199 
200  M0_PRE(M0_IS0(tx));
201 
202  *tx = (struct m0_be_tx){
203  .t_id = tid,
204  .t_engine = m0_be_domain_engine(dom),
205  .t_dom = dom,
206  .t_persistent = persistent,
207  .t_discarded = discarded,
208  .t_filler = filler,
209  .t_datum = datum,
210  .t_payload_prepared = 0,
211  .t_fast = false,
212  .t_gc_enabled = false,
213  .t_gc_free = NULL,
214  .t_gc_param = NULL,
215  .t_exclusive = false,
216  .t_recovering = false,
217  };
218 
219  m0_sm_init(&tx->t_sm, &be_tx_sm_conf, M0_BTS_PREPARE, sm_group);
221 
222  for (state = 0; state < ARRAY_SIZE(be_tx_ast_offset); ++state) {
223  if (be_tx_ast_offset[state] != 0) {
224  *be_tx_ast(tx, state) = (struct m0_sm_ast) {
225  .sa_cb = be_tx_ast_cb,
226  .sa_datum = (void *) state,
227  };
228  }
229  }
230 
232  m0_be_tx_get(tx);
233 
235 }
236 
237 M0_INTERNAL void m0_be_tx_fini(struct m0_be_tx *tx)
238 {
239  enum m0_be_tx_state state;
240 
241  M0_ENTRY("tx=%p", tx);
243  M0_PRE(tx->t_ref == 0);
244 
246 
247  for (state = 0; state < ARRAY_SIZE(be_tx_ast_offset); ++state) {
248  if (be_tx_ast_offset[state] != 0)
249  m0_sm_ast_cancel(tx->t_sm.sm_grp, be_tx_ast(tx, state));
250  }
251  /*
252  * Note: m0_sm_fini() will call be_tx_state_invariant(), so
253  * m0_be_tx::t_reg_area should be finalized after m0_be_tx::t_sm.
254  */
255  m0_sm_fini(&tx->t_sm);
257  m0_free(tx->t_payload.b_addr);
258 }
259 
260 M0_INTERNAL void m0_be_tx_prep(struct m0_be_tx *tx,
261  const struct m0_be_tx_credit *credit)
262 {
263  M0_ENTRY("tx=%p credit="BETXCR_F, tx, BETXCR_P(credit));
265 
266  m0_be_tx_credit_add(&tx->t_prepared, credit);
267 
269 }
270 
271 M0_INTERNAL void m0_be_tx_payload_prep(struct m0_be_tx *tx, m0_bcount_t size)
272 {
273  M0_ENTRY("tx=%p size=%"PRIu64, tx, size);
275 
276  tx->t_payload_prepared += size;
277 
279 }
280 
281 M0_INTERNAL void m0_be_tx_open(struct m0_be_tx *tx)
282 {
283  M0_ENTRY("tx=%p t_prepared="BETXCR_F" t_payload_prepared=%"PRIu64,
284  tx, BETXCR_P(&tx->t_prepared), tx->t_payload_prepared);
286 
288  M0_LOG(M0_NOTICE, "tx=%p t_prepared="BETXCR_F,
289  tx, BETXCR_P(&tx->t_prepared));
290  be_tx_state_move(tx, M0_BTS_FAILED, -EINVAL);
291  } else {
293  }
294 
296  M0_LEAVE();
297 }
298 
299 static void be_tx_make_reg_d(struct m0_be_tx *tx,
300  struct m0_be_reg_d *rd,
301  const struct m0_be_reg *reg)
302 {
303  struct m0_be_seg *seg;
304 
305  /* TODO cache seg if the performance impact is significant */
307  *rd = M0_BE_REG_D(M0_BE_REG(reg->br_seg == NULL ? seg : reg->br_seg,
308  reg->br_size, reg->br_addr), NULL);
310 }
311 
312 M0_INTERNAL void m0_be_tx_capture(struct m0_be_tx *tx,
313  const struct m0_be_reg *reg)
314 {
315  struct m0_be_reg_d rd;
316 
318 
319  be_tx_make_reg_d(tx, &rd, reg);
320  rd.rd_gen_idx = m0_be_reg_gen_idx(reg);
322 }
323 
324 M0_INTERNAL void
325 m0_be_tx_uncapture(struct m0_be_tx *tx, const struct m0_be_reg *reg)
326 {
327  struct m0_be_reg_d rd;
328 
330 
331  be_tx_make_reg_d(tx, &rd, reg);
333 }
334 
335 static void addb2_add_tx_attrs(const struct m0_be_tx *tx)
336 {
337  uint64_t tx_sm_id = m0_sm_id_get(&tx->t_sm);
338 
339  M0_ADDB2_ADD(M0_AVI_ATTR, tx_sm_id,
341  tx->t_payload.b_nob);
342  M0_ADDB2_ADD(M0_AVI_ATTR, tx_sm_id,
344  tx->t_payload_prepared);
345  M0_ADDB2_ADD(M0_AVI_ATTR, tx_sm_id,
348  M0_ADDB2_ADD(M0_AVI_ATTR, tx_sm_id,
351  M0_ADDB2_ADD(M0_AVI_ATTR, tx_sm_id,
354  M0_ADDB2_ADD(M0_AVI_ATTR, tx_sm_id,
357  M0_ADDB2_ADD(M0_AVI_ATTR, tx_sm_id,
360 }
361 
362 M0_INTERNAL void m0_be_tx_close(struct m0_be_tx *tx)
363 {
364  M0_ENTRY("tx=%p", tx);
366 
367  addb2_add_tx_attrs(tx);
369 
370  M0_LEAVE();
371 }
372 
373 M0_INTERNAL void m0_be_tx_get(struct m0_be_tx *tx)
374 {
375  M0_ENTRY("tx=%p t_ref=%"PRIu32" state=%s",
377  M0_PRE(be_tx_is_locked(tx));
379 
380  M0_CNT_INC(tx->t_ref);
381 }
382 
383 M0_INTERNAL void m0_be_tx_put(struct m0_be_tx *tx)
384 {
385  M0_ENTRY("tx=%p t_ref=%"PRIu32" state=%s",
387  M0_PRE(be_tx_is_locked(tx));
388 
389  M0_CNT_DEC(tx->t_ref);
390  if (tx->t_ref == 0 && m0_be_tx_state(tx) != M0_BTS_FAILED)
392 }
393 
394 M0_INTERNAL int m0_be_tx_timedwait(struct m0_be_tx *tx,
395  uint64_t states,
396  m0_time_t deadline)
397 {
398  int rc;
399 
400  M0_ENTRY("tx=%p state=%s states=%" PRIu64 " deadline=%"PRIu64,
401  tx, m0_be_tx_state_name(m0_be_tx_state(tx)), states, deadline);
402  M0_PRE(be_tx_is_locked(tx));
406 
407  rc = m0_sm_timedwait(&tx->t_sm, states, deadline);
408  M0_ASSERT_INFO(M0_IN(rc, (0, -ETIMEDOUT)), "rc=%d", rc);
409  return M0_RC(rc == 0 ? tx->t_sm.sm_rc : rc);
410 }
411 
412 M0_INTERNAL enum m0_be_tx_state m0_be_tx_state(const struct m0_be_tx *tx)
413 {
414  return tx->t_sm.sm_state;
415 }
416 
417 M0_INTERNAL const char *m0_be_tx_state_name(enum m0_be_tx_state state)
418 {
419  return m0_sm_conf_state_name(&be_tx_sm_conf, state);
420 }
421 
422 static void be_tx_state_move_ast(struct m0_be_tx *tx, enum m0_be_tx_state state)
423 {
425 
426  M0_ENTRY("tx=%p %s -> %s",
428 
429  if (tx_state < M0_BTS_CLOSED || state == tx_state + 1) {
430  /*
431  * If we have state transition to M0_BTS_FAILED here
432  * then transaction exceeds engine tx size limit.
433  */
434  be_tx_state_move(tx, state,
435  state == M0_BTS_FAILED ? -E2BIG : 0);
436  } else {
437  while (tx_state < state)
438  be_tx_state_move(tx, ++tx_state, 0);
439  }
440 }
441 
442 static int be_tx_memory_allocate(struct m0_be_tx *tx)
443 {
444  int rc;
445 
447  if (tx->t_payload_prepared > 0)
449  if (tx->t_payload.b_addr == NULL && tx->t_payload.b_nob != 0) {
450  rc = -ENOMEM;
451  M0_LOG(M0_ERROR, "tx=%p t_payload_prepared=%" PRIu64 " rc=%d",
452  tx, tx->t_payload_prepared, rc);
453  } else {
456  if (rc != 0) {
457  m0_free0(&tx->t_payload.b_addr);
458  M0_LOG(M0_ERROR, "tx=%p t_prepared="BETXCR_F" rc=%d",
459  tx, BETXCR_P(&tx->t_prepared), rc);
460  }
461  }
462  return M0_RC(rc);
463 }
464 
465 static void be_tx_gc(struct m0_be_tx *tx)
466 {
467  void (*gc_free)(struct m0_be_tx *, void *param);
468  void *gc_param;
469 
470  M0_ENTRY("tx=%p t_gc_free=%p t_gc_param=%p",
471  tx, tx->t_gc_free, tx->t_gc_param);
472  gc_free = tx->t_gc_free;
473  gc_param = tx->t_gc_param;
474  m0_be_tx_fini(tx);
475  if (gc_free != NULL)
476  gc_free(tx, gc_param);
477  else
478  m0_free(tx);
479 }
480 
481 static void be_tx_state_move(struct m0_be_tx *tx,
482  enum m0_be_tx_state state,
483  int rc)
484 {
485  bool tx_is_freed = false;
486 
487  M0_ENTRY("tx=%p rc=%d %s -> %s", tx, rc,
489  m0_be_tx_state_name(state));
490 
492  M0_PRE(be_tx_is_locked(tx));
493  M0_PRE(ergo(rc != 0, state == M0_BTS_FAILED));
496  M0_BTS_PLACED, M0_BTS_DONE)), rc == 0));
497 
498  if (state == M0_BTS_ACTIVE) {
500  if (rc != 0)
501  state = M0_BTS_FAILED;
502  }
503 
504  if (state == M0_BTS_LOGGED && tx->t_persistent != NULL)
505  tx->t_persistent(tx);
506  if (state == M0_BTS_DONE && tx->t_discarded != NULL)
507  tx->t_discarded(tx);
508 
509  m0_sm_move(&tx->t_sm, rc, state);
510  m0_be_engine__tx_state_set(tx->t_engine, tx, state);
511 
512  if (M0_IN(state, (M0_BTS_PLACED, M0_BTS_FAILED)))
513  m0_be_tx_put(tx);
514 
515  if (state == M0_BTS_DONE && tx->t_gc_enabled) {
516  be_tx_gc(tx);
517  tx_is_freed = true;
518  }
519 
520  M0_POST(tx_is_freed || m0_be_tx__invariant(tx));
521  M0_LEAVE();
522 }
523 
524 M0_INTERNAL void m0_be_tx__state_post(struct m0_be_tx *tx,
525  enum m0_be_tx_state state)
526 {
527  /* XXX move to group_fom doc */
528  /*
529  * tx_group's fom and tx's sm may belong different sm_groups (e.g.,
530  * they may be processed by different localities).
531  *
532  * locality
533  * --------
534  * sm_group sm_group sm_group
535  * | | | | |
536  * | | | | |
537  * tx_group | | | | |
538  * -------- | | | | |
539  * fom -' | | | |
540  * | tx tx | tx | | tx
541  * | -- -- | -- | | --
542  * `- sm sm -' sm -' `- sm
543  *
544  * ->fo_tick() of tx_group's fom shall not assume that sm_group of
545  * tx's sm is locked. In order to advance tx's sm, ->fo_tick()
546  * implementation should post an AST to tx's sm_group.
547  */
550  M0_LOG(M0_DEBUG, "tx=%p state=%s", tx, m0_be_tx_state_name(state));
551 
552  m0_sm_ast_post(tx->t_sm.sm_grp, be_tx_ast(tx, state));
553 }
554 
555 M0_INTERNAL bool m0_be_tx__invariant(const struct m0_be_tx *tx)
556 {
557  return _0C(m0_be_tx_state(tx) < M0_BTS_NR) &&
559 }
560 
561 static bool be_tx_is_locked(const struct m0_be_tx *tx)
562 {
563  return m0_mutex_is_locked(&tx->t_sm.sm_grp->s_lock);
564 }
565 
566 M0_INTERNAL struct m0_be_reg_area *m0_be_tx__reg_area(struct m0_be_tx *tx)
567 {
568  return &tx->t_reg_area;
569 }
570 
571 M0_INTERNAL int m0_be_tx_open_sync(struct m0_be_tx *tx)
572 {
573  enum m0_be_tx_state state;
574  int rc;
575 
576  m0_be_tx_open(tx);
578  M0_TIME_NEVER);
579 
580  state = m0_be_tx_state(tx);
581  M0_ASSERT_INFO(equi(rc == 0, state == M0_BTS_ACTIVE) &&
582  equi(rc != 0, state == M0_BTS_FAILED),
583  "tx=%p rc=%d state=%s",
584  tx, rc, m0_be_tx_state_name(state));
585  return M0_RC(rc);
586 }
587 
588 M0_INTERNAL void m0_be_tx_exclusive_open(struct m0_be_tx *tx)
589 {
590  tx->t_exclusive = true;
591  m0_be_tx_open(tx);
592 }
593 
594 M0_INTERNAL int m0_be_tx_exclusive_open_sync(struct m0_be_tx *tx)
595 {
596  int rc;
597 
598  tx->t_exclusive = true;
599  rc = m0_be_tx_open_sync(tx);
601  return M0_RC(rc);
602 }
603 
604 M0_INTERNAL void m0_be_tx_close_sync(struct m0_be_tx *tx)
605 {
606  bool gc_enabled;
607  int rc;
608 
609  tx->t_fast = true;
610  /*
611  * m0_be_tx_timedwait() can't be used on transactions with
612  * GC enabled. So GC is disabled and called manually if it
613  * is needed.
614  */
615  gc_enabled = tx->t_gc_enabled;
616  tx->t_gc_enabled = false;
617  m0_be_tx_close(tx);
619  M0_ASSERT_INFO(rc == 0, "Transaction can't fail after m0_be_tx_open(): "
620  "rc = %d, tx = %p", rc, tx);
621  if (gc_enabled)
622  be_tx_gc(tx);
623 }
624 
625 M0_INTERNAL bool m0_be_tx__is_fast(struct m0_be_tx *tx)
626 {
627  return tx->t_fast;
628 }
629 
630 M0_INTERNAL int m0_be_tx_fol_add(struct m0_be_tx *tx, struct m0_fol_rec *rec)
631 {
632  M0_PRE(be_tx_is_locked(tx));
634 
635  return m0_fol_rec_encode(rec, &tx->t_payload);
636 }
637 
638 M0_INTERNAL void m0_be_tx_force(struct m0_be_tx *tx)
639 {
640  M0_PRE(be_tx_is_locked(tx));
642 
643  M0_ENTRY("tx=%p", tx);
644 
645  /* let be engine do the dirty part */
647 }
648 
649 M0_INTERNAL bool m0_be_tx__is_exclusive(const struct m0_be_tx *tx)
650 {
651  return tx->t_exclusive;
652 }
653 
654 M0_INTERNAL void m0_be_tx__recovering_set(struct m0_be_tx *tx)
655 {
656  tx->t_recovering = true;
657 }
658 
659 M0_INTERNAL bool m0_be_tx__is_recovering(struct m0_be_tx *tx)
660 {
661  return tx->t_recovering;
662 }
663 
664 M0_INTERNAL void m0_be_tx_deconstruct(struct m0_be_tx *tx,
665  struct m0_be_fmt_tx *ftx)
666 {
667  *ftx = M0_BE_FMT_TX(tx->t_payload, tx->t_id);
668 }
669 
670 M0_INTERNAL void m0_be_tx_reconstruct(struct m0_be_tx *tx,
671  const struct m0_be_fmt_tx *ftx)
672 {
673  int rc;
674 
677 
678  /*
679  * Temporary solution.
680  * In the future it will be no preallocated payload buffer for each tx.
681  * It will be preallocated in the group and will be filled by
682  * user-supplied callbacks.
683  */
684  rc = m0_buf_copy(&tx->t_payload, &ftx->bft_payload);
685  M0_ASSERT_INFO(rc == 0, "rc=%d", rc);
686  tx->t_id = ftx->bft_id;
687 }
688 
689 M0_INTERNAL void m0_be_tx__group_assign(struct m0_be_tx *tx,
690  struct m0_be_tx_group *gr)
691 {
692  if (!m0_be_tx__is_recovering(tx))
693  tx->t_group = gr;
694 }
695 
696 static bool be_should_break(struct m0_be_engine *eng,
697  uint64_t fraction,
698  const struct m0_be_tx_credit *accum,
699  const struct m0_be_tx_credit *delta)
700 {
701  struct m0_be_tx_credit total = *accum;
702  struct m0_be_tx_credit max;
703 
704  M0_PRE(fraction > 0);
705 
706  m0_be_tx_credit_add(&total, delta);
708 
709  max.tc_reg_size /= fraction;
710  max.tc_reg_nr /= fraction;
711  return !m0_be_tx_credit_le(&total, &max);
712 }
713 
714 M0_INTERNAL bool m0_be_should_break(struct m0_be_engine *eng,
715  const struct m0_be_tx_credit *accum,
716  const struct m0_be_tx_credit *delta)
717 {
718  return be_should_break(eng, 1, accum, delta);
719 }
720 
721 M0_INTERNAL bool m0_be_should_break_half(struct m0_be_engine *eng,
722  const struct m0_be_tx_credit *accum,
723  const struct m0_be_tx_credit *delta)
724 {
725  return be_should_break(eng, 2, accum, delta);
726 }
727 
728 M0_INTERNAL void m0_be_tx_gc_enable(struct m0_be_tx *tx,
729  void (*gc_free)(struct m0_be_tx *,
730  void *param),
731  void *param)
732 {
733  M0_ENTRY("tx=%p gc_free=%p param=%p", tx, gc_free, param);
734 
736  M0_BTS_ACTIVE)));
737 
738  tx->t_gc_enabled = true;
739  tx->t_gc_free = gc_free;
740  tx->t_gc_param = param;
741 }
742 
743 M0_INTERNAL void m0_be_tx_lsn_set(struct m0_be_tx *tx,
744  m0_bindex_t lsn,
745  m0_bindex_t lsn_discarded)
746 {
747  /*
748  * This function is called from m0_be_tx_group_close().
749  * When the BE tx group this transaction belongs to is being closed
750  * the tx sm group is not locked - this is why BE_TX_LOCKED_AT_STATE
751  * could not be used here.
752  */
754 
755  tx->t_lsn = lsn;
756  tx->t_lsn_discarded = lsn_discarded;
757  M0_LEAVE("tx=%p t_lsn=%" PRIu64 " t_lsn_discarded=%"PRIu64,
758  tx, tx->t_lsn, tx->t_lsn_discarded);
759 }
760 
761 M0_INTERNAL void m0_be_tx_lsn_get(struct m0_be_tx *tx,
762  m0_bindex_t *lsn,
763  m0_bindex_t *lsn_discarded)
764 {
765  M0_ENTRY("tx=%p t_lsn=%" PRIu64 " t_lsn_discarded=%"PRIu64,
766  tx, tx->t_lsn, tx->t_lsn_discarded);
768  M0_BTS_DONE)));
769 
770  *lsn = tx->t_lsn;
771  *lsn_discarded = tx->t_lsn_discarded;
772 }
773 
774 M0_EXTERN struct m0_sm_conf op_states_conf;
775 M0_INTERNAL int m0_be_tx_mod_init(void)
776 {
782 }
783 
784 M0_INTERNAL void m0_be_tx_mod_fini(void)
785 {
790 }
791 
792 #undef BE_TX_LOCKED_AT_STATE
793 
795 #undef M0_TRACE_SUBSYSTEM
796 
797 /*
798  * Local variables:
799  * c-indentation-style: "K&R"
800  * c-basic-offset: 8
801  * tab-width: 8
802  * fill-column: 80
803  * scroll-step: 1
804  * End:
805  */
806 /*
807  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
808  */
struct m0_be_tx_credit t_prepared
Definition: tx.h:300
bool t_recovering
Definition: tx.h:402
static struct m0_sm_trans_descr be_tx_sm_trans[]
Definition: tx.c:164
M0_INTERNAL void m0_be_tx_close_sync(struct m0_be_tx *tx)
Definition: tx.c:604
#define M0_PRE(cond)
M0_INTERNAL void m0_sm_conf_init(struct m0_sm_conf *conf)
Definition: sm.c:340
#define BETXCR_F
Definition: tx_credit.h:102
M0_INTERNAL int m0_sm_addb2_init(struct m0_sm_conf *conf, uint64_t id, uint64_t counter)
Definition: sm.c:846
M0_INTERNAL void m0_be_tx_lsn_set(struct m0_be_tx *tx, m0_bindex_t lsn, m0_bindex_t lsn_discarded)
Definition: tx.c:743
#define NULL
Definition: misc.h:38
static void be_tx_ast_cb(struct m0_sm_group *sm_group, struct m0_sm_ast *ast)
Definition: tx.c:94
#define ergo(a, b)
Definition: misc.h:293
bool t_gc_enabled
Definition: tx.h:392
void(* sa_cb)(struct m0_sm_group *grp, struct m0_sm_ast *)
Definition: sm.h:506
m0_be_tx_state
Definition: tx.h:214
Definition: sm.h:350
unsigned long rd_gen_idx
Definition: tx_regmap.h:64
const m0_time_t M0_TIME_NEVER
Definition: time.c:108
void * b_addr
Definition: buf.h:39
static void be_tx_gc(struct m0_be_tx *tx)
Definition: tx.c:465
static struct m0_sm_ast * be_tx_ast(struct m0_be_tx *tx, enum m0_be_tx_state state)
Definition: tx.c:105
uint64_t m0_time_t
Definition: time.h:37
#define M0_LOG(level,...)
Definition: trace.h:167
M0_LEAVE()
M0_INTERNAL bool m0_be_reg_area__invariant(const struct m0_be_reg_area *ra)
Definition: tx_regmap.c:609
M0_INTERNAL void m0_be_tx__recovering_set(struct m0_be_tx *tx)
Definition: tx.c:654
M0_INTERNAL void m0_sm_ast_post(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:135
struct m0_be_tx_credit bra_prepared
Definition: tx_regmap.h:242
static void be_tx_state_move(struct m0_be_tx *tx, enum m0_be_tx_state state, int rc)
Definition: tx.c:481
const struct m0_be_tx_credit m0_be_tx_credit_invalid
Definition: tx_credit.c:41
M0_INTERNAL void m0_be_tx_exclusive_open(struct m0_be_tx *tx)
Definition: tx.c:588
M0_INTERNAL struct m0_be_reg_area * m0_be_tx__reg_area(struct m0_be_tx *tx)
Definition: tx.c:566
m0_bcount_t br_size
Definition: seg.h:144
uint64_t m0_bindex_t
Definition: types.h:80
static struct m0_addb2_mach * mach
Definition: storage.c:42
#define M0_BITS(...)
Definition: misc.h:236
uint64_t m0_bcount_t
Definition: types.h:77
Definition: sm.h:504
M0_INTERNAL struct m0_be_seg * m0_be_domain_seg_by_addr(struct m0_be_domain *dom, void *addr)
Definition: domain.c:999
#define container_of(ptr, type, member)
Definition: misc.h:33
M0_ADDB2_ADD(M0_AVI_FS_CREATE, new_fid.f_container, new_fid.f_key, mode, rc)
M0_INTERNAL bool m0_sm_addb2_counter_init(struct m0_sm *sm)
Definition: sm.c:891
M0_INTERNAL int m0_be_tx_open_sync(struct m0_be_tx *tx)
Definition: tx.c:571
M0_INTERNAL unsigned long m0_be_reg_gen_idx(const struct m0_be_reg *reg)
Definition: seg.c:469
static int be_tx_memory_allocate(struct m0_be_tx *tx)
Definition: tx.c:442
M0_INTERNAL void m0_be_tx_prep(struct m0_be_tx *tx, const struct m0_be_tx_credit *credit)
Definition: tx.c:260
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
M0_INTERNAL int m0_be_engine__exclusive_open_invariant(struct m0_be_engine *en, struct m0_be_tx *excl)
Definition: engine.c:921
m0_bcount_t bra_area_used
Definition: tx_regmap.h:241
#define M0_BE_REG_D(reg, buf)
Definition: tx_regmap.h:67
M0_INTERNAL void m0_be_reg_area_capture(struct m0_be_reg_area *ra, struct m0_be_reg_d *rd)
Definition: tx_regmap.c:751
bool m0_be_reg__invariant(const struct m0_be_reg *reg)
Definition: seg.c:290
M0_INTERNAL bool m0_be_tx__is_fast(struct m0_be_tx *tx)
Definition: tx.c:625
M0_INTERNAL int m0_sm_timedwait(struct m0_sm *mach, uint64_t states, m0_time_t deadline)
Definition: sm.c:387
M0_INTERNAL void m0_be_reg_area_fini(struct m0_be_reg_area *ra)
Definition: tx_regmap.c:602
M0_INTERNAL int m0_be_reg_area_init(struct m0_be_reg_area *ra, const struct m0_be_tx_credit *prepared, enum m0_be_reg_area_type type)
Definition: tx_regmap.c:559
struct m0_be_reg rd_reg
Definition: tx_regmap.h:53
return M0_RC(rc)
m0_be_tx_cb_t t_discarded
Definition: tx.h:318
#define equi(a, b)
Definition: misc.h:297
#define M0_BE_FMT_TX(payload, id)
Definition: fmt.h:368
struct m0_be_domain * t_dom
Definition: tx.h:291
#define M0_ENTRY(...)
Definition: trace.h:170
static struct m0_sm_ast ast[NR]
Definition: locality.c:44
M0_INTERNAL void * m0_alloc_nz(size_t size)
Definition: memory.c:115
M0_EXTERN struct m0_sm_conf op_states_conf
Definition: tx.c:774
M0_INTERNAL struct m0_be_engine * m0_be_domain_engine(struct m0_be_domain *dom)
Definition: domain.c:461
#define PRIu64
Definition: types.h:58
void * t_gc_param
Definition: tx.h:394
void * sa_datum
Definition: sm.h:508
M0_INTERNAL bool m0_be_tx_credit_eq(const struct m0_be_tx_credit *c0, const struct m0_be_tx_credit *c1)
Definition: tx_credit.c:105
M0_INTERNAL void m0_be_tx_deconstruct(struct m0_be_tx *tx, struct m0_be_fmt_tx *ftx)
Definition: tx.c:664
struct m0_be_tx_group * t_group
Definition: tx.h:372
M0_INTERNAL void m0_be_engine__tx_state_set(struct m0_be_engine *en, struct m0_be_tx *tx, enum m0_be_tx_state state)
Definition: engine.c:639
struct m0_be_tx_credit bra_captured
Definition: tx_regmap.h:247
#define m0_free0(pptr)
Definition: memory.h:77
static void be_tx_state_move_ast(struct m0_be_tx *tx, enum m0_be_tx_state state)
Definition: tx.c:422
m0_bcount_t b_nob
Definition: buf.h:38
static void tx_state(struct m0_addb2__context *ctx, const uint64_t *v, char *buf)
Definition: dump.c:841
const char * scf_name
Definition: sm.h:352
M0_INTERNAL bool m0_mutex_is_locked(const struct m0_mutex *mutex)
Definition: mutex.c:95
M0_INTERNAL void m0_be_tx__group_assign(struct m0_be_tx *tx, struct m0_be_tx_group *gr)
Definition: tx.c:689
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
M0_INTERNAL void m0_be_tx_open(struct m0_be_tx *tx)
Definition: tx.c:281
static struct m0_stob_domain * dom
Definition: storage.c:38
static long long max(long long a, long long b)
Definition: crate.c:196
m0_bcount_t t_payload_prepared
Definition: tx.h:365
struct m0_sm_group * sm_grp
Definition: sm.h:321
m0_bcount_t tc_reg_nr
Definition: tx_credit.h:84
M0_INTERNAL int m0_be_tx_exclusive_open_sync(struct m0_be_tx *tx)
Definition: tx.c:594
#define M0_POST(cond)
M0_INTERNAL void m0_sm_addb2_fini(struct m0_sm_conf *conf)
Definition: sm.c:870
M0_INTERNAL bool m0_be_tx__is_exclusive(const struct m0_be_tx *tx)
Definition: tx.c:649
int32_t sm_rc
Definition: sm.h:336
static bool be_should_break(struct m0_be_engine *eng, uint64_t fraction, const struct m0_be_tx_credit *accum, const struct m0_be_tx_credit *delta)
Definition: tx.c:696
m0_bindex_t t_lsn_discarded
Definition: tx.h:350
M0_INTERNAL void m0_be_tx_lsn_get(struct m0_be_tx *tx, m0_bindex_t *lsn, m0_bindex_t *lsn_discarded)
Definition: tx.c:761
#define BETXCR_P(c)
Definition: tx_credit.h:113
M0_INTERNAL bool m0_be_should_break_half(struct m0_be_engine *eng, const struct m0_be_tx_credit *accum, const struct m0_be_tx_credit *delta)
Definition: tx.c:721
static void be_tx_make_reg_d(struct m0_be_tx *tx, struct m0_be_reg_d *rd, const struct m0_be_reg *reg)
Definition: tx.c:299
struct m0_buf bft_payload
Definition: fmt.h:364
uint32_t t_ref
Definition: tx.h:374
struct m0_mutex s_lock
Definition: sm.h:514
uint64_t t_id
Definition: tx.h:284
Definition: seg.h:66
struct m0_sm t_sm
Definition: tx.h:281
Definition: seg.h:142
M0_INTERNAL int m0_buf_copy(struct m0_buf *dest, const struct m0_buf *src)
Definition: buf.c:104
bool t_fast
Definition: tx.h:383
M0_INTERNAL void m0_be_tx_close(struct m0_be_tx *tx)
Definition: tx.c:362
M0_INTERNAL void m0_be_engine__tx_fini(struct m0_be_engine *en, struct m0_be_tx *tx)
Definition: engine.c:631
M0_INTERNAL void m0_be_engine_tx_size_max(struct m0_be_engine *en, struct m0_be_tx_credit *cred, m0_bcount_t *payload_size)
Definition: engine.c:937
static struct m0_sm_state_descr be_tx_states[M0_BTS_NR]
Definition: tx.c:113
#define BE_TX_LOCKED_AT_STATE(tx, states)
Definition: tx.c:58
M0_INTERNAL enum m0_be_tx_state m0_be_tx_state(const struct m0_be_tx *tx)
Definition: tx.c:412
M0_INTERNAL void m0_be_reg_area_uncapture(struct m0_be_reg_area *ra, const struct m0_be_reg_d *rd)
Definition: tx_regmap.c:775
uint32_t sd_flags
Definition: sm.h:378
#define PRIu32
Definition: types.h:66
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 void m0_be_tx_mod_fini(void)
Definition: tx.c:784
static bool be_tx_state_invariant(const struct m0_sm *mach)
Definition: tx.c:50
#define M0_CNT_INC(cnt)
Definition: arith.h:226
M0_INTERNAL void m0_be_tx_init(struct m0_be_tx *tx, uint64_t tid, struct m0_be_domain *dom, struct m0_sm_group *sm_group, m0_be_tx_cb_t persistent, m0_be_tx_cb_t discarded, void(*filler)(struct m0_be_tx *tx, void *payload), void *datum)
Definition: tx.c:188
M0_INTERNAL void m0_sm_init(struct m0_sm *mach, const struct m0_sm_conf *conf, uint32_t state, struct m0_sm_group *grp)
Definition: sm.c:313
M0_INTERNAL void m0_be_tx_reconstruct(struct m0_be_tx *tx, const struct m0_be_fmt_tx *ftx)
Definition: tx.c:670
#define M0_IS0(obj)
Definition: misc.h:70
bool t_exclusive
Definition: tx.h:388
void(* t_gc_free)(struct m0_be_tx *tx, void *param)
Definition: tx.h:393
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
uint64_t t_lsn
Definition: tx.h:344
m0_be_tx_cb_t t_persistent
Definition: tx.h:308
Definition: sm.h:301
M0_INTERNAL void m0_be_tx_uncapture(struct m0_be_tx *tx, const struct m0_be_reg *reg)
Definition: tx.c:325
m0_bcount_t size
Definition: di.c:39
#define _0C(exp)
Definition: assert.h:311
M0_INTERNAL void m0_sm_move(struct m0_sm *mach, int32_t rc, int state)
Definition: sm.c:485
M0_INTERNAL bool m0_be_should_break(struct m0_be_engine *eng, const struct m0_be_tx_credit *accum, const struct m0_be_tx_credit *delta)
Definition: tx.c:714
#define IS_IN_ARRAY(idx, array)
Definition: misc.h:311
M0_INTERNAL void m0_be_engine__tx_force(struct m0_be_engine *en, struct m0_be_tx *tx)
Definition: engine.c:684
struct m0_buf t_payload
Definition: tx.h:364
static bool be_tx_is_locked(const struct m0_be_tx *tx)
Definition: tx.c:561
M0_INTERNAL bool m0_be_tx__is_recovering(struct m0_be_tx *tx)
Definition: tx.c:659
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_CNT_DEC(cnt)
Definition: arith.h:219
static void addb2_add_tx_attrs(const struct m0_be_tx *tx)
Definition: tx.c:335
#define M0_ASSERT_INFO(cond, fmt,...)
M0_INTERNAL const char * m0_be_tx_state_name(enum m0_be_tx_state state)
Definition: tx.c:417
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_sm_ast_cancel(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:183
static int total
Definition: base.c:302
M0_INTERNAL bool m0_be_tx_credit_le(const struct m0_be_tx_credit *c0, const struct m0_be_tx_credit *c1)
Definition: tx_credit.c:98
M0_INTERNAL int m0_be_tx_fol_add(struct m0_be_tx *tx, struct m0_fol_rec *rec)
Definition: tx.c:630
struct m0_be_reg_area t_reg_area
Definition: tx.h:301
M0_INTERNAL void m0_sm_conf_fini(struct m0_sm_conf *conf)
Definition: sm.c:376
M0_INTERNAL void m0_be_tx_capture(struct m0_be_tx *tx, const struct m0_be_reg *reg)
Definition: tx.c:312
Definition: tx.h:270
M0_INTERNAL uint64_t m0_sm_id_get(const struct m0_sm *sm)
Definition: sm.c:1021
M0_INTERNAL bool m0_be_tx__invariant(const struct m0_be_tx *tx)
Definition: tx.c:555
void m0_free(void *data)
Definition: memory.c:146
M0_INTERNAL void m0_be_tx__state_post(struct m0_be_tx *tx, enum m0_be_tx_state state)
Definition: tx.c:524
struct m0_be_seg * br_seg
Definition: seg.h:143
void * br_addr
Definition: seg.h:145
M0_INTERNAL int m0_be_tx_mod_init(void)
Definition: tx.c:775
uint32_t sm_state
Definition: sm.h:307
void(* m0_be_tx_cb_t)(const struct m0_be_tx *tx)
Definition: tx.h:277
uint64_t bft_id
Definition: fmt.h:365
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
#define offsetof(typ, memb)
Definition: misc.h:29
static struct m0_sm_state_descr states[C_NR]
Definition: sm.c:512
M0_INTERNAL void m0_be_tx_force(struct m0_be_tx *tx)
Definition: tx.c:638
M0_INTERNAL void m0_be_engine__tx_init(struct m0_be_engine *en, struct m0_be_tx *tx, enum m0_be_tx_state state)
Definition: engine.c:623
m0_bcount_t tc_reg_size
Definition: tx_credit.h:86
struct m0_be_engine * t_engine
Definition: tx.h:285
M0_INTERNAL int m0_fol_rec_encode(struct m0_fol_rec *rec, struct m0_buf *at)
Definition: fol.c:314
const uint64_t payload[]
Definition: base.c:65
M0_INTERNAL const char * m0_sm_conf_state_name(const struct m0_sm_conf *conf, int state)
Definition: sm.c:774
Definition: tx.h:280
struct m0_sm_conf be_tx_sm_conf
Definition: tx.c:176
static const ptrdiff_t be_tx_ast_offset[M0_BTS_NR+1]
Definition: tx.c:82
M0_INTERNAL void m0_sm_fini(struct m0_sm *mach)
Definition: sm.c:331