1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2017, 2021, MariaDB Corporation.
5 
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free Software
8 Foundation; version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17 
18 *****************************************************************************/
19 
20 /**************************************************//**
21 @file include/trx0purge.h
22 Purge old versions
23 
24 Created 3/26/1996 Heikki Tuuri
25 *******************************************************/
26 
27 #ifndef trx0purge_h
28 #define trx0purge_h
29 
30 #include "trx0rseg.h"
31 #include "que0types.h"
32 
33 #include <queue>
34 
35 /** A dummy undo record used as a return value when we have a whole undo log
36 which needs no purge */
37 extern trx_undo_rec_t	trx_purge_dummy_rec;
38 
39 /** Prepend the history list with an undo log.
40 Remove the undo log segment from the rseg slot if it is too big for reuse.
41 @param[in]	trx		transaction
42 @param[in,out]	undo		undo log
43 @param[in,out]	mtr		mini-transaction */
44 void
45 trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr);
46 /**
47 Run a purge batch.
48 @param n_tasks   number of purge tasks to submit to the queue
49 @param truncate  whether to truncate the history at the end of the batch
50 @return number of undo log pages handled in the batch */
51 ulint trx_purge(ulint n_tasks, bool truncate);
52 
53 /** Rollback segements from a given transaction with trx-no
54 scheduled for purge. */
55 class TrxUndoRsegs {
56 private:
57 	typedef std::vector<trx_rseg_t*, ut_allocator<trx_rseg_t*> >
58 		trx_rsegs_t;
59 public:
60 	typedef trx_rsegs_t::iterator iterator;
61 	typedef trx_rsegs_t::const_iterator const_iterator;
62 
TrxUndoRsegs()63 	TrxUndoRsegs() {}
64 
65 	/** Constructor */
TrxUndoRsegs(trx_rseg_t & rseg)66 	TrxUndoRsegs(trx_rseg_t& rseg)
67 		: trx_no(rseg.last_trx_no()), m_rsegs(1, &rseg) {}
68 	/** Constructor */
TrxUndoRsegs(trx_id_t trx_no,trx_rseg_t & rseg)69 	TrxUndoRsegs(trx_id_t trx_no, trx_rseg_t& rseg)
70 		: trx_no(trx_no), m_rsegs(1, &rseg) {}
71 
72 	bool operator!=(const TrxUndoRsegs& other) const
73 	{ return trx_no != other.trx_no; }
empty()74 	bool empty() const { return m_rsegs.empty(); }
erase(iterator & it)75 	void erase(iterator& it) { m_rsegs.erase(it); }
begin()76 	iterator begin() { return(m_rsegs.begin()); }
end()77 	iterator end() { return(m_rsegs.end()); }
begin()78 	const_iterator begin() const { return m_rsegs.begin(); }
end()79 	const_iterator end() const { return m_rsegs.end(); }
80 
81 	/** Compare two TrxUndoRsegs based on trx_no.
82 	@param elem1 first element to compare
83 	@param elem2 second element to compare
84 	@return true if elem1 > elem2 else false.*/
operator()85 	bool operator()(const TrxUndoRsegs& lhs, const TrxUndoRsegs& rhs)
86 	{
87 		return(lhs.trx_no > rhs.trx_no);
88 	}
89 
90 	/** Copy of trx_rseg_t::last_trx_no() */
91 	trx_id_t trx_no= 0;
92 private:
93 	/** Rollback segments of a transaction, scheduled for purge. */
94 	trx_rsegs_t m_rsegs{};
95 };
96 
97 typedef std::priority_queue<
98 	TrxUndoRsegs,
99 	std::vector<TrxUndoRsegs, ut_allocator<TrxUndoRsegs> >,
100 	TrxUndoRsegs>	purge_pq_t;
101 
102 /** Chooses the rollback segment with the oldest committed transaction */
103 struct TrxUndoRsegsIterator {
104 	/** Constructor */
105 	TrxUndoRsegsIterator();
106 	/** Sets the next rseg to purge in purge_sys.
107 	Executed in the purge coordinator thread.
108 	@return whether anything is to be purged */
109 	inline bool set_next();
110 
111 private:
112 	// Disable copying
113 	TrxUndoRsegsIterator(const TrxUndoRsegsIterator&);
114 	TrxUndoRsegsIterator& operator=(const TrxUndoRsegsIterator&);
115 
116 	/** The current element to process */
117 	TrxUndoRsegs			m_rsegs;
118 	/** Track the current element in m_rsegs */
119 	TrxUndoRsegs::const_iterator	m_iter;
120 };
121 
122 /** The control structure used in the purge operation */
123 class purge_sys_t
124 {
125 public:
126 	/** latch protecting view, m_enabled */
127 	MY_ALIGNED(CACHE_LINE_SIZE)
128 	mutable rw_lock_t		latch;
129 private:
130 	/** The purge will not remove undo logs which are >= this view */
131 	MY_ALIGNED(CACHE_LINE_SIZE)
132 	ReadViewBase	view;
133 	/** whether purge is enabled; protected by latch and std::atomic */
134 	std::atomic<bool>		m_enabled;
135 	/** number of pending stop() calls without resume() */
136 	Atomic_counter<int32_t>		m_paused;
137 public:
138 	que_t*		query;		/*!< The query graph which will do the
139 					parallelized purge operation */
140 
141 	/** Iterator to the undo log records of committed transactions */
142 	struct iterator
143 	{
144 		bool operator<=(const iterator& other) const
145 		{
146 			if (trx_no < other.trx_no) return true;
147 			if (trx_no > other.trx_no) return false;
148 			return undo_no <= other.undo_no;
149 		}
150 
151 		/** trx_t::no of the committed transaction */
152 		trx_id_t	trx_no;
153 		/** The record number within the committed transaction's undo
154 		log, increasing, purged from from 0 onwards */
155 		undo_no_t	undo_no;
156 	};
157 
158 	/** The tail of the purge queue; the last parsed undo log of a
159 	committed transaction. */
160 	iterator	tail;
161 	/** The head of the purge queue; any older undo logs of committed
162 	transactions may be discarded (history list truncation). */
163 	iterator	head;
164 	/*-----------------------------*/
165 	bool		next_stored;	/*!< whether rseg holds the next record
166 					to purge */
167 	trx_rseg_t*	rseg;		/*!< Rollback segment for the next undo
168 					record to purge */
169 	uint32_t	page_no;	/*!< Page number for the next undo
170 					record to purge, page number of the
171 					log header, if dummy record */
172 	uint32_t	hdr_page_no;	/*!< Header page of the undo log where
173 					the next record to purge belongs */
174 	uint16_t	offset;		/*!< Page offset for the next undo
175 					record to purge, 0 if the dummy
176 					record */
177 	uint16_t	hdr_offset;	/*!< Header byte offset on the page */
178 
179 
180 	TrxUndoRsegsIterator
181 			rseg_iter;	/*!< Iterator to get the next rseg
182 					to process */
183 
184 	purge_pq_t	purge_queue;	/*!< Binary min-heap, ordered on
185 					TrxUndoRsegs::trx_no. It is protected
186 					by the pq_mutex */
187 	PQMutex		pq_mutex;	/*!< Mutex protecting purge_queue */
188 
189 	/** Undo tablespace file truncation (only accessed by the
190 	srv_purge_coordinator_thread) */
191 	struct {
192 		/** The undo tablespace that is currently being truncated */
193 		fil_space_t*	current;
194 		/** The undo tablespace that was last truncated */
195 		fil_space_t*	last;
196 	} truncate;
197 
198 	/** Heap for reading the undo log records */
199 	mem_heap_t*	heap;
200   /**
201     Constructor.
202 
203     Some members may require late initialisation, thus we just mark object as
204     uninitialised. Real initialisation happens in create().
205   */
206 
purge_sys_t()207   purge_sys_t(): m_enabled(false), heap(nullptr) {}
208 
209   /** Create the instance */
210   void create();
211 
212   /** Close the purge system on shutdown */
213   void close();
214 
215   /** @return whether purge is enabled */
enabled()216   bool enabled() { return m_enabled.load(std::memory_order_relaxed); }
217   /** @return whether the purge coordinator is paused */
paused()218   bool paused()
219   { return m_paused != 0; }
220 
221   /** Enable purge at startup. Not protected by latch; the main thread
222   will wait for purge_sys.enabled() in srv_start() */
coordinator_startup()223   void coordinator_startup()
224   {
225     ut_ad(!enabled());
226     m_enabled.store(true, std::memory_order_relaxed);
227   }
228 
229   /** Disable purge at shutdown */
coordinator_shutdown()230   void coordinator_shutdown()
231   {
232     ut_ad(enabled());
233     m_enabled.store(false, std::memory_order_relaxed);
234   }
235 
236   /** @return whether the purge tasks are active */
237   bool running() const;
238   /** Stop purge during FLUSH TABLES FOR EXPORT */
239   void stop();
240   /** Resume purge at UNLOCK TABLES after FLUSH TABLES FOR EXPORT */
241   void resume();
242   /** A wrapper around ReadView::changes_visible(). */
changes_visible(trx_id_t id,const table_name_t & name)243   bool changes_visible(trx_id_t id, const table_name_t &name) const
244   {
245     ut_ad(rw_lock_own(&latch, RW_LOCK_S));
246     return view.changes_visible(id, name);
247   }
248   /** A wrapper around ReadView::low_limit_no(). */
low_limit_no()249   trx_id_t low_limit_no() const
250   {
251 #if 0 /* Unfortunately we don't hold this assertion, see MDEV-22718. */
252     ut_ad(rw_lock_own(&latch, RW_LOCK_S));
253 #endif
254     return view.low_limit_no();
255   }
256   /** A wrapper around trx_sys_t::clone_oldest_view(). */
clone_oldest_view()257   void clone_oldest_view()
258   {
259     rw_lock_x_lock(&latch);
260     trx_sys.clone_oldest_view(&view);
261     rw_lock_x_unlock(&latch);
262   }
263 };
264 
265 /** The global data structure coordinating a purge */
266 extern purge_sys_t	purge_sys;
267 
268 #endif /* trx0purge_h */
269