polardbxengine/storage/innobase/include/lizard0cleanout.h

403 lines
11 KiB
C++

/* Copyright (c) 2018, 2021, Alibaba and/or its affiliates. All rights reserved.
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 also distributed 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/PolarDB-X Engine hereby grant you an
additional permission to link the program and your derivative works with the
separately licensed software that they have included with
MySQL/PolarDB-X Engine.
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 */
/** @file include/lizard0cleanout.h
Lizard cleanout operation
Created 2020-04-15 by Jianwei.zhao
*******************************************************/
#ifndef lizard0cleanout_h
#define lizard0cleanout_h
#include "buf0types.h"
#include "page0types.h"
#include "rem0types.h"
#include "trx0types.h"
#include "ut0mutex.h"
#include "lizard0undo0types.h"
#include "lizard0ut.h"
struct mtr_t;
struct dict_index_t;
struct page_zip_des_t;
struct txn_rec_t;
struct btr_pcur_t;
#ifdef UNIV_PFS_MUTEX
/* lizard undo hdr hash mutex PFS key */
extern mysql_pfs_key_t lizard_undo_hdr_hash_mutex_key;
#endif
/** Undo log header page as key */
using Undo_hdr_key = std::pair<space_id_t, page_no_t>;
struct Undo_hdr {
space_id_t space_id;
page_no_t page_no;
};
namespace std {
template <>
struct hash<Undo_hdr_key> {
public:
typedef Undo_hdr_key argument_type;
typedef size_t result_type;
size_t operator()(const Undo_hdr_key &p) const;
};
} // namespace std
/** Compare function */
class Undo_hdr_equal {
public:
bool operator()(const Undo_hdr_key &lhs, const Undo_hdr_key &rhs) const;
};
/** Hash table of undo log header pages */
typedef std::unordered_map<Undo_hdr_key, bool, std::hash<Undo_hdr_key>,
Undo_hdr_equal,
ut_allocator<std::pair<const Undo_hdr_key, bool>>>
Undo_hdr_hash;
/*----------------------------------------------------------------*/
namespace lizard {
extern bool opt_cleanout_write_redo;
/** Whether do the safe cleanout */
extern bool opt_cleanout_safe_mode;
/**
Put txn undo into hash table.
@param[in] undo txn undo memory structure.
*/
void txn_undo_hash_insert(trx_undo_t *undo);
/**
Put all the undo log segment into hash table include active undo,
cached undo, history list, free list.
@param[in] space_id rollback segment space
@param[in] rseg_hdr rollback segment header page
@param[in] rseg rollback segment memory object
@param[in] mtr mtr that hold the rseg hdr page
*/
void trx_rseg_init_undo_hdr_hash(space_id_t space_id, trx_rsegf_t *rseg_hdr,
trx_rseg_t *rseg, mtr_t *mtr);
/** Undo log segments */
class Undo_logs {
public:
Undo_logs();
virtual ~Undo_logs();
bool insert(Undo_hdr hdr);
bool exist(Undo_hdr hdr);
private:
ib_mutex_t m_mutex;
Undo_hdr_hash m_hash;
};
#define TXN_UNDO_HASH_PARTITIONS 64
/** Global txn undo logs container */
extern Partition<Undo_logs, Undo_hdr, TXN_UNDO_HASH_PARTITIONS> *txn_undo_logs;
void txn_undo_hash_init();
void txn_undo_hash_close();
/**
Write redo log when updating scn and uba fileds in physical records.
@param[in] rec physical record
@param[in] index dict that interprets the row record
@param[in] txn_rec txn info from the record
@param[in] mtr mtr
*/
void btr_cur_upd_lizard_fields_clust_rec_log(const rec_t *rec,
const dict_index_t *index,
const txn_rec_t* txn_rec,
mtr_t *mtr);
/**
Parse the txn info from redo log record, and apply it if necessary.
@param[in] ptr buffer
@param[in] end buffer end
@param[in] page page (NULL if it's just get the length)
@param[in] page_zip compressed page, or NULL
@param[in] index index corresponding to page
@return return the end of log record or NULL
*/
byte *btr_cur_parse_lizard_fields_upd_clust_rec(byte *ptr, byte *end_ptr,
page_t *page,
page_zip_des_t *page_zip,
const dict_index_t *index);
/*----------------------------------------------------------------*/
/* Lizard cleanout structure and function. */
/*----------------------------------------------------------------*/
/** Whether disable the delayed cleanout when read */
extern bool opt_cleanout_disable;
/** Commit cleanout profiles */
#define COMMIT_CLEANOUT_MAX_NUM (ulint(-1))
#define COMMIT_CLEANOUT_DEFAULT_ROWS 3
extern ulint commit_cleanout_max_rows;
/** Lizard max scan record count once cleanout one page.*/
extern ulint cleanout_max_scans_on_page;
/** Lizard max clean record count once cleanout one page.*/
extern ulint cleanout_max_cleans_on_page;
enum cleanout_mode_enum { CLEANOUT_BY_CURSOR, CLEANOUT_BY_PAGE };
extern ulong cleanout_mode;
class Page {
public:
Page() : m_page_id(0, 0), m_index(nullptr) {}
Page(const page_id_t &page_id, const dict_index_t *index);
Page(const Page &);
Page(const Page &&) = delete;
Page &operator=(const Page &page);
bool operator==(const Page &page) {
if (m_index != nullptr && page.m_index != nullptr &&
m_index == page.m_index && m_page_id.equals_to(page.m_page_id))
return true;
return false;
}
const page_id_t &page() const { return m_page_id; }
const dict_index_t *index() const { return m_index; }
private:
page_id_t m_page_id;
const dict_index_t *m_index;
};
/** All the pages need to cleanout within pcur */
typedef std::vector<Page, ut_allocator<Page>> Pages;
/** Committed txn container */
typedef std::unordered_map<
trx_id_t, txn_commit_t, std::hash<trx_id_t>, std::equal_to<trx_id_t>,
ut_allocator<std::pair<const trx_id_t, txn_commit_t>>>
Txn_commits;
/**
Collected pages that will be cleanout soon.
*/
class Cleanout_pages {
public:
explicit Cleanout_pages()
: m_pages(), m_txns(), m_page_num(0), m_txn_num(0), m_last_page() {}
virtual ~Cleanout_pages();
void init();
bool is_empty();
const Txn_commits *txns() const { return &m_txns; }
ulint page_count() const { return m_page_num; }
ulint txn_count() const { return m_txn_num; }
template <typename Func>
ulint iterate_page(Func &functor) {
ulint cleaned = 0;
for (auto it : m_pages) {
cleaned += functor(it);
}
return cleaned;
}
/**
Add the committed trx into hash map.
@param[in] trx_id
@param[in] trx_commit
@retval true Add success
@retval false Add failure
*/
bool push_trx(trx_id_t trx_id, txn_commit_t txn_commit);
/**
Add the page which needed to cleanout into vector.
@param[in] page_id
@param[in] index
*/
void push_page(const page_id_t &page_id, const dict_index_t *index);
private:
Pages m_pages;
Txn_commits m_txns;
ulint m_page_num;
ulint m_txn_num;
Page m_last_page;
};
/*----------------------------------------------------------------*/
/* Lizard cleanout by cursor. */
/*----------------------------------------------------------------*/
class Cursor {
public:
explicit Cursor()
: m_old_stored(false),
m_old_rec(nullptr),
m_block(nullptr),
m_index(nullptr),
m_modify_clock(0),
m_withdraw_clock(0),
m_is_used_by_tcn(false) {}
explicit Cursor(bool is_tcn)
: m_old_stored(false),
m_old_rec(nullptr),
m_block(nullptr),
m_index(nullptr),
m_modify_clock(0),
m_withdraw_clock(0),
m_is_used_by_tcn(is_tcn) {}
Cursor(const Cursor &);
Cursor &operator=(const Cursor &);
bool store_position(btr_pcur_t *pcur);
bool store_position(dict_index_t *index, buf_block_t *block, rec_t *rec);
bool restore_position(mtr_t *mtr) const;
bool stored() const { return m_old_stored; }
rec_t *get_rec() const { return m_old_rec; }
dict_index_t *get_index() const { return m_index; }
buf_block_t *get_block() const { return m_block; }
page_id_t page_id() const { return m_page_id; }
const Txn_commits *txns() const { return &m_txns; }
void push_back(trx_id_t trx_id, txn_commit_t txn_commit) {
m_txns.insert(std::pair<trx_id_t, txn_commit_t>(trx_id, txn_commit));
}
bool used_by_tcn() const { return m_is_used_by_tcn; }
private:
bool m_old_stored;
rec_t *m_old_rec;
buf_block_t *m_block;
dict_index_t *m_index;
uint64_t m_modify_clock;
ulint m_withdraw_clock;
page_id_t m_page_id;
/** Used by TCN cache */
Txn_commits m_txns;
bool m_is_used_by_tcn;
};
/** All the cursors need to cleanout within pcur */
typedef std::vector<Cursor, ut_allocator<Cursor>> Cursors;
/**
Collected cursor that will be cleanout soon.
*/
class Cleanout_cursors {
public:
explicit Cleanout_cursors()
: m_cursors(), m_txns(), m_cursor_num(0), m_txn_num(0) {}
virtual ~Cleanout_cursors();
void init();
bool is_empty();
const Txn_commits *txns() const { return &m_txns; }
ulint cursor_count() const { return m_cursor_num; }
ulint txn_count() const { return m_txn_num; }
template <typename Func>
ulint iterate_cursor(Func &functor) {
ulint cleaned = 0;
for (auto it : m_cursors) {
cleaned += functor(it);
}
return cleaned;
}
/**
Add the committed trx into hash map.
@param[in] trx_id
@param[in] trx_commit
@retval true Add success
@retval false Add failure
*/
bool push_trx(trx_id_t trx_id, txn_commit_t txn_commit);
/**
Add the page which needed to cleanout into vector.
@param[in] page_id
@param[in] index
*/
void push_cursor(const Cursor &cursor);
void push_cursor_by_page(const Cursor &cursor, trx_id_t trx_id,
txn_commit_t txn_commit);
private:
Cursors m_cursors;
Txn_commits m_txns;
ulint m_cursor_num;
ulint m_txn_num;
};
} // namespace lizard
#endif