File: transaction_info.h

package info (click to toggle)
mysql-8.0 8.0.44-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,272,892 kB
  • sloc: cpp: 4,685,345; ansic: 412,712; pascal: 108,395; java: 83,641; perl: 30,221; cs: 27,067; sql: 26,594; python: 21,816; sh: 17,285; yacc: 17,169; php: 11,522; xml: 7,388; javascript: 7,083; makefile: 1,793; lex: 1,075; awk: 670; asm: 520; objc: 183; ruby: 97; lisp: 86
file content (741 lines) | stat: -rw-r--r-- 23,309 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
/* Copyright (c) 2000, 2025, Oracle and/or its affiliates.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License, version 2.0,
   as published by the Free Software Foundation.

   This program is designed to work with certain software (including
   but not limited to OpenSSL) that is licensed under separate terms,
   as designated in a particular file or component or in included license
   documentation.  The authors of MySQL hereby grant you an additional
   permission to link the program and your derivative works with the
   separately licensed software that they have either included with
   the program or referenced in the documentation.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License, version 2.0, for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */

#ifndef TRANSACTION_INFO_INCLUDED
#define TRANSACTION_INFO_INCLUDED

#include <stddef.h>
#include <sys/types.h>

#include "my_alloc.h"
#include "my_dbug.h"
#include "my_inttypes.h"
#include "my_sys.h"                             // strmake_root
#include "sql/mdl.h"                            // MDL_savepoint
#include "sql/rpl_transaction_ctx.h"            // Rpl_transaction_ctx
#include "sql/rpl_transaction_write_set_ctx.h"  // Transaction_write_set_ctx
#include "sql/xa.h"                             // XID_STATE

class Ha_trx_info;
class Ha_trx_info_list;
class THD;
struct handlerton;

struct SAVEPOINT {
  SAVEPOINT *prev;
  char *name;
  size_t length;
  Ha_trx_info *ha_list;
  /** State of metadata locks before this savepoint was set. */
  MDL_savepoint mdl_savepoint;
};

class Transaction_ctx {
 public:
  enum enum_trx_scope { STMT = 0, SESSION };

  SAVEPOINT *m_savepoints;

  void register_ha(enum_trx_scope scope, Ha_trx_info *ha_info, handlerton *ht);

 public:
  struct THD_TRANS {
    /* true is not all entries in the ht[] support 2pc */
    bool m_no_2pc;
    int m_rw_ha_count;
    /* storage engines that registered in this transaction */
    Ha_trx_info *m_ha_list;

   private:
    /*
      The purpose of this member variable (i.e. flag) is to keep track of
      statements which cannot be rolled back safely(completely).
      For example,

      * statements that modified non-transactional tables. The value
      MODIFIED_NON_TRANS_TABLE is set within mysql_insert, mysql_update,
      mysql_delete, etc if a non-transactional table is modified.

      * 'DROP TEMPORARY TABLE' and 'CREATE TEMPORARY TABLE' statements.
      The former sets the value DROPPED_TEMP_TABLE and the latter
      the value CREATED_TEMP_TABLE.

      The tracked statements are modified in scope of:

      * transaction, when the variable is a member of
      THD::m_transaction.m_scope_info[SESSION]

      * top-level statement or sub-statement, when the variable is a
      member of THD::m_transaction.m_scope_info[STMT]

      This member has the following life cycle:

      * m_scope_info[STMT].m_unsafe_rollback_flags is used to keep track of
      top-level statements which cannot be rolled back safely. At the end of the
      statement, the value of m_scope_info[STMT].m_unsafe_rollback_flags is
      merged with m_scope_info[SESSION].m_unsafe_rollback_flags
      and gets reset.

      * m_scope_info[SESSION].cannot_safely_rollback is reset at the end
      of transaction

      * Since we do not have a dedicated context for execution of
      a sub-statement, to keep track of non-transactional changes in a
      sub-statement, we re-use m_scope_info[STMT].m_unsafe_rollback_flags.
      At entrance into a sub-statement, a copy of the value of
      m_scope_info[STMT].m_unsafe_rollback_flags (containing the changes of the
      outer statement) is saved on stack.
      Then m_scope_info[STMT].m_unsafe_rollback_flags is reset to 0 and the
      substatement is executed. Then the new value is merged
      with the saved value.
    */

