/** * Copyright (c) 2023 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 #include "ob_tablet_meta_table_compaction_operator.h" #include "lib/mysqlclient/ob_mysql_result.h" #include "lib/oblog/ob_log.h" #include "lib/string/ob_sql_string.h" #include "share/inner_table/ob_inner_table_schema.h" #include "share/ob_dml_sql_splicer.h" #include "share/tablet/ob_tablet_filter.h" #include "share/ob_service_epoch_proxy.h" #include "share/scn.h" #include "observer/ob_server_struct.h" #include "share/tablet/ob_tablet_table_operator.h" namespace oceanbase { namespace share { using namespace oceanbase::common; using namespace oceanbase::common::sqlclient; int ObTabletMetaTableCompactionOperator::batch_set_info_status( const uint64_t tenant_id, const ObIArray &tablet_ls_pairs, int64_t &affected_rows) { int ret = OB_SUCCESS; int64_t pairs_count = tablet_ls_pairs.count(); int64_t start_idx = 0; int64_t end_idx = min(MAX_BATCH_COUNT, pairs_count); while (OB_SUCC(ret) && (start_idx < end_idx)) { if (OB_FAIL(inner_batch_set_info_status_( tenant_id, tablet_ls_pairs, start_idx, end_idx, affected_rows))) { LOG_WARN("fail to inner batch set by sql", KR(ret), K(tenant_id), K(tablet_ls_pairs), K(start_idx), K(end_idx)); } else { start_idx = end_idx; end_idx = min(start_idx + MAX_BATCH_COUNT, pairs_count); } } return ret; } int ObTabletMetaTableCompactionOperator::inner_batch_set_info_status_( const uint64_t tenant_id, const ObIArray &tablet_ls_pairs, const int64_t start_idx, const int64_t end_idx, int64_t &affected_rows) { int ret = OB_SUCCESS; ObSqlString sql; const uint64_t meta_tenant_id = gen_meta_tenant_id(tenant_id); if (OB_FAIL(sql.append_fmt( "UPDATE %s SET status = '%ld' WHERE tenant_id = %ld AND (tablet_id,ls_id) IN ((", OB_ALL_TABLET_META_TABLE_TNAME, (int64_t)ObTabletReplica::ScnStatus::SCN_STATUS_ERROR, tenant_id))) { LOG_WARN("fail to assign sql", KR(ret), K(tenant_id)); } else { for (int64_t idx = start_idx; OB_SUCC(ret) && (idx < end_idx); ++idx) { const ObTabletID &tablet_id = tablet_ls_pairs.at(idx).get_tablet_id(); const ObLSID &ls_id = tablet_ls_pairs.at(idx).get_ls_id(); if (OB_UNLIKELY(!tablet_id.is_valid_with_tenant(tenant_id) || !ls_id.is_valid_with_tenant(tenant_id))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid tablet_id with tenant", KR(ret), K(tenant_id), K(tablet_id), K(ls_id)); } else if (OB_FAIL(sql.append_fmt( "'%lu', %ld%s", tablet_id.id(), ls_id.id(), ((idx == end_idx - 1) ? "))" : "), (")))) { LOG_WARN("fail to assign sql", KR(ret), K(tablet_id)); } } } int64_t tmp_affected_rows = 0; if (FAILEDx(GCTX.sql_proxy_->write(meta_tenant_id, sql.ptr(), tmp_affected_rows))) { LOG_WARN("fail to execute sql", KR(ret), K(tenant_id), K(meta_tenant_id), K(sql)); } else if (tmp_affected_rows > 0) { affected_rows += tmp_affected_rows; LOG_INFO("success to update checksum error status", K(ret), K(sql), K(tenant_id), K(tablet_ls_pairs), K(tmp_affected_rows)); } return ret; } int ObTabletMetaTableCompactionOperator::get_status( const ObTabletCompactionScnInfo &input_info, ObTabletCompactionScnInfo &ret_info) { int ret = OB_SUCCESS; ret_info.reset(); ObISQLClient *sql_client = GCTX.sql_proxy_; if (OB_UNLIKELY(!input_info.is_valid())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(input_info)); } else if (OB_ISNULL(sql_client)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sql client is null", K(ret), KP(sql_client)); } else if (OB_FAIL(do_select(*sql_client, false/*select_for_update*/, input_info, ret_info))) { if (OB_ENTRY_NOT_EXIST != ret) { LOG_WARN("failed to select from tablet compaction scn tablet", KR(ret), K(input_info)); } } return ret; } int ObTabletMetaTableCompactionOperator::do_select( ObISQLClient &sql_client, const bool select_with_update, const ObTabletCompactionScnInfo &input_info, ObTabletCompactionScnInfo &ret_info) { int ret = OB_SUCCESS; ObSqlString sql; const uint64_t meta_tenant_id = gen_meta_tenant_id(input_info.tenant_id_); ret_info = input_info; // assign tenant_id / ls_id / tablet_id if (OB_FAIL(sql.append_fmt( "SELECT max(report_scn) as report_scn, max(status) as status" " FROM %s WHERE tenant_id = '%lu' AND ls_id = '%ld' AND tablet_id = '%ld'%s", OB_ALL_TABLET_META_TABLE_TNAME, input_info.tenant_id_, input_info.ls_id_, input_info.tablet_id_, select_with_update ? " FOR UPDATE" : ""))) { LOG_WARN("failed to append fmt", K(ret), K(input_info)); } else { ret = execute_select_sql(sql_client, meta_tenant_id, sql, ret_info); } return ret; } int ObTabletMetaTableCompactionOperator::execute_select_sql( ObISQLClient &sql_client, const int64_t meta_tenant_id, const ObSqlString &sql, ObTabletCompactionScnInfo &ret_info) { int ret = OB_SUCCESS; SMART_VAR(ObMySQLProxy::MySQLResult, res) { ObMySQLResult *result = nullptr; if (OB_FAIL(sql_client.read(res, meta_tenant_id, sql.ptr()))) { LOG_WARN("fail to do read", KR(ret), K(meta_tenant_id), K(sql)); } else if (OB_ISNULL(result = res.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get result", KR(ret), K(meta_tenant_id), K(sql)); } else if (OB_FAIL(construct_compaction_related_info(*result, ret_info))) { if (OB_ENTRY_NOT_EXIST != ret) { LOG_WARN("fail to get medium snapshot info", KR(ret), KP(result), K(sql)); } } else { LOG_TRACE("success to get medium snapshot info", K(ret_info)); } } return ret; } int ObTabletMetaTableCompactionOperator::batch_update_unequal_report_scn_tablet( const uint64_t tenant_id, const share::ObLSID &ls_id, const int64_t major_frozen_scn, const common::ObIArray &input_tablet_id_array) { int ret = OB_SUCCESS; const uint64_t meta_tenant_id = gen_meta_tenant_id(tenant_id); int64_t start_idx = 0; int64_t end_idx = min(MAX_BATCH_COUNT, input_tablet_id_array.count()); common::ObSEArray unequal_tablet_id_array; if (OB_ISNULL(GCTX.sql_proxy_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sql proxy is unexpected null", K(ret)); } else { LOG_INFO("start to update unequal tablet id array", KR(ret), K(ls_id), K(major_frozen_scn), "input_tablet_id_array_cnt", input_tablet_id_array.count()); } while (OB_SUCC(ret) && (start_idx < end_idx)) { ObSqlString sql; if (OB_FAIL(sql.append_fmt( "select distinct(tablet_id) from %s where tenant_id = '%lu' AND ls_id = '%ld'" " AND tablet_id IN (", OB_ALL_TABLET_META_TABLE_TNAME, tenant_id, ls_id.id()))) { LOG_WARN("failed to assign sql", K(ret), K(tenant_id), K(start_idx)); } else if (OB_FAIL(append_tablet_id_array(tenant_id, input_tablet_id_array, start_idx, end_idx, sql))) { LOG_WARN("fail to append tablet id array", KR(ret), K(tenant_id), K(input_tablet_id_array.count()), K(start_idx), K(end_idx)); } else if (OB_FAIL(sql.append_fmt(") AND report_scn < '%lu'", major_frozen_scn))) { LOG_WARN("failed to assign sql", K(ret), K(tenant_id), K(start_idx)); } else { SMART_VAR(ObISQLClient::ReadResult, result) { if (OB_FAIL(GCTX.sql_proxy_->read(result, meta_tenant_id, sql.ptr()))) { LOG_WARN("fail to execute sql", KR(ret), K(tenant_id), K(meta_tenant_id), "sql", sql.ptr()); } else if (OB_ISNULL(result.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get mysql result", KR(ret), "sql", sql.ptr()); } else if (OB_FAIL(construct_tablet_id_array(*result.get_result(), unequal_tablet_id_array))) { LOG_WARN("fail to construct tablet id array", KR(ret), "sql", sql.ptr()); } else if (unequal_tablet_id_array.count() > 0) { LOG_TRACE("success to get uneuqal tablet_id array", K(ret), K(unequal_tablet_id_array)); } } if (OB_FAIL(ret) || unequal_tablet_id_array.empty()) { } else if (unequal_tablet_id_array.count() < MAX_BATCH_COUNT && end_idx != input_tablet_id_array.count()) { // before last round, check count // do nothing } else if (OB_FAIL(inner_batch_update_unequal_report_scn_tablet( tenant_id, ls_id, major_frozen_scn, unequal_tablet_id_array))) { LOG_WARN("fail to update unequal tablet id array", KR(ret), "sql", sql.ptr()); } else { unequal_tablet_id_array.reuse(); } } if (OB_SUCC(ret)) { start_idx = end_idx; end_idx = min(start_idx + MAX_BATCH_COUNT, input_tablet_id_array.count()); } } return ret; } int ObTabletMetaTableCompactionOperator::get_min_compaction_scn( const uint64_t tenant_id, SCN &min_compaction_scn) { int ret = OB_SUCCESS; const int64_t start_time_us = ObTimeUtil::current_time(); if (OB_UNLIKELY(!is_valid_tenant_id(tenant_id))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id)); } else { const uint64_t meta_tenant_id = gen_meta_tenant_id(tenant_id); int64_t estimated_timeout_us = 0; ObTimeoutCtx timeout_ctx; // set trx_timeout and query_timeout based on tablet_replica_cnt if (OB_FAIL(ObTabletMetaTableCompactionOperator::get_estimated_timeout_us(tenant_id, estimated_timeout_us))) { LOG_WARN("fail to get estimated_timeout_us", KR(ret), K(tenant_id)); } else if (OB_FAIL(timeout_ctx.set_trx_timeout_us(estimated_timeout_us))) { LOG_WARN("fail to set trx timeout", KR(ret), K(estimated_timeout_us)); } else if (OB_FAIL(timeout_ctx.set_timeout(estimated_timeout_us))) { LOG_WARN("fail to set abs timeout", KR(ret), K(estimated_timeout_us)); } else { ObSqlString sql; SMART_VAR(ObISQLClient::ReadResult, res) { ObMySQLResult *result = nullptr; if (OB_FAIL(sql.assign_fmt("SELECT MIN(compaction_scn) as value FROM %s WHERE tenant_id =" " '%ld' ", OB_ALL_TABLET_META_TABLE_TNAME, tenant_id))) { LOG_WARN("failed to append fmt", K(ret), K(tenant_id)); } else if (OB_FAIL(GCTX.sql_proxy_->read(res, meta_tenant_id, sql.ptr()))) { LOG_WARN("fail to execute sql", KR(ret), K(tenant_id), K(meta_tenant_id), K(sql)); } else if (OB_ISNULL(result = res.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get mysql result", KR(ret), K(tenant_id), K(sql)); } else if (OB_FAIL(result->next())) { LOG_WARN("get next result failed", KR(ret), K(tenant_id), K(sql)); } else { uint64_t min_compaction_scn_val = UINT64_MAX; EXTRACT_UINT_FIELD_MYSQL(*result, "value", min_compaction_scn_val, uint64_t); if (FAILEDx(min_compaction_scn.convert_for_inner_table_field(min_compaction_scn_val))) { LOG_WARN("fail to convert uint64_t to SCN", KR(ret), K(min_compaction_scn_val)); } } } } LOG_INFO("finish to get min_compaction_scn", KR(ret), K(tenant_id), K(min_compaction_scn), "cost_time_us", ObTimeUtil::current_time() - start_time_us, K(estimated_timeout_us)); } return ret; } int ObTabletMetaTableCompactionOperator::construct_tablet_id_array( sqlclient::ObMySQLResult &result, common::ObIArray &tablet_id_array) { int ret = OB_SUCCESS; int64_t tablet_id = 0; while (OB_SUCC(ret)) { if (OB_FAIL(result.next())) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; } else { LOG_WARN("fail to get next result", KR(ret)); } break; } else if (OB_FAIL(result.get_int("tablet_id", tablet_id))) { LOG_WARN("fail to get uint", KR(ret)); } else if (OB_FAIL(tablet_id_array.push_back(ObTabletID(tablet_id)))) { LOG_WARN("failed to push back tablet id", K(ret), K(tablet_id)); } } return ret; } int ObTabletMetaTableCompactionOperator::append_tablet_id_array( const uint64_t tenant_id, const common::ObIArray &input_tablet_id_array, const int64_t start_idx, const int64_t end_idx, ObSqlString &sql) { int ret = OB_SUCCESS; for (int64_t idx = start_idx; OB_SUCC(ret) && (idx < end_idx); ++idx) { const ObTabletID &tablet_id = input_tablet_id_array.at(idx); if (OB_UNLIKELY(!tablet_id.is_valid_with_tenant(tenant_id))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid tablet_id with tenant", KR(ret), K(tenant_id), K(tablet_id)); } else if (OB_FAIL(sql.append_fmt( "%s %ld", start_idx == idx ? "" : ",", tablet_id.id()))) { LOG_WARN("fail to assign sql", KR(ret), K(idx), K(tablet_id)); } } return ret; } int ObTabletMetaTableCompactionOperator::inner_batch_update_unequal_report_scn_tablet( const uint64_t tenant_id, const share::ObLSID &ls_id, const int64_t major_frozen_scn, const common::ObIArray &unequal_tablet_id_array) { int ret = OB_SUCCESS; int64_t affected_rows = 0; const uint64_t meta_tenant_id = gen_meta_tenant_id(tenant_id); ObSqlString sql; #ifdef ERRSIM ret = OB_E(EventTable::EN_COMPACTION_UPDATE_REPORT_SCN) ret; if (OB_FAIL(ret)) { LOG_INFO("ERRSIM EN_COMPACTION_UPDATE_REPORT_SCN", K(ret)); } #endif if (FAILEDx(sql.append_fmt( "UPDATE %s t1 SET report_scn=if(compaction_scn>'%lu' ,'%lu', compaction_scn) WHERE " "tenant_id='%lu' AND ls_id='%ld' AND tablet_id IN (", OB_ALL_TABLET_META_TABLE_TNAME, major_frozen_scn, major_frozen_scn, tenant_id, ls_id.id()))) { LOG_WARN("failed to append fmt", K(ret), K(tenant_id), K(ls_id)); } else if (OB_FAIL(append_tablet_id_array(tenant_id, unequal_tablet_id_array, 0, unequal_tablet_id_array.count(), sql))) { LOG_WARN("fail to append tablet id array", KR(ret), K(tenant_id), K(unequal_tablet_id_array)); } else if (OB_FAIL(sql.append_fmt(") AND report_scn <'%lu'", major_frozen_scn))) { LOG_WARN("failed to assign sql", K(ret), K(tenant_id), K(ls_id)); } else if (OB_FAIL(GCTX.sql_proxy_->write(meta_tenant_id, sql.ptr(), affected_rows))) { LOG_WARN("fail to execute sql", KR(ret), K(tenant_id), K(meta_tenant_id), K(sql)); } else if (affected_rows > 0) { LOG_INFO("success to update unequal report_scn", K(ret), K(sql), K(tenant_id), K(ls_id), K(unequal_tablet_id_array.count())); } return ret; } int ObTabletMetaTableCompactionOperator::construct_compaction_related_info( sqlclient::ObMySQLResult &result, ObTabletCompactionScnInfo &info) { int ret = OB_SUCCESS; uint64_t report_scn_in_table = 0; int64_t status = 0; if (OB_FAIL(result.get_uint("report_scn", report_scn_in_table))) { if (OB_ERR_NULL_VALUE == ret) { ret = OB_ENTRY_NOT_EXIST; } else { LOG_WARN("failed to get int", KR(ret), K(info)); } } else if (OB_FAIL(result.get_int("status", status))) { LOG_WARN("failed to get int", KR(ret), K(status)); } else if (OB_UNLIKELY(!ObTabletReplica::is_status_valid((ObTabletReplica::ScnStatus)status))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("status is invalid", KR(ret), K(status)); } else { info.report_scn_ = (int64_t)report_scn_in_table; info.status_ = ObTabletReplica::ScnStatus(status); } return ret; } int ObTabletMetaTableCompactionOperator::batch_update_report_scn( const uint64_t tenant_id, const uint64_t global_broadcast_scn_val, const ObTabletReplica::ScnStatus &except_status, const volatile bool &stop, const int64_t expected_epoch) { int ret = OB_SUCCESS; const int64_t start_time_us = ObTimeUtil::current_time(); const int64_t BATCH_UPDATE_CNT = 1000; uint64_t compat_version = 0; if (OB_UNLIKELY(!is_valid_tenant_id(tenant_id))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id)); } else if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { LOG_WARN("fail to get data version", KR(ret), K(tenant_id)); } else if (compat_version < DATA_VERSION_4_1_0_0) { // do nothing until schema upgrade } else { LOG_INFO("start to batch update report scn", KR(ret), K(tenant_id), K(global_broadcast_scn_val), K(expected_epoch)); const uint64_t meta_tenant_id = gen_meta_tenant_id(tenant_id); bool update_done = false; SMART_VAR(ObArray, tablet_ids) { while (OB_SUCC(ret) && !update_done && !stop) { bool is_match = true; ObMySQLTransaction trans; ObSqlString sql; int64_t affected_rows = 0; if (OB_FAIL(ObTabletMetaTableCompactionOperator::get_next_batch_tablet_ids(tenant_id, BATCH_UPDATE_CNT, tablet_ids))) { LOG_WARN("fail to get next batch of tablet_ids", KR(ret), K(tenant_id), K(BATCH_UPDATE_CNT)); } else if (0 == tablet_ids.count()) { update_done = true; LOG_INFO("finish all rounds of batch update report scn", KR(ret), K(tenant_id), "cost_time_us", ObTimeUtil::current_time() - start_time_us); } else if (OB_FAIL(construct_batch_update_report_scn_sql_str_(tenant_id, global_broadcast_scn_val, except_status, tablet_ids, sql))) { LOG_WARN("fail to construct batch update sql str", KR(ret), K(tenant_id), K(global_broadcast_scn_val), K(except_status)); } else if (OB_FAIL(trans.start(GCTX.sql_proxy_, meta_tenant_id))) { LOG_WARN("fail to start transaction", KR(ret), K(tenant_id), K(meta_tenant_id)); } else if (OB_FAIL(ObServiceEpochProxy::check_service_epoch_with_trans(trans, tenant_id, ObServiceEpochProxy::FREEZE_SERVICE_EPOCH, expected_epoch, is_match))) { LOG_WARN("fail to check service_epoch with trans", KR(ret), K(tenant_id), K(expected_epoch)); } else if (is_match) { if (OB_FAIL(trans.write(meta_tenant_id, sql.ptr(), affected_rows))) { LOG_WARN("fail to execute sql", KR(ret), K(tenant_id), K(meta_tenant_id), K(sql)); } } else { // !is_match ret = OB_FREEZE_SERVICE_EPOCH_MISMATCH; LOG_WARN("freeze_service_epoch mismatch, do not update report_scn on this server", KR(ret), K(tenant_id)); } ret = trans.handle_trans_in_the_end(ret); LOG_INFO("finish one round of batch update report scn", KR(ret), K(tenant_id), K(affected_rows), K(BATCH_UPDATE_CNT)); } } } return ret; } int ObTabletMetaTableCompactionOperator::batch_update_status( const uint64_t tenant_id, const int64_t expected_epoch) { int ret = OB_SUCCESS; const int64_t start_time_us = ObTimeUtil::current_time(); const int64_t BATCH_UPDATE_CNT = 1000; uint64_t compat_version = 0; if (OB_UNLIKELY(!is_valid_tenant_id(tenant_id))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id)); } else if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { LOG_WARN("fail to get data version", KR(ret), K(tenant_id)); } else if (compat_version < DATA_VERSION_4_1_0_0) { // do nothing until schema upgrade } else { LOG_INFO("start to batch update status", KR(ret), K(tenant_id), K(expected_epoch)); const uint64_t meta_tenant_id = gen_meta_tenant_id(tenant_id); bool update_done = false; SMART_VAR(ObArray, tablet_ids) { while (OB_SUCC(ret) && !update_done) { bool is_match = true; ObMySQLTransaction trans; ObSqlString sql; int64_t affected_rows = 0; if (OB_FAIL(ObTabletMetaTableCompactionOperator::get_next_batch_tablet_ids(tenant_id, BATCH_UPDATE_CNT, tablet_ids))) { LOG_WARN("fail to get next batch of tablet_ids", KR(ret), K(tenant_id), K(BATCH_UPDATE_CNT)); } else if (0 == tablet_ids.count()) { update_done = true; LOG_INFO("finish all rounds of batch update status", KR(ret), K(tenant_id), "cost_time_us", ObTimeUtil::current_time() - start_time_us); } else if (OB_FAIL(construct_batch_update_status_sql_str_(tenant_id, tablet_ids, sql))) { LOG_WARN("fail to construct batch update sql str", KR(ret), K(tenant_id)); } else if (OB_FAIL(trans.start(GCTX.sql_proxy_, meta_tenant_id))) { LOG_WARN("fail to start transaction", KR(ret), K(tenant_id), K(meta_tenant_id)); } else if (OB_FAIL(ObServiceEpochProxy::check_service_epoch_with_trans(trans, tenant_id, ObServiceEpochProxy::FREEZE_SERVICE_EPOCH, expected_epoch, is_match))) { LOG_WARN("fail to check service_epoch with trans", KR(ret), K(tenant_id), K(expected_epoch)); } else if (is_match) { if (OB_FAIL(trans.write(meta_tenant_id, sql.ptr(), affected_rows))) { LOG_WARN("fail to execute sql", KR(ret), K(tenant_id), K(meta_tenant_id), K(sql)); } } else { // !is_match ret = OB_FREEZE_SERVICE_EPOCH_MISMATCH; LOG_WARN("freeze_service_epoch mismatch, do not update status on this server", KR(ret), K(tenant_id)); } ret = trans.handle_trans_in_the_end(ret); LOG_INFO("finish one round of batch update status", KR(ret), K(tenant_id), K(affected_rows), K(BATCH_UPDATE_CNT)); } } } return ret; } int ObTabletMetaTableCompactionOperator::batch_get_tablet_ids( const uint64_t tenant_id, const ObSqlString &sql, ObIArray &tablet_ids) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_valid_tenant_id(tenant_id))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id)); } else { tablet_ids.reuse(); const uint64_t meta_tenant_id = gen_meta_tenant_id(tenant_id); SMART_VAR(ObISQLClient::ReadResult, res) { ObMySQLResult *result = nullptr; if (OB_FAIL(GCTX.sql_proxy_->read(res, meta_tenant_id, sql.ptr()))) { LOG_WARN("fail to execute sql", KR(ret), K(tenant_id), K(meta_tenant_id), K(sql)); } else if (OB_ISNULL(result = res.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get mysql result", KR(ret), K(tenant_id), K(sql)); } else if (OB_FAIL(construct_tablet_id_array(*result, tablet_ids))) { LOG_WARN("fail to push_back tablet_id", KR(ret)); } } LOG_INFO("finish to batch get tablet_ids", KR(ret), K(tenant_id), K(sql)); } return ret; } int ObTabletMetaTableCompactionOperator::construct_batch_update_report_scn_sql_str_( const uint64_t tenant_id, const uint64_t global_braodcast_scn_val, const ObTabletReplica::ScnStatus &except_status, const ObIArray &tablet_ids, ObSqlString &sql) { int ret = OB_SUCCESS; const int64_t tablet_ids_cnt = tablet_ids.count(); if (OB_UNLIKELY(!is_valid_tenant_id(tenant_id) || tablet_ids.empty())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id), K(tablet_ids)); } else if (OB_FAIL(sql.assign_fmt("UPDATE %s SET report_scn = '%lu' WHERE tenant_id = '%ld' AND" " tablet_id >= '%lu' AND tablet_id <= '%lu' AND compaction_scn >= '%lu' AND report_scn" " < '%lu' AND status != '%ld'", OB_ALL_TABLET_META_TABLE_TNAME, global_braodcast_scn_val, tenant_id, tablet_ids.at(0).id(), tablet_ids.at(tablet_ids_cnt - 1).id(), global_braodcast_scn_val, global_braodcast_scn_val, (int64_t)except_status))) { LOG_WARN("fail to assign sql", KR(ret), K(tenant_id), K(global_braodcast_scn_val), K(except_status), "start_tablet_id", tablet_ids.at(0), "end_tablet_id", tablet_ids.at(tablet_ids_cnt - 1)); } return ret; } int ObTabletMetaTableCompactionOperator::construct_batch_update_status_sql_str_( const uint64_t tenant_id, const ObIArray &tablet_ids, ObSqlString &sql) { int ret = OB_SUCCESS; const int64_t tablet_ids_cnt = tablet_ids.count(); if (OB_UNLIKELY(!is_valid_tenant_id(tenant_id) || tablet_ids.empty())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id), K(tablet_ids)); } else if (OB_FAIL(sql.assign_fmt("UPDATE %s SET status = '%ld' WHERE tenant_id = '%ld' AND" " tablet_id >= '%lu' AND tablet_id <= '%lu' AND status = '%ld'", OB_ALL_TABLET_META_TABLE_TNAME, (int64_t)ObTabletReplica::ScnStatus::SCN_STATUS_IDLE, tenant_id, tablet_ids.at(0).id(), tablet_ids.at(tablet_ids_cnt - 1).id(), (int64_t)ObTabletReplica::ScnStatus::SCN_STATUS_ERROR))) { LOG_WARN("fail to assign sql", KR(ret), K(tenant_id), "start_tablet_id", tablet_ids.at(0), "end_tablet_id", tablet_ids.at(tablet_ids_cnt - 1)); } return ret; } int ObTabletMetaTableCompactionOperator::get_estimated_timeout_us( const uint64_t tenant_id, int64_t &estimated_timeout_us) { int ret = OB_SUCCESS; int64_t tablet_replica_cnt = 0; if (OB_UNLIKELY(!is_valid_tenant_id(tenant_id))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id)); } else if (OB_FAIL(ObTabletMetaTableCompactionOperator::get_tablet_replica_cnt(tenant_id, tablet_replica_cnt))) { LOG_WARN("fail to get tablet replica cnt", KR(ret), K(tenant_id)); } else { estimated_timeout_us = tablet_replica_cnt * 1000L; // 1ms for each tablet replica estimated_timeout_us = MAX(estimated_timeout_us, THIS_WORKER.get_timeout_remain()); estimated_timeout_us = MIN(estimated_timeout_us, 3 * 3600 * 1000 * 1000L); estimated_timeout_us = MAX(estimated_timeout_us, GCONF.rpc_timeout); } return ret; } int ObTabletMetaTableCompactionOperator::get_tablet_replica_cnt( const uint64_t tenant_id, int64_t &tablet_replica_cnt) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_valid_tenant_id(tenant_id))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id)); } else { const uint64_t meta_tenant_id = gen_meta_tenant_id(tenant_id); ObSqlString sql; SMART_VAR(ObISQLClient::ReadResult, res) { ObMySQLResult *result = nullptr; if (OB_FAIL(sql.append_fmt("SELECT COUNT(*) as cnt from %s WHERE tenant_id = '%lu' ", OB_ALL_TABLET_META_TABLE_TNAME, tenant_id))) { LOG_WARN("failed to append fmt", K(ret), K(tenant_id)); } else if (OB_FAIL(GCTX.sql_proxy_->read(res, meta_tenant_id, sql.ptr()))) { LOG_WARN("fail to execute sql", KR(ret), K(tenant_id), K(meta_tenant_id), K(sql)); } else if (OB_ISNULL(result = res.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get mysql result", KR(ret), K(tenant_id), K(sql)); } else if (OB_FAIL(result->next())) { LOG_WARN("get next result failed", KR(ret), K(tenant_id), K(sql)); } else { EXTRACT_INT_FIELD_MYSQL(*result, "cnt", tablet_replica_cnt, int64_t); } } } return ret; } int ObTabletMetaTableCompactionOperator::batch_update_report_scn( const uint64_t tenant_id, const uint64_t global_broadcast_scn_val, const ObIArray &tablet_pairs, const ObTabletReplica::ScnStatus &except_status, const int64_t expected_epoch) { int ret = OB_SUCCESS; int64_t affected_rows = 0; uint64_t compat_version = 0; ObDMLSqlSplicer dml; const int64_t all_pair_cnt = tablet_pairs.count(); if (OB_UNLIKELY((all_pair_cnt < 1) || !is_valid_tenant_id(tenant_id))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id), K(all_pair_cnt)); } else if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { LOG_WARN("fail to get data version", KR(ret), K(tenant_id)); } else if (compat_version < DATA_VERSION_4_1_0_0) { } else { const uint64_t meta_tenant_id = gen_meta_tenant_id(tenant_id); for (int64_t i = 0; OB_SUCC(ret) && (i < all_pair_cnt); i += MAX_BATCH_COUNT) { const int64_t cur_end_idx = MIN(i + MAX_BATCH_COUNT, all_pair_cnt); ObMySQLTransaction trans; ObSqlString sql; bool is_match = true; if (OB_FAIL(sql.append_fmt( "UPDATE %s SET report_scn = '%lu' WHERE tenant_id = %ld AND (tablet_id,ls_id) IN (", OB_ALL_TABLET_META_TABLE_TNAME, global_broadcast_scn_val, tenant_id))) { LOG_WARN("fail to assign sql", KR(ret), K(tenant_id), K(global_broadcast_scn_val)); } else { // handle each batch tablet_ls_pairs for (int64_t idx = i; OB_SUCC(ret) && (idx < cur_end_idx); ++idx) { const ObTabletID &tablet_id = tablet_pairs.at(idx).get_tablet_id(); const ObLSID &ls_id = tablet_pairs.at(idx).get_ls_id(); if (OB_UNLIKELY(!tablet_id.is_valid_with_tenant(tenant_id) || !ls_id.is_valid_with_tenant(tenant_id))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid tablet_id with tenant", KR(ret), K(tenant_id), K(tablet_id), K(ls_id)); } else if (OB_FAIL(sql.append_fmt( "%s (%ld,%ld)", i == idx ? "" : ",", tablet_id.id(), ls_id.id()))) { LOG_WARN("fail to assign sql", KR(ret), K(tablet_id)); } } // end for if (FAILEDx(sql.append_fmt(") AND compaction_scn >= '%lu' AND report_scn < '%lu' AND status != %ld", global_broadcast_scn_val, global_broadcast_scn_val, (int64_t)(except_status)))) { LOG_WARN("fail to assign sql", KR(ret), K(tenant_id), K(meta_tenant_id), K(except_status), K(global_broadcast_scn_val)); } else if (OB_FAIL(trans.start(GCTX.sql_proxy_, meta_tenant_id))) { LOG_WARN("fail to start transaction", KR(ret), K(tenant_id), K(meta_tenant_id)); } else if (OB_FAIL(ObServiceEpochProxy::check_service_epoch_with_trans(trans, tenant_id, ObServiceEpochProxy::FREEZE_SERVICE_EPOCH, expected_epoch, is_match))) { LOG_WARN("fail to check service_epoch with trans", KR(ret), K(tenant_id), K(expected_epoch)); } else if (is_match) { if (OB_FAIL(trans.write(meta_tenant_id, sql.ptr(), affected_rows))) { LOG_WARN("fail to execute sql", KR(ret), K(tenant_id), K(meta_tenant_id), K(sql)); } else { LOG_TRACE("success to update report_scn", KR(ret), K(tenant_id), K(meta_tenant_id), K(tablet_pairs), K(sql)); } } else { // !is_match ret = OB_FREEZE_SERVICE_EPOCH_MISMATCH; LOG_WARN("freeze_service_epoch mismatch, do not update report_scn on this server", KR(ret), K(tenant_id)); } } ret = trans.handle_trans_in_the_end(ret); } } return ret; } int ObTabletMetaTableCompactionOperator::get_next_batch_tablet_ids( const uint64_t tenant_id, const int64_t batch_update_cnt, ObIArray &tablet_ids) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_valid_tenant_id(tenant_id) || batch_update_cnt < 1)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id), K(batch_update_cnt)); } else { ObSqlString sql; ObTabletID start_tablet_id = ObTabletID(ObTabletID::INVALID_TABLET_ID); if (tablet_ids.count() > 0) { start_tablet_id = tablet_ids.at(tablet_ids.count() - 1); } tablet_ids.reuse(); if (OB_FAIL(sql.append_fmt("SELECT DISTINCT tablet_id from %s WHERE tenant_id = '%ld' " "AND tablet_id > '%ld' ORDER BY tenant_id, tablet_id ASC LIMIT %ld", OB_ALL_TABLET_META_TABLE_TNAME, tenant_id, start_tablet_id.id(), batch_update_cnt))) { LOG_WARN("failed to append fmt", K(ret), K(tenant_id), K(start_tablet_id), K(batch_update_cnt)); } else if (OB_FAIL(batch_get_tablet_ids(tenant_id, sql, tablet_ids))) { LOG_WARN("fail to batch get tablet_ids", KR(ret), K(tenant_id), K(start_tablet_id), K(batch_update_cnt)); } } return ret; } int ObTabletMetaTableCompactionOperator::range_scan_for_compaction( const uint64_t tenant_id, const int64_t compaction_scn, const common::ObTabletID &start_tablet_id, const int64_t batch_size, const bool add_report_scn_filter, common::ObTabletID &end_tablet_id, ObIArray &tablet_infos) { int ret = OB_SUCCESS; tablet_infos.reset(); if (OB_UNLIKELY(!is_valid_tenant_id(tenant_id) || batch_size <= 0)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id), K(start_tablet_id), K(batch_size)); } else if (start_tablet_id.id() == INT64_MAX) { ret = OB_ITER_END; } else { ObTabletID tmp_start_tablet_id = start_tablet_id; ObTabletID tmp_end_tablet_id; while (OB_SUCC(ret) && tmp_start_tablet_id.id() < INT64_MAX) { if (OB_SUCC(inner_range_scan_for_compaction( tenant_id, compaction_scn, tmp_start_tablet_id, batch_size, add_report_scn_filter, tmp_end_tablet_id, tablet_infos))) { if (tablet_infos.empty()) { tmp_start_tablet_id = tmp_end_tablet_id; tmp_end_tablet_id.reset(); } else { break; } } } // end of while if (OB_SUCC(ret)) { end_tablet_id = tmp_end_tablet_id; if (tablet_infos.empty()) { ret = OB_ITER_END; } } } return ret; } int ObTabletMetaTableCompactionOperator::inner_range_scan_for_compaction( const uint64_t tenant_id, const int64_t compaction_scn, const common::ObTabletID &start_tablet_id, const int64_t batch_size, const bool add_report_scn_filter, common::ObTabletID &end_tablet_id, ObIArray &tablet_infos) { int ret = OB_SUCCESS; ObTabletID max_tablet_id; if (OB_ISNULL(GCTX.sql_proxy_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sql proxy in ctx is null", KR(ret), K(GCTX.sql_proxy_)); } else if (OB_FAIL(inner_get_max_tablet_id_in_range(tenant_id, start_tablet_id, batch_size, max_tablet_id))) { if (OB_ITER_END != ret) { LOG_WARN("failed to get max tablet id in range", KR(ret), K(start_tablet_id)); } else { ret = OB_SUCCESS; max_tablet_id = ObTabletID(INT64_MAX); } } if (OB_SUCC(ret)) { SMART_VAR(ObISQLClient::ReadResult, result) { const uint64_t sql_tenant_id = gen_meta_tenant_id(tenant_id); ObSqlString sql; ObSqlString report_scn_sql; if (add_report_scn_filter && OB_FAIL(report_scn_sql.append_fmt("AND report_scn < %ld", compaction_scn))) { LOG_WARN("fail to assign sql", KR(ret), K(report_scn_sql)); } else if (OB_FAIL(sql.append_fmt( "SELECT * from %s where tenant_id=%lu AND tablet_id > %ld AND tablet_id <= %ld %s", OB_ALL_TABLET_META_TABLE_TNAME, tenant_id, start_tablet_id.id(), max_tablet_id.id(), add_report_scn_filter ? report_scn_sql.ptr() : ""))) { LOG_WARN("fail to assign sql", KR(ret), K(sql)); } else if (OB_FAIL(GCTX.sql_proxy_->read(result, sql_tenant_id, sql.ptr()))) { LOG_WARN("execute sql failed", KR(ret), K(tenant_id), K(sql_tenant_id), K(sql)); } else if (OB_ISNULL(result.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get mysql result failed", KR(ret), K(sql)); } else if (OB_FAIL(ObTabletTableOperator::construct_tablet_infos(*result.get_result(), tablet_infos))) { LOG_WARN("construct tablet info failed", KR(ret), K(sql), K(tablet_infos)); } else { end_tablet_id = max_tablet_id; LOG_INFO("success to get tablet info", KR(ret), K(batch_size), K(tablet_infos), K(end_tablet_id), K(add_report_scn_filter)); } } } return ret; } int ObTabletMetaTableCompactionOperator::inner_get_max_tablet_id_in_range( const uint64_t tenant_id, const common::ObTabletID &start_tablet_id, const int64_t batch_size, common:: ObTabletID &end_tablet_id) { int ret = OB_SUCCESS; ObSqlString sql; sqlclient::ObMySQLResult *result_ptr = nullptr; const uint64_t sql_tenant_id = gen_meta_tenant_id(tenant_id); int64_t tablet_id = 0; SMART_VAR(ObISQLClient::ReadResult, result) { if (OB_FAIL(sql.append_fmt("SELECT tablet_id FROM %s " "WHERE tenant_id = %lu AND tablet_id > %ld ORDER BY tablet_id asc LIMIT 1 OFFSET %ld", OB_ALL_TABLET_META_TABLE_TNAME, tenant_id, start_tablet_id.id(), batch_size))) { LOG_WARN("fail to assign sql", KR(ret), K(sql)); } else if (OB_FAIL(GCTX.sql_proxy_->read(result, sql_tenant_id, sql.ptr()))) { LOG_WARN("execute sql failed", KR(ret), K(tenant_id), K(sql_tenant_id), K(sql)); } else if (OB_ISNULL(result_ptr = result.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get mysql result failed", KR(ret), K(sql)); } else if (OB_FAIL(result_ptr->next())) { if (OB_ITER_END != ret) { LOG_WARN("fail to get next result", KR(ret)); } } else if (OB_FAIL(result_ptr->get_int("tablet_id", tablet_id))) { LOG_WARN("fail to get uint", KR(ret)); } else { end_tablet_id = tablet_id; } } return ret; } } // end namespace share } // end namespace oceanbase