4549 lines
196 KiB
C++
4549 lines
196 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#define USING_LOG_PREFIX SHARE_SCHEMA
|
|
#include "share/ob_define.h"
|
|
#include "lib/oblog/ob_log.h"
|
|
#include "lib/profile/ob_trace_id.h"
|
|
#include "lib/time/ob_time_utility.h"
|
|
#include "lib/container/ob_vector.h"
|
|
#include "lib/mysqlclient/ob_mysql_transaction.h"
|
|
#include "lib/utility/ob_print_utils.h"
|
|
#include "share/schema/ob_schema_getter_guard.h"
|
|
#include "share/schema/ob_multi_version_schema_service.h"
|
|
#include "share/schema/ob_schema_utils.h"
|
|
#include "share/schema/ob_schema_mgr.h"
|
|
#include "share/rc/ob_context.h"
|
|
#include "share/ob_schema_status_proxy.h"
|
|
#include "share/ob_global_stat_proxy.h"
|
|
// for materialized view
|
|
#include "sql/parser/ob_parser.h"
|
|
#include "sql/resolver/dml/ob_dml_resolver.h"
|
|
#include "sql/resolver/dml/ob_view_table_resolver.h"
|
|
#include "sql/session/ob_sql_session_info.h"
|
|
#include "observer/ob_server.h"
|
|
|
|
namespace oceanbase {
|
|
using namespace common;
|
|
using namespace common::hash;
|
|
using namespace oceanbase::sql;
|
|
using namespace oceanbase::observer;
|
|
|
|
namespace share {
|
|
namespace schema {
|
|
|
|
bool allow_lazy()
|
|
{
|
|
static volatile bool allow = false;
|
|
static int64_t last_check_ts = 0;
|
|
const static int CHECK_INTERVAL = 10 * 1000 * 1000; // 10s
|
|
|
|
if (!ATOMIC_LOAD(&allow)) {
|
|
// Before version 2.0, it must not be supported
|
|
if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2000) {
|
|
LOG_INFO("[SCHEMA] allow_lazy: cluster version is before 2.0, lazy mode is not allowed",
|
|
"cluster_version",
|
|
to_cstring(ObClusterVersion::get_instance()));
|
|
} else {
|
|
const int64_t now = ObTimeUtility::current_time();
|
|
if (now - last_check_ts < CHECK_INTERVAL) {
|
|
// do-nothing
|
|
} else {
|
|
int ret = OB_SUCCESS;
|
|
const ObTableSchema* index_table = NULL;
|
|
ObSchemaGetterGuard schema_guard;
|
|
const uint64_t index_table_id = combine_id(OB_SYS_TENANT_ID, OB_ALL_TABLE_HISTORY_IDX_DATA_TABLE_ID_TID);
|
|
int64_t schema_version = OB_INVALID_VERSION;
|
|
if (OB_FAIL(
|
|
ObMultiVersionSchemaService::get_instance().get_tenant_schema_guard(OB_SYS_TENANT_ID, schema_guard))) {
|
|
LOG_WARN("get schema guard failed", K(ret));
|
|
} else if (OB_FAIL(schema_guard.get_table_schema(index_table_id, index_table))) {
|
|
LOG_WARN("get table schema failed", K(ret));
|
|
} else if (OB_FAIL(schema_guard.get_schema_version(OB_SYS_TENANT_ID, schema_version))) {
|
|
LOG_WARN("fail to get schema_version", K(ret), K(schema_version));
|
|
} else if (NULL != index_table && index_table->can_read_index()) {
|
|
// open lazy mode
|
|
LOG_WARN("[SCHEMA] allow_lazy: __all_table_history index is ready, enable lazy mode on",
|
|
K(allow),
|
|
K(index_table_id),
|
|
K(schema_version));
|
|
ATOMIC_SET(&allow, true);
|
|
} else {
|
|
LOG_WARN("[SCHEMA] allow_lazy: __all_table_history index is not ready, "
|
|
"lazy mode is not allowed",
|
|
K(last_check_ts),
|
|
K(allow),
|
|
K(index_table_id),
|
|
K(schema_version));
|
|
}
|
|
last_check_ts = now;
|
|
}
|
|
}
|
|
} else {
|
|
LOG_DEBUG("[SCHEMA] allow_lazy: allow lazy mode", K(allow));
|
|
}
|
|
|
|
return allow;
|
|
}
|
|
|
|
bool ObMultiVersionSchemaService::g_skip_resolve_materialized_view_definition_ = false;
|
|
|
|
const char* ObMultiVersionSchemaService::print_refresh_schema_mode(const RefreshSchemaMode mode)
|
|
{
|
|
const char* mode_str = "UNKNOWN";
|
|
|
|
switch (mode) {
|
|
case NORMAL: {
|
|
mode_str = "normal";
|
|
break;
|
|
}
|
|
case FORCE_FALLBACK: {
|
|
mode_str = "force_fallback";
|
|
break;
|
|
}
|
|
case FORCE_LAZY: {
|
|
mode_str = "force_lazy";
|
|
break;
|
|
}
|
|
default: {
|
|
mode_str = "UNKNOWN";
|
|
break;
|
|
}
|
|
}
|
|
|
|
return mode_str;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
#define dbg_construct_task 0
|
|
|
|
ObSchemaConstructTask::ObSchemaConstructTask()
|
|
{
|
|
(void)pthread_mutex_init(&schema_mutex_, NULL);
|
|
(void)pthread_cond_init(&schema_cond_, NULL);
|
|
}
|
|
|
|
ObSchemaConstructTask::~ObSchemaConstructTask()
|
|
{
|
|
(void)pthread_mutex_destroy(&schema_mutex_);
|
|
(void)pthread_cond_destroy(&schema_cond_);
|
|
}
|
|
|
|
ObSchemaConstructTask& ObSchemaConstructTask::get_instance()
|
|
{
|
|
static ObSchemaConstructTask task;
|
|
return task;
|
|
}
|
|
|
|
// FIXME: After the schema is split, the schema_version between tenants may be repeated,
|
|
// but the probability is relatively small, and it can be changed to restrict concurrency by (tenant_id, version) later
|
|
// blocked if existing same version, or over max parallel size
|
|
void ObSchemaConstructTask::cc_before(const int64_t version)
|
|
{
|
|
lock();
|
|
if (count() == 0) {
|
|
// leader
|
|
} else {
|
|
do {
|
|
if (exist(version)) {
|
|
wait(version);
|
|
} else {
|
|
break;
|
|
}
|
|
} while (true);
|
|
}
|
|
|
|
do {
|
|
if (count() > MAX_PARALLEL_TASK) {
|
|
wait(version);
|
|
} else {
|
|
add(version);
|
|
unlock();
|
|
break;
|
|
}
|
|
} while (true);
|
|
}
|
|
|
|
// must called after cc_before
|
|
void ObSchemaConstructTask::cc_after(const int64_t version)
|
|
{
|
|
lock();
|
|
remove(version);
|
|
wakeup(version);
|
|
unlock();
|
|
}
|
|
|
|
void ObSchemaConstructTask::lock()
|
|
{
|
|
(void)pthread_mutex_lock(&schema_mutex_);
|
|
}
|
|
|
|
void ObSchemaConstructTask::unlock()
|
|
{
|
|
(void)pthread_mutex_unlock(&schema_mutex_);
|
|
}
|
|
|
|
void ObSchemaConstructTask::wait(const int64_t version)
|
|
{
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
|
ts.tv_sec += 1;
|
|
if (dbg_construct_task) {
|
|
LOG_WARN("task: waiting", K(version), K(count()));
|
|
}
|
|
int rc = 0;
|
|
do {
|
|
rc = pthread_cond_timedwait(&schema_cond_, &schema_mutex_, &ts);
|
|
} while (0);
|
|
(void)rc; // make compiler happy
|
|
}
|
|
|
|
void ObSchemaConstructTask::wakeup(const int64_t version)
|
|
{
|
|
if (dbg_construct_task) {
|
|
LOG_WARN("task: wakingup", K(version), K(count()));
|
|
}
|
|
(void)pthread_cond_broadcast(&schema_cond_);
|
|
}
|
|
|
|
int ObSchemaConstructTask::get_idx(int64_t id)
|
|
{
|
|
int hit_idx = -1;
|
|
for (int i = 0; i < schema_tasks_.count(); i++) {
|
|
if (id == schema_tasks_.at(i)) {
|
|
hit_idx = i;
|
|
break;
|
|
}
|
|
}
|
|
return hit_idx;
|
|
}
|
|
|
|
// must protected by mutex
|
|
void ObSchemaConstructTask::add(int64_t id)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_SUCCESS != (ret = schema_tasks_.push_back(id))) {
|
|
LOG_WARN("failed to push back task", K(id), K(ret));
|
|
}
|
|
|
|
if (dbg_construct_task) {
|
|
LOG_WARN("task: add ", K(id), K(count()));
|
|
}
|
|
}
|
|
|
|
// must protected by mutex
|
|
void ObSchemaConstructTask::remove(int64_t id)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int idx = get_idx(id);
|
|
if (idx != -1) {
|
|
if (OB_SUCCESS != (ret = schema_tasks_.remove(idx))) {
|
|
LOG_WARN("failed to remove task", K(id), K(ret));
|
|
}
|
|
} else {
|
|
LOG_WARN("failed to get task idx", K(id));
|
|
}
|
|
|
|
if (dbg_construct_task) {
|
|
LOG_WARN("task: remove", K(id), K(count()));
|
|
}
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::init_multi_version_schema_struct(const uint64_t tenant_id)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObSchemaStore* schema_store = NULL;
|
|
if (OB_ISNULL(schema_store = schema_store_map_.get(tenant_id))) {
|
|
if (OB_FAIL(schema_store_map_.create(tenant_id, init_version_cnt_, init_version_cnt_for_liboblog_))) {
|
|
LOG_WARN("fail to create schema store", K(ret), K(tenant_id));
|
|
}
|
|
} else {
|
|
LOG_INFO("schema store already exist", K(ret), K(tenant_id));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::update_schema_cache(
|
|
common::ObIArray<ObTableSchema*>& schema_array, const bool is_force)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
LOG_DEBUG("update schema cache", K(lbt()));
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < schema_array.count(); ++i) {
|
|
ObTableSchema* table = schema_array.at(i);
|
|
if (OB_ISNULL(table)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema is null", K(ret));
|
|
} else if ((OB_ALL_TABLE_HISTORY_TID == extract_pure_id(table->get_table_id()) ||
|
|
OB_ALL_TABLE_V2_HISTORY_TID == extract_pure_id(table->get_table_id()) ||
|
|
OB_ALL_BACKUP_PIECE_FILES_TID == extract_pure_id(table->get_table_id())) &&
|
|
table->get_index_tid_count() <= 0) {
|
|
// Prevent resetting index_tid_array in the second stage of refreshing the schema
|
|
uint64_t index_id = OB_INVALID_ID;
|
|
if (OB_ALL_TABLE_HISTORY_TID == extract_pure_id(table->get_table_id())) {
|
|
index_id = combine_id(table->get_tenant_id(), OB_ALL_TABLE_HISTORY_IDX_DATA_TABLE_ID_TID);
|
|
} else if (OB_ALL_TABLE_V2_HISTORY_TID == extract_pure_id(table->get_table_id())) {
|
|
index_id = combine_id(table->get_tenant_id(), OB_ALL_TABLE_V2_HISTORY_IDX_DATA_TABLE_ID_TID);
|
|
} else if (OB_ALL_BACKUP_PIECE_FILES_TID == extract_pure_id(table->get_table_id())) {
|
|
index_id = combine_id(table->get_tenant_id(), OB_ALL_BACKUP_PIECE_FILES_IDX_DATA_TABLE_ID_TID);
|
|
}
|
|
if (ObSchemaService::g_liboblog_mode_ && GET_MIN_CLUSTER_VERSION() <= CLUSTER_VERSION_2000) {
|
|
// skip
|
|
} else if (OB_FAIL(table->add_simple_index_info(ObAuxTableMetaInfo(index_id, USER_INDEX, OB_INVALID_VERSION)))) {
|
|
LOG_WARN("fail to add simple_index_info", K(ret), K(index_id));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(schema_cache_.put_schema(
|
|
TABLE_SCHEMA, table->get_table_id(), table->get_schema_version(), *table, is_force))) {
|
|
LOG_WARN("put schema failed", K(ret));
|
|
} else {
|
|
LOG_INFO("put schema succeed", K(*table));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::update_schema_cache(common::ObIArray<ObTableSchema>& schema_array, const bool is_force)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
LOG_DEBUG("update schema cache", K(lbt()));
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < schema_array.count(); ++i) {
|
|
ObTableSchema& table = schema_array.at(i);
|
|
if ((OB_ALL_TABLE_HISTORY_TID == extract_pure_id(table.get_table_id()) ||
|
|
OB_ALL_TABLE_V2_HISTORY_TID == extract_pure_id(table.get_table_id()) ||
|
|
OB_ALL_BACKUP_PIECE_FILES_TID == extract_pure_id(table.get_table_id())) &&
|
|
table.get_index_tid_count() <= 0) {
|
|
// Prevent resetting index_tid_array in the second stage of refreshing the schema
|
|
uint64_t index_id = OB_INVALID_ID;
|
|
if (OB_ALL_TABLE_HISTORY_TID == extract_pure_id(table.get_table_id())) {
|
|
index_id = combine_id(table.get_tenant_id(), OB_ALL_TABLE_HISTORY_IDX_DATA_TABLE_ID_TID);
|
|
} else if (OB_ALL_TABLE_V2_HISTORY_TID == extract_pure_id(table.get_table_id())) {
|
|
index_id = combine_id(table.get_tenant_id(), OB_ALL_TABLE_V2_HISTORY_IDX_DATA_TABLE_ID_TID);
|
|
} else if (OB_ALL_BACKUP_PIECE_FILES_TID == extract_pure_id(table.get_table_id())) {
|
|
index_id = combine_id(table.get_tenant_id(), OB_ALL_BACKUP_PIECE_FILES_IDX_DATA_TABLE_ID_TID);
|
|
}
|
|
if (ObSchemaService::g_liboblog_mode_ && GET_MIN_CLUSTER_VERSION() <= CLUSTER_VERSION_2000) {
|
|
// skip
|
|
} else if (OB_FAIL(table.add_simple_index_info(ObAuxTableMetaInfo(index_id, USER_INDEX, OB_INVALID_VERSION)))) {
|
|
LOG_WARN("fail to add simple_index_info", K(ret), K(index_id));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(schema_cache_.put_schema(
|
|
TABLE_SCHEMA, table.get_table_id(), table.get_schema_version(), table, is_force))) {
|
|
LOG_WARN("put schema failed", K(ret), "table_id", table.get_table_id());
|
|
} else {
|
|
LOG_INFO("put schema succeed", K(table));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::update_schema_cache(const common::ObIArray<ObTenantSchema>& schema_array)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
LOG_DEBUG("update schema cache", K(lbt()));
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < schema_array.count(); ++i) {
|
|
const ObTenantSchema& tenant = schema_array.at(i);
|
|
if (OB_FAIL(schema_cache_.put_schema(TENANT_SCHEMA, tenant.get_tenant_id(), tenant.get_schema_version(), tenant))) {
|
|
LOG_WARN("put schema failed", K(ret));
|
|
} else {
|
|
LOG_INFO("put schema succeed", K(tenant));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::update_schema_cache(const share::schema::ObSysVariableSchema& schema)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
LOG_DEBUG("update schema cache", K(lbt()));
|
|
if (OB_FAIL(
|
|
schema_cache_.put_schema(SYS_VARIABLE_SCHEMA, schema.get_tenant_id(), schema.get_schema_version(), schema))) {
|
|
LOG_WARN("put schema failed", K(ret));
|
|
} else {
|
|
LOG_INFO("put schema succeed", K(schema));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// for materialized view, construct the 'full schema' with 'column generated rules'
|
|
int ObMultiVersionSchemaService::build_full_materalized_view_schema(
|
|
ObSchemaGetterGuard& schema_guard, ObIAllocator& allocator, ObTableSchema*& view_schema)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
const uint64_t tenant_id = view_schema->get_tenant_id();
|
|
const ObTenantSchema* tenant_schema = NULL;
|
|
if (OB_FAIL(schema_guard.get_tenant_info(tenant_id, tenant_schema))) {
|
|
LOG_WARN("fail to get tenant schema", K(tenant_id), K(ret));
|
|
} else if (OB_ISNULL(tenant_schema)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL ptr", K(tenant_schema), K(ret));
|
|
} else {
|
|
ObParser parser(allocator, DEFAULT_MYSQL_MODE);
|
|
ParseResult view_result;
|
|
// parse view define
|
|
const ObString& view_def = view_schema->get_view_schema().get_view_definition();
|
|
if (OB_FAIL(parser.parse(view_def, view_result))) {
|
|
LOG_WARN("parse view defination failed", K(view_def), K(ret));
|
|
} else {
|
|
// resolve params
|
|
ObResolverParams resolver_ctx;
|
|
ObSchemaChecker schema_checker;
|
|
ObStmtFactory stmt_factory(allocator);
|
|
ObRawExprFactory expr_factory(allocator);
|
|
ObSQLSessionInfo default_session;
|
|
if (OB_FAIL(schema_checker.init(schema_guard))) {
|
|
LOG_WARN("fail to init schema_checker", K(ret));
|
|
} else if (OB_FAIL(default_session.init(0, 0, 0, &allocator))) {
|
|
LOG_WARN("init empty session failed", K(ret));
|
|
} else if (OB_FAIL(default_session.load_default_sys_variable(false, false))) {
|
|
LOG_WARN("session load default system variable failed", K(ret));
|
|
} else if (OB_FAIL(default_session.init_tenant(tenant_schema->get_tenant_name(), tenant_id))) {
|
|
LOG_WARN("fail to set tenant", "tenant", tenant_schema->get_tenant_name(), "id", tenant_id, K(ret));
|
|
} else {
|
|
resolver_ctx.allocator_ = &allocator;
|
|
resolver_ctx.schema_checker_ = &schema_checker;
|
|
resolver_ctx.session_info_ = &default_session;
|
|
resolver_ctx.stmt_factory_ = &stmt_factory;
|
|
resolver_ctx.expr_factory_ = &expr_factory;
|
|
resolver_ctx.query_ctx_ = stmt_factory.get_query_ctx();
|
|
ObSelectResolver view_resolver(resolver_ctx);
|
|
|
|
ParseNode* view_stmt_node = view_result.result_tree_->children_[0];
|
|
if (!view_stmt_node) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected children for view result after parse", K(ret));
|
|
} else if (OB_FAIL(view_resolver.resolve(*view_stmt_node))) {
|
|
LOG_WARN("resolve view definition failed", K(ret));
|
|
} else {
|
|
ObSelectStmt* select_stmt = view_resolver.get_select_stmt();
|
|
if (OB_ISNULL(select_stmt)) {
|
|
LOG_WARN("NULL ptr", K(ret), K(select_stmt));
|
|
} else if (OB_FAIL(view_resolver.make_materalized_view_schema(*select_stmt, *view_schema))) {
|
|
LOG_WARN("fail to make materialized view schema", K(ret), K(*view_schema));
|
|
} else {
|
|
LOG_INFO("make materialized view schema succeed", K(*view_schema));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// In order to facilitate the processing of the tenant_space table and index, the logic of updating the schema_cache
|
|
// is placed in the upper layer, and at the same time, the schema_guard is passed in to obtain the tenant schema
|
|
// Whether it is lazy mode is distinguished by whether mgr is NULL
|
|
int ObMultiVersionSchemaService::get_schema(const ObSchemaMgr* mgr, const ObRefreshSchemaStatus& schema_status,
|
|
const ObSchemaType schema_type, const uint64_t schema_id, const int64_t schema_version, ObKVCacheHandle& handle,
|
|
const ObSchema*& schema)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
schema = NULL;
|
|
|
|
const bool is_lazy = NULL == mgr;
|
|
uint64_t tenant_id = extract_tenant_id(schema_id);
|
|
if (TENANT_SCHEMA == schema_type || SYS_VARIABLE_SCHEMA == schema_type) {
|
|
tenant_id = schema_id;
|
|
}
|
|
if (TABLE_SIMPLE_SCHEMA == schema_type && !ObSchemaService::g_liboblog_mode_) {
|
|
// The simple table schema is currently only available for liboblog
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("fail to get simple table", K(ret), KP(mgr), K(schema_id), K(schema_version), K(lbt()));
|
|
} else if ((TABLE_SCHEMA == schema_type || TABLE_SIMPLE_SCHEMA == schema_type) &&
|
|
OB_ALL_CORE_TABLE_TID == extract_pure_id(schema_id)) {
|
|
schema = schema_cache_.get_all_core_table();
|
|
} else if (OB_FAIL(schema_cache_.get_schema(schema_type, schema_id, schema_version, handle, schema))) {
|
|
if (ret != OB_ENTRY_NOT_EXIST) {
|
|
LOG_WARN("get schema from cache failed", K(schema_type), K(schema_id), K(schema_version), K(ret));
|
|
} else {
|
|
ret = OB_SUCCESS;
|
|
LOG_DEBUG("schema cache miss", K(schema_type), K(schema_id), K(schema_version));
|
|
|
|
ObSchema* tmp_schema = NULL;
|
|
ObArenaAllocator allocator(ObModIds::OB_TEMP_VARIABLES);
|
|
|
|
// fetch schema and renew cache
|
|
// fetch schema
|
|
uint64_t fetch_schema_id = schema_id;
|
|
uint64_t fetch_tenant_id = tenant_id;
|
|
ObRefreshSchemaStatus fetch_schema_status = schema_status;
|
|
bool need_change = false;
|
|
if (OB_FAIL(need_change_schema_id(schema_type, schema_id, need_change))) {
|
|
LOG_WARN("fail to check if schema_id need change", K(ret), K(schema_type), K(schema_id));
|
|
} else if (need_change || TENANT_SCHEMA == schema_type) {
|
|
if (need_change) {
|
|
fetch_schema_id = combine_id(OB_SYS_TENANT_ID, schema_id);
|
|
}
|
|
fetch_tenant_id = OB_SYS_TENANT_ID;
|
|
fetch_schema_status.reset();
|
|
fetch_schema_status.tenant_id_ = schema_status.is_valid() ? OB_SYS_TENANT_ID : OB_INVALID_TENANT_ID;
|
|
}
|
|
|
|
bool has_hit = false;
|
|
// Use this to mark whether the schema exists in the specified version
|
|
bool not_exist = false;
|
|
// Query the version history dictionary table
|
|
if (OB_FAIL(ret)) {
|
|
} else if (is_lazy &&
|
|
(TENANT_SCHEMA == schema_type || TABLE_SCHEMA == schema_type || TABLE_SIMPLE_SCHEMA == schema_type ||
|
|
TABLEGROUP_SCHEMA == schema_type || DATABASE_SCHEMA == schema_type)) {
|
|
ObSchemaType fetch_schema_type = TABLE_SIMPLE_SCHEMA == schema_type ? TABLE_SCHEMA : schema_type;
|
|
VersionHisKey key(fetch_schema_type, fetch_schema_id);
|
|
VersionHisVal val;
|
|
if (OB_FAIL(get_schema_version_history(
|
|
fetch_schema_status, fetch_tenant_id, schema_version, key, val, not_exist))) {
|
|
LOG_WARN("fail to get schema version history",
|
|
K(ret),
|
|
K(fetch_schema_status),
|
|
K(fetch_tenant_id),
|
|
K(key),
|
|
K(schema_version));
|
|
} else if (fetch_schema_id != schema_id) {
|
|
// During the upgrade process, the schema_version of the system table corresponding to the system tenant
|
|
// may not be obtained. To avoid the fetch_schema error caused by the small schema_version input,
|
|
// try to fetch it again with the schema_id
|
|
if (not_exist || schema_version < val.min_version_) {
|
|
LOG_INFO("sys schema not found under specified version, try fetch again",
|
|
K(ret),
|
|
K(key),
|
|
K(val),
|
|
K(schema_version));
|
|
VersionHisKey fetch_key(fetch_schema_type, schema_id);
|
|
if (OB_FAIL(get_schema_version_history(
|
|
fetch_schema_status, fetch_tenant_id, schema_version, fetch_key, val, not_exist))) {
|
|
LOG_WARN("fail to get schema version history",
|
|
K(ret),
|
|
K(fetch_schema_status),
|
|
K(fetch_tenant_id),
|
|
K(fetch_key),
|
|
K(schema_version));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && !not_exist) {
|
|
int i = 0;
|
|
for (; i < val.valid_cnt_; ++i) {
|
|
if (val.versions_[i] <= schema_version) {
|
|
break;
|
|
}
|
|
}
|
|
if (i < val.valid_cnt_) {
|
|
const int64_t precise_version = val.versions_[i];
|
|
if (0 == i && val.is_deleted_) {
|
|
not_exist = true;
|
|
LOG_INFO("schema has been deleted under specified version",
|
|
K(ret),
|
|
K(key),
|
|
K(val),
|
|
K(schema_version),
|
|
K(precise_version));
|
|
} else {
|
|
// Access cache with accurate version
|
|
if (OB_FAIL(schema_cache_.get_schema(schema_type,
|
|
// Fetch_schema_id cannot be used here
|
|
schema_id,
|
|
precise_version,
|
|
handle,
|
|
schema))) {
|
|
if (ret != OB_ENTRY_NOT_EXIST) {
|
|
LOG_WARN("get schema from cache failed", K(key), K(schema_version), K(precise_version), K(ret));
|
|
} else {
|
|
ret = OB_SUCCESS;
|
|
}
|
|
} else {
|
|
// Accurate version hits, return directly
|
|
LOG_DEBUG("precise version hit",
|
|
K(key),
|
|
K(schema_version),
|
|
K(precise_version),
|
|
K(fetch_tenant_id),
|
|
K(schema_id),
|
|
"schema_type",
|
|
schema_type_str(schema_type));
|
|
has_hit = true;
|
|
}
|
|
}
|
|
} else if (schema_version < val.min_version_) {
|
|
not_exist = true;
|
|
LOG_INFO("schema has not been created under specified version", K(ret), K(key), K(val), K(schema_version));
|
|
} else {
|
|
// i >= cnt
|
|
// Older than the cached version, this situation is considered to be a very rare scenario,
|
|
// the "two" in the 28 theory
|
|
// directly uses the given schema_version to look up the table
|
|
LOG_INFO("precise version not founded since schema version is too old, "
|
|
"will retrieve it from inner table",
|
|
K(key),
|
|
K(val),
|
|
K(schema_version),
|
|
"schema_type",
|
|
schema_type_str(schema_type));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret) && !not_exist && !has_hit) {
|
|
ObWorker::CompatMode compat_mode = ObWorker::CompatMode::MYSQL;
|
|
if ((TABLE_SCHEMA == schema_type || TABLE_SIMPLE_SCHEMA == schema_type) &&
|
|
OB_FAIL(ObCompatModeGetter::get_tenant_mode(tenant_id, compat_mode))) {
|
|
LOG_WARN("failed to get_tenant_compat_mode", K(tenant_id), K(ret));
|
|
} else {
|
|
if (fetch_schema_id != schema_id) {
|
|
// use sys tenant here
|
|
compat_mode = ObWorker::CompatMode::MYSQL;
|
|
}
|
|
// FIXME: Reliance on thread local variables should be reduced as much as possible,
|
|
// and Oracle related processing needs to put lower layer in the future.
|
|
CompatModeGuard compat_mode_guard(compat_mode);
|
|
if (OB_FAIL(schema_fetcher_.fetch_schema(
|
|
schema_type, fetch_schema_status, fetch_schema_id, schema_version, allocator, tmp_schema))) {
|
|
LOG_WARN("fetch schema failed",
|
|
K(schema_type),
|
|
K(fetch_schema_id),
|
|
K(schema_version),
|
|
K(fetch_schema_status),
|
|
K(ret));
|
|
} else if (OB_ISNULL(tmp_schema)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL ptr", K(tmp_schema), K(ret));
|
|
}
|
|
if (OB_ERR_UNEXPECTED == ret) {
|
|
int tmp_ret = OB_SUCCESS;
|
|
// For newly-added tenant-level system tables, due to the order of table creation,
|
|
// the user tenant system table schema_version is too small. When the schema_version and fetch_schema_id of
|
|
// the user tenant system table are used to refresh the schema, an error of -4016 will be reported.
|
|
// In this case, the schema_id needs to be used again. test
|
|
if (fetch_schema_id == schema_id) {
|
|
} else if (OB_SUCCESS != (tmp_ret = schema_fetcher_.fetch_schema(schema_type,
|
|
fetch_schema_status, // system tenant
|
|
schema_id,
|
|
schema_version,
|
|
allocator,
|
|
tmp_schema))) {
|
|
LOG_WARN("fetch schema failed", K(schema_type), K(schema_id), K(schema_version), K(tmp_ret), K(ret));
|
|
} else if (OB_ISNULL(tmp_schema)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL ptr", K(tmp_schema), K(tmp_ret), K(ret));
|
|
} else {
|
|
ret = OB_SUCCESS; // override ret
|
|
LOG_INFO(
|
|
"fetch tenant space schema with precise schema version", K(schema_id), K(schema_version), K(ret));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (TABLE_SIMPLE_SCHEMA == schema_type) {
|
|
ObSimpleTableSchemaV2* table_schema = static_cast<ObSimpleTableSchemaV2*>(tmp_schema);
|
|
// process tenant space table
|
|
if (need_change) {
|
|
ObSimpleTableSchemaV2* dst_table = NULL;
|
|
if (OB_FAIL(make_tenant_space_schema(allocator, tenant_id, *table_schema, dst_table))) {
|
|
LOG_WARN("make tenant space schema failed", K(ret));
|
|
} else if (OB_ISNULL(dst_table)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL ptr", K(ret), K(dst_table));
|
|
} else {
|
|
tmp_schema = dst_table;
|
|
table_schema = dst_table;
|
|
}
|
|
}
|
|
} else if (TABLE_SCHEMA == schema_type) {
|
|
ObTableSchema* table_schema = static_cast<ObTableSchema*>(tmp_schema);
|
|
// process tenant space table
|
|
if (need_change) {
|
|
ObTableSchema* dst_table = NULL;
|
|
if (OB_FAIL(make_tenant_space_schema(allocator, tenant_id, *table_schema, dst_table))) {
|
|
LOG_WARN("make tenant space schema failed", K(ret));
|
|
} else if (OB_ISNULL(dst_table)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL ptr", K(ret), K(dst_table));
|
|
} else {
|
|
tmp_schema = dst_table;
|
|
table_schema = dst_table;
|
|
}
|
|
}
|
|
// process index
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_ALL_CORE_TABLE_TID == extract_pure_id(fetch_schema_id)) {
|
|
// do-nothing
|
|
} else if (table_schema->is_index_table() ||
|
|
(table_schema->is_view_table() && !table_schema->is_materialized_view())) {
|
|
// do-nothing
|
|
} else if ((OB_ALL_TABLE_HISTORY_TID == extract_pure_id(fetch_schema_id) ||
|
|
OB_ALL_TABLE_V2_HISTORY_TID == extract_pure_id(fetch_schema_id) ||
|
|
OB_ALL_BACKUP_PIECE_FILES_TID == extract_pure_id(fetch_schema_id)) &&
|
|
(!ObSchemaService::g_liboblog_mode_ || GET_MIN_CLUSTER_VERSION() > CLUSTER_VERSION_2000)) {
|
|
// The new version of OB and liboblog connect to clusters greater than 2.0, the system table index
|
|
// has taken effect, and index_tid_array can be constructed directly
|
|
uint64_t index_id = OB_INVALID_ID;
|
|
if (OB_ALL_TABLE_HISTORY_TID == extract_pure_id(fetch_schema_id)) {
|
|
index_id = combine_id(extract_tenant_id(schema_id), OB_ALL_TABLE_HISTORY_IDX_DATA_TABLE_ID_TID);
|
|
} else if (OB_ALL_TABLE_V2_HISTORY_TID == extract_pure_id(fetch_schema_id)) {
|
|
index_id = combine_id(extract_tenant_id(schema_id), OB_ALL_TABLE_V2_HISTORY_IDX_DATA_TABLE_ID_TID);
|
|
} else if (OB_ALL_BACKUP_PIECE_FILES_TID == extract_pure_id(fetch_schema_id)) {
|
|
index_id = combine_id(extract_tenant_id(schema_id), OB_ALL_BACKUP_PIECE_FILES_IDX_DATA_TABLE_ID_TID);
|
|
}
|
|
if (OB_FAIL(table_schema->add_simple_index_info(
|
|
ObAuxTableMetaInfo(index_id, USER_INDEX, OB_INVALID_VERSION)))) {
|
|
LOG_WARN("fail to add simple_index_info", K(ret), K(index_id));
|
|
}
|
|
} else if (is_lazy) {
|
|
ObSEArray<ObAuxTableMetaInfo, 8> aux_table_metas;
|
|
const int64_t table_schema_version = table_schema->get_schema_version();
|
|
if (OB_FAIL(schema_service_->fetch_aux_tables(fetch_schema_status,
|
|
fetch_tenant_id,
|
|
fetch_schema_id,
|
|
table_schema_version,
|
|
*sql_proxy_,
|
|
aux_table_metas))) {
|
|
LOG_WARN("get index failed", K(ret), K(fetch_schema_id), K(table_schema_version), K(schema_version));
|
|
} else {
|
|
FOREACH_CNT_X(tmp_aux_table_meta, aux_table_metas, OB_SUCC(ret))
|
|
{
|
|
const ObAuxTableMetaInfo& aux_table_meta = *tmp_aux_table_meta;
|
|
const uint64_t aux_table_tid = combine_id(tenant_id, extract_pure_id(aux_table_meta.table_id_));
|
|
if (USER_INDEX == aux_table_meta.table_type_) {
|
|
if (OB_FAIL(table_schema->add_simple_index_info(ObAuxTableMetaInfo(
|
|
aux_table_tid, aux_table_meta.table_type_, aux_table_meta.drop_schema_version_)))) {
|
|
LOG_WARN("fail to add simple_index_info", K(ret), K(aux_table_meta));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (OB_FAIL(add_aux_schema_from_mgr(*mgr, *table_schema, USER_INDEX))) {
|
|
LOG_WARN("get index schemas failed", K(ret), K(*table_schema));
|
|
} else if (OB_FAIL(add_aux_schema_from_mgr(*mgr, *table_schema, AUX_VERTIAL_PARTITION_TABLE))) {
|
|
LOG_WARN("get aux vp table schemas failed", K(ret), K(*table_schema));
|
|
}
|
|
}
|
|
}
|
|
// process mv
|
|
if (OB_SUCC(ret)) {
|
|
if (MATERIALIZED_VIEW == table_schema->get_table_type() &&
|
|
!g_skip_resolve_materialized_view_definition_) {
|
|
// Ideally, the current function should no longer rely on schema_guard,
|
|
// but in order to deal with compatibility, it has to be used here
|
|
ObSchemaGetterGuard schema_guard;
|
|
const ObSimpleTableSchemaV2* mv_schema = NULL;
|
|
if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed", K(ret));
|
|
} else if (OB_FAIL(schema_guard.get_table_schema(schema_id, mv_schema))) {
|
|
LOG_WARN("get table schema failed", K(schema_id), K(ret));
|
|
} else if (mv_schema != NULL && mv_schema->get_schema_version() == schema_version) {
|
|
// do-nothing
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard, schema_version, true))) {
|
|
LOG_WARN("get schema guard failed", K(schema_version), K(ret));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(build_full_materalized_view_schema(schema_guard, allocator, table_schema))) {
|
|
LOG_WARN("fail to make columns for materialized table schema", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
int64_t precise_version = schema_version;
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_ISNULL(tmp_schema)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL ptr", K(tmp_schema), K(ret));
|
|
} else if (TABLE_SCHEMA == schema_type) {
|
|
ObTableSchema* table_schema = static_cast<ObTableSchema*>(tmp_schema);
|
|
precise_version = table_schema->get_schema_version();
|
|
// add debug info
|
|
if (OB_ALL_TABLE_HISTORY_TID == extract_pure_id(table_schema->get_table_id()) ||
|
|
OB_ALL_TABLE_V2_HISTORY_TID == extract_pure_id(table_schema->get_table_id()) ||
|
|
OB_ALL_BACKUP_PIECE_FILES_TID == extract_pure_id(table_schema->get_table_id())) {
|
|
ObTaskController::get().allow_next_syslog();
|
|
LOG_INFO("fetch __all_table_history schema",
|
|
K(ret),
|
|
K(schema_status),
|
|
K(fetch_schema_status),
|
|
K(schema_id),
|
|
K(schema_version),
|
|
K(precise_version),
|
|
"schema_mgr_version",
|
|
OB_ISNULL(mgr) ? 0 : mgr->get_schema_version(),
|
|
"table_name",
|
|
table_schema->get_table_name(),
|
|
"index_cnt",
|
|
table_schema->get_index_tid_count());
|
|
}
|
|
} else if (TABLE_SIMPLE_SCHEMA == schema_type) {
|
|
ObSimpleTableSchemaV2* table_schema = static_cast<ObSimpleTableSchemaV2*>(tmp_schema);
|
|
precise_version = table_schema->get_schema_version();
|
|
} else if (TENANT_SCHEMA == schema_type) {
|
|
ObTenantSchema* tenant_schema = static_cast<ObTenantSchema*>(tmp_schema);
|
|
precise_version = tenant_schema->get_schema_version();
|
|
} else if (TABLEGROUP_SCHEMA == schema_type) {
|
|
ObTablegroupSchema* tablegroup_schema = static_cast<ObTablegroupSchema*>(tmp_schema);
|
|
precise_version = tablegroup_schema->get_schema_version();
|
|
} else if (DATABASE_SCHEMA == schema_type) {
|
|
ObDatabaseSchema* database_schema = static_cast<ObDatabaseSchema*>(tmp_schema);
|
|
precise_version = database_schema->get_schema_version();
|
|
}
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
if (OB_SUCC(ret) && is_lazy) {
|
|
// The expectation of lazy mode is to use the specific schema's schema_version to take guard.
|
|
// add a check to see if there is any usage that does not match the expected behavior.
|
|
if (TABLE_SCHEMA == schema_type || TABLE_SIMPLE_SCHEMA == schema_type || TENANT_SCHEMA == schema_type ||
|
|
TABLEGROUP_SCHEMA == schema_type || DATABASE_SCHEMA == schema_type) {
|
|
if (precise_version != schema_version) {
|
|
LOG_INFO("schema_version not match in lazy mode",
|
|
K(ret),
|
|
K(precise_version),
|
|
K(schema_version),
|
|
K(schema_id),
|
|
K(schema_type),
|
|
K(lbt()));
|
|
}
|
|
} else {
|
|
LOG_INFO("schema_type not match in lazy mode",
|
|
K(ret),
|
|
K(schema_version),
|
|
K(schema_id),
|
|
K(schema_type),
|
|
K(lbt()));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// renew cache
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(schema_cache_.put_and_fetch_schema(
|
|
schema_type, schema_id, precise_version, *tmp_schema, handle, schema))) {
|
|
LOG_WARN("put and fetch schema failed",
|
|
K(schema_type),
|
|
K(schema_id),
|
|
K(precise_version),
|
|
K(schema_version),
|
|
KR(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::add_aux_schema_from_mgr(
|
|
const ObSchemaMgr& mgr, ObTableSchema& table_schema, const ObTableType table_type)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSEArray<const ObSimpleTableSchemaV2*, 8> simple_aux_tables;
|
|
if (OB_FAIL(mgr.get_aux_schemas(table_schema.get_table_id(), simple_aux_tables, table_type))) {
|
|
LOG_WARN("get aux table schemas failed", K(ret), K(table_schema.get_table_id()));
|
|
} else {
|
|
FOREACH_CNT_X(tmp_simple_aux_table, simple_aux_tables, OB_SUCC(ret))
|
|
{
|
|
const ObSimpleTableSchemaV2* simple_aux_table = *tmp_simple_aux_table;
|
|
if (OB_ISNULL(simple_aux_table)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL ptr", K(ret));
|
|
} else {
|
|
if (simple_aux_table->is_index_table() || simple_aux_table->is_materialized_view()) {
|
|
if (OB_FAIL(table_schema.add_simple_index_info(ObAuxTableMetaInfo(simple_aux_table->get_table_id(),
|
|
simple_aux_table->get_table_type(),
|
|
simple_aux_table->get_drop_schema_version())))) {
|
|
LOG_WARN("fail to add simple_index_info", K(ret), K(*simple_aux_table));
|
|
}
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("unexpected", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Tenant-level system tables are restricted to non-partitioned tables
|
|
int ObMultiVersionSchemaService::make_tenant_space_schema(ObIAllocator& allocator, const uint64_t tenant_id,
|
|
const ObSimpleTableSchemaV2& src_table, ObSimpleTableSchemaV2*& dst_table)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
dst_table = NULL;
|
|
|
|
if (OB_INVALID_TENANT_ID == src_table.get_tenant_id()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(src_table.get_tenant_id()));
|
|
} else {
|
|
ObSimpleTableSchemaV2* allocated_table = NULL;
|
|
ObSimpleTableSchemaV2 tmp_table;
|
|
if (OB_FAIL(tmp_table.assign(src_table))) {
|
|
LOG_WARN("fail to assign schema", K(ret));
|
|
} else {
|
|
tmp_table.set_tenant_id(tenant_id);
|
|
tmp_table.set_table_id(combine_id(tenant_id, tmp_table.get_table_id()));
|
|
if (tmp_table.get_tablegroup_id() != OB_INVALID_ID) {
|
|
tmp_table.set_tablegroup_id(combine_id(tenant_id, tmp_table.get_tablegroup_id()));
|
|
}
|
|
if (tmp_table.get_data_table_id() > 0) {
|
|
tmp_table.set_data_table_id(combine_id(tenant_id, tmp_table.get_data_table_id()));
|
|
}
|
|
tmp_table.set_database_id(combine_id(tenant_id, tmp_table.get_database_id()));
|
|
tmp_table.set_primary_zone(ObString());
|
|
tmp_table.set_locality(ObString());
|
|
tmp_table.set_previous_locality(ObString());
|
|
ObArray<ObString> empty_zones;
|
|
tmp_table.set_zone_list(empty_zones);
|
|
if (tmp_table.has_partition()) {
|
|
// reset partition option
|
|
tmp_table.reset_partition_schema();
|
|
tmp_table.get_part_option().set_max_used_part_id(0);
|
|
tmp_table.get_part_option().set_partition_cnt_within_partition_table(0);
|
|
}
|
|
if (ObSchemaUtils::alloc_schema(allocator, tmp_table, allocated_table)) {
|
|
LOG_WARN("alloc table failed", K(ret));
|
|
} else if (OB_ISNULL(allocated_table)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL ptr", K(ret), K(allocated_table));
|
|
} else {
|
|
dst_table = allocated_table;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Tenant-level system tables are restricted to non-partitioned tables
|
|
int ObMultiVersionSchemaService::make_tenant_space_schema(
|
|
ObIAllocator& allocator, const uint64_t tenant_id, const ObTableSchema& src_table, ObTableSchema*& dst_table)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
dst_table = NULL;
|
|
|
|
if (OB_INVALID_TENANT_ID == src_table.get_tenant_id()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(src_table.get_tenant_id()));
|
|
} else {
|
|
ObTableSchema* allocated_table = NULL;
|
|
ObTableSchema tmp_table;
|
|
if (OB_FAIL(tmp_table.assign(src_table))) {
|
|
LOG_WARN("fail to assign schema", K(ret));
|
|
} else {
|
|
tmp_table.set_tenant_id(tenant_id);
|
|
tmp_table.set_table_id(combine_id(tenant_id, tmp_table.get_table_id()));
|
|
if (tmp_table.get_tablegroup_id() != OB_INVALID_ID) {
|
|
tmp_table.set_tablegroup_id(combine_id(tenant_id, tmp_table.get_tablegroup_id()));
|
|
}
|
|
if (tmp_table.get_data_table_id() > 0) {
|
|
tmp_table.set_data_table_id(combine_id(tenant_id, tmp_table.get_data_table_id()));
|
|
}
|
|
tmp_table.set_database_id(combine_id(tenant_id, tmp_table.get_database_id()));
|
|
tmp_table.set_primary_zone(ObString());
|
|
tmp_table.set_locality(ObString());
|
|
tmp_table.set_previous_locality(ObString());
|
|
ObArray<ObString> empty_zones;
|
|
tmp_table.set_zone_list(empty_zones);
|
|
if (tmp_table.has_partition()) {
|
|
// reset partition option
|
|
tmp_table.reset_partition_schema();
|
|
tmp_table.get_part_option().set_max_used_part_id(0);
|
|
tmp_table.get_part_option().set_partition_cnt_within_partition_table(0);
|
|
}
|
|
if (OB_FAIL(update_table_columns(tenant_id, tmp_table))) {
|
|
LOG_WARN("update_table_columns failed", K(tenant_id), K(tmp_table), K(ret));
|
|
} else if (ObSchemaUtils::alloc_schema(allocator, tmp_table, allocated_table)) {
|
|
LOG_WARN("alloc table failed", K(ret));
|
|
} else if (OB_ISNULL(allocated_table)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL ptr", K(ret), K(allocated_table));
|
|
} else {
|
|
dst_table = allocated_table;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::put_fallback_liboblog_schema_to_slot(ObSchemaMgrCache& schema_mgr_cache_for_liboblog,
|
|
ObSchemaMemMgr& mem_mgr_for_liboblog, ObSchemaMgr*& target_mgr, ObSchemaMgrHandle& handle)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(put_fallback_schema_to_slot(target_mgr, schema_mgr_cache_for_liboblog, mem_mgr_for_liboblog, handle))) {
|
|
LOG_WARN("put fallback schema to slot failed", K(ret));
|
|
} else {
|
|
// protect by the lock mem_mgr_for_liboblog_mutex_, so no concurrent here
|
|
static int64_t last_dump_time = 0;
|
|
int64_t current_time = ObTimeUtility::current_time();
|
|
if (current_time - last_dump_time > 60000000) { // print every 60 seconds
|
|
schema_mgr_cache_for_liboblog_.dump();
|
|
last_dump_time = current_time;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* put fallback schema to slot for liboblog and check need to switch allocator
|
|
*/
|
|
int ObMultiVersionSchemaService::put_fallback_schema_to_slot(ObSchemaMgr*& new_mgr, ObSchemaMgrCache& schema_mgr_cache,
|
|
ObSchemaMemMgr& schema_mem_mgr, ObSchemaMgrHandle& handle)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSchemaMgr* eli_schema_mgr = NULL;
|
|
const int64_t start_time = ObTimeUtility::current_time();
|
|
if (OB_FAIL(schema_mgr_cache.put(new_mgr, eli_schema_mgr, &handle))) {
|
|
LOG_WARN("put schema mgr failed", K(ret));
|
|
} else {
|
|
int64_t cost = ObTimeUtility::current_time() - start_time;
|
|
LOG_INFO("put schema mgr succeed",
|
|
K(cost),
|
|
"schema_version",
|
|
new_mgr->get_schema_version(),
|
|
"eliminated_schema_version",
|
|
NULL != eli_schema_mgr ? eli_schema_mgr->get_schema_version() : OB_INVALID_VERSION);
|
|
if (OB_NOT_NULL(eli_schema_mgr)) {
|
|
LOG_INFO("[SCHEMA_RELEASE] free schema mgr",
|
|
"tenant_id",
|
|
eli_schema_mgr->get_tenant_id(),
|
|
"schema_version",
|
|
eli_schema_mgr->get_schema_version());
|
|
eli_schema_mgr->~ObSchemaMgr();
|
|
if (OB_FAIL(schema_mem_mgr.free(static_cast<void*>(eli_schema_mgr)))) {
|
|
LOG_WARN("free eli schema mgr falied", K(ret));
|
|
} else {
|
|
// The allocator of the schema_mgr generated by the schema fallback is independent
|
|
// and does not need to be released through switch_allocator.
|
|
// For the current use scenarios of OB, liboblog, and agentserver in 2.x, fallback will not consume
|
|
// non-latest schema mgr for a long time, and the memory release of schema_mgr generated by fallback
|
|
// can be accelerated through background thread inspection.
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::alloc_schema_mgr_for_liboblog(
|
|
ObSchemaMemMgr& mem_mgr_for_liboblog, ObSchemaMgr*& schema_mgr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSchemaMgr* new_mgr = NULL;
|
|
void* tmp_ptr = NULL;
|
|
ObIAllocator* allocator = NULL;
|
|
if (OB_FAIL(mem_mgr_for_liboblog.alloc(sizeof(ObSchemaMgr), tmp_ptr, &allocator))) {
|
|
LOG_WARN("alloc mem for liboblog falied", K(ret));
|
|
} else if (OB_ISNULL(allocator) || OB_ISNULL(tmp_ptr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("tmp ptr or allocator is null", K(ret), K(tmp_ptr), K(allocator));
|
|
} else {
|
|
new_mgr = new (tmp_ptr) ObSchemaMgr();
|
|
schema_mgr = new_mgr;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::free_schema_mgr_for_liboblog(
|
|
ObSchemaMemMgr& mem_mgr_for_liboblog, ObSchemaMgr* schema_mgr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_NOT_NULL(schema_mgr)) {
|
|
LOG_INFO("[SCHEMA_RELEASE] free schema mgr",
|
|
"tenant_id",
|
|
schema_mgr->get_tenant_id(),
|
|
"schema_version",
|
|
schema_mgr->get_schema_version());
|
|
schema_mgr->~ObSchemaMgr();
|
|
if (OB_FAIL(mem_mgr_for_liboblog.free(static_cast<void*>(schema_mgr)))) {
|
|
LOG_ERROR("free schema_mgr for liboblog failed", K(ret), K(schema_mgr));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* fallback to target_version
|
|
*
|
|
*/
|
|
int ObMultiVersionSchemaService::fallback_schema_mgr_for_liboblog(const ObRefreshSchemaStatus& schema_status,
|
|
const int64_t target_version, const int64_t latest_local_version, const ObSchemaMgr*& schema_mgr,
|
|
ObSchemaMgrHandle& handle)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSchemaMgrCache* schema_mgr_cache_for_liboblog = &schema_mgr_cache_for_liboblog_;
|
|
ObSchemaMemMgr* mem_mgr_for_liboblog = &mem_mgr_for_liboblog_;
|
|
ObSchemaMgrCache* schema_mgr_cache = &schema_mgr_cache_;
|
|
// add concurrency control for fallback
|
|
ObSchemaConstructTask& task = ObSchemaConstructTask::get_instance();
|
|
uint64_t tenant_id = schema_status.tenant_id_;
|
|
task.cc_before(target_version);
|
|
if (OB_INVALID_TENANT_ID != tenant_id) {
|
|
// Determine whether the schema has been split according to whether the tenant_id is legal
|
|
ObSchemaStore* schema_store = NULL;
|
|
if (NULL == (schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
LOG_WARN("fail to get schema_store", K(ret));
|
|
} else if (OB_FAIL(mem_mgr_for_liboblog_map_.get_refactored(tenant_id, mem_mgr_for_liboblog))) {
|
|
LOG_WARN("fail to get mem mgr", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(mem_mgr_for_liboblog)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("mem_mgr is null", K(ret), K(tenant_id));
|
|
} else {
|
|
schema_mgr_cache = &schema_store->schema_mgr_cache_;
|
|
schema_mgr_cache_for_liboblog = &schema_store->schema_mgr_cache_for_liboblog_;
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(schema_mgr_cache_for_liboblog->get(target_version, schema_mgr, handle))) {
|
|
if (OB_ENTRY_NOT_EXIST != ret) {
|
|
LOG_WARN("get schema mgr failed", K(ret), K(target_version));
|
|
schema_mgr_cache_for_liboblog->dump();
|
|
} else if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN(
|
|
"full schema is not ready, cann't get fallback schema guard", K(ret), K(schema_status), K(target_version));
|
|
} else {
|
|
LOG_INFO("[FALLBACK_SCHEMA] schema mgr cache for liboblog miss", K(schema_status), K(target_version));
|
|
const ObSchemaMgr* target_mgr = NULL;
|
|
ObSchemaMgrHandle target_mgr_handle;
|
|
// true if 1) miss in fallback OR 2) hit but with larger abs
|
|
bool need_extra_get = false;
|
|
|
|
// for faster fallback, find the schema manager with nearest version:
|
|
ret = schema_mgr_cache_for_liboblog->get_nearest(target_version, target_mgr, target_mgr_handle);
|
|
if (OB_FAIL(ret)) {
|
|
if (OB_ENTRY_NOT_EXIST != ret) {
|
|
LOG_ERROR("get_nearest schema_mgr failed", K(ret), K(schema_status), K(target_version));
|
|
} else {
|
|
need_extra_get = true;
|
|
LOG_INFO("get from liboblog slot failed, need extra get", K(ret), K(schema_status), K(target_version));
|
|
}
|
|
} else {
|
|
if (NULL == target_mgr) {
|
|
ret = OB_SCHEMA_ERROR;
|
|
LOG_ERROR("get target_mgr is NULL", K(ret), K(schema_status), K(target_version));
|
|
} else if (llabs(target_mgr->get_schema_version() - target_version) >
|
|
llabs(latest_local_version - target_version)) {
|
|
need_extra_get = true;
|
|
LOG_INFO("get from liboblog slot failed, need extra get",
|
|
K(ret),
|
|
K(schema_status),
|
|
K(target_version),
|
|
K(latest_local_version));
|
|
}
|
|
}
|
|
|
|
if (need_extra_get) {
|
|
// reset to success due to might OB_ENTRY_NOT_EXIST
|
|
if (OB_FAIL(schema_mgr_cache->get(latest_local_version, target_mgr, target_mgr_handle))) {
|
|
LOG_WARN("get schema mgr failed", K(ret), K(schema_status), K(target_version), K(latest_local_version));
|
|
schema_mgr_cache_.dump();
|
|
} else if (NULL == target_mgr) {
|
|
ret = OB_SCHEMA_ERROR;
|
|
LOG_ERROR("get target_mgr is NULL", K(ret), K(schema_status), K(target_version));
|
|
} else {
|
|
}
|
|
}
|
|
|
|
int64_t from_version = OB_INVALID_VERSION;
|
|
ObSchemaMgr tmp_mgr;
|
|
if (OB_SUCC(ret)) {
|
|
lib::ObMutexGuard mutex_guard(mem_mgr_for_liboblog_mutex_);
|
|
from_version = target_mgr->get_schema_version();
|
|
if (OB_FAIL(tmp_mgr.init())) {
|
|
LOG_WARN("init tmp_mgr failed", K(ret), K(schema_status), K(from_version), K(target_version));
|
|
} else {
|
|
const int64_t start = ObTimeUtility::current_time();
|
|
if (OB_FAIL(tmp_mgr.deep_copy(*target_mgr))) {
|
|
LOG_WARN("deep copy schema_mgr failed", K(ret), K(schema_status), K(from_version), K(target_version));
|
|
}
|
|
LOG_INFO("deep copy schema_mgr cost",
|
|
"cost",
|
|
ObTimeUtility::current_time() - start,
|
|
K(schema_status),
|
|
K(from_version),
|
|
K(target_version));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
ObSchemaMgr* new_mgr = NULL;
|
|
target_mgr_handle.reset();
|
|
if (OB_FAIL(fallback_schema_mgr(schema_status, tmp_mgr, target_version))) {
|
|
LOG_WARN("fallback schema mgr falied", K(ret), K(schema_status), K(from_version), K(target_version));
|
|
} else if (OB_FAIL(alloc_schema_mgr_for_liboblog(*mem_mgr_for_liboblog, new_mgr))) {
|
|
LOG_WARN(
|
|
"alloc schema mgr for liboblog failed", K(ret), K(schema_status), K(from_version), K(target_version));
|
|
} else if (OB_ISNULL(new_mgr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("new_mgr is null", K(ret), K(schema_status), K(from_version), K(target_version));
|
|
} else if (OB_FAIL(new_mgr->init())) {
|
|
LOG_WARN("init new_mgr failed", K(ret), K(schema_status), K(from_version), K(target_version));
|
|
} else {
|
|
const int64_t start = ObTimeUtility::current_time();
|
|
if (OB_FAIL(new_mgr->deep_copy(tmp_mgr))) {
|
|
LOG_WARN("fail to copy mgr", K(ret));
|
|
}
|
|
LOG_INFO("deep copy schema_mgr cost", "cost", ObTimeUtility::current_time() - start);
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(put_fallback_liboblog_schema_to_slot(
|
|
*schema_mgr_cache_for_liboblog, *mem_mgr_for_liboblog, new_mgr, handle))) {
|
|
LOG_WARN("put fallback schema to slot failed", K(ret));
|
|
} else {
|
|
schema_mgr = new_mgr;
|
|
}
|
|
}
|
|
if (OB_FAIL(ret) && !OB_ISNULL(new_mgr)) {
|
|
int tmp_ret = OB_SUCCESS;
|
|
schema_mgr = NULL;
|
|
if (OB_SUCCESS != (tmp_ret = free_schema_mgr_for_liboblog(*mem_mgr_for_liboblog, new_mgr))) {
|
|
LOG_ERROR("fail to free schema mgr", K(ret), K(tmp_ret), K(from_version));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LOG_INFO("[FALLBACK_SCHEMA] fallback schema mgr for liboblog finish",
|
|
K(ret),
|
|
K(schema_status),
|
|
K(from_version),
|
|
K(target_version),
|
|
K(lbt()));
|
|
}
|
|
} else {
|
|
LOG_DEBUG("[FALLBACK_SCHEMA] get schema_mgr from cache", K(schema_status), K(target_version));
|
|
}
|
|
task.cc_after(target_version);
|
|
return ret;
|
|
}
|
|
|
|
// Schema_guard implementation before schema split
|
|
int ObMultiVersionSchemaService::get_inner_schema_guard(ObSchemaGetterGuard& guard,
|
|
int64_t schema_version /* = common::OB_INVALID_VERSION*/,
|
|
const RefreshSchemaMode refresh_schema_mode /* = RefreshSchemaMode::NORMAL */)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t latest_local_version = OB_INVALID_VERSION;
|
|
int64_t snapshot_version = OB_INVALID_VERSION;
|
|
bool is_standby_cluster = false;
|
|
if (OB_FAIL(guard.fast_reset())) {
|
|
LOG_WARN("fail to reset guard", K(ret));
|
|
} else if (OB_FAIL(guard.init(is_standby_cluster))) {
|
|
LOG_WARN("fail to init guard", K(ret));
|
|
} else if (OB_FAIL(get_tenant_refreshed_schema_version(OB_SYS_TENANT_ID, latest_local_version))) {
|
|
LOG_WARN("fail to get latest_local_version", K(ret));
|
|
} else if (schema_version > latest_local_version) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("specified schema version larger than latest schema version, need retry",
|
|
K(ret),
|
|
"specified schema version",
|
|
schema_version,
|
|
"latest schema version",
|
|
latest_local_version,
|
|
K(lbt()));
|
|
} else if (OB_INVALID_VERSION == schema_version) {
|
|
snapshot_version = latest_local_version;
|
|
} else {
|
|
snapshot_version = schema_version;
|
|
// liboblog need not care baseline schema version
|
|
if (!ObSchemaService::g_liboblog_mode_) {
|
|
// for max avaliablity, ignore tmp_ret
|
|
int tmp_ret = OB_SUCCESS;
|
|
int64_t baseline_schema_version = -1;
|
|
if (OB_SUCCESS != (tmp_ret = get_baseline_schema_version(baseline_schema_version))) {
|
|
LOG_WARN("get baseline schema version failed", K(tmp_ret));
|
|
} else if (baseline_schema_version != -1 && schema_version < baseline_schema_version) {
|
|
LOG_INFO("change schema version to baseline",
|
|
"schema version",
|
|
schema_version,
|
|
"baseline version",
|
|
baseline_schema_version);
|
|
snapshot_version = baseline_schema_version;
|
|
}
|
|
}
|
|
}
|
|
|
|
const ObSchemaMgr* schema_mgr = NULL;
|
|
ObSchemaMgrHandle handle;
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(schema_mgr_cache_.get(snapshot_version, schema_mgr, handle))) {
|
|
if (OB_ENTRY_NOT_EXIST != ret) {
|
|
LOG_WARN("get schema mgr failed", K(ret), K(snapshot_version));
|
|
} else if (RefreshSchemaMode::FORCE_LAZY == refresh_schema_mode) {
|
|
ret = OB_SUCCESS;
|
|
} else if (!allow_lazy() || (RefreshSchemaMode::FORCE_FALLBACK == refresh_schema_mode)) {
|
|
// fallback
|
|
ObRefreshSchemaStatus dummy_schema_status;
|
|
if (OB_FAIL(schema_mgr_cache_for_liboblog_.get(snapshot_version, schema_mgr, handle))) {
|
|
if (OB_ENTRY_NOT_EXIST != ret) {
|
|
LOG_WARN("get schema mgr failed", K(ret), K(snapshot_version));
|
|
} else if (OB_FAIL(fallback_schema_mgr_for_liboblog(
|
|
dummy_schema_status, snapshot_version, latest_local_version, schema_mgr, handle))) {
|
|
LOG_WARN("fallback schema mgr for liboblog failed", K(ret), K(snapshot_version), K(latest_local_version));
|
|
}
|
|
}
|
|
} else {
|
|
ret = OB_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
guard.snapshot_version_ = snapshot_version;
|
|
guard.schema_service_ = this;
|
|
guard.mgr_ = schema_mgr;
|
|
guard.mgr_handle_ = handle;
|
|
guard.schema_guard_type_ = ObSchemaGetterGuard::SCHEMA_GUARD;
|
|
LOG_DEBUG("use schema guard with old mode", K(ret), K(snapshot_version));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::get_schema_guard(
|
|
ObSchemaGetterGuard& guard, const RefreshSchemaMode refresh_schema_mode /* = RefreshSchemaMode::NORMAL */)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_schema_splited = GCTX.is_schema_splited();
|
|
bool is_standby_cluster = GCTX.is_standby_cluster();
|
|
int64_t schema_version = OB_INVALID_VERSION;
|
|
if (!is_schema_splited) {
|
|
// old schema refresh
|
|
if (OB_FAIL(get_inner_schema_guard(guard, schema_version, refresh_schema_mode))) {
|
|
LOG_WARN("fail to get schema guard",
|
|
K(schema_version),
|
|
"refresh_schema_mode",
|
|
print_refresh_schema_mode(refresh_schema_mode));
|
|
}
|
|
} else {
|
|
// new schema refresh
|
|
int64_t sys_snapshot_version = OB_INVALID_VERSION;
|
|
ObSchemaStore* sys_schema_store = NULL;
|
|
ObSEArray<uint64_t, 1> tenant_ids;
|
|
bool restore_tenant_exist = true;
|
|
if (OB_INVALID_VERSION != schema_version) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN(
|
|
"failed to get schema guard with specified schema_version after schema splited", K(ret), K(schema_version));
|
|
} else if (OB_FAIL(guard.fast_reset())) {
|
|
LOG_WARN("fail to reset guard", K(ret));
|
|
} else if (OB_FAIL(guard.init(is_standby_cluster))) {
|
|
LOG_WARN("fail to init guard", K(ret));
|
|
} else if (OB_FAIL(get_tenant_refreshed_schema_version(OB_SYS_TENANT_ID, sys_snapshot_version))) {
|
|
LOG_WARN("fail to get sys refreshed schema version", K(ret));
|
|
} else if (ObSchemaService::g_liboblog_mode_) {
|
|
// // Avoid using schema_status_proxy for agentserver and liboblog
|
|
restore_tenant_exist = false;
|
|
} else if (OB_FAIL(check_restore_tenant_exist(tenant_ids, restore_tenant_exist))) {
|
|
LOG_WARN("fail to check restore tenant exist", K(ret));
|
|
} else {
|
|
}
|
|
|
|
ObArray<ObRefreshSchemaStatus> schema_status_array;
|
|
if (OB_SUCC(ret) && (is_standby_cluster || restore_tenant_exist)) {
|
|
ObSchemaStatusProxy* schema_status_proxy = GCTX.schema_status_proxy_;
|
|
if (OB_ISNULL(schema_status_proxy)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_status_proxy is null", K(ret));
|
|
} else if (OB_FAIL(schema_status_proxy->get_refresh_schema_status(schema_status_array))) {
|
|
LOG_WARN("fail to get refresh schema status", K(ret));
|
|
} else {
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
const ObSchemaMgrInfo* sys_schema_mgr_info = NULL;
|
|
ObRefreshSchemaStatus schema_status;
|
|
const RefreshSchemaMode need_fallback = RefreshSchemaMode::NORMAL;
|
|
if (OB_FAIL(get_schema_status(schema_status_array, OB_SYS_TENANT_ID, schema_status))) {
|
|
LOG_WARN("fail to get schema status", K(ret));
|
|
} else if (NULL == (sys_schema_store = schema_store_map_.get(OB_SYS_TENANT_ID))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("fail to get sys schema store");
|
|
} else if (OB_FAIL(add_schema_mgr_info(guard,
|
|
sys_schema_store,
|
|
schema_status,
|
|
OB_SYS_TENANT_ID,
|
|
sys_snapshot_version,
|
|
sys_snapshot_version,
|
|
need_fallback))) {
|
|
LOG_WARN("fail to add schema mgr info",
|
|
K(ret),
|
|
K(sys_snapshot_version),
|
|
"refresh_schema_mode",
|
|
print_refresh_schema_mode(need_fallback));
|
|
} else if (OB_FAIL(guard.get_schema_mgr_info(OB_SYS_TENANT_ID, sys_schema_mgr_info))) {
|
|
LOG_WARN("fail to get sys schema mgr info", K(ret));
|
|
} else if (OB_ISNULL(sys_schema_mgr_info->get_schema_mgr())) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("get simple schema in lazy mode not supported", K(ret));
|
|
} else {
|
|
ObArray<const ObSimpleTenantSchema*> tenant_schemas;
|
|
const ObSchemaMgr* sys_schema_mgr = sys_schema_mgr_info->get_schema_mgr();
|
|
if (OB_FAIL(sys_schema_mgr->get_tenant_schemas(tenant_schemas))) {
|
|
LOG_WARN("fail to get tenant_schemas", K(ret));
|
|
} else {
|
|
FOREACH_X(tenant, tenant_schemas, OB_SUCC(ret))
|
|
{
|
|
int64_t tenant_snapshot_version = OB_INVALID_VERSION;
|
|
ObSchemaStore* schema_store = NULL;
|
|
schema_status.reset();
|
|
uint64_t tenant_id = OB_INVALID_TENANT_ID;
|
|
if (OB_ISNULL(tenant) || OB_ISNULL(*tenant)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("tenant schema is null", K(ret));
|
|
} else if (FALSE_IT(tenant_id = (*tenant)->get_tenant_id())) {
|
|
} else if (OB_SYS_TENANT_ID == tenant_id) {
|
|
// skip
|
|
} else if (NULL == (schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("get tenant schema store fail, maybe local schema is old", K(ret), KPC(*tenant));
|
|
} else if (OB_CORE_SCHEMA_VERSION == (tenant_snapshot_version = schema_store->get_refreshed_version())) {
|
|
// If the tenant has not been created, you can only use the guard to obtain
|
|
// the tenant-level system table schema, and no error will be reported at this time
|
|
LOG_INFO("tenant maybe not create yet, just skip", K(ret), KPC(*tenant), K(tenant_snapshot_version));
|
|
} else {
|
|
// switchover/failover not clear schema_status, Cannot trust schema_status content unconditionally
|
|
if (is_standby_cluster || (*tenant)->is_restore()) {
|
|
if (OB_FAIL(get_schema_status(schema_status_array, tenant_id, schema_status))) {
|
|
LOG_WARN("fail to get schema status", K(ret), KPC(*tenant));
|
|
}
|
|
} else {
|
|
schema_status.tenant_id_ = tenant_id;
|
|
}
|
|
if (FAILEDx(add_schema_mgr_info(guard,
|
|
schema_store,
|
|
schema_status,
|
|
tenant_id,
|
|
tenant_snapshot_version,
|
|
tenant_snapshot_version,
|
|
refresh_schema_mode))) {
|
|
LOG_WARN("fail to add schema mgr info",
|
|
K(ret),
|
|
KPC(*tenant),
|
|
K(tenant_snapshot_version),
|
|
"refresh_schema_mode",
|
|
print_refresh_schema_mode(refresh_schema_mode));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
guard.schema_service_ = this;
|
|
guard.schema_guard_type_ = ObSchemaGetterGuard::SCHEMA_GUARD;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Specify the version to take schema_guard.
|
|
* If sys_schema_version is not specified, it means that the system tenant
|
|
* takes the latest schema version refreshed to the local machine
|
|
* - tenant_schema_version: Indicates the version of the schema of the user tenant except the system tables.
|
|
* - sys_schema_version: Indicates the version of the schema of the system tenant and the sys tables in user tenant.
|
|
*/
|
|
int ObMultiVersionSchemaService::get_tenant_schema_guard(const uint64_t tenant_id, ObSchemaGetterGuard& guard,
|
|
int64_t tenant_schema_version /* = common::OB_INVALID_VERSION*/,
|
|
int64_t sys_schema_version /* = common::OB_INVALID_VERSION*/,
|
|
const RefreshSchemaMode refresh_schema_mode /* = RefreshSchemaMode::NORMAL */)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_schema_splited = GCTX.is_schema_splited();
|
|
bool is_standby_cluster = GCTX.is_standby_cluster();
|
|
if (!is_schema_splited) {
|
|
// old schema refresh process
|
|
if (OB_FAIL(get_inner_schema_guard(guard, tenant_schema_version, refresh_schema_mode))) {
|
|
LOG_WARN("fail to get schema guard",
|
|
K(tenant_schema_version),
|
|
"refresh_schema_mode",
|
|
print_refresh_schema_mode(refresh_schema_mode));
|
|
}
|
|
} else {
|
|
// For system tenants, tenant_schema_version and sys_schema_version are consistent
|
|
sys_schema_version = OB_SYS_TENANT_ID == tenant_id ? tenant_schema_version : sys_schema_version;
|
|
|
|
// new schema refresh process
|
|
int64_t sys_latest_local_version = OB_INVALID_VERSION;
|
|
int64_t tenant_latest_local_version = OB_INVALID_VERSION;
|
|
int64_t sys_snapshot_version = OB_INVALID_VERSION;
|
|
int64_t tenant_snapshot_version = OB_INVALID_VERSION;
|
|
int64_t baseline_schema_version = OB_INVALID_VERSION;
|
|
ObRefreshSchemaStatus sys_schema_status;
|
|
ObRefreshSchemaStatus tenant_schema_status;
|
|
ObSchemaStore* sys_schema_store = NULL;
|
|
ObSchemaStore* tenant_schema_store = NULL;
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(guard.fast_reset())) {
|
|
LOG_WARN("fail to reset schema guard", K(ret));
|
|
} else if (OB_FAIL(guard.init(is_standby_cluster))) {
|
|
LOG_WARN("fail to init guard", K(ret));
|
|
}
|
|
sys_schema_status.tenant_id_ = OB_SYS_TENANT_ID;
|
|
|
|
// get system tenant schema_mgr_info
|
|
if (OB_FAIL(ret)) {
|
|
} else if (NULL == (sys_schema_store = schema_store_map_.get(OB_SYS_TENANT_ID))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get sys schema store fail");
|
|
} else if (OB_INVALID_VERSION == (sys_latest_local_version = sys_schema_store->get_refreshed_version())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("sys refreshed schema version is invalid", K(ret), K(sys_latest_local_version), K(sys_schema_version));
|
|
} else if (sys_schema_version > sys_latest_local_version) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("specified schema version larger than latest schema version, need retry",
|
|
K(ret),
|
|
K(sys_schema_version),
|
|
K(sys_latest_local_version),
|
|
K(lbt()));
|
|
} else {
|
|
sys_snapshot_version = OB_INVALID_VERSION == sys_schema_version ? sys_latest_local_version : sys_schema_version;
|
|
if (!ObSchemaService::g_liboblog_mode_ && OB_INVALID_VERSION != sys_schema_version) {
|
|
// for max avaliablity, ignore tmp_ret
|
|
int tmp_ret = OB_SUCCESS;
|
|
if (OB_SUCCESS != (tmp_ret = get_baseline_schema_version(baseline_schema_version))) {
|
|
LOG_WARN("get baseline schema version failed", K(tmp_ret));
|
|
}
|
|
}
|
|
if (OB_INVALID_VERSION != baseline_schema_version && OB_INVALID_VERSION != sys_schema_version &&
|
|
sys_schema_version < baseline_schema_version) {
|
|
LOG_INFO("change sys schema version to baseline",
|
|
"sys schema version",
|
|
sys_schema_version,
|
|
"baseline version",
|
|
baseline_schema_version);
|
|
sys_snapshot_version = baseline_schema_version;
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(add_schema_mgr_info(guard,
|
|
sys_schema_store,
|
|
sys_schema_status,
|
|
OB_SYS_TENANT_ID,
|
|
sys_snapshot_version,
|
|
sys_latest_local_version,
|
|
refresh_schema_mode))) {
|
|
LOG_WARN("fail to add schema mgr info",
|
|
K(ret),
|
|
K(sys_snapshot_version),
|
|
"refresh_schema_mode",
|
|
print_refresh_schema_mode(refresh_schema_mode));
|
|
} else {
|
|
// The guard will be used in subsequent check_tenant_is_restore, and some members will be set up here
|
|
// to avoid reporting errors during subsequent consumption of guard
|
|
guard.tenant_id_ = OB_SYS_TENANT_ID;
|
|
guard.schema_service_ = this;
|
|
guard.schema_guard_type_ = ObSchemaGetterGuard::TENANT_SCHEMA_GUARD;
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
bool is_restore = false;
|
|
if (OB_SYS_TENANT_ID == tenant_id) {
|
|
// Avoid circular dependencies
|
|
} else if (ObSchemaService::g_liboblog_mode_) {
|
|
tenant_schema_status.tenant_id_ = tenant_id;
|
|
} else if (!guard.is_standby_cluster() && OB_FAIL(check_tenant_is_restore(&guard, tenant_id, is_restore))) {
|
|
LOG_WARN("fail to check restore tenant exist", K(ret), K(tenant_id));
|
|
} else if (guard.is_standby_cluster() || is_restore) {
|
|
ObSchemaStatusProxy* schema_status_proxy = GCTX.schema_status_proxy_;
|
|
if (OB_ISNULL(schema_status_proxy)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_status_proxy is null", K(ret));
|
|
} else if (OB_FAIL(schema_status_proxy->get_refresh_schema_status(tenant_id, tenant_schema_status))) {
|
|
LOG_WARN("fail to get refresh schema status", K(ret));
|
|
}
|
|
} else {
|
|
tenant_schema_status.tenant_id_ = tenant_id;
|
|
}
|
|
}
|
|
|
|
// get user tenant schema_mgr_info
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_SYS_TENANT_ID == tenant_id) {
|
|
// The system tenant has already taken it, you can skip here
|
|
} else if (OB_CORE_SCHEMA_VERSION == tenant_schema_version) {
|
|
// the scenario where specifying the version takes the guard. At this time, the tenant has not been created yet,
|
|
// and a special schema_version will be passed in. At this time, no error will be reported to avoid
|
|
// error of the tenant building in transaction two.
|
|
LOG_DEBUG("tenant maybe not create yet, just skip", K(ret), K(tenant_id));
|
|
} else if (NULL == (tenant_schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("get tenant schema store fail, maybe local schema is old", K(ret), K(tenant_id));
|
|
} else if (OB_CORE_SCHEMA_VERSION == (tenant_latest_local_version = tenant_schema_store->get_refreshed_version()) &&
|
|
OB_INVALID_VERSION == tenant_schema_version) {
|
|
// Take guard for non-specified version. If the tenant has not been created, it only use the guard to get
|
|
// the tenant-level system table schema, and no error will be reported at this time.
|
|
LOG_DEBUG("tenant maybe not create yet, just skip", K(ret), K(tenant_id));
|
|
} else if (tenant_schema_version > tenant_latest_local_version) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("specified schema version larger than latest schema version, need retry",
|
|
K(ret),
|
|
K(tenant_schema_version),
|
|
K(tenant_latest_local_version),
|
|
K(sys_schema_version),
|
|
K(sys_latest_local_version),
|
|
K(lbt()));
|
|
} else {
|
|
tenant_snapshot_version =
|
|
OB_INVALID_VERSION == tenant_schema_version ? tenant_latest_local_version : tenant_schema_version;
|
|
// After the schema is split, the schema_version between tenants is incomparable. In order to avoid
|
|
// snapshot access or physical recovery scenarios, the baseline_schema_version is larger than
|
|
// the user tenant schema_version and an error is reported. The version judgment is added here.
|
|
if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2210 && OB_INVALID_VERSION != baseline_schema_version &&
|
|
OB_INVALID_VERSION != tenant_schema_version && tenant_schema_version < baseline_schema_version &&
|
|
OB_SYS_TENANT_ID != tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant schema version",
|
|
K(ret),
|
|
K(tenant_id),
|
|
K(tenant_schema_version),
|
|
K(baseline_schema_version));
|
|
}
|
|
|
|
// check tenant exist
|
|
const ObSchemaMgrInfo* sys_schema_mgr_info = NULL;
|
|
if (OB_FAIL(ret)) {
|
|
} else if (sys_snapshot_version == tenant_schema_store->get_checked_sys_version()) {
|
|
// sys schema version match, no need to check tenant existence.
|
|
} else if (OB_FAIL(guard.get_schema_mgr_info(OB_SYS_TENANT_ID, sys_schema_mgr_info))) {
|
|
LOG_WARN("fail to get sys schema mgr info", K(ret));
|
|
} else if (OB_ISNULL(sys_schema_mgr_info->get_schema_mgr())) {
|
|
// lazy mode
|
|
const ObSchema* base_schema = NULL;
|
|
ObKVCacheHandle handle;
|
|
if (OB_FAIL(get_schema(
|
|
NULL, sys_schema_status, TENANT_SCHEMA, tenant_id, tenant_snapshot_version, handle, base_schema))) {
|
|
LOG_WARN("fail to get tenant schema", K(ret), K(tenant_id), K(tenant_snapshot_version));
|
|
} else if (OB_ISNULL(base_schema)) {
|
|
ret = OB_TENANT_NOT_EXIST;
|
|
LOG_WARN("tenant not exist", K(ret), K(tenant_id), "schema_version", tenant_snapshot_version);
|
|
}
|
|
} else {
|
|
const ObSimpleTenantSchema* tenant_schema = NULL;
|
|
const ObSchemaMgr* sys_schema_mgr = sys_schema_mgr_info->get_schema_mgr();
|
|
if (OB_FAIL(sys_schema_mgr->get_tenant_schema(tenant_id, tenant_schema))) {
|
|
LOG_WARN("fail to get tenant schema", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(tenant_schema)) {
|
|
ret = OB_TENANT_NOT_EXIST;
|
|
LOG_WARN("tenant not exist",
|
|
K(ret),
|
|
K(tenant_id),
|
|
"schema_version",
|
|
sys_schema_mgr->get_schema_version(),
|
|
K(lbt()));
|
|
} else {
|
|
tenant_schema_store->update_checked_sys_version(sys_snapshot_version);
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(add_schema_mgr_info(guard,
|
|
tenant_schema_store,
|
|
tenant_schema_status,
|
|
tenant_id,
|
|
tenant_snapshot_version,
|
|
tenant_latest_local_version,
|
|
refresh_schema_mode))) {
|
|
LOG_WARN("fail to add schema mgr info",
|
|
K(ret),
|
|
K(tenant_id),
|
|
K(tenant_snapshot_version),
|
|
"refresh_schema_mode",
|
|
print_refresh_schema_mode(refresh_schema_mode));
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
guard.tenant_id_ = tenant_id;
|
|
LOG_DEBUG("get tenant schema guard", K(tenant_id), K(tenant_schema_version), K(sys_schema_version));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret) && OB_TENANT_HAS_BEEN_DROPPED != ret && ObSchemaService::g_liboblog_mode_) {
|
|
TenantStatus tenant_status = TENANT_STATUS_INVALID;
|
|
int temp_ret = query_tenant_status(tenant_id, tenant_status);
|
|
if (OB_SUCCESS != temp_ret) {
|
|
LOG_WARN("query tenant status failed", K(ret), K(temp_ret), K(tenant_id));
|
|
} else if (TENANT_DELETED == tenant_status) {
|
|
LOG_INFO("tenant has been dropped, no need retry", K(ret), K(tenant_id));
|
|
ret = OB_TENANT_HAS_BEEN_DROPPED; // overwrite ret
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::get_tenant_ids(ObIArray<uint64_t>& tenant_ids)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
share::schema::ObSchemaGetterGuard schema_guard;
|
|
if (OB_FAIL(get_tenant_schema_guard(OB_SYS_TENANT_ID, schema_guard))) {
|
|
LOG_WARN("fail to get schema guard", K(ret));
|
|
} else if (OB_FAIL(schema_guard.get_tenant_ids(tenant_ids))) {
|
|
LOG_WARN("get all tenants failed", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::get_tenant_full_schema_guard(
|
|
const uint64_t tenant_id, ObSchemaGetterGuard& guard, bool check_formal /*= true*/)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_TENANT_SCHEMA_NOT_FULL;
|
|
if (EXECUTE_COUNT_PER_SEC(1)) {
|
|
LOG_WARN("tenant schema not full", K(ret), K(tenant_id));
|
|
}
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, guard))) {
|
|
LOG_WARN("failed to get tenant schema guard", K(ret), K(tenant_id));
|
|
} else if (check_formal && OB_FAIL(guard.check_formal_guard())) {
|
|
LOG_WARN("schema_guard is not formal", K(ret), K(tenant_id));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::add_schema_mgr_info(ObSchemaGetterGuard& schema_guard, ObSchemaStore* schema_store,
|
|
const ObRefreshSchemaStatus& schema_status, const uint64_t tenant_id, const int64_t snapshot_version,
|
|
const int64_t latest_local_version, const RefreshSchemaMode refresh_schema_mode /* = RefreshSchemaMode::NORMAL */)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObSchemaMgr* schema_mgr = NULL;
|
|
ObSchemaMgrInfo* new_schema_mgr_info = NULL;
|
|
if (OB_INVALID_TENANT_ID == tenant_id || snapshot_version <= 0 || latest_local_version <= 0 || NULL == schema_store) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id or snapshot_version", K(ret), K(tenant_id), K(snapshot_version), KP(schema_store));
|
|
} else if (schema_status.tenant_id_ != tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid schema_status or tenant_id", K(ret), K(tenant_id), K(snapshot_version), K(schema_status));
|
|
} else if (schema_status.snapshot_timestamp_ >= 0 && snapshot_version > schema_status.readable_schema_version_) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("tenant schema is not readable now", K(ret), K(tenant_id), K(snapshot_version), K(schema_status));
|
|
} else {
|
|
ObSchemaMgrHandle handle(schema_guard.mod_);
|
|
ObSchemaMgrInfo schema_mgr_info(tenant_id, snapshot_version, schema_mgr, handle, schema_status);
|
|
int64_t count = schema_guard.schema_mgr_infos_.count();
|
|
// Guaranteed to be monotonically increasing when inserted
|
|
if (count > 0 && schema_guard.schema_mgr_infos_[count - 1].get_tenant_id() >= tenant_id) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("tenant_id should greator than the last one",
|
|
K(ret),
|
|
"pre_tenant_id",
|
|
schema_guard.schema_mgr_infos_[count - 1].get_tenant_id(),
|
|
K(tenant_id));
|
|
} else if (OB_FAIL(schema_guard.schema_mgr_infos_.push_back(schema_mgr_info))) {
|
|
LOG_WARN("fail to push back schema_mgr_info", K(ret), K(tenant_id));
|
|
} else {
|
|
new_schema_mgr_info = &schema_guard.schema_mgr_infos_.at(count);
|
|
}
|
|
}
|
|
|
|
ObSchemaMgrHandle& handle = new_schema_mgr_info->get_schema_mgr_handle();
|
|
bool need_fallback = false;
|
|
if (OB_FAIL(ret)) {
|
|
} else if (RefreshSchemaMode::FORCE_FALLBACK == refresh_schema_mode) {
|
|
// Avoid force_fallback mode occupying the schema slot to cause OOM, schema_mgr deep_copy to
|
|
// schema_mgr_cache_for_liboblog
|
|
need_fallback = true;
|
|
} else if (OB_FAIL(schema_store->schema_mgr_cache_.get(snapshot_version, schema_mgr, handle))) {
|
|
if (OB_ENTRY_NOT_EXIST != ret) {
|
|
LOG_WARN("get schema mgr failed", K(ret), K(snapshot_version));
|
|
} else if (RefreshSchemaMode::FORCE_LAZY == refresh_schema_mode) {
|
|
ret = OB_SUCCESS;
|
|
} else {
|
|
ret = OB_SUCCESS;
|
|
// Compatible with before liboblog 2.0 version
|
|
need_fallback = !allow_lazy();
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && need_fallback) {
|
|
// fallback
|
|
if (OB_FAIL(schema_store->schema_mgr_cache_for_liboblog_.get(snapshot_version, schema_mgr, handle))) {
|
|
if (OB_ENTRY_NOT_EXIST != ret) {
|
|
LOG_WARN("[FALLBACK_SCHEMA] get schema mgr failed", K(ret), K(schema_status), K(snapshot_version));
|
|
} else if (OB_FAIL(fallback_schema_mgr_for_liboblog(
|
|
schema_status, snapshot_version, latest_local_version, schema_mgr, handle))) {
|
|
LOG_WARN("[FALLBACK_SCHEMA] fallback schema mgr for liboblog failed",
|
|
K(ret),
|
|
K(schema_status),
|
|
K(snapshot_version),
|
|
K(latest_local_version));
|
|
} else {
|
|
LOG_INFO("[FALLBACK_SCHEMA] get schema_mgr by fallback schema_mgr",
|
|
K(schema_status),
|
|
K(snapshot_version),
|
|
K(latest_local_version));
|
|
}
|
|
} else {
|
|
LOG_DEBUG("[FALLBACK_SCHEMA] get schema_mgr by fallback schema_mgr",
|
|
K(schema_status),
|
|
K(snapshot_version),
|
|
K(latest_local_version));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
new_schema_mgr_info->set_schema_mgr(schema_mgr);
|
|
if (snapshot_version == latest_local_version
|
|
// && RefreshSchemaMode::FORCE_LAZY != refresh_schema_mode
|
|
&& OB_ISNULL(schema_mgr)) {
|
|
LOG_INFO("should not be lazy mode", K(ret), KPC(new_schema_mgr_info), K(latest_local_version));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Background description:
|
|
* There are two sources of this schema_version
|
|
* 1. schema_version of SSTABLE:
|
|
* This is the initial transmission of RS. The schema_version cannot guarantee that the schema of the database table
|
|
* and the index table when the table is created can be seen at the same time.
|
|
* it may only see one of them, which has historical problems.
|
|
*
|
|
* 2. schema_version of minor or major compaction:
|
|
* 1) 1.4.x
|
|
* - minor freeze uses the schema_verison on the memstore (no push when no data is written,
|
|
* so the schema_verison must be able to see the corresponding table schema);
|
|
* - Merge the DDL thread, and ensure that there is no concurrent table creation when taking the schema_version,
|
|
* so the schema_version must be able to see the Partition created before the merge.
|
|
* 2) 2.0, 2.1.x:
|
|
* - minor freeze uses the schema_version corresponding to gc_snapshot_version, and minor freeze and major freeze
|
|
* confirm the schema_version does not go through the DDL thread, so the concurrently created Partition
|
|
* may not be seen in the corresponding schema_version.
|
|
* 3) 2.2.x:
|
|
* - The snapshot point & schema_version of minor freeze and major freeze is split by tenant,
|
|
* and the DDL thread is used.
|
|
*
|
|
* In summary: 1.4.x & 2.2.x use SSTABLE & minor freeze and major freeze schema_version
|
|
* must get the schema of the table to be merged;
|
|
* 2.0 & 2.1.x When table_schema cannot be obtained from a given schema_version,
|
|
* orig_schema_version must be used to obtain table_schema.
|
|
*
|
|
* save_schema_version is schema_version or the corresponding orig_schema_version
|
|
*/
|
|
int ObMultiVersionSchemaService::retry_get_schema_guard(const int64_t schema_version, const uint64_t table_id,
|
|
ObSchemaGetterGuard& schema_guard, int64_t& save_schema_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
int32_t retry_time = 0;
|
|
const ObTableSchema* table_schema = NULL;
|
|
const uint64_t tenant_id = extract_tenant_id(table_id);
|
|
const uint64_t fetch_tenant_id = is_sys_table(table_id) ? OB_SYS_TENANT_ID : tenant_id;
|
|
save_schema_version = schema_version;
|
|
|
|
if (!ObSchemaService::is_formal_version(schema_version) || 0 == schema_version) {
|
|
// There are several special versions of schema_version, here only warning is printed, and the version is not
|
|
// verified
|
|
// 1. schema_version = 0 : Before 223, the partition did not record the schema_version,
|
|
// and the minor free will use this value to get the schema;
|
|
// 2. schema_version = 1 : 225 The demand for schema_history recovery point calculation.
|
|
// Merger will increase the partition's schema_version, and the system tenant 1 version schema_version is 1.
|
|
// 3. schema_version = 2 : The first schema_version version of bootstrap (only memory is used temporarily);
|
|
// 4. informal version : System tenant has system table/core table changes
|
|
// For version 0~2, system tenant will be automatically converted to baseline_schema_version,
|
|
// and user tenants will report an error; the informative version has little effect on the full schema
|
|
// Here the defense is removed first, only print warn
|
|
LOG_WARN("get schema guard with informal version", K(table_id), K(schema_version));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
while (retry_time < MAX_RETRY_TIMES) {
|
|
bool is_dropped = false;
|
|
if (OB_FAIL(check_if_tenant_has_been_dropped(tenant_id, is_dropped))) {
|
|
if (OB_NOT_INIT != ret) {
|
|
LOG_WARN("check if tenant has been dropped failed", K(ret), K(table_id));
|
|
}
|
|
} else if (is_dropped) {
|
|
ret = OB_TENANT_HAS_BEEN_DROPPED;
|
|
LOG_WARN("tenant has been deleted, just skip", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(fetch_tenant_id, schema_guard, schema_version))) {
|
|
if (OB_SCHEMA_EAGAIN != ret) {
|
|
LOG_WARN("fail to get tenant schema guard", K(ret), K(table_id), K(schema_version));
|
|
}
|
|
}
|
|
if (OB_SCHEMA_EAGAIN != ret && OB_NOT_INIT != ret) {
|
|
break;
|
|
} else {
|
|
usleep(RETRY_INTERVAL_US);
|
|
++retry_time;
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
LOG_WARN("fail to get tenant schema guard", K(ret), K(table_id), K(schema_version));
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
LOG_WARN("fail to get schema guard", K(ret), K(schema_version));
|
|
} else if (OB_FAIL(schema_guard.get_table_schema(table_id, table_schema))) {
|
|
LOG_WARN("failed to get table schema", K(ret), K(table_id));
|
|
} else if (OB_NOT_NULL(table_schema)) {
|
|
// success
|
|
} else {
|
|
// table not exist , return guard which can get original table schema
|
|
ObRefreshSchemaStatus schema_status;
|
|
schema_status.tenant_id_ = schema_guard.is_schema_splited() ? fetch_tenant_id : OB_INVALID_TENANT_ID;
|
|
|
|
bool is_restore = false;
|
|
if (OB_SYS_TENANT_ID == fetch_tenant_id || ObSchemaService::g_liboblog_mode_) {
|
|
// skip
|
|
} else if (!schema_guard.is_standby_cluster() &&
|
|
OB_FAIL(check_tenant_is_restore(&schema_guard, fetch_tenant_id, is_restore))) {
|
|
LOG_WARN("fail to check restore tenant exist", K(ret), K(fetch_tenant_id));
|
|
} else if (schema_guard.is_standby_cluster() || is_restore) {
|
|
ObSchemaStatusProxy* schema_status_proxy = GCTX.schema_status_proxy_;
|
|
if (OB_ISNULL(schema_status_proxy)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_status_proxy is null", K(ret));
|
|
} else if (OB_FAIL(schema_status_proxy->get_refresh_schema_status(fetch_tenant_id, schema_status))) {
|
|
LOG_WARN("fail to get refresh schema status", K(ret));
|
|
} else {
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (is_inner_table(table_id)) {
|
|
// To add tenant-level system tables, first build ordinary tenant system tables, then system tenant system tables,
|
|
// and then the schema_version when building tables on the user tenant system tables meta will be pushed up.
|
|
// At this time, the schema will not be obtained and support is required.
|
|
int64_t baseline_schema_version = OB_INVALID_VERSION;
|
|
if (OB_FAIL(get_baseline_schema_version(baseline_schema_version))) {
|
|
LOG_WARN("fail to get baseline schema version", K(ret));
|
|
} else if (baseline_schema_version <= 0) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("baseline schema version is invalid, try later", K(ret), K(table_id), K(schema_version));
|
|
} else {
|
|
// try use version_his_map
|
|
VersionHisKey key(TABLE_SCHEMA, table_id);
|
|
VersionHisVal val;
|
|
int ret = version_his_map_.get_refactored(key, val);
|
|
if (OB_SUCCESS != ret) {
|
|
LOG_WARN("fail to get table version history", K(ret), K(key), K(schema_version));
|
|
} else if (OB_HASH_NOT_EXIST == ret) { // overwrite ret
|
|
int64_t local_version = OB_INVALID_VERSION;
|
|
if (OB_FAIL(get_tenant_refreshed_schema_version(OB_SYS_TENANT_ID, local_version))) {
|
|
LOG_WARN("fail to get tenant refreshed schema_version", K(ret), K(key), K(schema_version));
|
|
} else if (local_version <= OB_CORE_SCHEMA_VERSION) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("local schema is old, try later", K(ret), K(key), K(schema_version), K(local_version));
|
|
} else if (OB_FAIL(construct_schema_version_history(schema_status, local_version, key, val))) {
|
|
LOG_WARN("fail to load table schema version history", K(ret), K(key), K(schema_version));
|
|
} else if (0 >= val.min_version_ || 0 == val.valid_cnt_) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("sys table not exist", K(ret), K(key), K(val), K(schema_version));
|
|
} else {
|
|
save_schema_version = max(val.min_version_, baseline_schema_version);
|
|
}
|
|
} else {
|
|
save_schema_version = max(val.min_version_, baseline_schema_version);
|
|
}
|
|
}
|
|
} else {
|
|
// try use orig_schema_version
|
|
if (OB_FAIL(ret)) {
|
|
} else if (NULL == schema_service_) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_service_ is null", K(ret));
|
|
} else if (OB_FAIL(schema_service_->get_ori_schema_version(
|
|
schema_status, fetch_tenant_id, table_id, save_schema_version))) {
|
|
if (OB_ITER_END == ret) {
|
|
// There are several situations where orig_schema_version cannot be obtained:
|
|
// 1. The table built in 1.4.x does not have orig_schema_version,
|
|
// and the following situations occur when entering this branch:
|
|
// - The schema_version is derived from major or minor freeze and is a relatively large value.
|
|
// At this time, the table has been dropped, and errors will continue to be reported
|
|
// until the partition is recycled by the GC logic;
|
|
// - BUG, should not enter this branch.
|
|
// 2. 2.0 and 2.1.x concurrently build tables, the transaction is not committed and needs to be tried again.
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("orig_schema_version not exist, try again", K(ret), K(table_id), K(schema_version));
|
|
} else {
|
|
LOG_WARN("failed to get_ori_schema_version", K(ret), K(save_schema_version), K(table_id));
|
|
}
|
|
} else if (schema_version > save_schema_version) {
|
|
// If the specified version is greater than orig_schema_version, the table can be determined to be deleted
|
|
ret = OB_TABLE_IS_DELETED;
|
|
ObTaskController::get().allow_next_syslog();
|
|
LOG_INFO("table is deleted", K(ret), K(table_id), K(schema_version), K(save_schema_version));
|
|
} else {
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
while (retry_time < MAX_RETRY_TIMES) {
|
|
bool is_dropped = false;
|
|
if (OB_FAIL(check_if_tenant_has_been_dropped(tenant_id, is_dropped))) {
|
|
if (OB_NOT_INIT != ret) {
|
|
LOG_WARN("check if tenant has been dropped failed", K(ret), K(table_id));
|
|
}
|
|
} else if (is_dropped) {
|
|
ret = OB_TENANT_HAS_BEEN_DROPPED;
|
|
LOG_WARN("tenant has been deleted, just skip", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(fetch_tenant_id, schema_guard, save_schema_version))) {
|
|
if (OB_SCHEMA_EAGAIN != ret) {
|
|
LOG_WARN("fail to get tenant schema guard", K(ret), K(table_id), K(schema_version), K(save_schema_version));
|
|
}
|
|
}
|
|
if (OB_SCHEMA_EAGAIN != ret && OB_NOT_INIT != ret) {
|
|
break;
|
|
} else {
|
|
usleep(RETRY_INTERVAL_US);
|
|
++retry_time;
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
LOG_WARN("fail to get tenant schema guard", K(ret), K(table_id), K(schema_version), K(save_schema_version));
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
LOG_WARN("fail to get tenant schema guard", K(ret), K(table_id), K(schema_version), K(save_schema_version));
|
|
} else if (OB_FAIL(schema_guard.get_table_schema(table_id, table_schema))) {
|
|
LOG_WARN("failed to get table schema", K(ret), K(table_id), K(schema_version), K(save_schema_version));
|
|
} else if (OB_ISNULL(table_schema)) {
|
|
ret = OB_SCHEMA_ERROR;
|
|
LOG_WARN("table should exist", K(ret), K(table_id), K(schema_version), K(save_schema_version));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
schema_guard.schema_guard_type_ = ObSchemaGetterGuard::TABLE_SCHEMA_GUARD;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
ObMultiVersionSchemaService::ObMultiVersionSchemaService()
|
|
{
|
|
init_ = false;
|
|
response_notify_schema_ts_ = 0;
|
|
refreshed_schema_version_ = -1;
|
|
received_broadcast_version_ = -1;
|
|
with_timestamp_ = false;
|
|
init_version_cnt_ = OB_INVALID_COUNT;
|
|
init_version_cnt_for_liboblog_ = OB_INVALID_COUNT;
|
|
last_refreshed_schema_info_.reset();
|
|
}
|
|
|
|
ObMultiVersionSchemaService::~ObMultiVersionSchemaService()
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
// FIXME: Will there be a memory leak
|
|
int ObMultiVersionSchemaService::destroy()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
schema_store_map_.destroy();
|
|
with_timestamp_ = false;
|
|
return ret;
|
|
}
|
|
|
|
ObMultiVersionSchemaService& ObMultiVersionSchemaService::get_instance()
|
|
{
|
|
static ObMultiVersionSchemaService THE_ONE;
|
|
return THE_ONE;
|
|
}
|
|
|
|
// init in main thread
|
|
int ObMultiVersionSchemaService::init(ObMySQLProxy* sql_proxy, ObDbLinkProxy* dblink_proxy,
|
|
const ObCommonConfig* config, const int64_t init_version_count, const int64_t init_version_count_for_liboblog,
|
|
const bool with_timestamp)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (true == init_) {
|
|
ret = OB_INIT_TWICE;
|
|
LOG_WARN("init schema manager twice, ", K(ret));
|
|
} else if (OB_FAIL(ObServerSchemaService::init(sql_proxy, dblink_proxy, config))) {
|
|
LOG_WARN("failed to init base class ObServerSchemaService,", K(ret));
|
|
} else if (OB_FAIL(schema_fetcher_.init(schema_service_, sql_proxy))) {
|
|
LOG_WARN("fail to init schema cache", K(ret));
|
|
} else if (OB_FAIL(schema_cache_.init())) {
|
|
LOG_WARN("fail to init schema cache", K(ret));
|
|
} else if (OB_FAIL(schema_mgr_cache_.init(init_version_count, ObSchemaMgrCache::REFRESH))) {
|
|
LOG_WARN("fail to init schema mgr cache", K(ret));
|
|
} else if (OB_FAIL(
|
|
schema_mgr_cache_for_liboblog_.init(init_version_count_for_liboblog, ObSchemaMgrCache::FALLBACK))) {
|
|
LOG_WARN("fail to init schema mgr cache", K(ret));
|
|
} else {
|
|
// init sys schema struct
|
|
init_version_cnt_ = init_version_count;
|
|
init_version_cnt_for_liboblog_ = init_version_count_for_liboblog;
|
|
with_timestamp_ = with_timestamp;
|
|
if (OB_FAIL(schema_store_map_.init(TENANT_MAP_BUCKET_NUM))) {
|
|
LOG_WARN("fail to init schema store map", K(ret));
|
|
} else if (OB_FAIL(init_multi_version_schema_struct(OB_SYS_TENANT_ID))) {
|
|
LOG_WARN("fail to init multi version schema struct", K(ret));
|
|
} else if (OB_FAIL(init_sys_tenant_user_schema())) {
|
|
LOG_WARN("fail to init schema cache", K(ret));
|
|
} else if (OB_FAIL(init_original_schema())) {
|
|
LOG_WARN("failed to init original schema", K(ret));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool ObMultiVersionSchemaService::check_inner_stat() const
|
|
{
|
|
bool ret = true;
|
|
if (!ObServerSchemaService::check_inner_stat() || !init_) {
|
|
ret = false;
|
|
LOG_WARN("inner stat error", K(init_));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// add sys_tenant/user schema to cache, just for bootstrap
|
|
// 1. before bootstrap : 'alter system bootstrap' (obmp_connect will fetch user_info)
|
|
// 2. during bootstrap : 'create_partition' will fetch tenant_schema
|
|
int ObMultiVersionSchemaService::init_sys_tenant_user_schema()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObTenantSchema sys_tenant;
|
|
ObSysVariableSchema sys_variable;
|
|
ObUserInfo sys_user;
|
|
|
|
sys_tenant.set_tenant_id(OB_SYS_TENANT_ID);
|
|
sys_tenant.set_schema_version(OB_CORE_SCHEMA_VERSION);
|
|
|
|
sys_user.set_tenant_id(OB_SYS_TENANT_ID);
|
|
sys_user.set_user_id(combine_id(OB_SYS_TENANT_ID, OB_SYS_USER_ID));
|
|
sys_user.set_priv_set(OB_PRIV_ALL | OB_PRIV_GRANT | OB_PRIV_BOOTSTRAP);
|
|
sys_user.set_schema_version(OB_CORE_SCHEMA_VERSION);
|
|
|
|
sys_variable.set_tenant_id(OB_SYS_TENANT_ID);
|
|
sys_variable.set_schema_version(OB_CORE_SCHEMA_VERSION);
|
|
sys_variable.set_name_case_mode(OB_ORIGIN_AND_INSENSITIVE);
|
|
|
|
if (OB_FAIL(sys_variable.load_default_system_variable(true))) {
|
|
LOG_WARN("load sys tenant default system variable failed", K(ret));
|
|
} else if (OB_FAIL(sys_tenant.set_tenant_name(OB_SYS_TENANT_NAME))) {
|
|
LOG_WARN("Set tenant name error", K(ret));
|
|
} else if (OB_FAIL(sys_user.set_user_name(OB_SYS_USER_NAME))) {
|
|
LOG_WARN("Set user name error", K(ret));
|
|
} else if (OB_FAIL(sys_user.set_host(OB_SYS_HOST_NAME))) {
|
|
LOG_WARN("Set host name error", K(ret));
|
|
} else if (OB_FAIL(schema_cache_.put_schema(
|
|
TENANT_SCHEMA, sys_tenant.get_tenant_id(), sys_tenant.get_schema_version(), sys_tenant))) {
|
|
LOG_WARN("put schema failed", K(ret));
|
|
} else if (OB_FAIL(schema_cache_.put_schema(
|
|
USER_SCHEMA, sys_user.get_user_id(), sys_user.get_schema_version(), sys_user))) {
|
|
LOG_WARN("put schema failed", K(ret));
|
|
} else if (OB_FAIL(schema_cache_.put_schema(
|
|
SYS_VARIABLE_SCHEMA, sys_variable.get_tenant_id(), sys_variable.get_schema_version(), sys_variable))) {
|
|
LOG_WARN("put schema failed", K(ret));
|
|
} else {
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// only used by bootstrap
|
|
int ObMultiVersionSchemaService::init_sys_schema(const ObIArray<ObTableSchema>& table_schemas)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
lib::ObMutexGuard guard(schema_refresh_mutex_);
|
|
// FIXME: Directly use the new mode to refresh the schema in the bootstrap phase
|
|
if (GCONF.__schema_split_mode) {
|
|
(void)GCTX.set_split_schema_version(0);
|
|
(void)GCTX.set_split_schema_version_v2(0);
|
|
}
|
|
|
|
ObArray<const ObTableSchema*> tables;
|
|
FOREACH_CNT_X(table_schema, table_schemas, OB_SUCCESS == ret)
|
|
{
|
|
if (OB_FAIL(tables.push_back(table_schema))) {
|
|
LOG_WARN("failed to add table_schema", K(ret));
|
|
}
|
|
// put sys_schemas to cache, for bootstrap
|
|
else if (OB_FAIL(schema_cache_.put_schema(
|
|
TABLE_SCHEMA, table_schema->get_table_id(), table_schema->get_schema_version(), *table_schema))) {
|
|
LOG_WARN("put sys schema to schema cache failed", K(ret), K(*table_schema));
|
|
} else {
|
|
LOG_INFO("add sys table schema", K(ret), K(*table_schema));
|
|
}
|
|
}
|
|
|
|
ObArray<ObSimpleTableSchemaV2> simple_table_schemas;
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(convert_to_simple_schema(table_schemas, simple_table_schemas))) {
|
|
LOG_WARN("failed to convert", K(ret));
|
|
} else if (GCTX.is_schema_splited()) {
|
|
ObSchemaMgr* schema_mgr_for_cache = NULL;
|
|
if (OB_FAIL(schema_mgr_for_cache_map_.get_refactored(OB_SYS_TENANT_ID, schema_mgr_for_cache))) {
|
|
LOG_WARN("fail to get schema mgr for cache", K(ret), K(ret));
|
|
} else if (OB_ISNULL(schema_mgr_for_cache)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_mgr is null", K(ret));
|
|
} else if (OB_FAIL(schema_mgr_for_cache->add_tables(simple_table_schemas))) {
|
|
LOG_WARN("failed to add tables", K(ret));
|
|
} else if (FALSE_IT(schema_mgr_for_cache->set_schema_version(OB_CORE_SCHEMA_VERSION + 1))) {
|
|
} else if (OB_FAIL(add_schema(OB_SYS_TENANT_ID, false))) {
|
|
LOG_WARN("fail to add schema_manager_for_cache into snapshot", K(ret));
|
|
} else {
|
|
LOG_INFO("init sys schema succ with new mode", K(ret));
|
|
}
|
|
} else {
|
|
// FIXME: For the convenience of debugging, the old schema refresh logic during bootstrap is retained,
|
|
// but there is no need to be compatible here.
|
|
if (OB_ISNULL(schema_mgr_for_cache_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_mgr_for_cache_ is null", K(ret));
|
|
} else if (OB_FAIL(schema_mgr_for_cache_->add_tables(simple_table_schemas))) {
|
|
LOG_WARN("failed to add tables", K(ret));
|
|
} else if (FALSE_IT(schema_mgr_for_cache_->set_schema_version(OB_CORE_SCHEMA_VERSION + 1))) {
|
|
} else if (OB_FAIL(add_schema(false))) {
|
|
LOG_WARN("fail to add schema_manager_for_cache into snapshot", K(ret));
|
|
} else {
|
|
LOG_INFO("init sys schema succ with old mode", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// check table exist
|
|
// table_schema_version: Indicates the schema_version corresponding to table_schema
|
|
// 1) OB_INVALID_VERSION, Indicates to take the latest version of the local guard
|
|
// (not the latest version of the internal table)
|
|
// 2) table_schema_version > local refreshed schema_version, Indicates that the local schema is behind,
|
|
// and a special error code is returned
|
|
// 3) table_schema_version <= local refreshed schema_version: Indicates that the local schema is new enough,
|
|
// take the latest version of the local guard for judgment
|
|
int ObMultiVersionSchemaService::check_table_exist(const uint64_t tenant_id, const uint64_t database_id,
|
|
const ObString& table_name, const bool is_index, const int64_t table_schema_version, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
bool is_system_table = false;
|
|
if (OB_FAIL(ObSysTableChecker::is_sys_table_name(database_id, table_name, is_system_table))) {
|
|
LOG_WARN("fail to check if table is system table", K(ret), K(database_id), K(table_name));
|
|
} else {
|
|
uint64_t fetch_tenant_id = is_system_table ? OB_SYS_TENANT_ID : tenant_id;
|
|
int64_t local_version = OB_INVALID_VERSION;
|
|
if (!is_tenant_full_schema(fetch_tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited, ", K(ret), K(database_id), K(table_name));
|
|
} else if (table_schema_version >= 0 &&
|
|
OB_FAIL(get_tenant_refreshed_schema_version(fetch_tenant_id, local_version))) {
|
|
LOG_WARN(
|
|
"fail to get local schema version", K(ret), K(fetch_tenant_id), K(table_name), K(table_schema_version));
|
|
} else if (table_schema_version > local_version) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("local schema is old, try again", K(ret), K(fetch_tenant_id), K(table_name), K(table_schema_version));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(fetch_tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret), K(database_id), K(table_name));
|
|
} else if (OB_SUCCESS !=
|
|
(ret = schema_guard.check_table_exist(
|
|
tenant_id, database_id, table_name, is_index, ObSchemaGetterGuard::ALL_TYPES, exist))) {
|
|
LOG_WARN("failed to check table exist, ", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// table_schema_version: schema_version of table_schema
|
|
// 1) OB_INVALID_VERSION, Indicates to take the latest version of the local guard
|
|
// (not the latest version of the internal table)
|
|
// 2) table_schema_version > local refreshed schema_version, Indicates that the local schema is behind,
|
|
// and a special error code is returned
|
|
// 3) table_schema_version <= local refreshed schema_version: Indicates that the local schema is new enough,
|
|
// take the latest version of the local guard for judgment
|
|
int ObMultiVersionSchemaService::check_table_exist(
|
|
const uint64_t table_id, const int64_t table_schema_version, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
uint64_t tenant_id = extract_tenant_id(table_id);
|
|
uint64_t fetch_tenant_id = is_sys_table(table_id) ? OB_SYS_TENANT_ID : tenant_id;
|
|
int64_t local_version = OB_INVALID_VERSION;
|
|
if (!is_tenant_full_schema(fetch_tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited,", K(ret), K(table_id));
|
|
} else if (table_schema_version >= 0 &&
|
|
OB_FAIL(get_tenant_refreshed_schema_version(fetch_tenant_id, local_version))) {
|
|
LOG_WARN("fail to get local schema version", K(ret), K(fetch_tenant_id), K(table_id), K(table_schema_version));
|
|
} else if (table_schema_version > local_version) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("local schema is old, try again", K(ret), K(fetch_tenant_id), K(table_id), K(table_schema_version));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(fetch_tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret), K(table_id));
|
|
} else if (OB_FAIL(schema_guard.check_table_exist(table_id, exist))) {
|
|
LOG_WARN("failed to check table exist,", K(table_id), K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_database_exist(
|
|
const uint64_t tenant_id, const ObString& database_name, uint64_t& database_id, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited, ", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.check_database_exist(tenant_id, database_name, exist, &database_id))) {
|
|
LOG_WARN("failed to check database exist, ", K(tenant_id), "tablegroup_name", to_cstring(database_name), K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_tablegroup_exist(
|
|
const uint64_t tenant_id, const ObString& tablegroup_name, uint64_t& tablegroup_id, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited,", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.check_tablegroup_exist(tenant_id, tablegroup_name, exist, &tablegroup_id))) {
|
|
LOG_WARN(
|
|
"failed to check tablegroup exist, ", K(tenant_id), "tablegroup_name", to_cstring(tablegroup_name), K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_partition_exist(
|
|
const uint64_t table_id, const int64_t phy_partition_id, const bool check_dropped_partition, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
uint64_t tenant_id = extract_tenant_id(table_id);
|
|
uint64_t fetch_tenant_id = is_sys_table(table_id) ? OB_SYS_TENANT_ID : tenant_id;
|
|
if (!is_tenant_full_schema(fetch_tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited,", K(ret), K(fetch_tenant_id), K(tenant_id), K(table_id));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(fetch_tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret), K(fetch_tenant_id), K(table_id));
|
|
} else if (OB_FAIL(
|
|
schema_guard.check_partition_exist(table_id, phy_partition_id, check_dropped_partition, exist))) {
|
|
LOG_WARN("failed to check partition exist", K(table_id), K(phy_partition_id), K(ret));
|
|
} else {
|
|
LOG_DEBUG("check_partition_exist",
|
|
K(table_id),
|
|
K(check_dropped_partition),
|
|
K(phy_partition_id),
|
|
K(exist),
|
|
K(fetch_tenant_id));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_if_tenant_has_been_dropped(const uint64_t tenant_id, bool& is_dropped)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_dropped = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(OB_SYS_TENANT_ID)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited,", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(OB_SYS_TENANT_ID, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(schema_guard.check_if_tenant_has_been_dropped(tenant_id, is_dropped))) {
|
|
LOG_WARN("failed to check if tenant has been dropped", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::get_database_schema(const uint64_t database_id, const ObDatabaseSchema*& db_schema)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
uint64_t tenant_id = extract_tenant_id(database_id);
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema manager not inited, ", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(get_database_schema(database_id, db_schema))) {
|
|
LOG_WARN("get database schema failed ", K(ret));
|
|
} else if (NULL == db_schema) {
|
|
ret = OB_ERR_NO_DB_SELECTED;
|
|
LOG_WARN("not find this database schema", K(database_id), K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::init_original_schema()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
const bool force_add = true;
|
|
if (OB_FAIL(add_schema(force_add))) {
|
|
LOG_WARN("fail to add schema_manager_for_cache into snapshot", K(ret));
|
|
} else if (OB_FAIL(add_schema(OB_SYS_TENANT_ID, force_add))) {
|
|
LOG_WARN("fail to add schema_manager_for_cache into snapshot", K(ret));
|
|
} else {
|
|
init_ = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// schema version must incremental
|
|
int ObMultiVersionSchemaService::add_schema(const bool force_add)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (!force_add && !check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (OB_ISNULL(schema_mgr_for_cache_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_mgr_for_cache_ is null", K(ret));
|
|
} else {
|
|
int64_t refreshed_schema_version = ATOMIC_LOAD(&refreshed_schema_version_);
|
|
int64_t received_broadcast_version = ATOMIC_LOAD(&received_broadcast_version_);
|
|
int64_t new_schema_version = schema_mgr_for_cache_->get_schema_version();
|
|
ALLOW_NEXT_LOG();
|
|
LOG_INFO("add schema", K(refreshed_schema_version), K(new_schema_version));
|
|
if (refreshed_schema_version > new_schema_version) {
|
|
LOG_WARN("add schema is old", K(refreshed_schema_version), K(new_schema_version), K(received_broadcast_version));
|
|
}
|
|
void* tmp_ptr = NULL;
|
|
ObSchemaMgr* new_mgr = NULL;
|
|
ObSchemaMgr* eli_schema_mgr = NULL;
|
|
if (OB_FAIL(mem_mgr_.alloc(sizeof(ObSchemaMgr), tmp_ptr))) {
|
|
LOG_WARN("alloc mem falied", K(ret));
|
|
} else if (FALSE_IT(new_mgr = new (tmp_ptr) ObSchemaMgr)) {
|
|
// will not reach here
|
|
} else if (OB_FAIL(new_mgr->init())) {
|
|
LOG_WARN("init schema mgr falied", K(ret));
|
|
} else if (OB_FAIL(new_mgr->assign(*schema_mgr_for_cache_))) {
|
|
LOG_WARN("assign schema mgr falied", K(ret));
|
|
} else if (OB_FAIL(schema_mgr_cache_.put(new_mgr, eli_schema_mgr))) {
|
|
LOG_WARN("put schema mgr failed", K(ret));
|
|
if (OB_EAGAIN == ret) {
|
|
int64_t tmp_ret = OB_SUCCESS;
|
|
LOG_INFO("[SCHEMA_RELEASE] free schema mgr",
|
|
"tenant_id",
|
|
new_mgr->get_tenant_id(),
|
|
"schema_version",
|
|
new_mgr->get_schema_version());
|
|
new_mgr->~ObSchemaMgr();
|
|
const int64_t nsv = new_mgr->get_schema_version();
|
|
if (OB_SUCCESS != (tmp_ret = mem_mgr_.free(new_mgr))) {
|
|
LOG_ERROR("free new_mgr failed", K(tmp_ret), K(nsv));
|
|
}
|
|
}
|
|
} else {
|
|
LOG_INFO("put schema mgr succeed",
|
|
"schema_version",
|
|
new_mgr->get_schema_version(),
|
|
"eliminated_schema_version",
|
|
NULL != eli_schema_mgr ? eli_schema_mgr->get_schema_version() : OB_INVALID_VERSION);
|
|
if (OB_NOT_NULL(eli_schema_mgr)) {
|
|
LOG_INFO("[SCHEMA_RELEASE] free schema mgr",
|
|
"tenant_id",
|
|
eli_schema_mgr->get_tenant_id(),
|
|
"schema_version",
|
|
eli_schema_mgr->get_schema_version());
|
|
bool can_switch = false;
|
|
int64_t alloc_cnt = 0;
|
|
int64_t switch_cnt = ObSchemaService::g_liboblog_mode_ ? init_version_cnt_ : GCONF._max_schema_slot_num;
|
|
eli_schema_mgr->~ObSchemaMgr();
|
|
if (OB_FAIL(mem_mgr_.free(static_cast<void*>(eli_schema_mgr)))) {
|
|
LOG_WARN("free eli schema mgr falied", K(ret));
|
|
} else if (OB_FAIL(mem_mgr_.check_can_switch_allocator(can_switch))) {
|
|
LOG_WARN("check can switch allocator falied", K(ret));
|
|
} else if (OB_FAIL(mem_mgr_.get_cur_alloc_cnt(alloc_cnt))) {
|
|
LOG_WARN("get current alloc count falied", K(ret));
|
|
} else if (can_switch && alloc_cnt > switch_cnt) {
|
|
// Switch allocator && rewrite schema_mgr_for_cache_
|
|
void* tmp_ptr = NULL;
|
|
ObIAllocator* allocator = NULL;
|
|
ObSchemaMgr* old_mgr = schema_mgr_for_cache_;
|
|
ObSchemaMgr* new_mgr = NULL;
|
|
if (OB_FAIL(mem_mgr_.switch_allocator())) {
|
|
LOG_WARN("switch allocator falied", K(ret));
|
|
} else if (OB_FAIL(mem_mgr_.alloc(sizeof(ObSchemaMgr), tmp_ptr, &allocator))) {
|
|
LOG_WARN("alloc mem falied", K(ret));
|
|
} else if (FALSE_IT(new_mgr = new (tmp_ptr) ObSchemaMgr(*allocator))) {
|
|
// will not reach here
|
|
} else if (OB_FAIL(new_mgr->init())) {
|
|
LOG_WARN("init new schema mgr falied", K(ret));
|
|
} else if (OB_FAIL(new_mgr->deep_copy(*old_mgr))) {
|
|
LOG_WARN("deep copy old schema mgr falied", K(ret));
|
|
} else {
|
|
LOG_INFO("[SCHEMA_RELEASE] free schema mgr",
|
|
"tenant_id",
|
|
old_mgr->get_tenant_id(),
|
|
"schema_version",
|
|
old_mgr->get_schema_version());
|
|
old_mgr->~ObSchemaMgr();
|
|
if (OB_FAIL(mem_mgr_.free(static_cast<void*>(old_mgr)))) {
|
|
LOG_WARN("free old schema mgr falied", K(ret));
|
|
} else {
|
|
schema_mgr_for_cache_ = new_mgr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
refreshed_schema_version = -1;
|
|
bool found = false;
|
|
do {
|
|
refreshed_schema_version = ATOMIC_LOAD(&refreshed_schema_version_);
|
|
if (new_schema_version <= refreshed_schema_version) {
|
|
found = true;
|
|
}
|
|
} while (!found && !ATOMIC_BCAS(&refreshed_schema_version_, refreshed_schema_version, new_schema_version));
|
|
LOG_INFO("[REFRESH_SCHEMA] change refreshed_schema_version with old mode", K(new_schema_version));
|
|
// Because RS only notifies other observers through RPC,
|
|
// the received_broadcast_version of the local observer is not updated
|
|
// This variable will be copied in obmp_query to ob_latest_schema_version in the session variable
|
|
// The proxy will use the variable ob_latest_schema_version to ensure that
|
|
// multiple observers are connected to the same schema version.
|
|
int64_t received_broadcast_version = -1;
|
|
found = false;
|
|
do {
|
|
received_broadcast_version = ATOMIC_LOAD(&received_broadcast_version_);
|
|
if (new_schema_version <= received_broadcast_version) {
|
|
found = true;
|
|
}
|
|
} while (!found && !ATOMIC_BCAS(&received_broadcast_version_, received_broadcast_version, new_schema_version));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// schema version must incremental
|
|
int ObMultiVersionSchemaService::add_schema(const uint64_t tenant_id, const bool force_add)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObSchemaMgr* schema_mgr_for_cache = NULL;
|
|
ObSchemaMemMgr* mem_mgr = NULL;
|
|
ObSchemaMgrCache* schema_mgr_cache = NULL;
|
|
int64_t refreshed_schema_version = OB_INVALID_VERSION;
|
|
int64_t received_broadcast_version = OB_INVALID_VERSION;
|
|
ObSchemaStore* schema_store = NULL;
|
|
if (!force_add && !check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
LOG_WARN("fail to get schema_store", K(ret));
|
|
} else if (OB_FAIL(schema_mgr_for_cache_map_.get_refactored(tenant_id, schema_mgr_for_cache))) {
|
|
LOG_WARN("fail to get schema mgr for cache", K(ret), K(ret));
|
|
} else if (OB_ISNULL(schema_mgr_for_cache)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_mgr is null", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(mem_mgr_map_.get_refactored(tenant_id, mem_mgr))) {
|
|
LOG_WARN("fail to get mem mgr", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(mem_mgr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("mem_mgr is null", K(ret), K(tenant_id));
|
|
} else {
|
|
schema_mgr_cache = &schema_store->schema_mgr_cache_;
|
|
int64_t new_schema_version = schema_mgr_for_cache->get_schema_version();
|
|
refreshed_schema_version = schema_store->get_refreshed_version();
|
|
ALLOW_NEXT_LOG();
|
|
LOG_INFO("add schema", K(refreshed_schema_version), K(new_schema_version));
|
|
if (refreshed_schema_version > new_schema_version) {
|
|
LOG_WARN("add schema is old", K(refreshed_schema_version), K(new_schema_version), K(received_broadcast_version));
|
|
}
|
|
void* tmp_ptr = NULL;
|
|
ObSchemaMgr* new_mgr = NULL;
|
|
ObSchemaMgr* eli_schema_mgr = NULL;
|
|
bool is_exist = false;
|
|
if (OB_FAIL(schema_mgr_cache->check_schema_mgr_exist(new_schema_version, is_exist))) {
|
|
LOG_WARN("fail to check schema_mgr exist", K(ret), K(tenant_id), K(new_schema_version));
|
|
} else if (is_exist) {
|
|
LOG_INFO("schema mgr already exist, just skip", K(ret), K(tenant_id), K(new_schema_version), K(lbt()));
|
|
} else if (OB_FAIL(mem_mgr->alloc(sizeof(ObSchemaMgr), tmp_ptr))) {
|
|
LOG_WARN("alloc mem falied", K(ret));
|
|
} else if (FALSE_IT(new_mgr = new (tmp_ptr) ObSchemaMgr)) {
|
|
// will not reach here
|
|
} else if (OB_FAIL(new_mgr->init())) {
|
|
LOG_WARN("init schema mgr falied", K(ret));
|
|
} else if (OB_FAIL(new_mgr->assign(*schema_mgr_for_cache))) {
|
|
LOG_WARN("assign schema mgr falied", K(ret));
|
|
} else if (OB_FAIL(schema_mgr_cache->put(new_mgr, eli_schema_mgr))) {
|
|
LOG_WARN("put schema mgr failed", K(ret));
|
|
if (OB_EAGAIN == ret) {
|
|
LOG_INFO("[SCHEMA_RELEASE] free schema mgr",
|
|
"tenant_id",
|
|
new_mgr->get_tenant_id(),
|
|
"schema_version",
|
|
new_mgr->get_schema_version());
|
|
int64_t tmp_ret = OB_SUCCESS;
|
|
new_mgr->~ObSchemaMgr();
|
|
const int64_t nsv = new_mgr->get_schema_version();
|
|
if (OB_SUCCESS != (tmp_ret = mem_mgr->free(new_mgr))) {
|
|
LOG_ERROR("free new_mgr failed", K(tmp_ret), K(nsv));
|
|
}
|
|
}
|
|
} else {
|
|
LOG_INFO("put schema mgr succeed",
|
|
"schema_version",
|
|
new_mgr->get_schema_version(),
|
|
"eliminated_schema_version",
|
|
NULL != eli_schema_mgr ? eli_schema_mgr->get_schema_version() : OB_INVALID_VERSION);
|
|
if (OB_NOT_NULL(eli_schema_mgr)) {
|
|
LOG_INFO("[SCHEMA_RELEASE] free schema mgr",
|
|
"tenant_id",
|
|
eli_schema_mgr->get_tenant_id(),
|
|
"schema_version",
|
|
eli_schema_mgr->get_schema_version());
|
|
eli_schema_mgr->~ObSchemaMgr();
|
|
if (OB_FAIL(mem_mgr->free(static_cast<void*>(eli_schema_mgr)))) {
|
|
LOG_WARN("free eli schema mgr falied", K(ret));
|
|
}
|
|
}
|
|
// try switch allocator
|
|
if (OB_SUCC(ret)) {
|
|
bool can_switch = false;
|
|
int64_t alloc_cnt = 0;
|
|
int64_t switch_cnt = ObSchemaService::g_liboblog_mode_ ? init_version_cnt_ : GCONF._max_schema_slot_num;
|
|
if (OB_FAIL(mem_mgr->check_can_switch_allocator(can_switch))) {
|
|
LOG_WARN("check can switch allocator falied", K(ret));
|
|
} else if (OB_FAIL(mem_mgr->get_cur_alloc_cnt(alloc_cnt))) {
|
|
LOG_WARN("get current alloc count falied", K(ret));
|
|
} else if (can_switch && alloc_cnt > switch_cnt) {
|
|
// Switch allocator && rewrite schema_mgr_for_cache_
|
|
LOG_INFO("try to switch allocator",
|
|
K(ret),
|
|
K(tenant_id),
|
|
"schema_version",
|
|
schema_mgr_for_cache->get_schema_version());
|
|
void* tmp_ptr = NULL;
|
|
ObIAllocator* allocator = NULL;
|
|
ObSchemaMgr* old_mgr = schema_mgr_for_cache;
|
|
ObSchemaMgr* new_mgr = NULL;
|
|
bool overwrite = true;
|
|
if (OB_FAIL(mem_mgr->switch_allocator())) {
|
|
LOG_WARN("switch allocator falied", K(ret));
|
|
} else if (OB_FAIL(mem_mgr->alloc(sizeof(ObSchemaMgr), tmp_ptr, &allocator))) {
|
|
LOG_WARN("alloc mem falied", K(ret));
|
|
} else if (FALSE_IT(new_mgr = new (tmp_ptr) ObSchemaMgr(*allocator))) {
|
|
// will not reach here
|
|
} else if (OB_FAIL(new_mgr->init())) {
|
|
LOG_WARN("init new schema mgr falied", K(ret));
|
|
} else if (OB_FAIL(new_mgr->deep_copy(*old_mgr))) {
|
|
LOG_WARN("deep copy old schema mgr falied", K(ret));
|
|
} else if (OB_FAIL(schema_mgr_for_cache_map_.set_refactored(tenant_id, new_mgr, overwrite))) {
|
|
LOG_WARN("fail to get schema mgr for cache", K(ret), K(ret));
|
|
} else {
|
|
LOG_INFO("[SCHEMA_RELEASE] free schema mgr",
|
|
"tenant_id",
|
|
old_mgr->get_tenant_id(),
|
|
"schema_version",
|
|
old_mgr->get_schema_version());
|
|
old_mgr->~ObSchemaMgr();
|
|
if (OB_FAIL(mem_mgr->free(static_cast<void*>(old_mgr)))) {
|
|
LOG_WARN("free old schema mgr falied", K(ret));
|
|
} else {
|
|
schema_mgr_for_cache = new_mgr;
|
|
}
|
|
}
|
|
}
|
|
LOG_DEBUG("check can switch", K(ret), K(tenant_id), K(can_switch), K(alloc_cnt), K(switch_cnt));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
schema_store->update_refreshed_version(new_schema_version);
|
|
LOG_INFO("[REFRESH_SCHEMA] change refreshed_schema_version with new mode", K(tenant_id), K(new_schema_version));
|
|
// Because RS only notifies other observers through RPC, the received_broadcast_version of the local observer
|
|
// is not updated
|
|
// This variable will be copied in obmp_query to ob_latest_schema_version in the session variable
|
|
// The proxy will use the variable ob_latest_schema_version to ensure that
|
|
// multiple observers are connected to the same schema version.
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::refresh_and_add_schema(int64_t expected_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
lib::ObMutexGuard guard(schema_refresh_mutex_);
|
|
auto func = [&]() {
|
|
// Ensure that the memory on the stack requested in the refresh schema process also uses the default 500 tenant
|
|
ObArenaAllocator allocator(ObModIds::OB_MODULE_PAGE_ALLOCATOR, OB_MALLOC_BIG_BLOCK_SIZE, OB_SERVER_TENANT_ID);
|
|
schema_stack_allocator() = &allocator;
|
|
if (OB_FAIL(refresh_schema(expected_version))) {
|
|
LOG_WARN("fail to refresh_schema and update schema_manager_for_cache", K(ret));
|
|
}
|
|
schema_stack_allocator() = nullptr;
|
|
};
|
|
CREATE_WITH_TEMP_ENTITY_P(!ObSchemaService::g_liboblog_mode_, RESOURCE_OWNER, common::OB_SERVER_TENANT_ID)
|
|
{
|
|
func();
|
|
}
|
|
else
|
|
{
|
|
// Two considerations, one is that there is no omt module in one side, and the other is
|
|
// that the tenant has not been loaded during the omt startup phase.
|
|
func();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::async_refresh_schema(const uint64_t tenant_id, const int64_t schema_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t local_schema_version = OB_INVALID_VERSION;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid arg", K(ret), K(tenant_id), K(schema_version));
|
|
} else if (!ObSchemaService::is_formal_version(schema_version)) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("should retry", K(ret), K(tenant_id), K(schema_version));
|
|
} else if (OB_FAIL(get_tenant_refreshed_schema_version(tenant_id, local_schema_version))) {
|
|
LOG_WARN("fail to get tenant refreshed schema version", K(ret), K(tenant_id), K(schema_version));
|
|
} else if (local_schema_version >= schema_version) {
|
|
// do nothing
|
|
} else {
|
|
int64_t retry_cnt = 0;
|
|
int64_t MAX_RETRY_CNT = 1000;
|
|
int64_t RETRY_IDLE_TIME = 100 * 1000L; // 100ms
|
|
while (OB_SUCC(ret)) {
|
|
if (THIS_WORKER.is_timeout() || (INT64_MAX == THIS_WORKER.get_timeout_ts() && retry_cnt >= MAX_RETRY_CNT)) {
|
|
ret = OB_TIMEOUT;
|
|
LOG_WARN("already timeout", K(ret), K(tenant_id), K(schema_version));
|
|
} else if (OB_FAIL(get_tenant_refreshed_schema_version(tenant_id, local_schema_version))) {
|
|
LOG_WARN("fail to get tenant refreshed schema version", K(ret), K(tenant_id), K(schema_version));
|
|
} else if (local_schema_version >= schema_version) {
|
|
// success
|
|
break;
|
|
} else if (OB_ISNULL(GCTX.ob_service_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("observice is null", K(ret));
|
|
} else {
|
|
if (0 != retry_cnt % 20) {
|
|
// try refresh schema each 2s
|
|
} else if (OB_FAIL(GCTX.ob_service_->submit_async_refresh_schema_task(tenant_id, schema_version))) {
|
|
if (OB_EAGAIN == ret || OB_SIZE_OVERFLOW == ret) {
|
|
ret = OB_SUCCESS;
|
|
} else {
|
|
LOG_WARN("fail to submit async refresh schema task", K(ret), K(tenant_id), K(schema_version));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
retry_cnt++;
|
|
usleep(RETRY_IDLE_TIME);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* 1. If tenant_id is OB_INVALID_TENANT_ID, it means refresh the schema of all tenants,
|
|
* otherwise only the schema of the corresponding tenant will be refreshed.
|
|
* 2. The new schema_version broadcast mechanism does not support the read-only zone scheme. For details, see:
|
|
* 3. When refreshing the schema, you must first obtain the schema_version version
|
|
* that each tenant wants to refresh from the internal table:
|
|
* 1) For system tenants of the primary cluster and standalone cluster, the schema refresh is strengthened
|
|
* consistent read, and the max_schema_version is obtained directly from the corresponding __all_ddl_operation.
|
|
* 2) For user tenants of the standalone cluster, a consistent read is required to obtain
|
|
* the max_schema_version of the corresponding tenant from __all_core_table.
|
|
* 4. If a tenant fails to update to the specified version, an error will be reported and the external logic will try
|
|
* again
|
|
*/
|
|
int ObMultiVersionSchemaService::refresh_and_add_schema(
|
|
const ObIArray<uint64_t>& tenant_ids, bool use_new_mode /*= true*/, bool check_bootstrap /* = false*/)
|
|
{
|
|
LOG_INFO("[REFRESH_SCHEMA] start to refresh and add schema", K(tenant_ids));
|
|
int ret = OB_SUCCESS;
|
|
bool is_schema_splited = GCTX.is_schema_splited();
|
|
bool is_standby_cluster = GCTX.is_standby_cluster();
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (!is_schema_splited && !use_new_mode) {
|
|
// for compatible
|
|
// Currently expect_version will only specify a valid value when the heartbeat triggers the old schema refresh
|
|
// logic, and the rest are -1, so expect_version is not passed here
|
|
if (OB_FAIL(refresh_and_add_schema(-1))) {
|
|
LOG_WARN("fail to refresh and add schema", K(ret));
|
|
}
|
|
} else {
|
|
lib::ObMutexGuard guard(schema_refresh_mutex_);
|
|
auto func = [&]() {
|
|
ObSchemaStatusProxy* schema_status_proxy = GCTX.schema_status_proxy_;
|
|
// This is just to reduce SQL calls, the error code can be ignored
|
|
int tmp_ret = OB_SUCCESS;
|
|
bool restore_tenant_exist = false;
|
|
if (ObSchemaService::g_liboblog_mode_) {
|
|
// Avoid using schema_status_proxy for agentserver and liboblog
|
|
restore_tenant_exist = false;
|
|
} else if (OB_SUCCESS != (tmp_ret = check_restore_tenant_exist(tenant_ids, restore_tenant_exist))) {
|
|
LOG_WARN("fail to check restore tenant exist", K(ret), K(tmp_ret), K(tenant_ids));
|
|
restore_tenant_exist = true;
|
|
}
|
|
if (is_standby_cluster || restore_tenant_exist) {
|
|
if (OB_ISNULL(schema_status_proxy)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_status_proxy is null", K(ret));
|
|
} else if (OB_FAIL(schema_status_proxy->load_refresh_schema_status())) {
|
|
LOG_WARN("fail to load refresh schema status", K(ret));
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (check_bootstrap) {
|
|
// The schema refresh triggered by the heartbeat is forbidden in the bootstrap phase,
|
|
// and it needs to be judged in the schema_refresh_mutex_lock
|
|
int64_t baseline_schema_version = OB_INVALID_VERSION;
|
|
if (OB_FAIL(get_baseline_schema_version(baseline_schema_version))) {
|
|
LOG_WARN("fail to get baseline_schema_version", K(ret));
|
|
} else if (baseline_schema_version < 0) {
|
|
// still in bootstrap phase, refresh schema is not allowed
|
|
ret = OB_OP_NOT_ALLOW;
|
|
LOG_WARN("refresh schema in bootstrap phase is not allowed", K(ret));
|
|
}
|
|
}
|
|
|
|
// Ensure that the memory on the stack requested during the refresh schema process also uses the default 500
|
|
// tenant
|
|
ObArenaAllocator allocator(ObModIds::OB_MODULE_PAGE_ALLOCATOR, OB_MALLOC_BIG_BLOCK_SIZE, OB_SERVER_TENANT_ID);
|
|
schema_stack_allocator() = &allocator;
|
|
|
|
ObArray<uint64_t> all_tenant_ids;
|
|
if (OB_FAIL(ret)) {
|
|
} else if (0 == tenant_ids.count()) {
|
|
// refresh all tenant schema
|
|
ObSchemaMgr* schema_mgr = NULL;
|
|
if (OB_FAIL(refresh_tenant_schema(OB_SYS_TENANT_ID))) {
|
|
LOG_WARN("fail to refresh sys schema", K(ret), K(all_tenant_ids));
|
|
} else if (OB_FAIL(schema_mgr_for_cache_map_.get_refactored(OB_SYS_TENANT_ID, schema_mgr))) {
|
|
LOG_WARN("fail to get sys schema mgr for cache", K(ret));
|
|
} else if (OB_ISNULL(schema_mgr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_mgr is null", K(ret));
|
|
} else if (OB_FAIL(schema_mgr->get_tenant_ids(all_tenant_ids))) {
|
|
LOG_WARN("fail to get all tenant_ids", K(ret));
|
|
} else {
|
|
// Ignore that some tenants fail to refresh the schema,
|
|
// and need to report an error to the upper layer to avoid pushing up last_refresh_schema_info
|
|
int tmp_ret = OB_SUCCESS;
|
|
for (int64_t i = 0; i < all_tenant_ids.count(); i++) {
|
|
const uint64_t tenant_id = all_tenant_ids.at(i);
|
|
if (OB_SYS_TENANT_ID == tenant_id) {
|
|
// skip
|
|
} else if (OB_SUCCESS != (tmp_ret = refresh_tenant_schema(tenant_id))) {
|
|
LOG_WARN("fail to refresh tenant schema", K(tmp_ret), K(tenant_id));
|
|
}
|
|
if (OB_SUCCESS != tmp_ret && OB_SUCCESS == ret) {
|
|
ret = tmp_ret;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// Ignore that some tenants fail to refresh the schema,
|
|
// and need to report an error to the upper layer to avoid pushing up last_refresh_schema_info
|
|
int tmp_ret = OB_SUCCESS;
|
|
for (int64_t i = 0; i < tenant_ids.count(); i++) {
|
|
const uint64_t tenant_id = tenant_ids.at(i);
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
tmp_ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(tmp_ret), K(tenant_id));
|
|
} else if (OB_SUCCESS != (tmp_ret = refresh_tenant_schema(tenant_id))) {
|
|
LOG_WARN("fail to refresh tenant schema", K(tmp_ret), K(tenant_id));
|
|
}
|
|
if (OB_SUCCESS != tmp_ret && OB_SUCCESS == ret) {
|
|
ret = tmp_ret;
|
|
}
|
|
}
|
|
}
|
|
schema_stack_allocator() = nullptr;
|
|
};
|
|
CREATE_WITH_TEMP_ENTITY_P(!ObSchemaService::g_liboblog_mode_, RESOURCE_OWNER, common::OB_SERVER_TENANT_ID)
|
|
{
|
|
func();
|
|
}
|
|
else
|
|
{
|
|
// Two aspects are considered, one is that there is no omt module in one side,
|
|
// and the other is that the tenant has not been loaded during the omt startup phase.
|
|
func();
|
|
}
|
|
}
|
|
LOG_INFO("[REFRESH_SCHEMA] end refresh and add schema", K(ret), K(tenant_ids));
|
|
return ret;
|
|
}
|
|
|
|
// It is used to determine the initial Partition set when liboblog starts, and obtain the maximum schema_version
|
|
// that meets the requirements of <=timestamp. The schema_version should be as large as possible;
|
|
// it is also used for schema history recycle
|
|
// 1. Bootstrap non-split mode or tenant has no new ddl after upgrade split: return max (schema_version),
|
|
// compatible with non-split mode
|
|
// 2. Bootstrap split mode or tenant has new ddl after upgrade split:
|
|
// Return the schema_version corresponding to the largest transaction boundary
|
|
int ObMultiVersionSchemaService::get_schema_version_by_timestamp(
|
|
const ObRefreshSchemaStatus& schema_status, const uint64_t tenant_id, int64_t timestamp, int64_t& schema_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_INVALID_TENANT_ID == tenant_id || timestamp <= 0) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid arg", K(ret), K(tenant_id), K(timestamp));
|
|
} else if (OB_ISNULL(sql_proxy_) || OB_ISNULL(schema_service_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("proxy or schema_service is null", K(ret), KP(sql_proxy_), KP(schema_service_));
|
|
} else if (OB_FAIL(schema_service_->get_schema_version_by_timestamp(
|
|
*sql_proxy_, schema_status, tenant_id, timestamp, schema_version))) {
|
|
LOG_WARN("fail to get schema_version by timestamp", K(ret), K(tenant_id), K(timestamp));
|
|
}
|
|
LOG_INFO("[REFRESH_SCHEMA] get_schema_version_by_timestamp", K(ret), K(tenant_id), K(timestamp), K(schema_version));
|
|
return ret;
|
|
}
|
|
|
|
// Used to determine the tenant's starting schema_version during the operation of liboblog.
|
|
// Unlike the startup time, liboblog assumes that the Partition set of the tenant's initial user table is empty.
|
|
// In order to ensure that the ddl is not output and the Partition is not obtained,
|
|
// the schema_version needs to be as small as possible.
|
|
// Discuss several situations:
|
|
// 1. OB_DDL_ADD_TENANT: Indicates a tenant created in a non-split mode,
|
|
// and the schema_version can be the schema_version corresponding to OB_DDL_ADD_TENANT;
|
|
// 2. OB_DDL_ADD_TENANT_START: liboblog does not think that the tenant is created successfully,
|
|
// only outputs DDL without actual operation;
|
|
// 3. OB_DDL_ADD_TENANT_END: liboblog determines its working mode based on whether ob is in split mode at the start time
|
|
// and whether OB_DDL_FINISH_SCHEMA_SPLIT has been processed(Can be inconsistent with the working mode of the schema
|
|
// module)
|
|
// 3.1) 2.2 Tenants created in non-split mode: take the transaction boundary of transaction two,
|
|
// but at this time __all_ddl_operation is not split, and it is difficult to determine the transaction boundary.
|
|
// 3.2) 2.2 Tenants created by split mode: take the transaction boundary of transaction two,
|
|
// which is equivalent to the first transaction boundary of the tenant __all_ddl_operation.
|
|
// In summary, this interface is only used in the 3.2) scenario, and the rest of the scenarios are handled by liboblog.
|
|
int ObMultiVersionSchemaService::get_first_trans_end_schema_version(const uint64_t tenant_id, int64_t& schema_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
schema_version = OB_INVALID_VERSION;
|
|
if (!ObSchemaService::g_liboblog_mode_) {
|
|
ret = OB_OP_NOT_ALLOW;
|
|
LOG_WARN("only work for liboblog", K(ret));
|
|
} else if (OB_INVALID_TENANT_ID == tenant_id || OB_SYS_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid arg", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(sql_proxy_) || OB_ISNULL(schema_service_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("proxy or schema_service is null", K(ret), KP(sql_proxy_), KP(schema_service_));
|
|
} else if (OB_FAIL(schema_service_->get_first_trans_end_schema_version(*sql_proxy_, tenant_id, schema_version))) {
|
|
LOG_WARN("fail to get first trans end schema_version", K(ret), K(tenant_id));
|
|
}
|
|
LOG_INFO("[REFRESH_SCHEMA] get_first_trans_end_schema_version", K(ret), K(tenant_id), K(schema_version));
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::load_split_schema_version(int64_t& split_schema_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
split_schema_version = OB_INVALID_VERSION;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (!ObSchemaService::g_liboblog_mode_) {
|
|
ret = OB_OP_NOT_ALLOW;
|
|
LOG_WARN("only work for liboblog", K(ret));
|
|
} else if (OB_ISNULL(sql_proxy_) || OB_ISNULL(schema_service_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("proxy or schema_service_impl is null", K(ret), KP(sql_proxy_), KP(schema_service_));
|
|
} else if (OB_FAIL(schema_service_->load_split_schema_version(*sql_proxy_, split_schema_version))) {
|
|
LOG_WARN("fail to get split schema version", K(ret));
|
|
}
|
|
LOG_INFO("[REFRESH_SCHEMA] load_split_schema_version", K(ret), K(split_schema_version));
|
|
return ret;
|
|
}
|
|
|
|
// Only for liboblog, it will automatically switch the working mode of the schema module (old mode -> new mode)
|
|
// tenant_id is OB_INVALID_TENANT_ID, which means refreshing the schema of all tenants
|
|
int ObMultiVersionSchemaService::auto_switch_mode_and_refresh_schema(
|
|
const uint64_t tenant_id, const int64_t expected_schema_version /* = OB_INVALID_SCHEMA_VERSION */)
|
|
{
|
|
LOG_INFO("[REFRESH_SCHEMA] start to refresh and add schema", K(tenant_id));
|
|
int ret = OB_SUCCESS;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (!ObSchemaService::g_liboblog_mode_) {
|
|
ret = OB_OP_NOT_ALLOW;
|
|
LOG_WARN("only work for liboblog", K(ret));
|
|
} else if (OB_ISNULL(sql_proxy_) || OB_ISNULL(schema_service_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("proxy or schema_service_impl is null", K(ret), KP(sql_proxy_), KP(schema_service_));
|
|
} else {
|
|
lib::ObMutexGuard guard(schema_refresh_mutex_);
|
|
auto func = [&]() {
|
|
// Ensure that the memory on the stack requested during the refresh schema process also uses the default 500
|
|
// tenant
|
|
ObArenaAllocator allocator(ObModIds::OB_MODULE_PAGE_ALLOCATOR, OB_MALLOC_BIG_BLOCK_SIZE, OB_SERVER_TENANT_ID);
|
|
schema_stack_allocator() = &allocator;
|
|
|
|
bool need_refresh_schema = true; // The schema needs to be refreshed by default
|
|
// If the user configures expected_schema_version, first obtain the latest schema version.
|
|
// If the schema version is greater than or equal to expected_schema_version, there is no need to refresh the
|
|
// schema
|
|
if (OB_INVALID_TENANT_ID != tenant_id && OB_INVALID_SCHEMA_VERSION != expected_schema_version) {
|
|
// For a single tenant, its schema_version is always comparable whether it is the old version of
|
|
// the cluster-level schema_version or the new version of the group-level chema_version
|
|
int64_t refreshed_version = OB_INVALID_SCHEMA_VERSION;
|
|
if (OB_FAIL(get_tenant_refreshed_schema_version(tenant_id, refreshed_version))) {
|
|
if (OB_ENTRY_NOT_EXIST == ret) {
|
|
// The tenant does not exist. Normally, the schema needs to be refreshed.
|
|
need_refresh_schema = true;
|
|
ret = OB_SUCCESS;
|
|
} else {
|
|
LOG_ERROR("get_tenant_refreshed_schema_version fail", KR(ret), K(tenant_id));
|
|
}
|
|
} else {
|
|
need_refresh_schema = (expected_schema_version > refreshed_version);
|
|
if (!need_refresh_schema) {
|
|
LOG_INFO("tenant schema has been refreshed to expected schema version, need not refresh",
|
|
K(tenant_id),
|
|
K(expected_schema_version),
|
|
K(refreshed_version));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool use_new_mode = false;
|
|
ObArray<uint64_t> tenant_ids;
|
|
if (!GCTX.is_schema_splited()) {
|
|
// check current mode
|
|
int64_t split_schema_version = OB_INVALID_VERSION;
|
|
if (OB_FAIL(schema_service_->load_split_schema_version(*sql_proxy_, split_schema_version))) {
|
|
LOG_WARN("fail to get split schema version", K(ret));
|
|
} else if (split_schema_version < 0) {
|
|
// use old mode
|
|
if (!need_refresh_schema) {
|
|
// schema is new enough, just skip
|
|
} else if (OB_FAIL(refresh_schema(-1))) {
|
|
LOG_WARN("fail to refresh_schema and update schema_manager_for_cache", K(ret));
|
|
}
|
|
} else {
|
|
// use new mode & refresh all tenants' schema
|
|
use_new_mode = true;
|
|
(void)GCTX.set_split_schema_version(split_schema_version);
|
|
}
|
|
} else {
|
|
// use new mode & refresh specified tenant's schema
|
|
use_new_mode = true;
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
// refresh all tenant schema
|
|
} else if (OB_FAIL(tenant_ids.push_back(tenant_id))) {
|
|
LOG_WARN("fail to push_back tenant_id", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret) && use_new_mode) {
|
|
if (0 == tenant_ids.count()) {
|
|
// refresh all tenant schema
|
|
ObSchemaMgr* schema_mgr = NULL;
|
|
ObArray<uint64_t> all_tenant_ids;
|
|
if (OB_FAIL(refresh_tenant_schema(OB_SYS_TENANT_ID))) {
|
|
LOG_WARN("fail to refresh sys schema", K(ret), K(all_tenant_ids));
|
|
} else if (OB_FAIL(schema_mgr_for_cache_map_.get_refactored(OB_SYS_TENANT_ID, schema_mgr))) {
|
|
LOG_WARN("fail to get sys schema mgr for cache", K(ret));
|
|
} else if (OB_ISNULL(schema_mgr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_mgr is null", K(ret));
|
|
} else if (OB_FAIL(schema_mgr->get_tenant_ids(all_tenant_ids))) {
|
|
LOG_WARN("fail to get all tenant_ids", K(ret));
|
|
} else {
|
|
// Ignore that some tenants fail to refresh the schema, but need to report an error to the upper level
|
|
int tmp_ret = OB_SUCCESS;
|
|
for (int64_t i = 0; i < all_tenant_ids.count(); i++) {
|
|
const uint64_t tenant_id = all_tenant_ids.at(i);
|
|
if (OB_SYS_TENANT_ID == tenant_id) {
|
|
// skip
|
|
} else if (OB_SUCCESS != (tmp_ret = refresh_tenant_schema(tenant_id))) {
|
|
LOG_WARN("fail to refresh tenant schema", K(tmp_ret), K(tenant_id));
|
|
TenantStatus tenant_status = TENANT_STATUS_INVALID;
|
|
int temp_ret = query_tenant_status(tenant_id, tenant_status);
|
|
if (OB_SUCCESS != temp_ret) {
|
|
LOG_WARN("fail to query tenant status", K(tmp_ret), K(temp_ret), K(tenant_id));
|
|
} else if (TENANT_DELETED == tenant_status) {
|
|
LOG_INFO("tenant has been dropped, just ignore", K(tmp_ret), K(tenant_id));
|
|
tmp_ret = OB_SUCCESS;
|
|
}
|
|
}
|
|
if (OB_SUCCESS != tmp_ret && OB_SUCCESS == ret) {
|
|
ret = tmp_ret;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// single tenant schema refresh
|
|
int64_t local_version = OB_INVALID_VERSION;
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (!need_refresh_schema) {
|
|
// schema is new enough, just skip
|
|
} else if (OB_FAIL(get_tenant_refreshed_schema_version(tenant_id, local_version))) {
|
|
if (OB_ENTRY_NOT_EXIST == ret) {
|
|
// The tenant related data structure does not exist, trigger the system tenant schema refresh,
|
|
// and initialize the related data structure
|
|
if (OB_FAIL(refresh_tenant_schema(OB_SYS_TENANT_ID))) {
|
|
LOG_WARN("refresh sys schema failed", K(ret));
|
|
}
|
|
} else {
|
|
LOG_WARN("fail to get tenant refreshed schema version", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(refresh_tenant_schema(tenant_id))) {
|
|
LOG_WARN("fail to refresh tenant schema", K(ret), K(tenant_id));
|
|
TenantStatus tenant_status = TENANT_STATUS_INVALID;
|
|
int temp_ret = query_tenant_status(tenant_id, tenant_status);
|
|
if (OB_SUCCESS != temp_ret) {
|
|
LOG_WARN("query tenant status failed", K(ret), K(temp_ret), K(tenant_id));
|
|
} else if (TENANT_DELETED == tenant_status) {
|
|
LOG_INFO("tenant has been dropped, no need retry", K(ret), K(tenant_id));
|
|
ret = OB_TENANT_HAS_BEEN_DROPPED; // overwrite ret
|
|
}
|
|
}
|
|
}
|
|
}
|
|
schema_stack_allocator() = nullptr;
|
|
};
|
|
|
|
if (OB_SUCCESS == ret) {
|
|
CREATE_WITH_TEMP_ENTITY_P(!ObSchemaService::g_liboblog_mode_, RESOURCE_OWNER, common::OB_SERVER_TENANT_ID)
|
|
{
|
|
func();
|
|
}
|
|
else
|
|
{
|
|
// Two aspects are considered, one is that there is no omt module in one side,
|
|
// and the other is that the tenant has not been loaded during the omt startup phase.
|
|
func();
|
|
}
|
|
}
|
|
}
|
|
LOG_INFO("[REFRESH_SCHEMA] end refresh and add schema", K(ret), K(tenant_id));
|
|
return ret;
|
|
}
|
|
|
|
// refresh schema by tenant
|
|
// 1. System tenants strengthen the consistency of reading and brushing schema
|
|
// 2. user tenants of the primary cluster strengthened to read and refresh schema consistently
|
|
// 3. user tenants of the standalone cluster are weakly consistent in reading and refresh schema,
|
|
// and they need to obtain the weakly consistent read version number and the visible schema version
|
|
int ObMultiVersionSchemaService::refresh_tenant_schema(const uint64_t tenant_id)
|
|
{
|
|
LOG_INFO("[REFRESH_SCHEMA] start to refresh and add schema by tenant", K(tenant_id));
|
|
int ret = OB_SUCCESS;
|
|
bool refresh_full_schema = false;
|
|
bool is_standby_cluster = GCTX.is_standby_cluster();
|
|
bool is_restore = false;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(sql_proxy_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("proxy is null", K(ret));
|
|
} else if (!ObSchemaService::g_liboblog_mode_ && OB_FAIL(check_tenant_is_restore(NULL, tenant_id, is_restore))) {
|
|
LOG_WARN("fail to check restore tenant exist", K(ret), K(tenant_id));
|
|
} else {
|
|
int64_t new_received_schema_version = OB_INVALID_VERSION;
|
|
ObRefreshSchemaStatus refresh_schema_status;
|
|
ObISQLClient& sql_client = *sql_proxy_;
|
|
|
|
// read refresh_schema_status from inner table
|
|
if ((!is_standby_cluster && !is_restore) || OB_SYS_TENANT_ID == tenant_id) {
|
|
// 1. System tenants strengthen the consistency of reading and refresh schema
|
|
// 2. user tenants of the primary cluster strengthened to read and refresh schema consistently
|
|
refresh_schema_status.reset();
|
|
refresh_schema_status.tenant_id_ = tenant_id;
|
|
refresh_schema_status.snapshot_timestamp_ = OB_INVALID_TIMESTAMP;
|
|
refresh_schema_status.readable_schema_version_ = OB_INVALID_VERSION;
|
|
} else {
|
|
// 3. user tenants of the standalone cluster weaken the consistent read and refresh schema
|
|
// 4. primary cluster restore tenants are weak, consistent read and refresh schema
|
|
ObSchemaStatusProxy* schema_status_proxy = GCTX.schema_status_proxy_;
|
|
if (OB_ISNULL(schema_status_proxy)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_status_proxy is null", K(ret));
|
|
} else if (OB_FAIL(schema_status_proxy->get_refresh_schema_status(tenant_id, refresh_schema_status))) {
|
|
LOG_WARN("fail to get refresh schema status", K(ret), K(tenant_id));
|
|
} else if (refresh_schema_status.snapshot_timestamp_ == 0 ||
|
|
refresh_schema_status.readable_schema_version_ == 0) {
|
|
// The standalone cluster RS has not yet pushed the tenant's schema version (the standalone cluster RS
|
|
// needs to change the internal table first, and then change the memory value),
|
|
// and skip the tenant schema refresh at this time
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_INFO(
|
|
"[REFRESH_SCHEMA] tenant schema is not ready, just skip", K(ret), K(tenant_id), K(refresh_schema_status));
|
|
} else if (OB_INVALID_TIMESTAMP == refresh_schema_status.snapshot_timestamp_ &&
|
|
OB_INVALID_VERSION == refresh_schema_status.readable_schema_version_) {
|
|
// After the standalone cluster enters the flashback stage, the schema_status will be set to -1, -1;
|
|
// All future queries will be read more strongly
|
|
is_standby_cluster = false;
|
|
is_restore = false;
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
bool need_refresh = true;
|
|
if (OB_FAIL(refresh_full_schema_map_.get_refactored(tenant_id, refresh_full_schema))) {
|
|
LOG_WARN("refresh full schema", K(ret), K(tenant_id));
|
|
} else if (!refresh_full_schema) {
|
|
if ((!is_standby_cluster && !is_restore) || OB_SYS_TENANT_ID == tenant_id) {
|
|
ObRefreshSchemaStatus schema_status;
|
|
schema_status.tenant_id_ = tenant_id;
|
|
if (OB_FAIL(get_schema_version_in_inner_table(sql_client, schema_status, new_received_schema_version))) {
|
|
LOG_WARN("fail to get tenant schema version", K(ret), K(tenant_id));
|
|
} else {
|
|
}
|
|
} else {
|
|
new_received_schema_version = refresh_schema_status.readable_schema_version_;
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
ObSchemaStore* schema_store = schema_store_map_.get(tenant_id);
|
|
if (NULL == schema_store) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("fail to get schema store", K(ret));
|
|
} else {
|
|
schema_store->update_received_version(new_received_schema_version);
|
|
if (schema_store->get_refreshed_version() >= schema_store->get_received_version()) {
|
|
need_refresh = false;
|
|
LOG_INFO(
|
|
"[REFRESH_SCHEMA] local refreshed schema version is greater than received schema version, just skip",
|
|
K(ret),
|
|
K(tenant_id),
|
|
K(schema_store->received_version_),
|
|
K(schema_store->refreshed_version_));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret) && need_refresh) {
|
|
if (OB_FAIL(refresh_schema(refresh_schema_status))) {
|
|
LOG_WARN("fail to refresh schema by tenant", K(ret), K(refresh_schema_status));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LOG_INFO("[REFRESH_SCHEMA] end refresh and add schema by tenant", K(ret), K(tenant_id));
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::publish_schema()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(add_schema(false))) {
|
|
LOG_WARN("fail to add schema", K(ret));
|
|
} else {
|
|
set_response_notify_schema_ts(schema::CUR_NEW_VERSION);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::publish_schema(const uint64_t tenant_id)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const bool force_add = false;
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
if (OB_FAIL(publish_schema())) {
|
|
LOG_WARN("fail to publish schema with old mode", K(ret));
|
|
}
|
|
} else if (OB_FAIL(add_schema(tenant_id, force_add))) {
|
|
LOG_WARN("fail to add schema", K(ret), K(tenant_id));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ObMultiVersionSchemaService::set_response_notify_schema_ts(NewVersionType type)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t new_version = OB_INVALID_VERSION;
|
|
switch (type) {
|
|
case CUR_NEW_VERSION:
|
|
new_version = get_refreshed_schema_version();
|
|
break;
|
|
case GEN_NEW_VERSION:
|
|
ret = schema_service_->gen_new_schema_version(OB_SYS_TENANT_ID, OB_INVALID_VERSION, new_version);
|
|
if (OB_FAIL(ret)) {
|
|
LOG_ERROR("fail to generate new schema version", K(ret));
|
|
}
|
|
break;
|
|
default:
|
|
LOG_WARN("unexpected type", K(type));
|
|
}
|
|
|
|
response_notify_schema_ts_ = new_version;
|
|
}
|
|
|
|
int64_t ObMultiVersionSchemaService::get_response_notify_schema_ts()
|
|
{
|
|
return response_notify_schema_ts_;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int ObMultiVersionSchemaService::check_outline_exist_with_name(const uint64_t tenant_id, const uint64_t database_id,
|
|
const common::ObString& outline_name, uint64_t& outline_id, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited", K(ret));
|
|
} else if (OB_UNLIKELY(OB_INVALID_ID == tenant_id || OB_INVALID_ID == database_id || outline_name.empty())) {
|
|
LOG_WARN("invalid arguments", K(tenant_id), K(database_id), K(outline_name), K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.check_outline_exist_with_name(
|
|
tenant_id, database_id, outline_name, outline_id, exist))) {
|
|
LOG_WARN("failed to check outline name exist", K(tenant_id), K(database_id), K(outline_name), K(ret));
|
|
} else { /*do nothing*/
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_outline_exist_with_sql(
|
|
const uint64_t tenant_id, const uint64_t database_id, const common::ObString& paramlized_sql, bool& exist)
|
|
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.check_outline_exist_with_sql(tenant_id, database_id, paramlized_sql, exist))) {
|
|
LOG_WARN("failed to check outline sql exist", K(tenant_id), K(database_id), K(paramlized_sql), K(ret));
|
|
} else { /*do nothing*/
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_synonym_exist(const uint64_t tenant_id, const uint64_t database_id,
|
|
const common::ObString& synonym_name, bool& exist, uint64_t& synonym_id)
|
|
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.check_synonym_exist_with_name(
|
|
tenant_id, database_id, synonym_name, exist, synonym_id))) {
|
|
LOG_WARN("failed to check synonym sql exist", K(tenant_id), K(database_id), K(synonym_name), K(ret));
|
|
} else { /*do nothing*/
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_udf_exist(const uint64_t tenant_id, const common::ObString& name, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.check_udf_exist_with_name(tenant_id, name, exist))) {
|
|
LOG_WARN("failed to check udf sql exist", K(tenant_id), K(name), K(ret));
|
|
} else { /*do nothing*/
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_sequence_exist(
|
|
const uint64_t tenant_id, const uint64_t database_id, const common::ObString& name, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
uint64_t sequence_id = OB_INVALID_ID;
|
|
exist = false;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited", K(ret));
|
|
} else if (OB_FAIL(get_schema_guard(schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.check_sequence_exist_with_name(tenant_id, database_id, name, exist, sequence_id))) {
|
|
LOG_WARN("failed to check sequence exist", K(tenant_id), K(name), K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_outline_exist_with_sql_id(
|
|
const uint64_t tenant_id, const uint64_t database_id, const common::ObString& sql_id, bool& exist)
|
|
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.check_outline_exist_with_sql_id(tenant_id, database_id, sql_id, exist))) {
|
|
LOG_WARN("failed to check outline sql exist", K(tenant_id), K(database_id), K(sql_id), K(ret));
|
|
} else { /*do nothing*/
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//-----------For managing privileges-----------
|
|
|
|
int ObMultiVersionSchemaService::check_user_exist(
|
|
const uint64_t tenant_id, const common::ObString& user_name, const common::ObString& host_name, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
uint64_t user_id = OB_INVALID_ID;
|
|
ret = check_user_exist(tenant_id, user_name, host_name, user_id, exist);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_user_exist(const uint64_t tenant_id, const common::ObString& user_name,
|
|
const common::ObString& host_name, uint64_t& user_id, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.check_user_exist(tenant_id, user_name, host_name, exist, &user_id))) {
|
|
LOG_WARN("failed to check user exist", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_user_exist(const uint64_t tenant_id, const uint64_t user_id, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else {
|
|
SpinRLockGuard guard(schema_manager_rwlock_);
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (!is_tenant_full_schema(tenant_id)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(tenant_id, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.check_user_exist(tenant_id, user_id, exist))) {
|
|
LOG_WARN("failed to check table exist", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ObMultiVersionSchemaService::dump_schema_statistics()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
lib::ObMutexGuard guard(schema_refresh_mutex_);
|
|
bool is_schema_splited = GCTX.is_schema_splited();
|
|
LOG_INFO("[SCHEMA_STATISTICS] dump schema statistics info start");
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (!is_schema_splited) {
|
|
LOG_INFO("[SCHEMA_STATISTICS] dump schema for refresh start", K(ret));
|
|
if (OB_NOT_NULL(schema_mgr_for_cache_)) {
|
|
schema_mgr_for_cache_->dump();
|
|
}
|
|
mem_mgr_.dump();
|
|
schema_mgr_cache_.dump();
|
|
LOG_INFO("[SCHEMA_STATISTICS] dump schema for refresh end", K(ret));
|
|
|
|
LOG_INFO("[SCHEMA_STATISTICS] dump schema for fallback start", K(ret));
|
|
mem_mgr_for_liboblog_.dump();
|
|
schema_mgr_cache_for_liboblog_.dump();
|
|
LOG_INFO("[SCHEMA_STATISTICS] dump schema for fallback end", K(ret));
|
|
} else {
|
|
FOREACH(it, mem_mgr_map_)
|
|
{
|
|
uint64_t tenant_id = (*it).first;
|
|
ObSchemaMemMgr* mem_mgr = (*it).second;
|
|
LOG_INFO("[SCHEMA_STATISTICS] dump schema for refresh start", K(ret), K(tenant_id));
|
|
if (OB_ISNULL(mem_mgr)) {
|
|
LOG_INFO("mem_mgr is null", K(ret), K(tenant_id));
|
|
} else {
|
|
mem_mgr->dump();
|
|
|
|
ObSchemaMgr* schema_mgr_for_cache = NULL;
|
|
int tmp_ret = OB_SUCCESS;
|
|
if (OB_SUCCESS != (tmp_ret = schema_mgr_for_cache_map_.get_refactored(tenant_id, schema_mgr_for_cache))) {
|
|
if (OB_HASH_NOT_EXIST != tmp_ret) {
|
|
LOG_WARN("fail to get schema_mgr", K(tmp_ret), K(tenant_id));
|
|
}
|
|
} else {
|
|
schema_mgr_for_cache->dump();
|
|
}
|
|
|
|
ObSchemaStore* schema_store = NULL;
|
|
ObSchemaMgrCache* schema_mgr_cache = NULL;
|
|
if (OB_ISNULL(schema_store = schema_store_map_.get(tenant_id))) {
|
|
LOG_INFO("schema_store is null", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(schema_mgr_cache = &schema_store->schema_mgr_cache_)) {
|
|
LOG_INFO("schema_mgr_cache is null", K(ret), K(tenant_id));
|
|
} else {
|
|
schema_mgr_cache->dump();
|
|
}
|
|
}
|
|
LOG_INFO("[SCHEMA_STATISTICS] dump schema for refresh end", K(ret), K(tenant_id));
|
|
}
|
|
|
|
FOREACH(it, mem_mgr_for_liboblog_map_)
|
|
{
|
|
uint64_t tenant_id = (*it).first;
|
|
ObSchemaMemMgr* mem_mgr = (*it).second;
|
|
LOG_INFO("[SCHEMA_STATISTICS] dump schema for fallback start", K(ret), K(tenant_id));
|
|
if (OB_ISNULL(mem_mgr)) {
|
|
LOG_INFO("mem_mgr is null", K(ret), K(tenant_id));
|
|
} else {
|
|
mem_mgr->dump();
|
|
|
|
ObSchemaStore* schema_store = NULL;
|
|
ObSchemaMgrCache* schema_mgr_cache = NULL;
|
|
if (OB_ISNULL(schema_store = schema_store_map_.get(tenant_id))) {
|
|
LOG_INFO("schema_store is null", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(schema_mgr_cache = &schema_store->schema_mgr_cache_for_liboblog_)) {
|
|
LOG_INFO("schema_mgr_cache is null", K(ret), K(tenant_id));
|
|
} else {
|
|
schema_mgr_cache->dump();
|
|
}
|
|
}
|
|
LOG_INFO("[SCHEMA_STATISTICS] dump schema for fallback end", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::try_eliminate_schema_mgr()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObHashSet<uint64_t> candidates;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
}
|
|
// 1. try gc dropped tenant's schema mgr
|
|
if (FAILEDx(try_gc_tenant_schema_mgr())) {
|
|
LOG_WARN("fail to gc tenant schema mgr", K(ret));
|
|
}
|
|
// 2. try gc exist tenant's schema mgr
|
|
// - another allocator (only for refresh)
|
|
// - schema_mgr for fallback
|
|
if (FAILEDx(try_gc_existed_tenant_schema_mgr())) {
|
|
LOG_WARN("fail to gc existed tenant schema mgr", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// try gc dropped tenant's schema mgr
|
|
int ObMultiVersionSchemaService::try_gc_tenant_schema_mgr()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObHashSet<uint64_t> candidates;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (OB_FAIL(candidates.create(DEFAULT_TENANT_SET_SIZE))) {
|
|
LOG_WARN("fail to create hash set", K(ret));
|
|
} else if (OB_FAIL(get_gc_candidates(candidates))) {
|
|
LOG_WARN("fail to get gc candidates", K(ret));
|
|
} else {
|
|
FOREACH_X(it, candidates, OB_SUCC(ret))
|
|
{
|
|
if (OB_FAIL(try_gc_tenant_schema_mgr((*it).first))) {
|
|
LOG_WARN("fail to eliminate schema mgr", K(ret), "tenant_id", (*it).first);
|
|
} else {
|
|
LOG_INFO("try eliminate schema mgr", K(ret), "tenant_id", (*it).first);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::get_gc_candidates(ObHashSet<uint64_t>& candidates)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSchemaGetterGuard schema_guard;
|
|
ObArray<uint64_t> tenant_ids;
|
|
ObHashSet<uint64_t> tenant_id_set;
|
|
// The purpose of locking here is to ensure that there are no new tenants in the GC phase,
|
|
// and to prevent the new tenant schema from being considered as dropped tenants and being GC dropped
|
|
// during the shcema refresh process.
|
|
lib::ObMutexGuard guard(schema_refresh_mutex_);
|
|
if (!is_sys_full_schema()) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("full schema is not ready, cann't get fallback schema guard", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(OB_SYS_TENANT_ID, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.get_tenant_ids(tenant_ids))) {
|
|
LOG_WARN("fail to get tenant ids", K(ret));
|
|
} else if (OB_FAIL(tenant_id_set.create(DEFAULT_TENANT_SET_SIZE))) {
|
|
LOG_WARN("fail to create hash set", K(ret));
|
|
} else {
|
|
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < tenant_ids.count(); i++) {
|
|
if (OB_FAIL(tenant_id_set.set_refactored(tenant_ids.at(i)))) {
|
|
LOG_WARN("fail to push back tenant id", K(ret), K(tenant_ids.at(i)));
|
|
}
|
|
}
|
|
|
|
#define GET_GC_TENANT_CANDIDATES(MEM_MGR_MAP) \
|
|
FOREACH_X(it, MEM_MGR_MAP, OB_SUCC(ret)) \
|
|
{ \
|
|
bool can_release = false; \
|
|
uint64_t tenant_id = (*it).first; \
|
|
ObSchemaMemMgr* mem_mgr = (*it).second; \
|
|
ret = tenant_id_set.exist_refactored(tenant_id); \
|
|
if (OB_HASH_EXIST == ret) { \
|
|
ret = OB_SUCCESS; \
|
|
} else if (OB_HASH_NOT_EXIST != ret) { \
|
|
LOG_WARN("fail to check tenant exist", K(ret), K(tenant_id)); \
|
|
} else if (OB_ISNULL(mem_mgr)) { \
|
|
ret = OB_ERR_UNEXPECTED; \
|
|
LOG_WARN("mem_mgr is null", K(ret), K(tenant_id)); \
|
|
} else if (OB_FAIL(mem_mgr->check_can_release(can_release))) { \
|
|
LOG_WARN("fail to check if tenant can release", K(ret), K(tenant_id)); \
|
|
} else if (!can_release) { \
|
|
continue; \
|
|
} else if (OB_FAIL(candidates.set_refactored(tenant_id))) { \
|
|
LOG_WARN("fail to set candidate", K(ret), K(tenant_id)); \
|
|
} \
|
|
}
|
|
|
|
GET_GC_TENANT_CANDIDATES(mem_mgr_map_);
|
|
|
|
if (OB_SUCC(ret)) {
|
|
// In order to prevent the tenant schema from being released by mistake in the fallback process,
|
|
// lock protection is required here
|
|
lib::ObMutexGuard guard(mem_mgr_for_liboblog_mutex_);
|
|
GET_GC_TENANT_CANDIDATES(mem_mgr_for_liboblog_map_);
|
|
}
|
|
#undef GET_GC_TENANT_CANDIDATES
|
|
|
|
if (OB_SUCC(ret)) {
|
|
ret = candidates.exist_refactored(OB_SYS_TENANT_ID);
|
|
if (OB_HASH_NOT_EXIST != ret) {
|
|
LOG_WARN("sys tenant should not exist in candidates", K(ret));
|
|
} else {
|
|
ret = OB_SUCCESS;
|
|
}
|
|
}
|
|
|
|
// After the schema is split, it need to try to release the old schema memory management data structure,
|
|
// here OB_SYS_TENANT_ID refers to the old structure
|
|
bool is_schema_splited = GCTX.is_schema_splited();
|
|
if (OB_SUCC(ret)) {
|
|
bool can_release = false;
|
|
if (!is_schema_splited) {
|
|
// skip
|
|
} else if (OB_FAIL(mem_mgr_.check_can_release(can_release))) {
|
|
LOG_WARN("fail to check if tenant can release", K(ret));
|
|
} else if (!can_release) {
|
|
// skip
|
|
} else if (OB_FAIL(candidates.set_refactored(OB_SYS_TENANT_ID))) {
|
|
LOG_WARN("fail to set candidate", K(ret));
|
|
}
|
|
}
|
|
|
|
// After the schema is split, it need to try to release the old schema memory management data structure,
|
|
// here OB_SYS_TENANT_ID refers to the old structure
|
|
if (OB_SUCC(ret)) {
|
|
bool can_release = false;
|
|
lib::ObMutexGuard guard(mem_mgr_for_liboblog_mutex_);
|
|
if (!is_schema_splited) {
|
|
// skip
|
|
} else if (OB_FAIL(mem_mgr_for_liboblog_.check_can_release(can_release))) {
|
|
LOG_WARN("fail to check if tenant can release", K(ret));
|
|
} else if (!can_release) {
|
|
// skip
|
|
} else if (OB_FAIL(candidates.set_refactored(OB_SYS_TENANT_ID))) {
|
|
LOG_WARN("fail to set candidate", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Reclaim the memory occupied by schema_mgr
|
|
* 1. system tenant:
|
|
* - Recycle the schema_mgr_for_cache_ object
|
|
* - Try to reclaim the memory occupied by multi-version ObSchemaMgr occupied by schema_mem_mgr_
|
|
* - Try to reclaim the memory occupied by multiple versions of ObSchemaMgr occupied by schema_mem_mgr_for_liboblog_
|
|
* - reset refreshed_schema_version_ and received_broadcast_version_
|
|
* 2. user tenant
|
|
* - recycle schema_mgr_for_cache object
|
|
* - Try to reclaim the memory occupied by multiple versions of ObSchemaMgr occupied by schema_mem_mgr
|
|
* - Try to reclaim the memory occupied by multiple versions of ObSchemaMgr occupied by schema_mem_mgr_for_liboblog
|
|
* - reset refreshed_schema_version, received_broadcast_version and refresh_full_schema
|
|
*
|
|
*/
|
|
int ObMultiVersionSchemaService::try_gc_tenant_schema_mgr(uint64_t tenant_id)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (OB_INVALID_TENANT_ID == tenant_id || (OB_SYS_TENANT_ID == tenant_id && !GCTX.is_schema_splited())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(try_gc_tenant_schema_mgr_for_refresh(tenant_id))) {
|
|
LOG_WARN("fail to gc tenant schema mgr for refresh", KR(ret), K(tenant_id));
|
|
} else if (OB_FAIL(try_gc_tenant_schema_mgr_for_fallback(tenant_id))) {
|
|
LOG_WARN("fail to gc tenant schema mgr for fallback", KR(ret), K(tenant_id));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::try_gc_tenant_schema_mgr_for_refresh(uint64_t tenant_id)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (OB_INVALID_TENANT_ID == tenant_id || (OB_SYS_TENANT_ID == tenant_id && !GCTX.is_schema_splited())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else {
|
|
lib::ObMutexGuard guard(schema_refresh_mutex_);
|
|
ObSchemaMemMgr* mem_mgr = NULL;
|
|
ObSchemaMgrCache* schema_mgr_cache = NULL;
|
|
ObSchemaStore* schema_store = NULL;
|
|
|
|
if (OB_SYS_TENANT_ID == tenant_id) {
|
|
// Here, the system tenant refers to the old schema memory management data structure.
|
|
// After the schema is split, try to release this part of the memory
|
|
mem_mgr = &mem_mgr_;
|
|
schema_mgr_cache = &schema_mgr_cache_;
|
|
refreshed_schema_version_ = OB_INVALID_VERSION;
|
|
received_broadcast_version_ = OB_INVALID_VERSION;
|
|
} else if (NULL == (schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
LOG_WARN("fail to get schema_store", K(ret));
|
|
} else if (OB_FAIL(mem_mgr_map_.get_refactored(tenant_id, mem_mgr))) {
|
|
LOG_WARN("fail to get mem mgr", K(ret), K(tenant_id));
|
|
} else {
|
|
schema_store->reset_version();
|
|
schema_mgr_cache = &schema_store->schema_mgr_cache_;
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(try_gc_tenant_schema_mgr(mem_mgr, schema_mgr_cache))) {
|
|
LOG_WARN("fail to elimiante schema mgr", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(destroy_schema_struct(tenant_id))) {
|
|
LOG_WARN("fail to destroy schema struct", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
LOG_INFO("try gc schema mgr for refresh", K(ret), K(tenant_id));
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::try_gc_tenant_schema_mgr_for_fallback(
|
|
uint64_t tenant_id, bool use_new_mode /* = true */)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (OB_INVALID_TENANT_ID == tenant_id || (OB_SYS_TENANT_ID == tenant_id && !GCTX.is_schema_splited())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else {
|
|
lib::ObMutexGuard guard(mem_mgr_for_liboblog_mutex_);
|
|
ObSchemaMemMgr* mem_mgr = NULL;
|
|
ObSchemaMgrCache* schema_mgr_cache = NULL;
|
|
|
|
// reset schema mgr for fallback in old mode
|
|
if (OB_SUCC(ret) && OB_SYS_TENANT_ID == tenant_id) {
|
|
mem_mgr = &mem_mgr_for_liboblog_;
|
|
schema_mgr_cache = &schema_mgr_cache_for_liboblog_;
|
|
if (OB_FAIL(try_gc_tenant_schema_mgr(mem_mgr, schema_mgr_cache))) {
|
|
LOG_WARN("fail to elimiante schema mgr", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
|
|
// reset schema mgr for fallback in new mode
|
|
if (OB_SUCC(ret) && use_new_mode) {
|
|
ObSchemaStore* schema_store = NULL;
|
|
if (NULL == (schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
LOG_WARN("fail to get schema_store", K(ret));
|
|
} else if (OB_FAIL(mem_mgr_for_liboblog_map_.get_refactored(tenant_id, mem_mgr))) {
|
|
LOG_WARN("fail to get mem mgr", K(ret), K(tenant_id));
|
|
} else {
|
|
schema_mgr_cache = &schema_store->schema_mgr_cache_for_liboblog_;
|
|
if (OB_FAIL(try_gc_tenant_schema_mgr(mem_mgr, schema_mgr_cache))) {
|
|
LOG_WARN("fail to elimiante schema mgr", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LOG_INFO("try gc schema mgr for fallback", K(ret), K(tenant_id), K(use_new_mode));
|
|
return ret;
|
|
}
|
|
|
|
// need protect by lock
|
|
int ObMultiVersionSchemaService::try_gc_tenant_schema_mgr(ObSchemaMemMgr*& mem_mgr, ObSchemaMgrCache*& schema_mgr_cache)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(mem_mgr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("mem_mgr is null", K(ret));
|
|
} else if (OB_ISNULL(schema_mgr_cache)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_mgr_cache is null", K(ret));
|
|
} else {
|
|
ObSchemaMgr* eli_schema_mgr = NULL;
|
|
uint64_t tenant_id = mem_mgr->get_tenant_id();
|
|
do {
|
|
if (OB_FAIL(schema_mgr_cache->try_gc_tenant_schema_mgr(eli_schema_mgr))) {
|
|
LOG_WARN("fail to eliminate schema mgr", K(ret), K(tenant_id));
|
|
} else if (OB_NOT_NULL(eli_schema_mgr)) {
|
|
LOG_INFO("[SCHEMA_RELEASE] try to gc schema mgr",
|
|
"tenant_id",
|
|
eli_schema_mgr->get_tenant_id(),
|
|
"schema_version",
|
|
eli_schema_mgr->get_schema_version());
|
|
eli_schema_mgr->~ObSchemaMgr();
|
|
if (OB_FAIL(mem_mgr->free(static_cast<void*>(eli_schema_mgr)))) {
|
|
LOG_ERROR("free eli schema mgr falied", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
} while (OB_SUCC(ret) && OB_NOT_NULL(eli_schema_mgr));
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(mem_mgr->try_reset_allocator())) {
|
|
LOG_WARN("fail to reset allocator", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// try release exist tenant's another allocator
|
|
int ObMultiVersionSchemaService::try_gc_existed_tenant_schema_mgr()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSchemaGetterGuard schema_guard;
|
|
ObArray<uint64_t> tenant_ids;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (!is_sys_full_schema()) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_WARN("full schema is not ready, cann't get fallback schema guard", K(ret));
|
|
} else if (OB_FAIL(get_tenant_schema_guard(OB_SYS_TENANT_ID, schema_guard))) {
|
|
LOG_WARN("get schema guard failed ", K(ret));
|
|
} else if (OB_FAIL(schema_guard.get_tenant_ids(tenant_ids))) {
|
|
LOG_WARN("fail to get tenant ids", K(ret));
|
|
} else {
|
|
bool is_schema_splited = GCTX.is_schema_splited();
|
|
ObSchemaMemMgr* mem_mgr = NULL;
|
|
ObSchemaMgrCache* schema_mgr_cache = NULL;
|
|
if (!is_schema_splited) {
|
|
const uint64_t tenant_id = OB_INVALID_TENANT_ID; // old mode
|
|
mem_mgr = &mem_mgr_;
|
|
schema_mgr_cache = &schema_mgr_cache_;
|
|
if (OB_FAIL(try_gc_another_allocator(tenant_id, mem_mgr, schema_mgr_cache))) {
|
|
LOG_WARN("fail to gc another allocator", K(ret));
|
|
} else if (ObSchemaService::g_liboblog_mode_) {
|
|
// liboblog/agentserver do nothing
|
|
} else if (OB_FAIL(try_gc_tenant_schema_mgr_for_fallback(tenant_id, false))) {
|
|
LOG_WARN("fail to gc tenant schema mgr for fallback", KR(ret), K(tenant_id));
|
|
}
|
|
} else {
|
|
for (int64_t i = 0; i < tenant_ids.count(); i++) { // ignore ret
|
|
ObSchemaStore* schema_store = NULL;
|
|
const uint64_t tenant_id = tenant_ids.at(i);
|
|
if (NULL == (schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
LOG_WARN("fail to get schema_store", K(ret));
|
|
} else if (FALSE_IT(schema_mgr_cache = &schema_store->schema_mgr_cache_)) {
|
|
} else if (OB_FAIL(mem_mgr_map_.get_refactored(tenant_id, mem_mgr))) {
|
|
LOG_WARN("fail to get mem mgr", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(try_gc_another_allocator(tenant_id, mem_mgr, schema_mgr_cache))) {
|
|
LOG_WARN("fail to gc another allocator", K(ret), K(tenant_id));
|
|
} else if (ObSchemaService::g_liboblog_mode_) {
|
|
// liboblog/agentserver do nothing
|
|
} else if (OB_FAIL(try_gc_tenant_schema_mgr_for_fallback(tenant_id))) {
|
|
LOG_WARN("fail to gc tenant schema mgr for fallback", KR(ret), K(tenant_id));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// need protected by schema_refresh_mutex_
|
|
int ObMultiVersionSchemaService::try_gc_another_allocator(
|
|
const uint64_t tenant_id, ObSchemaMemMgr*& mem_mgr, ObSchemaMgrCache*& schema_mgr_cache)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (OB_ISNULL(mem_mgr) || OB_ISNULL(schema_mgr_cache)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("mem_mgr or schema_mgr_cahe is null", K(ret), K(tenant_id), KP(mem_mgr), KP(schema_mgr_cache));
|
|
} else if (tenant_id != mem_mgr->get_tenant_id()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("tenant_id not match", K(ret), K(tenant_id), "mem_tenant_id", mem_mgr->get_tenant_id());
|
|
} else {
|
|
lib::ObMutexGuard guard(schema_refresh_mutex_);
|
|
ObArray<void*> another_ptrs;
|
|
int64_t local_version = OB_INVALID_VERSION;
|
|
if (OB_FAIL(mem_mgr->get_another_ptrs(another_ptrs))) {
|
|
LOG_WARN("fail to get another ptrs", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(get_tenant_refreshed_schema_version(tenant_id, local_version))) {
|
|
LOG_WARN("fail to get local refreshed schema version", K(ret), K(tenant_id));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < another_ptrs.count(); i++) {
|
|
ObSchemaMgr* tmp_mgr = NULL;
|
|
if (OB_ISNULL(another_ptrs.at(i))) {
|
|
LOG_WARN("ptrs is null", K(ret), K(tenant_id), K(i));
|
|
} else if (FALSE_IT(tmp_mgr = static_cast<ObSchemaMgr*>(another_ptrs.at(i)))) {
|
|
} else if (tmp_mgr->get_schema_version() >= local_version) {
|
|
ret = OB_SCHEMA_EAGAIN;
|
|
LOG_INFO("schema mgr is in used, try reset another allocator next round",
|
|
K(ret),
|
|
K(tenant_id),
|
|
"version",
|
|
tmp_mgr->get_schema_version(),
|
|
K(local_version));
|
|
}
|
|
}
|
|
ObSchemaMgr* eli_schema_mgr = NULL;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < another_ptrs.count(); i++) {
|
|
if (OB_ISNULL(another_ptrs.at(i))) {
|
|
LOG_WARN("ptrs is null", K(ret), K(tenant_id), K(i));
|
|
} else if (FALSE_IT(eli_schema_mgr = static_cast<ObSchemaMgr*>(another_ptrs.at(i)))) {
|
|
} else if (OB_FAIL(schema_mgr_cache->try_elimiante_schema_mgr(eli_schema_mgr))) {
|
|
LOG_WARN("fail to elimiante schema_mgr", K(ret), K(tenant_id), K(eli_schema_mgr));
|
|
} else {
|
|
LOG_INFO("[SCHEMA_RELEASE] try to eliminate schema mgr",
|
|
"tenant_id",
|
|
eli_schema_mgr->get_tenant_id(),
|
|
"schema_version",
|
|
eli_schema_mgr->get_schema_version());
|
|
eli_schema_mgr->~ObSchemaMgr();
|
|
if (OB_FAIL(mem_mgr->free(static_cast<void*>(eli_schema_mgr)))) {
|
|
LOG_ERROR("free eli schema mgr falied", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(mem_mgr->try_reset_another_allocator())) {
|
|
LOG_WARN("fail to reset another allocator", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
}
|
|
LOG_INFO("try gc another allocator", K(ret), K(tenant_id));
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* The __all_recyclebin table is not multi-version, but multi-version information can be constructed
|
|
* based on other schema table information.
|
|
*
|
|
* There are two types of recycle bin database objects:
|
|
* 1) table:
|
|
* - object_name : table name, unique in cluster
|
|
* - table_id : table id, The table id remains unchanged before and after entering the recycle bin
|
|
* - tablegroup_id : The tablegroup_id that the table belongs to before entering the recycle bin, used for flashback
|
|
* - database_id : The database_id that the table belongs to before entering the recycle bin, used for flashback
|
|
* - original_name : Table_name before entering the recycle bin, used for flashback
|
|
* 2) database :
|
|
* - object_name : database name, unique in cluster
|
|
* - database_id : The current database_id, the database_id remains unchanged before and after entering the recycle
|
|
* bin
|
|
* - tablegroup_id : The default_tablegroup_id of the database before entering the recycle bin, used for flashback
|
|
*
|
|
* In addition to the different tenant_id of the backup and recovery cluster, the partition_key
|
|
* cannot be reused due to the failure of partition creation. Currently, it is not assumed that
|
|
* the pure_schema_id of the standalone cluster recovery cluster is the same.
|
|
* Currently, the mapping of the backup and recovery cluster schema_id is completed through schema_name,
|
|
* where the backup and recovery of __all_recyclebin is the same. The difference is that the schema of
|
|
* the related schema_id is not guaranteed to exist in the current version.
|
|
* 1. If there is a table in the tablegroup, or the default_tablegroup_id of the tenant or database is used,
|
|
* it is not allowed to be deleted. Because the table and database of the recycle bin cannot do DDL through external
|
|
* SQL. Therefore, the tablegroup used in __all_recyclebin can be guaranteed to be available in the current version.
|
|
* 2. Since the table of the recycle bin is transferred from the original database to __all_recyclebin,
|
|
* the original database may have been deleted in the current version (not in the recycle bin),
|
|
* so the current version may not get the corresponding database schema. In this case, the subsequent flashback
|
|
* must specify a new database, otherwise an error is expected, so the database_id backed up at this time can be -1.
|
|
* (FIXME: This interface is only used in non-lazy mode)
|
|
*/
|
|
int ObMultiVersionSchemaService::construct_recycle_objects(
|
|
ObSchemaGetterGuard& schema_guard, const uint64_t tenant_id, common::ObIArray<ObRecycleObject>& recycle_objects)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
recycle_objects.reset();
|
|
if (!check_inner_stat()) {
|
|
ret = OB_INNER_STAT_ERROR;
|
|
LOG_WARN("inner stat error", K(ret));
|
|
} else if (!ObSchemaService::g_liboblog_mode_) {
|
|
ret = OB_OP_NOT_ALLOW;
|
|
LOG_WARN("for backup used only", K(ret));
|
|
} else if (!increment_basepoint_set_) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("local schema not inited", K(ret));
|
|
} else if (OB_SYS_TENANT_ID == tenant_id || !is_valid_tenant_id(tenant_id)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(schema_service_) || OB_ISNULL(sql_proxy_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_service or proxy is null", K(ret), KP_(schema_service), KP_(sql_proxy));
|
|
} else {
|
|
// get tables in recyclebin
|
|
uint64_t recycle_db_id = combine_id(tenant_id, OB_RECYCLEBIN_SCHEMA_ID);
|
|
ObArray<const ObSimpleTableSchemaV2*> tables;
|
|
if (OB_FAIL(schema_guard.get_table_schemas_in_database(tenant_id, recycle_db_id, tables))) {
|
|
LOG_WARN("fail to get table schemas", K(ret), K(tenant_id), K(recycle_db_id));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < tables.count(); i++) {
|
|
const ObSimpleTableSchemaV2* table = tables.at(i);
|
|
ObRecycleObject recycle_object;
|
|
if (OB_ISNULL(table)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("table is null", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(schema_service_->construct_recycle_table_object(*sql_proxy_, *table, recycle_object))) {
|
|
LOG_WARN("fail to construct recycle table object",
|
|
K(ret),
|
|
K(tenant_id),
|
|
"table_id",
|
|
table->get_table_id(),
|
|
"schema_version",
|
|
table->get_schema_version());
|
|
} else if (OB_FAIL(recycle_objects.push_back(recycle_object))) {
|
|
LOG_WARN("fail to push back object", K(ret), K(recycle_object));
|
|
}
|
|
}
|
|
}
|
|
|
|
// get databases in recyclebin
|
|
ObArray<const ObDatabaseSchema*> databases;
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(schema_guard.get_database_schemas_in_tenant(tenant_id, databases))) {
|
|
LOG_WARN("fail to get databases", K(ret), K(tenant_id));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < databases.count(); i++) {
|
|
const ObDatabaseSchema* database = databases.at(i);
|
|
ObRecycleObject recycle_object;
|
|
if (OB_ISNULL(database)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("database is null", K(ret));
|
|
} else if (is_inner_db(database->get_database_id()) || !database->is_in_recyclebin()) {
|
|
// skip inner db or db not in recyclebin
|
|
} else if (OB_FAIL(
|
|
schema_service_->construct_recycle_database_object(*sql_proxy_, *database, recycle_object))) {
|
|
LOG_WARN("fail to construct recycle database object",
|
|
K(ret),
|
|
K(tenant_id),
|
|
"database_id",
|
|
database->get_database_id(),
|
|
"schema_version",
|
|
database->get_schema_version());
|
|
} else if (OB_FAIL(recycle_objects.push_back(recycle_object))) {
|
|
LOG_WARN("fail to push back object", K(ret), K(recycle_object));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool ObMultiVersionSchemaService::is_tenant_full_schema(const uint64_t tenant_id) const
|
|
{
|
|
bool bret = false;
|
|
if (OB_INVALID_TENANT_ID == tenant_id || OB_SYS_TENANT_ID == tenant_id) {
|
|
bret = is_sys_full_schema();
|
|
} else {
|
|
int64_t schema_version = OB_INVALID_VERSION;
|
|
int ret = get_tenant_refreshed_schema_version(tenant_id, schema_version);
|
|
bret = OB_SUCC(ret) && schema_version > OB_CORE_SCHEMA_VERSION;
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::get_tenant_refreshed_schema_version(
|
|
const uint64_t tenant_id, int64_t& schema_version, const bool core_version, const bool use_new_mode) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t refreshed_schema_version = OB_INVALID_VERSION;
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id), K(core_version));
|
|
} else if (!GCTX.is_schema_splited() && !use_new_mode) {
|
|
// old schema refresh
|
|
refreshed_schema_version = ATOMIC_LOAD(&refreshed_schema_version_);
|
|
} else {
|
|
// new schema refresh
|
|
const ObSchemaStore* schema_store = NULL;
|
|
if (NULL == (schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
LOG_WARN("fail to get schema_store", K(ret));
|
|
} else {
|
|
refreshed_schema_version = schema_store->get_refreshed_version();
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
schema_version =
|
|
(!core_version || refreshed_schema_version > 0) ? refreshed_schema_version : OB_CORE_SCHEMA_VERSION;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::get_tenant_received_broadcast_version(
|
|
const uint64_t tenant_id, int64_t& schema_version, const bool core_schema_version) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t received_broadcast_version = OB_INVALID_VERSION;
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id), K(core_schema_version));
|
|
} else if (!GCTX.is_schema_splited()) {
|
|
// old schema refresh
|
|
received_broadcast_version = ATOMIC_LOAD(&received_broadcast_version_);
|
|
} else {
|
|
// newschema refresh
|
|
const ObSchemaStore* schema_store = NULL;
|
|
if (NULL == (schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
LOG_WARN("fail to get schema_store", K(ret));
|
|
} else {
|
|
received_broadcast_version = schema_store->get_received_version();
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
schema_version =
|
|
(!core_schema_version || received_broadcast_version > 0) ? received_broadcast_version : OB_CORE_SCHEMA_VERSION;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::set_tenant_received_broadcast_version(const uint64_t tenant_id, const int64_t version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id), K(version));
|
|
} else if (version != OB_CORE_SCHEMA_VERSION) {
|
|
if (!GCTX.is_schema_splited()) {
|
|
int64_t received_broadcast_version = OB_INVALID_VERSION;
|
|
bool matched = false;
|
|
do {
|
|
received_broadcast_version = ATOMIC_LOAD(&received_broadcast_version_);
|
|
if (received_broadcast_version > version) {
|
|
ret = OB_OLD_SCHEMA_VERSION;
|
|
matched = true;
|
|
}
|
|
} while (OB_SUCCESS == ret && !matched &&
|
|
!ATOMIC_BCAS(&received_broadcast_version_, received_broadcast_version, version));
|
|
} else {
|
|
ObSchemaStore* schema_store = NULL;
|
|
if (NULL == (schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
LOG_WARN("fail to get schema_store", K(ret));
|
|
} else {
|
|
schema_store->update_received_version(version);
|
|
LOG_INFO("try to set tenant received_broadcast_version", K(ret), K(tenant_id), K(version));
|
|
}
|
|
}
|
|
} else {
|
|
ret = OB_OLD_SCHEMA_VERSION;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::get_last_refreshed_schema_info(ObRefreshSchemaInfo& schema_info)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
SpinRLockGuard guard(schema_info_rwlock_);
|
|
if (OB_FAIL(schema_info.assign(last_refreshed_schema_info_))) {
|
|
LOG_WARN("fail to assign schema info", K(ret), K(schema_info), K_(last_refreshed_schema_info));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::set_last_refreshed_schema_info(const ObRefreshSchemaInfo& schema_info)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
SpinWLockGuard guard(schema_info_rwlock_);
|
|
const uint64_t last_sequence_id = last_refreshed_schema_info_.get_sequence_id();
|
|
const uint64_t new_sequence_id = schema_info.get_sequence_id();
|
|
if (OB_INVALID_ID == new_sequence_id || (OB_INVALID_ID != last_sequence_id && last_sequence_id >= new_sequence_id)) {
|
|
LOG_INFO("no need to set last refreshed schema info", K(ret), K(last_refreshed_schema_info_), K(schema_info));
|
|
} else if (OB_FAIL(last_refreshed_schema_info_.assign(schema_info))) {
|
|
LOG_WARN("fail to assign last refreshed schema info", K(ret), K(schema_info), K_(last_refreshed_schema_info));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::gen_new_schema_version(uint64_t tenant_id, int64_t& schema_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t refreshed_schema_version = OB_INVALID_VERSION;
|
|
schema_version = OB_INVALID_VERSION;
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (GCTX.is_schema_splited() && OB_SYS_TENANT_ID != tenant_id) {
|
|
// When RS is started in schema split mode, since only the system tenant schema is refreshed,
|
|
// it is necessary to ensure that the user tenant schema is refreshed to the latest before DDL is executed.
|
|
if (OB_FAIL(get_tenant_refreshed_schema_version(tenant_id, refreshed_schema_version))) {
|
|
LOG_WARN("fail to get refreshed schema version", K(ret), K(tenant_id), K(refreshed_schema_version));
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_ISNULL(schema_service_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema service is null", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(schema_service_->gen_new_schema_version(tenant_id, refreshed_schema_version, schema_version))) {
|
|
LOG_WARN("fail to gen new schema_version", K(ret), K(tenant_id), K(refreshed_schema_version));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::get_new_schema_version(uint64_t tenant_id, int64_t& schema_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
schema_version = OB_INVALID_VERSION;
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(schema_service_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema service is null", K(ret), K(tenant_id));
|
|
} else {
|
|
ret = schema_service_->get_new_schema_version(tenant_id, schema_version);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// If schema_status_array is empty, it means strong consistent reading
|
|
int ObMultiVersionSchemaService::get_schema_status(const ObArray<ObRefreshSchemaStatus>& schema_status_array,
|
|
const uint64_t tenant_id, ObRefreshSchemaStatus& schema_status)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool finded = false;
|
|
schema_status.reset();
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (schema_status_array.empty()) {
|
|
schema_status.tenant_id_ = tenant_id;
|
|
} else {
|
|
FOREACH_X(schema_status_ptr, schema_status_array, !finded && OB_SUCC(ret))
|
|
{
|
|
if (OB_ISNULL(schema_status_ptr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema_status is null", K(ret));
|
|
} else if (schema_status_ptr->tenant_id_ == tenant_id) {
|
|
finded = true;
|
|
schema_status = *schema_status_ptr;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && !finded) {
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
LOG_WARN("tenant schema status not finded", K(ret), K(tenant_id));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::get_schema_version_history(const ObRefreshSchemaStatus& fetch_schema_status,
|
|
const uint64_t fetch_tenant_id, const int64_t schema_version, const VersionHisKey& key, VersionHisVal& val,
|
|
bool& not_exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
not_exist = false;
|
|
val.reset();
|
|
if (!key.is_valid() || schema_version < 0 || OB_INVALID_TENANT_ID == fetch_tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid arg", K(ret), K(key), K(fetch_tenant_id), K(schema_version));
|
|
} else {
|
|
int hash_ret = version_his_map_.get_refactored(key, val);
|
|
if (hash_ret == OB_HASH_NOT_EXIST || schema_version > val.snapshot_version_) {
|
|
int64_t snapshot_version = OB_INVALID_VERSION;
|
|
if (OB_FAIL(get_tenant_refreshed_schema_version(fetch_tenant_id, snapshot_version))) {
|
|
LOG_WARN("fail to get tenant refreshed schema_version", K(ret), K(fetch_tenant_id));
|
|
} else if (OB_FAIL(construct_schema_version_history(fetch_schema_status, snapshot_version, key, val))) {
|
|
LOG_WARN("construct failed", K(ret), K(snapshot_version), K(key));
|
|
} else if (0 == val.valid_cnt_) {
|
|
// FIXME: When the specified schema is too small, there is no corresponding record in the history,
|
|
// and a null pointer is returned.
|
|
// 1) The history is complete, indicating that the schema for a given version does not exist;
|
|
// 2) If history is reclaimed, it may also enter the branch, but considering the following points,
|
|
// it will not be processed for the time being:
|
|
// - 2.x not reclaim history
|
|
// - 1.4.x Even if history is reclaimed, it is also reclaiming long-awaited schema multi-version
|
|
// information,
|
|
// and the corresponding multi-version information is likely not to be relied on;
|
|
// - The reservoir fetches table_schema through retry_get_schema_guard, even if the incoming
|
|
// schema_version
|
|
// is too small, it will return the schema version that the table_schema exists for the first time
|
|
not_exist = true;
|
|
LOG_INFO("specific schema_version is small, schema not exist",
|
|
K(ret),
|
|
K(fetch_schema_status),
|
|
K(schema_version),
|
|
K(snapshot_version));
|
|
} else {
|
|
if (OB_FAIL(version_his_map_.set_refactored(key, val, 1 /*overwrite val*/))) {
|
|
LOG_WARN("set map failed", K(ret));
|
|
} else {
|
|
LOG_INFO("construct_schema_version_history succeed", K(key), K(val));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// Since the scenario where the standalone cluster is switched to the primary cluster cannot reset schema_status
|
|
// atomically, the schema_status of the primary cluster cannot be trusted. Taking into account the need to control
|
|
// schema playback after physical recovery, tenant_schema needs to be combined to determine whether schema_status needs
|
|
// to be used
|
|
int ObMultiVersionSchemaService::check_tenant_is_restore(
|
|
ObSchemaGetterGuard* schema_guard, const uint64_t tenant_id, bool& is_restore)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_restore = false;
|
|
if (OB_INVALID_TENANT_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (OB_SYS_TENANT_ID == tenant_id) {
|
|
is_restore = false;
|
|
} else if (OB_ISNULL(schema_guard)) {
|
|
ObSchemaGetterGuard tmp_guard;
|
|
if (OB_FAIL(get_tenant_schema_guard(OB_SYS_TENANT_ID, tmp_guard))) {
|
|
LOG_WARN("fail to get schema guard", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(tmp_guard.check_tenant_is_restore(tenant_id, is_restore))) {
|
|
LOG_WARN("fail to check tenant is restore", K(ret), K(tenant_id));
|
|
}
|
|
} else if (OB_FAIL(schema_guard->check_tenant_is_restore(tenant_id, is_restore))) {
|
|
LOG_WARN("fail to check tenant is restore", K(ret), K(tenant_id));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::check_restore_tenant_exist(const ObIArray<uint64_t>& tenant_ids, bool& exist)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
exist = false;
|
|
ObSchemaGetterGuard schema_guard;
|
|
if (1 == tenant_ids.count() && OB_SYS_TENANT_ID == tenant_ids.at(0)) {
|
|
exist = false;
|
|
} else if (OB_FAIL(get_tenant_schema_guard(OB_SYS_TENANT_ID, schema_guard))) {
|
|
LOG_WARN("fail to get sys schema_guard", K(ret));
|
|
} else {
|
|
ObArray<uint64_t> tmp_tenant_ids;
|
|
if (tenant_ids.count() == 0 && OB_FAIL(schema_guard.get_tenant_ids(tmp_tenant_ids))) {
|
|
LOG_WARN("fail to get tenant ids", K(ret));
|
|
} else {
|
|
const ObIArray<uint64_t>& tenants = 0 == tenant_ids.count() ? tmp_tenant_ids : tenant_ids;
|
|
const ObSimpleTenantSchema* tenant = NULL;
|
|
for (int64_t i = 0; OB_SUCC(ret) && !exist && i < tenants.count(); i++) {
|
|
const uint64_t tenant_id = tenants.at(i);
|
|
if (OB_FAIL(schema_guard.get_tenant_info(tenant_id, tenant))) {
|
|
LOG_WARN("fail to get tenant schema", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(tenant)) {
|
|
ret = OB_TENANT_NOT_EXIST;
|
|
LOG_WARN("tenant is null", K(ret));
|
|
} else if (tenant->is_restore()) {
|
|
exist = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// Obtain the least referenced schema version of the observer for schema recycling
|
|
int ObMultiVersionSchemaService::get_recycle_schema_version(const uint64_t tenant_id, int64_t& schema_version)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
schema_version = OB_INVALID_VERSION;
|
|
const ObSchemaStore* schema_store = NULL;
|
|
if (OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == tenant_id) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid tenant_id", K(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(schema_store = schema_store_map_.get(tenant_id))) {
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
LOG_WARN("schema store not exist", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(schema_store->schema_mgr_cache_.get_recycle_schema_version(schema_version))) {
|
|
LOG_WARN("fail to get recycle schema version", K(ret), K(schema_version));
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
schema_version = OB_INVALID_VERSION;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObMultiVersionSchemaService::fetch_link_table_schema(const ObDbLinkSchema& dblink_schema,
|
|
const ObString& database_name, const ObString& table_name, ObIAllocator& allocator, ObTableSchema*& table_schema)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(schema_service_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema service is NULL", K(ret));
|
|
} else if (OB_FAIL(schema_service_->get_link_table_schema(
|
|
dblink_schema, database_name, table_name, allocator, table_schema))) {
|
|
LOG_WARN("get link table schema failed", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
} // end of namespace schema
|
|
} // end of namespace share
|
|
} // end of namespace oceanbase
|