    unsigned int m_unsafe_rollback_flags;
    /*
      Define the type of statements which cannot be rolled back safely.
      Each type occupies one bit in m_unsafe_rollback_flags.
    */
    static unsigned int const MODIFIED_NON_TRANS_TABLE = 0x01;
    static unsigned int const CREATED_TEMP_TABLE = 0x02;
    static unsigned int const DROPPED_TEMP_TABLE = 0x04;

   public:
    bool cannot_safely_rollback() const { return m_unsafe_rollback_flags > 0; }
    unsigned int get_unsafe_rollback_flags() const {
      return m_unsafe_rollback_flags;
    }
    void set_unsafe_rollback_flags(unsigned int flags) {
      DBUG_PRINT("debug", ("set_unsafe_rollback_flags: %d", flags));
      m_unsafe_rollback_flags = flags;
    }
    void add_unsafe_rollback_flags(unsigned int flags) {
      DBUG_PRINT("debug", ("add_unsafe_rollback_flags: %d", flags));
      m_unsafe_rollback_flags |= flags;
    }
    void reset_unsafe_rollback_flags() {
      DBUG_PRINT("debug", ("reset_unsafe_rollback_flags"));
      m_unsafe_rollback_flags = 0;
    }
    void mark_modified_non_trans_table() {
      DBUG_PRINT("debug", ("mark_modified_non_trans_table"));
      m_unsafe_rollback_flags |= MODIFIED_NON_TRANS_TABLE;
    }
    bool has_modified_non_trans_table() const {
      return m_unsafe_rollback_flags & MODIFIED_NON_TRANS_TABLE;
    }
    void mark_created_temp_table() {
      DBUG_PRINT("debug", ("mark_created_temp_table"));
      m_unsafe_rollback_flags |= CREATED_TEMP_TABLE;
    }
    bool has_created_temp_table() const {
      return m_unsafe_rollback_flags & CREATED_TEMP_TABLE;
    }
    void mark_dropped_temp_table() {
      DBUG_PRINT("debug", ("mark_dropped_temp_table"));
      m_unsafe_rollback_flags |= DROPPED_TEMP_TABLE;
    }
    bool has_dropped_temp_table() const {
      return m_unsafe_rollback_flags & DROPPED_TEMP_TABLE;
    }

    void reset() {
      m_no_2pc = false;
      m_rw_ha_count = 0;
      reset_unsafe_rollback_flags();
    }
    bool is_empty() const { return m_ha_list == nullptr; }
  };

 private:
  THD_TRANS m_scope_info[2];

  XID_STATE m_xid_state;

  MEM_ROOT m_mem_root;  // Transaction-life memory allocation pool

 public:
  /*
    (Mostly) binlog-specific fields use while flushing the caches
    and committing transactions.
    We don't use bitfield any more in the struct. Modification will
    be lost when concurrently updating multiple bit fields. It will
    cause a race condition in a multi-threaded application. And we
    already caught a race condition case between xid_written and
    ready_preempt in MYSQL_BIN_LOG::ordered_commit.
  */
  struct {
    bool enabled{false};      // see ha_enable_transaction()
    bool xid_written{false};  // The session wrote an XID
    bool real_commit{false};  // Is this a "real" commit?
    bool commit_low{false};   // see MYSQL_BIN_LOG::ordered_commit
    bool run_hooks{false};    // Call the after_commit hook
#ifndef NDEBUG
    bool ready_preempt{false};  // internal in MYSQL_BIN_LOG::ordered_commit
#endif
  } m_flags;
  /* Binlog-specific logical timestamps. */
  /*
    Store for the transaction's commit parent sequence_number.
    The value specifies this transaction dependency with a "parent"
    transaction.
    The member is assigned, when the transaction is about to commit
    in binlog to a value of the last committed transaction's sequence_number.
    This and last_committed as numbers are kept ever incremented
    regardless of binary logs being rotated or when transaction
    is logged in multiple pieces.
    However the logger to the binary log may convert them
    according to its specification.
  */
  int64 last_committed;
  /*
    The transaction's private logical timestamp assigned at the
    transaction prepare phase. The timestamp enumerates transactions
    in the binary log. The value is gained through incrementing (stepping) a
    global clock.
    Eventually the value is considered to increase max_committed_transaction
    system clock when the transaction has committed.
  */
  int64 sequence_number;

