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
|