409 lines
13 KiB
C++
409 lines
13 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/lizard0dict.h
|
|
Special Lizard tablespace definition.
|
|
|
|
Created 2020-03-19 by Jianwei.zhao
|
|
*******************************************************/
|
|
|
|
#include "lizard0dict.h"
|
|
#include "dict0dd.h"
|
|
#include "dict0mem.h"
|
|
#include "row0mysql.h"
|
|
#include "lizard0data0types.h"
|
|
#include "lizard0undo.h"
|
|
|
|
namespace lizard {
|
|
|
|
/** The space name of lizard */
|
|
const char *dict_lizard::s_lizard_space_name = "innodb_lizard";
|
|
|
|
/** The file name of lizard space */
|
|
const char *dict_lizard::s_lizard_space_file_name = "lizard.ibd";
|
|
|
|
static_assert(DATA_SCN_ID == 3, "DATA_SCN_ID != 3");
|
|
static_assert(DATA_SCN_ID_LEN == 8, "DATA_SCN_ID_LEN != 8");
|
|
static_assert(DATA_UNDO_PTR == 4, "DATA_UNDO_PTR != 4");
|
|
static_assert(DATA_UNDO_PTR_LEN == 8, "DATA_UNDO_PTR_LEN != 8");
|
|
|
|
static_assert(DATA_GCN_ID == 5, "DATA_GCN_ID != 5");
|
|
static_assert(DATA_GCN_ID_LEN == 8, "DATA_GCN_ID_LEN != 8");
|
|
|
|
/** Lizard: First several undo tablespaces will be treated as txn tablespace */
|
|
const char *dict_lizard::s_default_txn_space_names[] = {
|
|
"innodb_undo_001", "innodb_undo_002", "innodb_undo_003", "innodb_undo_004"};
|
|
|
|
/** Judge the undo tablespace is txn tablespace by name */
|
|
bool is_txn_space_by_name(const char *name) {
|
|
if (name && (strcmp(name, dict_lizard::s_default_txn_space_names[0]) == 0 ||
|
|
strcmp(name, dict_lizard::s_default_txn_space_names[1]) == 0 ||
|
|
strcmp(name, dict_lizard::s_default_txn_space_names[2]) == 0 ||
|
|
strcmp(name, dict_lizard::s_default_txn_space_names[3]) == 0))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
Add the SCN and UBA column into dict_table_t, for example:
|
|
dict_table_t::col_names "...DB_SCN_ID\0DATA_UNDO_PTR\0..."
|
|
|
|
@param[in] table dict_table_t
|
|
@param[in] heap memory slice
|
|
*/
|
|
void dict_table_add_lizard_columns(dict_table_t *table, mem_heap_t *heap) {
|
|
ut_ad(table && heap);
|
|
|
|
if (table->is_intrinsic()) return;
|
|
|
|
dict_mem_table_add_col(table, heap, "DB_SCN_ID", DATA_SYS,
|
|
DATA_SCN_ID | DATA_NOT_NULL, DATA_SCN_ID_LEN);
|
|
|
|
dict_mem_table_add_col(table, heap, "DB_UNDO_PTR", DATA_SYS,
|
|
DATA_UNDO_PTR | DATA_NOT_NULL, DATA_UNDO_PTR_LEN);
|
|
|
|
dict_mem_table_add_col(table, heap, "DB_GCN_ID", DATA_SYS,
|
|
DATA_GCN_ID | DATA_NOT_NULL, DATA_GCN_ID_LEN);
|
|
}
|
|
|
|
/**
|
|
Init txn_desc with the creator trx when created.
|
|
|
|
@param[in] index the index being created
|
|
@param[in] trx creator transaction
|
|
@return DB_SUCCESS Success
|
|
*/
|
|
dberr_t dd_index_init_txn_desc(dict_index_t *index, trx_t *trx) {
|
|
dberr_t err = DB_SUCCESS;
|
|
ut_ad(index->table);
|
|
ut_ad(!mutex_own(&trx->undo_mutex));
|
|
|
|
/** If a table is temporary, or even intrinsic, its dict info will not
|
|
be written to dict tables. */
|
|
if (!index->table->is_temporary()) {
|
|
mutex_enter(&trx->undo_mutex);
|
|
err = trx_always_assign_txn_undo(trx);
|
|
mutex_exit(&trx->undo_mutex);
|
|
|
|
if (err == DB_SUCCESS) {
|
|
assert_trx_scn_initial(trx);
|
|
assert_undo_ptr_allocated(trx->txn_desc.undo_ptr);
|
|
ut_ad(lizard_undo_ptr_is_active(trx->txn_desc.undo_ptr));
|
|
|
|
index->txn.uba = trx->txn_desc.undo_ptr;
|
|
index->txn.scn = trx->txn_desc.cmmt.scn;
|
|
index->txn.gcn = trx->txn_desc.cmmt.gcn;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
Check if a index should be seen by a transaction.
|
|
|
|
@param[in] index the index being opened.
|
|
@param[in] trx transaction.
|
|
@return true if visible
|
|
*/
|
|
bool dd_index_modificatsion_visible(dict_index_t *index, const trx_t *trx,
|
|
bool is_as_of, scn_t as_of_scn,
|
|
gcn_t as_of_gcn) {
|
|
txn_rec_t rec_txn;
|
|
scn_t scn = index->txn.scn.load();
|
|
gcn_t gcn = index->txn.gcn.load();
|
|
ut_ad(trx);
|
|
|
|
rec_txn = {
|
|
index->trx_id,
|
|
scn,
|
|
index->txn.uba,
|
|
gcn,
|
|
};
|
|
|
|
if (scn == SCN_NULL || gcn == GCN_NULL) {
|
|
lizard::txn_rec_real_state_by_misc(&rec_txn);
|
|
/** It might be stored many times but they should be the same value */
|
|
index->txn.scn.store(rec_txn.scn);
|
|
index->txn.gcn.store(rec_txn.gcn);
|
|
}
|
|
|
|
if (is_as_of) {
|
|
ut_ad(as_of_scn != SCN_NULL || as_of_gcn != GCN_NULL);
|
|
|
|
if (as_of_scn != SCN_NULL) {
|
|
ut_ad(as_of_gcn == GCN_NULL);
|
|
return (rec_txn.scn != SCN_NULL && as_of_scn != SCN_NULL &&
|
|
rec_txn.scn <= as_of_scn);
|
|
} else {
|
|
ut_ad(as_of_scn == SCN_NULL);
|
|
if (srv_equal_gcn_visible)
|
|
return (rec_txn.gcn != GCN_NULL && as_of_gcn != GCN_NULL &&
|
|
rec_txn.gcn <= as_of_gcn);
|
|
else
|
|
return (rec_txn.gcn != GCN_NULL && as_of_gcn != GCN_NULL &&
|
|
rec_txn.gcn < as_of_gcn);
|
|
}
|
|
} else {
|
|
ut_ad(trx->vision.is_active());
|
|
/**
|
|
When is_usable() is executed concurrently, SCN and UBA will be not
|
|
consistent, the vision judgement only depend on real SCN, UBA state
|
|
will be used to code defense, so here omit the check.
|
|
*/
|
|
return trx->vision.modifications_visible(&rec_txn, index->table->name,
|
|
false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Fill index txn information from se_private_data.
|
|
|
|
@param[in,out] index the index being opened.
|
|
@param[in] p se_private_data from the mysql.indexes record.
|
|
@return true if failed
|
|
*/
|
|
bool dd_index_fill_txn_desc(dict_index_t *index, const dd::Properties &p) {
|
|
undo_ptr_t uba = 0;
|
|
scn_t scn = SCN_NULL;
|
|
gcn_t gcn = GCN_NULL;
|
|
|
|
if (p.get(dd_index_key_strings[DD_INDEX_UBA], &uba) ||
|
|
p.get(dd_index_key_strings[DD_INDEX_SCN], &scn))
|
|
return true;
|
|
|
|
/** GCN didn't add into properties first time, so judge it firstly. */
|
|
if (p.exists(dd_index_key_strings[DD_INDEX_GCN])) {
|
|
p.get(dd_index_key_strings[DD_INDEX_GCN], &gcn);
|
|
}
|
|
|
|
index->txn.uba = uba;
|
|
index->txn.scn = scn;
|
|
index->txn.gcn = gcn;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
Add the lizard columns into data dictionary in server
|
|
|
|
@param[in,out] dd_table data dictionary cache object
|
|
@param[in,out] primary data dictionary primary key
|
|
*/
|
|
void dd_add_lizard_columns(dd::Table *dd_table, dd::Index *primary) {
|
|
ut_ad(dd_table && primary);
|
|
|
|
dd::Column *db_scn_id = dd_add_hidden_column(
|
|
dd_table, "DB_SCN_ID", DATA_SCN_ID_LEN, dd::enum_column_types::LONGLONG);
|
|
dd_add_hidden_element(primary, db_scn_id);
|
|
|
|
dd::Column *db_undo_ptr =
|
|
dd_add_hidden_column(dd_table, "DB_UNDO_PTR", DATA_UNDO_PTR_LEN,
|
|
dd::enum_column_types::LONGLONG);
|
|
dd_add_hidden_element(primary, db_undo_ptr);
|
|
|
|
dd::Column *db_gcn_id = dd_add_hidden_column(
|
|
dd_table, "DB_GCN_ID", DATA_GCN_ID_LEN, dd::enum_column_types::LONGLONG);
|
|
|
|
dd_add_hidden_element(primary, db_gcn_id);
|
|
}
|
|
|
|
#if defined UNIV_DEBUG || defined LIZARD_DEBUG
|
|
/**
|
|
Check the dict_table_t object
|
|
|
|
@param[in] table dict_table_t
|
|
|
|
@return true Success
|
|
*/
|
|
bool lizard_dict_table_check(const dict_table_t *table) {
|
|
size_t n_cols;
|
|
size_t n_sys_cols;
|
|
dict_col_t *col;
|
|
const char *s;
|
|
bool is_intrinsic;
|
|
ulint i;
|
|
ut_a(table);
|
|
|
|
is_intrinsic = table->is_intrinsic();
|
|
s = table->col_names;
|
|
|
|
/** Check columns */
|
|
n_cols = table->n_cols;
|
|
if (is_intrinsic) {
|
|
n_sys_cols = DATA_ITT_N_SYS_COLS + DATA_ITT_N_LIZARD_COLS;
|
|
ut_a(n_cols > n_sys_cols);
|
|
for (i = 0; i < n_cols - n_sys_cols; i++) {
|
|
s += strlen(s) + 1;
|
|
}
|
|
/* Row id */
|
|
col = table->get_col(n_cols - n_sys_cols + DATA_ROW_ID);
|
|
ut_a(col->mtype == DATA_SYS);
|
|
ut_a(col->prtype == (DATA_ROW_ID | DATA_NOT_NULL));
|
|
ut_a(col->len == DATA_ROW_ID_LEN);
|
|
ut_a(strcmp(s, "DB_ROW_ID") == 0);
|
|
s += strlen(s) + 1;
|
|
|
|
/* trx id */
|
|
col = table->get_col(n_cols - n_sys_cols + DATA_TRX_ID);
|
|
ut_a(col->mtype == DATA_SYS);
|
|
ut_a(col->prtype == (DATA_TRX_ID | DATA_NOT_NULL));
|
|
ut_a(col->len == DATA_TRX_ID_LEN);
|
|
ut_a(strcmp(s, "DB_TRX_ID") == 0);
|
|
} else {
|
|
n_sys_cols = DATA_N_SYS_COLS + DATA_N_LIZARD_COLS;
|
|
/** If there are only virtual columns in the table, the following
|
|
equality is reached */
|
|
ut_a(n_cols >= n_sys_cols);
|
|
|
|
for (i = 0; i < n_cols - n_sys_cols; i++) {
|
|
s += strlen(s) + 1;
|
|
}
|
|
/* Row id */
|
|
col = table->get_col(n_cols - n_sys_cols + DATA_ROW_ID);
|
|
ut_a(col->mtype == DATA_SYS);
|
|
ut_a(col->prtype == (DATA_ROW_ID | DATA_NOT_NULL));
|
|
ut_a(col->len == DATA_ROW_ID_LEN);
|
|
ut_a(strcmp(s, "DB_ROW_ID") == 0);
|
|
s += strlen(s) + 1;
|
|
|
|
/* trx id */
|
|
col = table->get_col(n_cols - n_sys_cols + DATA_TRX_ID);
|
|
ut_a(col->mtype == DATA_SYS);
|
|
ut_a(col->prtype == (DATA_TRX_ID | DATA_NOT_NULL));
|
|
ut_a(col->len == DATA_TRX_ID_LEN);
|
|
ut_a(strcmp(s, "DB_TRX_ID") == 0);
|
|
s += strlen(s) + 1;
|
|
|
|
/* roll ptr */
|
|
col = table->get_col(n_cols - n_sys_cols + DATA_ROLL_PTR);
|
|
ut_a(col->mtype == DATA_SYS);
|
|
ut_a(col->prtype == (DATA_ROLL_PTR | DATA_NOT_NULL));
|
|
ut_a(col->len == DATA_ROLL_PTR_LEN);
|
|
ut_a(strcmp(s, "DB_ROLL_PTR") == 0);
|
|
s += strlen(s) + 1;
|
|
|
|
/* scn id */
|
|
col = table->get_col(n_cols - n_sys_cols + DATA_SCN_ID);
|
|
ut_a(col->mtype == DATA_SYS);
|
|
ut_a(col->prtype == (DATA_SCN_ID | DATA_NOT_NULL));
|
|
ut_a(col->len == DATA_SCN_ID_LEN);
|
|
ut_a(strcmp(s, "DB_SCN_ID") == 0);
|
|
s += strlen(s) + 1;
|
|
|
|
/* undo ptr */
|
|
col = table->get_col(n_cols - n_sys_cols + DATA_UNDO_PTR);
|
|
ut_a(col->mtype == DATA_SYS);
|
|
ut_a(col->prtype == (DATA_UNDO_PTR | DATA_NOT_NULL));
|
|
ut_a(col->len == DATA_UNDO_PTR_LEN);
|
|
ut_a(strcmp(s, "DB_UNDO_PTR") == 0);
|
|
s += strlen(s) + 1;
|
|
|
|
/* gcn id */
|
|
col = table->get_col(n_cols - n_sys_cols + DATA_GCN_ID);
|
|
ut_a(col->mtype == DATA_SYS);
|
|
ut_a(col->prtype == (DATA_GCN_ID | DATA_NOT_NULL));
|
|
ut_a(col->len == DATA_GCN_ID_LEN);
|
|
ut_a(strcmp(s, "DB_GCN_ID") == 0);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
Check the dict_incex object
|
|
|
|
@param[in] index dict_index_t
|
|
|
|
@return true Success
|
|
*/
|
|
bool lizard_dict_index_check(const dict_index_t *index) {
|
|
bool is_clust;
|
|
size_t n_uniq;
|
|
dict_field_t *field;
|
|
dict_col_t *col;
|
|
const char *col_name;
|
|
|
|
ut_a(index);
|
|
assert_lizard_dict_table_check(index->table);
|
|
is_clust = index->is_clustered();
|
|
|
|
if (is_clust) {
|
|
if (!index->table->is_intrinsic()) {
|
|
n_uniq = index->n_uniq;
|
|
/* trx_id */
|
|
field = index->get_field(n_uniq);
|
|
col = field->col;
|
|
col_name = index->table->get_col_name(col->ind);
|
|
ut_a(strcmp(col_name, "DB_TRX_ID") == 0);
|
|
|
|
/* roll ptr */
|
|
field = index->get_field(n_uniq + 1);
|
|
col = field->col;
|
|
col_name = index->table->get_col_name(col->ind);
|
|
ut_a(strcmp(col_name, "DB_ROLL_PTR") == 0);
|
|
|
|
/* scn id */
|
|
field = index->get_field(n_uniq + 2);
|
|
col = field->col;
|
|
col_name = index->table->get_col_name(col->ind);
|
|
ut_a(strcmp(col_name, "DB_SCN_ID") == 0);
|
|
|
|
/* undo ptr */
|
|
field = index->get_field(n_uniq + 3);
|
|
col = field->col;
|
|
col_name = index->table->get_col_name(col->ind);
|
|
ut_a(strcmp(col_name, "DB_UNDO_PTR") == 0);
|
|
|
|
/* gcn id */
|
|
field = index->get_field(n_uniq + 4);
|
|
col = field->col;
|
|
col_name = index->table->get_col_name(col->ind);
|
|
ut_a(strcmp(col_name, "DB_GCN_ID") == 0);
|
|
} else {
|
|
n_uniq = index->n_uniq;
|
|
/* trx_id */
|
|
field = index->get_field(n_uniq);
|
|
col = field->col;
|
|
col_name = index->table->get_col_name(col->ind);
|
|
ut_a(strcmp(col_name, "DB_TRX_ID") == 0);
|
|
}
|
|
} else {
|
|
for (size_t i = 0; i < index->n_def; i++) {
|
|
field = index->get_field(i);
|
|
col = field->col;
|
|
if (col->is_virtual()) {
|
|
col_name = dict_table_get_v_col_name(
|
|
index->table,
|
|
((dict_v_col_t*)(col))->v_pos);
|
|
} else {
|
|
col_name = index->table->get_col_name(col->ind);
|
|
}
|
|
ut_a(strcmp(col_name, "DB_TRX_ID") != 0 &&
|
|
strcmp(col_name, "DB_ROLL_PTR") != 0 &&
|
|
strcmp(col_name, "DB_SCN_ID") != 0 &&
|
|
strcmp(col_name, "DB_UNDO_PTR") != 0 &&
|
|
strcmp(col_name, "DB_GCN_ID") != 0);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#endif /* UNIV_DEBUG || LIZARD_DEBUG define */
|
|
} // namespace lizard
|