  void store_commit_parent(int64 last_arg) { last_committed = last_arg; }

  Transaction_ctx();
  virtual ~Transaction_ctx() { m_mem_root.Clear(); }

  void cleanup() {
    DBUG_TRACE;
    m_savepoints = nullptr;
    m_xid_state.cleanup();
    m_rpl_transaction_ctx.cleanup();
    m_transaction_write_set_ctx.reset_state();
    trans_begin_hook_invoked = false;
    m_mem_root.ClearForReuse();
    return;
  }

  bool is_active(enum_trx_scope scope) const {
    return m_scope_info[scope].m_ha_list != nullptr;
  }

  void push_unsafe_rollback_warnings(THD *thd);

  void merge_unsafe_rollback_flags() {
    /*
      Merge m_scope_info[STMT].unsafe_rollback_flags to
      m_scope_info[SESSION].unsafe_rollback_flags. If the statement
      cannot be rolled back safely, the transaction including
      this statement definitely cannot rolled back safely.
    */
    m_scope_info[SESSION].add_unsafe_rollback_flags(
        m_scope_info[STMT].get_unsafe_rollback_flags());
  }

  void init_mem_root_defaults(ulong trans_alloc_block_size, ulong) {
    m_mem_root.set_block_size(trans_alloc_block_size);
  }

  MEM_ROOT *transaction_memroot() { return &m_mem_root; }

  void *allocate_memory(unsigned int size) { return m_mem_root.Alloc(size); }

  void claim_memory_ownership(bool claim) { m_mem_root.Claim(claim); }

  void free_memory() { m_mem_root.Clear(); }

  char *strmake(const char *str, size_t len) {
    return strmake_root(&m_mem_root, str, len);
  }

  void invalidate_changed_tables_in_cache(THD *thd);

  void add_changed_table(const char *key, uint32 key_length);

  Ha_trx_info_list ha_trx_info(enum_trx_scope scope);

  void set_ha_trx_info(enum_trx_scope scope, Ha_trx_info *trx_info) {
    DBUG_TRACE;
    m_scope_info[scope].m_ha_list = trx_info;
    return;
  }

  XID_STATE *xid_state() { return &m_xid_state; }

  const XID_STATE *xid_state() const { return &m_xid_state; }

  bool cannot_safely_rollback(enum_trx_scope scope) const {
    return m_scope_info[scope].cannot_safely_rollback();
  }

  unsigned int get_unsafe_rollback_flags(enum_trx_scope scope) const {
    return m_scope_info[scope].get_unsafe_rollback_flags();
  }

  void set_unsafe_rollback_flags(enum_trx_scope scope, unsigned int flags) {
    m_scope_info[scope].set_unsafe_rollback_flags(flags);
  }

  void add_unsafe_rollback_flags(enum_trx_scope scope, unsigned int flags) {
    m_scope_info[scope].add_unsafe_rollback_flags(flags);
  }

  void reset_unsafe_rollback_flags(enum_trx_scope scope) {
    m_scope_info[scope].reset_unsafe_rollback_flags();
  }

  void mark_modified_non_trans_table(enum_trx_scope scope) {
    m_scope_info[scope].mark_modified_non_trans_table();
  }

  bool has_modified_non_trans_table(enum_trx_scope scope) const {
    return m_scope_info[scope].has_modified_non_trans_table();
  }

  void mark_created_temp_table(enum_trx_scope scope) {
    m_scope_info[scope].mark_created_temp_table();
  }

