Skip to content

Commit fb335b4

Browse files
committed
Allocate purge_sys statically
There is only one purge_sys. Allocate it statically in order to avoid dereferencing a pointer whenever accessing it. Also, align some members to their own cache line in order to avoid false sharing. purge_sys_t::create(): The deferred constructor. purge_sys_t::close(): The early destructor. undo::Truncate::create(): The deferred constructor. Because purge_sys.undo_trunc is constructed before the start-up parameters are parsed, the normal constructor would copy a wrong value of srv_purge_rseg_truncate_frequency. TrxUndoRsegsIterator: Do not forward-declare an inline constructor, because the static construction of purge_sys.rseg_iter would not have access to it.
1 parent a3a2b89 commit fb335b4

File tree

11 files changed

+254
-231
lines changed

11 files changed

+254
-231
lines changed

storage/innobase/include/trx0purge.h

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ typedef std::priority_queue<
142142
/** Chooses the rollback segment with the oldest committed transaction */
143143
struct TrxUndoRsegsIterator {
144144
/** Constructor */
145-
inline TrxUndoRsegsIterator();
145+
TrxUndoRsegsIterator();
146146
/** Sets the next rseg to purge in purge_sys.
147147
Executed in the purge coordinator thread.
148148
@return whether anything is to be purged */
@@ -204,17 +204,12 @@ namespace undo {
204204
/** Track UNDO tablespace mark for truncate. */
205205
class Truncate {
206206
public:
207-
208-
Truncate()
209-
:
210-
m_undo_for_trunc(ULINT_UNDEFINED),
211-
m_rseg_for_trunc(),
212-
m_scan_start(1),
213-
m_purge_rseg_truncate_frequency(
214-
static_cast<ulint>(
215-
srv_purge_rseg_truncate_frequency))
207+
void create()
216208
{
217-
/* Do Nothing. */
209+
m_undo_for_trunc = ULINT_UNDEFINED;
210+
m_scan_start = 1;
211+
m_purge_rseg_truncate_frequency =
212+
ulint(srv_purge_rseg_truncate_frequency);
218213
}
219214

220215
/** Clear the cached rollback segment. Normally done
@@ -401,31 +396,32 @@ namespace undo {
401396
/** The control structure used in the purge operation */
402397
class purge_sys_t
403398
{
399+
bool m_initialised;
404400
public:
405-
/** Construct the purge system. */
406-
purge_sys_t();
407-
/** Destruct the purge system. */
408-
~purge_sys_t();
409-
401+
MY_ALIGNED(CACHE_LINE_SIZE)
410402
rw_lock_t latch; /*!< The latch protecting the purge
411403
view. A purge operation must acquire an
412404
x-latch here for the instant at which
413405
it changes the purge view: an undo
414406
log operation can prevent this by
415407
obtaining an s-latch here. It also
416408
protects state and running */
409+
MY_ALIGNED(CACHE_LINE_SIZE)
417410
os_event_t event; /*!< State signal event;
418411
os_event_set() and os_event_reset()
419412
are protected by purge_sys_t::latch
420413
X-lock */
414+
MY_ALIGNED(CACHE_LINE_SIZE)
421415
ulint n_stop; /*!< Counter to track number stops */
416+
422417
volatile bool running; /*!< true, if purge is active,
423418
we check this without the latch too */
424419
volatile purge_state_t state; /*!< Purge coordinator thread states,
425420
we check this in several places
426421
without holding the latch. */
427422
que_t* query; /*!< The query graph which will do the
428423
parallelized purge operation */
424+
MY_ALIGNED(CACHE_LINE_SIZE)
429425
ReadView view; /*!< The purge will not remove undo logs
430426
which are >= this view (purge view) */
431427
ulint n_submitted; /*!< Count of total tasks submitted
@@ -486,10 +482,30 @@ class purge_sys_t
486482

487483
undo::Truncate undo_trunc; /*!< Track UNDO tablespace marked
488484
for truncate. */
485+
486+
487+
/**
488+
Constructor.
489+
490+
Some members may require late initialisation, thus we just mark object as
491+
uninitialised. Real initialisation happens in create().
492+
*/
493+
494+
purge_sys_t() : m_initialised(false) {}
495+
496+
497+
bool is_initialised() const { return m_initialised; }
498+
499+
500+
/** Create the instance */
501+
void create();
502+
503+
/** Close the purge system on shutdown */
504+
void close();
489505
};
490506

491507
/** The global data structure coordinating a purge */
492-
extern purge_sys_t* purge_sys;
508+
extern purge_sys_t purge_sys;
493509

494510
/** Info required to purge a record */
495511
struct trx_purge_rec_t {

storage/innobase/include/trx0sys.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -996,10 +996,10 @@ class trx_sys_t
996996
bool is_initialised() { return m_initialised; }
997997

998998

999-
/** Create the instance */
999+
/** Initialise the purge subsystem. */
10001000
void create();
10011001

1002-
/** Close the transaction system on shutdown */
1002+
/** Close the purge subsystem on shutdown. */
10031003
void close();
10041004

10051005
/** @return total number of active (non-prepared) transactions */

storage/innobase/lock/lock0lock.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5258,14 +5258,14 @@ lock_print_info_summary(
52585258
fprintf(file,
52595259
"Purge done for trx's n:o < " TRX_ID_FMT
52605260
" undo n:o < " TRX_ID_FMT " state: ",
5261-
purge_sys->tail.trx_no(),
5262-
purge_sys->tail.undo_no);
5261+
purge_sys.tail.trx_no(),
5262+
purge_sys.tail.undo_no);
52635263

52645264
/* Note: We are reading the state without the latch. One because it
52655265
will violate the latching order and two because we are merely querying
52665266
the state of the variable for display. */
52675267

5268-
switch (purge_sys->state){
5268+
switch (purge_sys.state){
52695269
case PURGE_STATE_INIT:
52705270
/* Should never be in this state while the system is running. */
52715271
ut_error;
@@ -5281,7 +5281,7 @@ lock_print_info_summary(
52815281
case PURGE_STATE_RUN:
52825282
fprintf(file, "running");
52835283
/* Check if it is waiting for more data to arrive. */
5284-
if (!purge_sys->running) {
5284+
if (!purge_sys.running) {
52855285
fprintf(file, " but idle");
52865286
}
52875287
break;

storage/innobase/read/read0read.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ void ReadView::close()
319319
*/
320320
void trx_sys_t::clone_oldest_view()
321321
{
322-
purge_sys->view.snapshot(0);
322+
purge_sys.view.snapshot(0);
323323
mutex_enter(&mutex);
324324
/* Find oldest view. */
325325
for (const ReadView *v= UT_LIST_GET_FIRST(m_views); v;
@@ -331,7 +331,7 @@ void trx_sys_t::clone_oldest_view()
331331
ut_delay(1);
332332

333333
if (state == READ_VIEW_STATE_OPEN)
334-
purge_sys->view.copy(*v);
334+
purge_sys.view.copy(*v);
335335
}
336336
mutex_exit(&mutex);
337337
}

storage/innobase/row/row0vers.cc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -436,11 +436,11 @@ row_vers_must_preserve_del_marked(
436436
const table_name_t& name,
437437
mtr_t* mtr)
438438
{
439-
ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_S));
439+
ut_ad(!rw_lock_own(&(purge_sys.latch), RW_LOCK_S));
440440

441-
mtr_s_lock(&purge_sys->latch, mtr);
441+
mtr_s_lock(&purge_sys.latch, mtr);
442442

443-
return(!purge_sys->view.changes_visible(trx_id, name));
443+
return(!purge_sys.view.changes_visible(trx_id, name));
444444
}
445445

446446
/** build virtual column value from current cluster index record data
@@ -866,7 +866,7 @@ row_vers_old_has_index_entry(
866866

867867
ut_ad(mtr_memo_contains_page_flagged(mtr, rec, MTR_MEMO_PAGE_X_FIX
868868
| MTR_MEMO_PAGE_S_FIX));
869-
ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_S));
869+
ut_ad(!rw_lock_own(&(purge_sys.latch), RW_LOCK_S));
870870

871871
clust_index = dict_table_get_first_index(index->table);
872872

@@ -889,7 +889,7 @@ row_vers_old_has_index_entry(
889889
/* The top of the stack of versions is locked by the
890890
mtr holding a latch on the page containing the
891891
clustered index record. The bottom of the stack is
892-
locked by the fact that the purge_sys->view must
892+
locked by the fact that the purge_sys.view must
893893
'overtake' any read view of an active transaction.
894894
Thus, it is safe to fetch the prefixes for
895895
externally stored columns. */
@@ -1121,7 +1121,7 @@ row_vers_build_for_consistent_read(
11211121
ut_ad(dict_index_is_clust(index));
11221122
ut_ad(mtr_memo_contains_page_flagged(mtr, rec, MTR_MEMO_PAGE_X_FIX
11231123
| MTR_MEMO_PAGE_S_FIX));
1124-
ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_S));
1124+
ut_ad(!rw_lock_own(&(purge_sys.latch), RW_LOCK_S));
11251125

11261126
ut_ad(rec_offs_validate(rec, index, *offsets));
11271127

@@ -1234,7 +1234,7 @@ row_vers_build_for_semi_consistent_read(
12341234
ut_ad(dict_index_is_clust(index));
12351235
ut_ad(mtr_memo_contains_page_flagged(mtr, rec, MTR_MEMO_PAGE_X_FIX
12361236
| MTR_MEMO_PAGE_S_FIX));
1237-
ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_S));
1237+
ut_ad(!rw_lock_own(&(purge_sys.latch), RW_LOCK_S));
12381238

12391239
ut_ad(rec_offs_validate(rec, index, *offsets));
12401240

storage/innobase/srv/srv0srv.cc

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,7 +1923,7 @@ srv_get_active_thread_type(void)
19231923
srv_sys_mutex_exit();
19241924

19251925
if (ret == SRV_NONE && srv_shutdown_state != SRV_SHUTDOWN_NONE
1926-
&& purge_sys != NULL) {
1926+
&& purge_sys.is_initialised()) {
19271927
/* Check only on shutdown. */
19281928
switch (trx_purge_state()) {
19291929
case PURGE_STATE_RUN:
@@ -1973,7 +1973,7 @@ srv_wake_purge_thread_if_not_active()
19731973
{
19741974
ut_ad(!srv_sys_mutex_own());
19751975

1976-
if (purge_sys->state == PURGE_STATE_RUN
1976+
if (purge_sys.state == PURGE_STATE_RUN
19771977
&& !my_atomic_loadlint(&srv_sys.n_threads_active[SRV_PURGE])
19781978
&& trx_sys.history_size()) {
19791979

@@ -2506,7 +2506,7 @@ srv_task_execute(void)
25062506
que_run_threads(thr);
25072507

25082508
my_atomic_addlint(
2509-
&purge_sys->n_completed, 1);
2509+
&purge_sys.n_completed, 1);
25102510
}
25112511

25122512
return(thr != NULL);
@@ -2559,17 +2559,17 @@ DECLARE_THREAD(srv_worker_thread)(
25592559
}
25602560

25612561
/* Note: we are checking the state without holding the
2562-
purge_sys->latch here. */
2563-
} while (purge_sys->state != PURGE_STATE_EXIT);
2562+
purge_sys.latch here. */
2563+
} while (purge_sys.state != PURGE_STATE_EXIT);
25642564

25652565
srv_free_slot(slot);
25662566

2567-
rw_lock_x_lock(&purge_sys->latch);
2567+
rw_lock_x_lock(&purge_sys.latch);
25682568

2569-
ut_a(!purge_sys->running);
2570-
ut_a(purge_sys->state == PURGE_STATE_EXIT);
2569+
ut_a(!purge_sys.running);
2570+
ut_a(purge_sys.state == PURGE_STATE_EXIT);
25712571

2572-
rw_lock_x_unlock(&purge_sys->latch);
2572+
rw_lock_x_unlock(&purge_sys.latch);
25732573

25742574
#ifdef UNIV_DEBUG_THREAD_CREATION
25752575
ib::info() << "Purge worker thread exiting, id "
@@ -2648,7 +2648,7 @@ srv_do_purge(ulint* n_total_purged)
26482648
}
26492649

26502650
ulint undo_trunc_freq =
2651-
purge_sys->undo_trunc.get_rseg_truncate_frequency();
2651+
purge_sys.undo_trunc.get_rseg_truncate_frequency();
26522652

26532653
ulint rseg_truncate_frequency = ut_min(
26542654
static_cast<ulint>(srv_purge_rseg_truncate_frequency),
@@ -2662,7 +2662,7 @@ srv_do_purge(ulint* n_total_purged)
26622662

26632663
} while (!srv_purge_should_exit(n_pages_purged)
26642664
&& n_pages_purged > 0
2665-
&& purge_sys->state == PURGE_STATE_RUN);
2665+
&& purge_sys.state == PURGE_STATE_RUN);
26662666

26672667
return(rseg_history_len);
26682668
}
@@ -2689,11 +2689,11 @@ srv_purge_coordinator_suspend(
26892689
int64_t sig_count = srv_suspend_thread(slot);
26902690

26912691
do {
2692-
rw_lock_x_lock(&purge_sys->latch);
2692+
rw_lock_x_lock(&purge_sys.latch);
26932693

2694-
purge_sys->running = false;
2694+
purge_sys.running = false;
26952695

2696-
rw_lock_x_unlock(&purge_sys->latch);
2696+
rw_lock_x_unlock(&purge_sys.latch);
26972697

26982698
/* We don't wait right away on the the non-timed wait because
26992699
we want to signal the thread that wants to suspend purge. */
@@ -2705,14 +2705,14 @@ srv_purge_coordinator_suspend(
27052705

27062706
sig_count = srv_suspend_thread(slot);
27072707

2708-
rw_lock_x_lock(&purge_sys->latch);
2708+
rw_lock_x_lock(&purge_sys.latch);
27092709

27102710
stop = (srv_shutdown_state == SRV_SHUTDOWN_NONE
2711-
&& purge_sys->state == PURGE_STATE_STOP);
2711+
&& purge_sys.state == PURGE_STATE_STOP);
27122712

27132713
if (!stop) {
2714-
ut_a(purge_sys->n_stop == 0);
2715-
purge_sys->running = true;
2714+
ut_a(purge_sys.n_stop == 0);
2715+
purge_sys.running = true;
27162716

27172717
if (timeout
27182718
&& rseg_history_len < 5000
@@ -2727,13 +2727,13 @@ srv_purge_coordinator_suspend(
27272727
stop = true;
27282728
}
27292729
} else {
2730-
ut_a(purge_sys->n_stop > 0);
2730+
ut_a(purge_sys.n_stop > 0);
27312731

27322732
/* Signal that we are suspended. */
2733-
os_event_set(purge_sys->event);
2733+
os_event_set(purge_sys.event);
27342734
}
27352735

2736-
rw_lock_x_unlock(&purge_sys->latch);
2736+
rw_lock_x_unlock(&purge_sys.latch);
27372737
} while (stop && srv_undo_sources);
27382738

27392739
srv_resume_thread(slot, 0, false);
@@ -2759,12 +2759,12 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
27592759
ut_a(trx_purge_state() == PURGE_STATE_INIT);
27602760
ut_a(srv_force_recovery < SRV_FORCE_NO_BACKGROUND);
27612761

2762-
rw_lock_x_lock(&purge_sys->latch);
2762+
rw_lock_x_lock(&purge_sys.latch);
27632763

2764-
purge_sys->running = true;
2765-
purge_sys->state = PURGE_STATE_RUN;
2764+
purge_sys.running = true;
2765+
purge_sys.state = PURGE_STATE_RUN;
27662766

2767-
rw_lock_x_unlock(&purge_sys->latch);
2767+
rw_lock_x_unlock(&purge_sys.latch);
27682768

27692769
#ifdef UNIV_PFS_THREAD
27702770
pfs_register_thread(srv_purge_thread_key);
@@ -2785,7 +2785,7 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
27852785

27862786
if (srv_shutdown_state == SRV_SHUTDOWN_NONE
27872787
&& srv_undo_sources
2788-
&& (purge_sys->state == PURGE_STATE_STOP
2788+
&& (purge_sys.state == PURGE_STATE_STOP
27892789
|| n_total_purged == 0)) {
27902790

27912791
srv_purge_coordinator_suspend(slot, rseg_history_len);
@@ -2809,20 +2809,20 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
28092809
srv_free_slot(slot);
28102810

28112811
/* Note that we are shutting down. */
2812-
rw_lock_x_lock(&purge_sys->latch);
2812+
rw_lock_x_lock(&purge_sys.latch);
28132813

2814-
purge_sys->state = PURGE_STATE_EXIT;
2814+
purge_sys.state = PURGE_STATE_EXIT;
28152815

28162816
/* If there are any pending undo-tablespace truncate then clear
28172817
it off as we plan to shutdown the purge thread. */
2818-
purge_sys->undo_trunc.clear();
2818+
purge_sys.undo_trunc.clear();
28192819

2820-
purge_sys->running = false;
2820+
purge_sys.running = false;
28212821

28222822
/* Ensure that the wait in trx_purge_stop() will terminate. */
2823-
os_event_set(purge_sys->event);
2823+
os_event_set(purge_sys.event);
28242824

2825-
rw_lock_x_unlock(&purge_sys->latch);
2825+
rw_lock_x_unlock(&purge_sys.latch);
28262826

28272827
#ifdef UNIV_DEBUG_THREAD_CREATION
28282828
ib::info() << "Purge coordinator exiting, id "

0 commit comments

Comments
 (0)