trx0purge.h 15.3 KB
Newer Older
1 2
/*****************************************************************************

3
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Marko Mäkelä's avatar
Marko Mäkelä committed
4
Copyright (c) 2017, 2018, MariaDB Corporation.
5 6 7 8 9 10 11 12 13 14

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

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 for more details.

You should have received a copy of the GNU General Public License along with
15 16
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17 18 19

*****************************************************************************/

20 21
/**************************************************//**
@file include/trx0purge.h
osku's avatar
osku committed
22 23 24 25 26 27 28 29
Purge old versions

Created 3/26/1996 Heikki Tuuri
*******************************************************/

#ifndef trx0purge_h
#define trx0purge_h

Marko Mäkelä's avatar
Marko Mäkelä committed
30
#include "trx0rseg.h"
osku's avatar
osku committed
31 32
#include "que0types.h"

33
/** A dummy undo record used as a return value when we have a whole undo log
osku's avatar
osku committed
34 35 36
which needs no purge */
extern trx_undo_rec_t	trx_purge_dummy_rec;

37
/********************************************************************//**
osku's avatar
osku committed
38
Calculates the file address of an undo log header when we have the file
39
address of its history list node.
40
@return file address of the log */
osku's avatar
osku committed
41 42 43 44
UNIV_INLINE
fil_addr_t
trx_purge_get_log_from_hist(
/*========================*/
45
	fil_addr_t	node_addr);	/*!< in: file address of the history
osku's avatar
osku committed
46
					list node of the log */
47 48 49 50 51
/** Prepend the history list with an undo log.
Remove the undo log segment from the rseg slot if it is too big for reuse.
@param[in]	trx		transaction
@param[in,out]	undo		undo log
@param[in,out]	mtr		mini-transaction */
osku's avatar
osku committed
52
void
53
trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr);
54
/*******************************************************************//**
55
This function runs a purge batch.
56
@return number of undo log pages handled in the batch */
osku's avatar
osku committed
57
ulint
58 59
trx_purge(
/*======*/
60 61 62 63 64
	ulint	n_purge_threads,	/*!< in: number of purge tasks to
					submit to task queue. */
	bool	truncate);		/*!< in: truncate history if true */
/*******************************************************************//**
Stop purge and wait for it to stop, move to PURGE_STATE_STOP. */
osku's avatar
osku committed
65
void
66 67 68 69 70 71 72 73 74 75 76 77 78
trx_purge_stop(void);
/*================*/
/*******************************************************************//**
Resume purge, move to PURGE_STATE_RUN. */
void
trx_purge_run(void);
/*================*/

/** Purge states */
enum purge_state_t {
	PURGE_STATE_INIT,		/*!< Purge instance created */
	PURGE_STATE_RUN,		/*!< Purge should be running */
	PURGE_STATE_STOP,		/*!< Purge should be stopped */
79 80
	PURGE_STATE_EXIT,		/*!< Purge has been shutdown */
	PURGE_STATE_DISABLED		/*!< Purge was never started */
81 82 83 84 85 86 87 88 89
};

/*******************************************************************//**
Get the purge state.
@return purge state. */
purge_state_t
trx_purge_state(void);
/*=================*/

90 91 92 93 94 95 96 97
/** 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;
98
	typedef trx_rsegs_t::const_iterator const_iterator;
99 100

	/** Default constructor */
101
	TrxUndoRsegs() {}
Marko Mäkelä's avatar
Marko Mäkelä committed
102 103
	/** Constructor */
	TrxUndoRsegs(trx_rseg_t& rseg)
104
		: m_commit(rseg.last_commit), m_rsegs(1, &rseg) {}
Marko Mäkelä's avatar
Marko Mäkelä committed
105 106
	/** Constructor */
	TrxUndoRsegs(trx_id_t trx_no, trx_rseg_t& rseg)
107
		: m_commit(trx_no << 1), m_rsegs(1, &rseg) {}
108

109 110
	/** @return the transaction commit identifier */
	trx_id_t trx_no() const { return m_commit >> 1; }
111

112 113
	bool operator!=(const TrxUndoRsegs& other) const
	{ return m_commit != other.m_commit; }
Marko Mäkelä's avatar
Marko Mäkelä committed
114 115 116 117
	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()); }
118 119
	const_iterator begin() const { return m_rsegs.begin(); }
	const_iterator end() const { return m_rsegs.end(); }