  bool has_created_temp_table(enum_trx_scope scope) const {
    return m_scope_info[scope].has_created_temp_table();
  }

  void mark_dropped_temp_table(enum_trx_scope scope) {
    m_scope_info[scope].mark_dropped_temp_table();
  }

  bool has_dropped_temp_table(enum_trx_scope scope) const {
    return m_scope_info[scope].has_dropped_temp_table();
  }

  void reset(enum_trx_scope scope) { m_scope_info[scope].reset(); }

  bool is_empty(enum_trx_scope scope) const {
    return m_scope_info[scope].is_empty();
  }

  void set_no_2pc(enum_trx_scope scope, bool value) {
    m_scope_info[scope].m_no_2pc = value;
  }

  bool no_2pc(enum_trx_scope scope) const {
    return m_scope_info[scope].m_no_2pc;
  }

  int rw_ha_count(enum_trx_scope scope) const {
    return m_scope_info[scope].m_rw_ha_count;
  }

  void set_rw_ha_count(enum_trx_scope scope, int value) {
    m_scope_info[scope].m_rw_ha_count = value;
  }

  void reset_scope(enum_trx_scope scope) {
    DBUG_TRACE;
    m_scope_info[scope].m_ha_list = nullptr;
    m_scope_info[scope].m_no_2pc = false;
    m_scope_info[scope].m_rw_ha_count = 0;
    return;
  }

  Rpl_transaction_ctx *get_rpl_transaction_ctx() {
    return &m_rpl_transaction_ctx;
  }

  const Rpl_transaction_ctx *get_rpl_transaction_ctx() const {
    return &m_rpl_transaction_ctx;
  }

  Rpl_transaction_write_set_ctx *get_transaction_write_set_ctx() {
    return &m_transaction_write_set_ctx;
  }

  const Rpl_transaction_write_set_ctx *get_transaction_write_set_ctx() const {
    return &m_transaction_write_set_ctx;
  }

  bool was_trans_begin_hook_invoked() { return trans_begin_hook_invoked; }

  void set_trans_begin_hook_invoked() { trans_begin_hook_invoked = true; }

 private:
  Rpl_transaction_ctx m_rpl_transaction_ctx;
  Rpl_transaction_write_set_ctx m_transaction_write_set_ctx;
  bool trans_begin_hook_invoked;
};

/**
  Either statement transaction or normal transaction - related
  thread-specific storage engine data.

  If a storage engine participates in a statement/transaction,
  an instance of this class is present in
  thd->m_transaction.m_scope_info[STMT|SESSION].ha_list. The addition
  this list is made by trans_register_ha().

  When it's time to commit or rollback, each element of ha_list
  is used to access storage engine's prepare()/commit()/rollback()
  methods, and also to evaluate if a full two phase commit is
  necessary.

  @sa General description of transaction handling in handler.cc.
*/

class Ha_trx_info {
 public:
  friend class Ha_trx_info_list;

  /**
    Register this storage engine in the given transaction context.
  */
  void register_ha(Transaction_ctx::THD_TRANS *trans, handlerton *ht_arg) {
    DBUG_TRACE;
    assert(m_flags == 0);
    assert(m_ht == nullptr);
    assert(m_next == nullptr);

    m_ht = ht_arg;
    m_flags = (int)TRX_READ_ONLY; /* Assume read-only at start. */

    if (trans->m_ha_list != this) {
      m_next = trans->m_ha_list;
      trans->m_ha_list = this;
    }

    return;
  }

  /**
    Clear, prepare for reuse.
  */

  void reset() {
    DBUG_TRACE;
    m_next = nullptr;
    m_ht = nullptr;
    m_flags = 0;
    return;
  }

  Ha_trx_info() { reset(); }

  void set_trx_read_write() {
    assert(is_started());
    m_flags |= (int)TRX_READ_WRITE;
  }

  bool is_trx_read_write() const {
    assert(is_started());
    return m_flags & (int)TRX_READ_WRITE;
  }

  bool is_started() const { return m_ht != nullptr; }

  /**
    Mark this transaction read-write if the argument is read-write.
  */

