diff options
Diffstat (limited to '')
-rw-r--r-- | storage/innobase/include/trx0purge.h | 181 |
1 files changed, 101 insertions, 80 deletions
diff --git a/storage/innobase/include/trx0purge.h b/storage/innobase/include/trx0purge.h index 0f4f8afa..1fb6cd68 100644 --- a/storage/innobase/include/trx0purge.h +++ b/storage/innobase/include/trx0purge.h @@ -55,80 +55,74 @@ Run a purge batch. @return number of undo log pages handled in the batch */ ulint trx_purge(ulint n_tasks, ulint history_size); -/** Rollback segements from a given transaction with trx-no -scheduled for purge. */ -class TrxUndoRsegs { -private: - typedef std::vector<trx_rseg_t*, ut_allocator<trx_rseg_t*> > - trx_rsegs_t; -public: - typedef trx_rsegs_t::iterator iterator; - typedef trx_rsegs_t::const_iterator const_iterator; - - TrxUndoRsegs() = default; - - /** Constructor */ - TrxUndoRsegs(trx_rseg_t& rseg) - : trx_no(rseg.last_trx_no()), m_rsegs(1, &rseg) {} - /** Constructor */ - TrxUndoRsegs(trx_id_t trx_no, trx_rseg_t& rseg) - : trx_no(trx_no), m_rsegs(1, &rseg) {} - - bool operator!=(const TrxUndoRsegs& other) const - { return trx_no != other.trx_no; } - bool empty() const { return m_rsegs.empty(); } - void erase(iterator& it) { m_rsegs.erase(it); } - iterator begin() { return(m_rsegs.begin()); } - iterator end() { return(m_rsegs.end()); } - const_iterator begin() const { return m_rsegs.begin(); } - const_iterator end() const { return m_rsegs.end(); } - - /** Compare two TrxUndoRsegs based on trx_no. - @param elem1 first element to compare - @param elem2 second element to compare - @return true if elem1 > elem2 else false.*/ - bool operator()(const TrxUndoRsegs& lhs, const TrxUndoRsegs& rhs) - { - return(lhs.trx_no > rhs.trx_no); - } - - /** Copy of trx_rseg_t::last_trx_no() */ - trx_id_t trx_no= 0; -private: - /** Rollback segments of a transaction, scheduled for purge. */ - trx_rsegs_t m_rsegs{}; -}; - -typedef std::priority_queue< - TrxUndoRsegs, - std::vector<TrxUndoRsegs, ut_allocator<TrxUndoRsegs> >, - TrxUndoRsegs> purge_pq_t; - -/** Chooses the rollback segment with the oldest committed transaction */ -struct TrxUndoRsegsIterator { - /** Constructor */ - TrxUndoRsegsIterator(); - /** Sets the next rseg to purge in purge_sys. - Executed in the purge coordinator thread. - @retval false when nothing is to be purged - @retval true when purge_sys.rseg->latch was locked */ - inline bool set_next(); - -private: - // Disable copying - TrxUndoRsegsIterator(const TrxUndoRsegsIterator&); - TrxUndoRsegsIterator& operator=(const TrxUndoRsegsIterator&); - - /** The current element to process */ - TrxUndoRsegs m_rsegs; - /** Track the current element in m_rsegs */ - TrxUndoRsegs::const_iterator m_iter; -}; - /** The control structure used in the purge operation */ class purge_sys_t { - friend TrxUndoRsegsIterator; + /** Min-heap based priority queue of (trx_no, trx_sys.rseg_array index) + pairs, ordered on trx_no. The highest 64-TRX_NO_SHIFT bits of each element is + trx_no, the lowest 8 bits is rseg's index in trx_sys.rseg_array. */ + class purge_queue + { + public: + typedef std::vector<uint64_t, ut_allocator<uint64_t>> container_type; + /** Number of bits reseved to shift trx_no in purge queue element */ + static constexpr unsigned TRX_NO_SHIFT= 8; + + bool empty() const { return m_array.empty(); } + void clear() { m_array.clear(); } + + /** Push (trx_no, trx_sys.rseg_array index) into min-heap. + @param trx_no_rseg (trx_no << TRX_NO_SHIFT | (trx_sys.rseg_array index)) */ + void push_trx_no_rseg(container_type::value_type trx_no_rseg) + { + m_array.push_back(trx_no_rseg); + std::push_heap(m_array.begin(), m_array.end(), + std::greater<container_type::value_type>()); + } + + /** Push rseg to priority queue. + @param trx_no trx_no of committed transaction + @param rseg rseg of committed transaction*/ + void push(trx_id_t trx_no, const trx_rseg_t &rseg) + { + ut_ad(trx_no < 1ULL << (DATA_TRX_ID_LEN * CHAR_BIT)); + ut_ad(&rseg >= trx_sys.rseg_array); + ut_ad(&rseg < trx_sys.rseg_array + TRX_SYS_N_RSEGS); + push_trx_no_rseg(trx_no << TRX_NO_SHIFT | + byte(&rseg - trx_sys.rseg_array)); + } + + /** Extracts rseg from (trx_no, trx_sys.rseg_array index) pair. + @param trx_no_rseg (trx_no << TRX_NO_SHIFT | (trx_sys.rseg_array index) + @return pointer to rseg in trx_sys.rseg_array */ + static trx_rseg_t *rseg(container_type::value_type trx_no_rseg) { + byte i= static_cast<byte>(trx_no_rseg); + ut_ad(i < TRX_SYS_N_RSEGS); + return &trx_sys.rseg_array[i]; + } + + /** Pop rseg from priority queue. + @return pointer to popped trx_rseg_t object */ + trx_rseg_t *pop() + { + ut_ad(!empty()); + std::pop_heap(m_array.begin(), m_array.end(), + std::greater<container_type::value_type>()); + trx_rseg_t *r = rseg(m_array.back()); + m_array.pop_back(); + return r; + } + + /** Clone m_array. + @return m_array clone */ + container_type clone_container() const{ return m_array; } + + private: + /** Array of (trx_no, trx_sys.rseg_array index) pairs. */ + container_type m_array; + }; + + public: /** latch protecting view, m_enabled */ alignas(CPU_LEVEL1_DCACHE_LINESIZE) mutable srw_spin_lock latch; @@ -244,15 +238,36 @@ private: record */ uint16_t hdr_offset; /*!< Header byte offset on the page */ + /** Binary min-heap of (trx_no, trx_sys.rseg_array index) pairs, ordered on + trx_no. It is protected by the pq_mutex */ + purge_queue purge_queue; + + /** Mutex protecting purge_queue */ + mysql_mutex_t pq_mutex; - TrxUndoRsegsIterator - rseg_iter; /*!< Iterator to get the next rseg - to process */ public: - purge_pq_t purge_queue; /*!< Binary min-heap, ordered on - TrxUndoRsegs::trx_no. It is protected - by the pq_mutex */ - mysql_mutex_t pq_mutex; /*!< Mutex protecting purge_queue */ + + void enqueue(trx_id_t trx_no, const trx_rseg_t &rseg) { + mysql_mutex_assert_owner(&pq_mutex); + purge_queue.push(trx_no, rseg); + } + + /** Push to purge queue without acquiring pq_mutex. + @param rseg rseg to push */ + void enqueue(const trx_rseg_t &rseg) { enqueue(rseg.last_trx_no(), rseg); } + + /** Clone purge queue container. + @return purge queue container clone */ + purge_queue::container_type clone_queue_container() const { + mysql_mutex_assert_owner(&pq_mutex); + return purge_queue.clone_container(); + } + + /** Acquare purge_queue_mutex */ + void queue_lock() { mysql_mutex_lock(&pq_mutex); } + + /** Release purge queue mutex */ + void queue_unlock() { mysql_mutex_unlock(&pq_mutex); } /** innodb_undo_log_truncate=ON state; only modified by purge_coordinator_callback() */ @@ -332,8 +347,9 @@ private: /** Update the last not yet purged history log info in rseg when we have purged a whole undo log. Advances also purge_trx_no - past the purged log. */ - void rseg_get_next_history_log(); + past the purged log. + @return whether anything is to be purged */ + bool rseg_get_next_history_log(); public: /** @@ -438,6 +454,11 @@ public: @param already_stopped True indicates purge threads were already stopped */ void stop_FTS(const dict_table_t &table, bool already_stopped=false); + + /** Cleanse purge queue to remove the rseg that reside in undo-tablespace + marked for truncate. + @param space undo tablespace being truncated */ + void cleanse_purge_queue(const fil_space_t &space); }; /** The global data structure coordinating a purge */ |