120 121 122 123 124 125 126

	/** 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)
	{
127
		return(lhs.m_commit > rhs.m_commit);
128 129 130
	}

private:
131 132
	/** Copy trx_rseg_t::last_commit */
	trx_id_t		m_commit;
133 134 135 136 137 138 139 140 141
	/** 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;

142
/** Chooses the rollback segment with the oldest committed transaction */
143 144
struct TrxUndoRsegsIterator {
	/** Constructor */
145
	inline TrxUndoRsegsIterator();
Marko Mäkelä's avatar
Marko Mäkelä committed
146
	/** Sets the next rseg to purge in purge_sys.
147
	Executed in the purge coordinator thread.
148
	@return whether anything is to be purged */
Marko Mäkelä's avatar
Marko Mäkelä committed
149
	inline bool set_next();
150 151 152 153 154 155 156

private:
	// Disable copying
	TrxUndoRsegsIterator(const TrxUndoRsegsIterator&);
	TrxUndoRsegsIterator& operator=(const TrxUndoRsegsIterator&);

	/** The current element to process */
157 158 159
	TrxUndoRsegs			m_rsegs;
	/** Track the current element in m_rsegs */
	TrxUndoRsegs::const_iterator	m_iter;
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

/* Namespace to hold all the related functions and variables need for truncate
of undo tablespace. */
namespace undo {

	typedef std::vector<ulint>		undo_spaces_t;
	typedef	std::vector<trx_rseg_t*>	rseg_for_trunc_t;

	/** Magic Number to indicate truncate action is complete. */
	const ib_uint32_t			s_magic = 76845412;

	/** Truncate Log file Prefix. */
	const char* const			s_log_prefix = "undo_";

	/** Truncate Log file Extension. */
	const char* const			s_log_ext = "trunc.log";

	/** Populate log file name based on space_id
	@param[in]	space_id	id of the undo tablespace.
	@return DB_SUCCESS or error code */
	dberr_t populate_log_file_name(
		ulint	space_id,
		char*&	log_file_name);

	/** Create the truncate log file.
	@param[in]	space_id	id of the undo tablespace to truncate.
	@return DB_SUCCESS or error code. */
	dberr_t init(ulint space_id);

	/** Mark completion of undo truncate action by writing magic number to
	the log file and then removing it from the disk.
	If we are going to remove it from disk then why write magic number ?
	This is to safeguard from unlink (file-system) anomalies that will keep
	the link to the file even after unlink action is successfull and
	ref-count = 0.
	@param[in]	space_id	id of the undo tablespace to truncate.*/
	void done(ulint	space_id);

	/** Check if TRUNCATE_DDL_LOG file exist.
	@param[in]	space_id	id of the undo tablespace.
	@return true if exist else false. */
	bool is_log_present(ulint space_id);

	/** Track UNDO tablespace mark for truncate. */
	class Truncate {
	public:

		Truncate()
			:
			m_undo_for_trunc(ULINT_UNDEFINED),
			m_rseg_for_trunc(),
			m_scan_start(1),
			m_purge_rseg_truncate_frequency(
				static_cast<ulint>(
				srv_purge_rseg_truncate_frequency))
		{
			/* Do Nothing. */
		}

		/** Clear the cached rollback segment. Normally done
		when purge is about to shutdown. */
		void clear()
		{
			reset();
			rseg_for_trunc_t	temp;
			m_rseg_for_trunc.swap(temp);
		}

		/** Is tablespace selected for truncate.
		@return true if undo tablespace is marked for truncate */
		bool is_marked() const
		{
			return(!(m_undo_for_trunc == ULINT_UNDEFINED));
		}

		/** Mark the tablespace for truncate.
		@param[in]	undo_id		tablespace for truncate. */
		void mark(ulint undo_id)
		{
			m_undo_for_trunc = undo_id;

			m_scan_start = (undo_id + 1)
					% (srv_undo_tablespaces_active + 1);
			if (m_scan_start == 0) {
				/* Note: UNDO tablespace ids starts from 1. */
				m_scan_start = 1;
			}

			/* We found an UNDO-tablespace to truncate so set the
			local purge rseg truncate frequency to 1. This will help
			accelerate the purge action and in turn truncate. */
			m_purge_rseg_truncate_frequency = 1;
		}

		/** Get the tablespace marked for truncate.
		@return tablespace id marked for truncate. */
		ulint get_marked_space_id() const
		{
			return(m_undo_for_trunc);
		}