  void coalesce_trx_with(const Ha_trx_info *stmt_trx) {
    this->coalesce_trx_with(*stmt_trx);
  }

  void coalesce_trx_with(const Ha_trx_info &stmt_trx) {
    /*
      Must be called only after the transaction has been started.
      Can be called many times, e.g. when we have many
      read-write statements in a transaction.
    */
    assert(is_started());
    if (stmt_trx.is_trx_read_write()) set_trx_read_write();
  }

  handlerton *ht() const {
    assert(is_started());
    return m_ht;
  }

 private:
  enum { TRX_READ_ONLY = 0, TRX_READ_WRITE = 1 };
  /**
    Auxiliary, used for ha_list management
  */
  Ha_trx_info *m_next;

  /**
    Although a given Ha_trx_info instance is currently always used
    for the same storage engine, 'ht' is not-NULL only when the
    corresponding storage is a part of a transaction.
  */
  handlerton *m_ht;

  /**
    Transaction flags related to this engine.
    Not-null only if this instance is a part of transaction.
    May assume a combination of enum values above.
  */
  uchar m_flags;
};

/**
  @class Ha_trx_info_list

  Container to hold and allow iteration over a set of Ha_trx_info objects.
 */
class Ha_trx_info_list {
 public:
  /**
   @class Iterator

   Implements a forward iterator for `Ha_trx_info_list`. The
   `Ha_trx_info_list` methods `begin` and `end` complete the requirements
   for algorithms usage.

   Since the container this iterator targets is a linked-list where the
   list and the list elements are the same, the invalidation rules are not
   the ones usually encontered in iterator classes. Invoking
   `Ha_trx_info::reset()`, which clears the pointer to next element in the
   list, doesn't invalidate the iterator, instead the pointer reference is
   kept by the iterator in order to allow the requirements for forward
   iterating to be valid. Therefore, although `Ha_trx_info::reset()`
   removes the element from the list, the iterator is no invalidated and
   iteration over the rest of the element is kept.
 */
  class Iterator {
   public:
    using difference_type = std::ptrdiff_t;
    using pointer = Ha_trx_info *;
    using reference = Ha_trx_info &;
    using iterator_category = std::forward_iterator_tag;

    Iterator(Ha_trx_info *parent);
    Iterator(std::nullptr_t);
    Iterator(Iterator const &rhs);
    virtual ~Iterator() = default;

    // BASIC ITERATOR METHODS //
    Iterator &operator=(const Iterator &rhs);
    Iterator &operator++();
    reference operator*() const;
    // END / BASIC ITERATOR METHODS //

    // INPUT ITERATOR METHODS //
    Iterator operator++(int);
    pointer operator->() const;
    bool operator==(Iterator const &rhs) const;
    bool operator==(Ha_trx_info const *rhs) const;
    bool operator==(Ha_trx_info const &rhs) const;
    bool operator!=(Iterator const &rhs) const;
    bool operator!=(Ha_trx_info const *rhs) const;
    bool operator!=(Ha_trx_info const &rhs) const;
    // END / INPUT ITERATOR METHODS //

    // OUTPUT ITERATOR METHODS //
    // reference operator*() const; <- already defined
    // iterator operator++(int); <- already defined
    // END / OUTPUT ITERATOR METHODS //

    // FORWARD ITERATOR METHODS //
    // Enable support for both input and output iterator
    // END / FORWARD ITERATOR METHODS //

   private:
    /** Item this iterator is currently pointing to  */
    Ha_trx_info *m_current{nullptr};
    /** Next item in the list  */
    Ha_trx_info *m_next{nullptr};

    Iterator &set_next();
  };

  /**
    Default constructor.
   */
  Ha_trx_info_list() = default;
  /**
    Class constructor that instantiates the underlying head of the list
    with the parameter.

    @param rhs The pointer to initialize the underlying list head with.
   */
  Ha_trx_info_list(Ha_trx_info *rhs);
  /**
    Copy constructor.

    @param rhs The object instance to copy content from.
   */
  Ha_trx_info_list(Ha_trx_info_list const &rhs);
  /**
    Move constructor.

    @param rhs The object instance to move content from.
   */
  Ha_trx_info_list(Ha_trx_info_list &&rhs);
  virtual ~Ha_trx_info_list() = default;