		/** Add rseg to truncate vector.
		@param[in,out]	rseg	rseg for truncate */
		void add_rseg_to_trunc(trx_rseg_t* rseg)
		{
			m_rseg_for_trunc.push_back(rseg);
		}

		/** Get number of rsegs registered for truncate.
		@return return number of rseg that belongs to tablespace mark
		for truncate. */
		ulint rsegs_size() const
		{
			return(m_rseg_for_trunc.size());
		}

		/** Get ith registered rseg.
		@param[in]	id	index of rseg to get.
		@return reference to registered rseg. */
		trx_rseg_t* get_ith_rseg(ulint id)
		{
			ut_ad(id < m_rseg_for_trunc.size());
			return(m_rseg_for_trunc.at(id));
		}

		/** Reset for next rseg truncate. */
		void reset()
		{
			m_undo_for_trunc = ULINT_UNDEFINED;
			m_rseg_for_trunc.clear();

			/* Sync with global value as we are done with
			truncate now. */
			m_purge_rseg_truncate_frequency = static_cast<ulint>(
				srv_purge_rseg_truncate_frequency);
		}

		/** Get the tablespace id to start scanning from.
		@return	id of UNDO tablespace to start scanning from. */
		ulint get_scan_start() const
		{
			return(m_scan_start);
		}

		/** Check if the tablespace needs fix-up (based on presence of
		DDL truncate log)
		@param	space_id	space id of the undo tablespace to check
		@return true if fix up is needed else false */
		bool needs_fix_up(ulint	space_id) const
		{
			return(is_log_present(space_id));
		}

		/** Add undo tablespace to truncate vector.
		@param[in]	space_id	space id of tablespace to
						truncate */
		static void add_space_to_trunc_list(ulint space_id)
		{
			s_spaces_to_truncate.push_back(space_id);
		}

		/** Clear the truncate vector. */
		static void clear_trunc_list()
		{
			s_spaces_to_truncate.clear();
		}

		/** Is tablespace marked for truncate.
		@param[in]	space_id	space id to check
		@return true if marked for truncate, else false. */
		static bool is_tablespace_truncated(ulint space_id)
		{
			return(std::find(s_spaces_to_truncate.begin(),
					 s_spaces_to_truncate.end(), space_id)
			       != s_spaces_to_truncate.end());
		}

		/** Was a tablespace truncated at startup
		@param[in]	space_id	space id to check
		@return whether space_id was truncated at startup */
		static bool was_tablespace_truncated(ulint space_id)
		{
			return(std::find(s_fix_up_spaces.begin(),
					 s_fix_up_spaces.end(),
					 space_id)
			       != s_fix_up_spaces.end());
		}

		/** Get local rseg purge truncate frequency
		@return rseg purge truncate frequency. */
		ulint get_rseg_truncate_frequency() const
		{
			return(m_purge_rseg_truncate_frequency);
		}

		/* Start writing log information to a special file.
		On successfull completion, file is removed.
		On crash, file is used to complete the truncate action.
		@param	space_id	space id of undo tablespace
		@return DB_SUCCESS or error code. */
		dberr_t start_logging(ulint space_id)
		{
			return(init(space_id));
		}

		/* Mark completion of logging./
		@param	space_id	space id of undo tablespace */
		void done_logging(ulint space_id)
		{
			return(done(space_id));
		}

	private:
		/** UNDO tablespace is mark for truncate. */
		ulint			m_undo_for_trunc;

		/** rseg that resides in UNDO tablespace is marked for
		truncate. */
		rseg_for_trunc_t	m_rseg_for_trunc;

		/** Start scanning for UNDO tablespace from this space_id.
		This is to avoid bias selection of one tablespace always. */
		ulint			m_scan_start;

		/** Rollback segment(s) purge frequency. This is local
		value maintained along with global value. It is set to global
		value on start but when tablespace is marked for truncate it
		is updated to 1 and then minimum value among 2 is used by
		purge action. */
		ulint			m_purge_rseg_truncate_frequency;