  /**
    Copy operator.

    @param rhs The object instance to copy content from.

    @return this object reference, for chaining puposes.
   */
  Ha_trx_info_list &operator=(Ha_trx_info_list const &rhs);
  /**
    Move operator.

    @param rhs The object instance to move content from.

    @return this object reference, for chaining puposes.
   */
  Ha_trx_info_list &operator=(Ha_trx_info_list &&rhs);
  /**
    Retrieves the reference to the undelying head of the list.

    @return The reference to the undelying head of the list.
   */
  Ha_trx_info &operator*();
  /**
    Retrieves the reference to the undelying head of the list.

    @return The reference to the undelying head of the list.
   */
  Ha_trx_info const &operator*() const;
  /**
    Retrieves the pointer to the undelying head of the list.

    @return The pointer to the undelying head of the list.
   */
  Ha_trx_info *operator->();
  /**
    Retrieves the pointer to the undelying head of the list.

    @return The pointer to the undelying head of the list.
   */
  Ha_trx_info const *operator->() const;
  /**
    Equality operator that compares with another instance of this class. It
    evaluates to true if both object's underlying head point to the same
    address.

    @param rhs The object to compare this object to.

    @return true if both object's underlying head point to the same
            address, false otherwise.
   */
  bool operator==(Ha_trx_info_list const &rhs) const;
  /**
    Equality operator that compares with an instance of Ha_trx_info
    class. It evaluates to true if this object's underlying head points to
    the same address of the parameter object.

    @param rhs The object to compare this object to.

    @return true if this object's underlying head point to the same address
            as the parameter object, false otherwise.
   */
  bool operator==(Ha_trx_info const *rhs) const;
  /**
    Equality operator that compares with null. It evaluates to true if this
    object's underlying head points to null.

    @param rhs The `nullptr` value

    @return true if this object's underlying head point to null, false
            otherwise.
   */
  bool operator==(std::nullptr_t rhs) const;
  /**
    Inequality operator that compares with another instance of this
    class. It evaluates to true if both object's underlying head point to
    the different addresses.

    @param rhs The object to compare this object to.

    @return true if both object's underlying head point to different
            addresses, false otherwise.
   */
  bool operator!=(Ha_trx_info_list const &rhs) const;
  /**
    Inequality operator that compares with an instance of Ha_trx_info
    class. It evaluates to true if this object's underlying head points to
    a different address of the parameter object.

    @param rhs The object to compare this object to.

    @return true if this object's underlying head point to different
            address as the parameter object, false otherwise.
   */
  bool operator!=(Ha_trx_info const *rhs) const;
  /**
    Inequality operator that compares with null. It evaluates to true if
    this object's underlying head points to a non-null value.

    @param rhs The `nullptr` value

    @return true if this object's underlying head point to a non-null
            value, false otherwise.
   */
  bool operator!=(std::nullptr_t rhs) const;
  /**
    Cast operator to `bool`. It returns true if the this object underlying
    list head doesn't point to null, false otherwise.

    @return true if the this object underlying list head doesn't point to
            null, false otherwise.
   */
  operator bool() const;
  /**
    Retrieves the pointer to the underlying list head.

    @return The underlying list head.
   */
  Ha_trx_info *head();
  /**
    Retrieves an iterator pointing to the underlying list head.

    @return An iterator pointing to the underlying list head.
   */
  Iterator begin();
  /**
    Retrieves an iterator pointing to the underlying list head.

    @return An iterator pointing to the underlying list head.
   */
  const Iterator begin() const;
  /**
    Retrieves an iterator pointing to null.

    @return An iterator pointing null.
   */
  Iterator end();
  /**
    Retrieves an iterator pointing to null.

    @return An iterator pointing null.
   */
  const Iterator end() const;

 private:
  /** The head of the list */
  Ha_trx_info *m_underlying{nullptr};
};

#endif