		/** List of UNDO tablespace(s) to truncate. */
		static undo_spaces_t	s_spaces_to_truncate;
	public:
		/** Undo tablespaces that were truncated at startup */
		static undo_spaces_t	s_fix_up_spaces;
	};	/* class Truncate */

};	/* namespace undo */

401
/** The control structure used in the purge operation */
Marko Mäkelä's avatar
Marko Mäkelä committed
402 403 404 405 406 407 408 409
class purge_sys_t
{
public:
	/** Construct the purge system. */
	purge_sys_t();
	/** Destruct the purge system. */
	~purge_sys_t();

410
	rw_lock_t	latch;		/*!< The latch protecting the purge
411 412
					view. A purge operation must acquire an
					x-latch here for the instant at which
osku's avatar
osku committed
413 414
					it changes the purge view: an undo
					log operation can prevent this by
415 416
					obtaining an s-latch here. It also
					protects state and running */
417 418
	os_event_t	event;		/*!< State signal event;
					os_event_set() and os_event_reset()
Marko Mäkelä's avatar
Marko Mäkelä committed
419
					are protected by purge_sys_t::latch
420
					X-lock */
421
	ulint		n_stop;		/*!< Counter to track number stops */
422 423
	volatile bool	running;	/*!< true, if purge is active,
					we check this without the latch too */
424 425 426 427 428
	volatile purge_state_t	state;	/*!< Purge coordinator thread states,
					we check this in several places
					without holding the latch. */
	que_t*		query;		/*!< The query graph which will do the
					parallelized purge operation */
429
	ReadView	view;		/*!< The purge will not remove undo logs
osku's avatar
osku committed
430
					which are >= this view (purge view) */
431
	ulint	n_submitted;	/*!< Count of total tasks submitted
432
					to the task queue */
433
	ulint	n_completed;	/*!< Count of total tasks completed */
434

435 436 437 438 439
	/** Iterator to the undo log records of committed transactions */
	struct iterator
	{
		bool operator<=(const iterator& other) const
		{
440 441
			if (commit < other.commit) return true;
			if (commit > other.commit) return false;
442 443 444
			return undo_no <= other.undo_no;
		}

445 446 447 448 449 450
		/** @return the commit number of the transaction */
		trx_id_t trx_no() const { return commit >> 1; }
		void reset_trx_no(trx_id_t trx_no) { commit = trx_no << 1; }

		/** 2 * trx_t::no + old_insert of the committed transaction */
		trx_id_t	commit;
451 452 453 454
		/** The record number within the committed transaction's undo
		log, increasing, purged from from 0 onwards */
		undo_no_t	undo_no;
	};
osku's avatar
osku committed
455

456 457
	/** The tail of the purge queue; the last parsed undo log of a
	committed transaction. */
458
	iterator	tail;
459 460
	/** The head of the purge queue; any older undo logs of committed
	transactions may be discarded (history list truncation). */
461
	iterator	head;
osku's avatar
osku committed
462
	/*-----------------------------*/
Marko Mäkelä's avatar
Marko Mäkelä committed
463 464
	bool		next_stored;	/*!< whether rseg holds the next record
					to purge */
465
	trx_rseg_t*	rseg;		/*!< Rollback segment for the next undo
osku's avatar
osku committed
466
					record to purge */
467
	ulint		page_no;	/*!< Page number for the next undo
osku's avatar
osku committed
468 469
					record to purge, page number of the
					log header, if dummy record */
470
	ulint		offset;		/*!< Page offset for the next undo
osku's avatar
osku committed
471 472
					record to purge, 0 if the dummy
					record */
473
	ulint		hdr_page_no;	/*!< Header page of the undo log where
osku's avatar
osku committed
474
					the next record to purge belongs */
475
	ulint		hdr_offset;	/*!< Header byte offset on the page */
476 477


Marko Mäkelä's avatar
Marko Mäkelä committed
478
	TrxUndoRsegsIterator
479 480 481
			rseg_iter;	/*!< Iterator to get the next rseg
					to process */

Marko Mäkelä's avatar
Marko Mäkelä committed
482
	purge_pq_t	purge_queue;	/*!< Binary min-heap, ordered on
483 484 485 486 487 488
					TrxUndoRsegs::trx_no. It is protected
					by the pq_mutex */
	PQMutex		pq_mutex;	/*!< Mutex protecting purge_queue */

	undo::Truncate	undo_trunc;	/*!< Track UNDO tablespace marked
					for truncate. */
osku's avatar
osku committed
489 490
};

Marko Mäkelä's avatar
Marko Mäkelä committed
491 492 493
/** The global data structure coordinating a purge */
extern purge_sys_t*	purge_sys;

494
/** Info required to purge a record */
495
struct trx_purge_rec_t {
496 497 498 499
	trx_undo_rec_t*	undo_rec;	/*!< Record to purge */
	roll_ptr_t	roll_ptr;	/*!< File pointr to UNDO record */
};

osku's avatar
osku committed
500 501
#include "trx0purge.ic"

502
#endif /* trx0purge_h */