diff --git a/src/observer/mysql/ob_query_driver.cpp b/src/observer/mysql/ob_query_driver.cpp index e76f95bb42..411f016f94 100644 --- a/src/observer/mysql/ob_query_driver.cpp +++ b/src/observer/mysql/ob_query_driver.cpp @@ -124,6 +124,7 @@ int ObQueryDriver::response_query_result(ObResultSet &result, bool is_cac_found_rows = result.is_calc_found_rows(); int64_t limit_count = OB_INVALID_COUNT == fetch_limit ? INT64_MAX : fetch_limit; int64_t row_num = 0; + ObSqlCtx *sql_ctx = result.get_exec_context().get_sql_ctx(); if (!has_top_limit && OB_INVALID_COUNT == fetch_limit) { limit_count = INT64_MAX; if (OB_FAIL(session_.get_sql_select_limit(limit_count))) { diff --git a/src/observer/mysql/ob_query_retry_ctrl.cpp b/src/observer/mysql/ob_query_retry_ctrl.cpp index f4e4e129de..a60f13d3e7 100644 --- a/src/observer/mysql/ob_query_retry_ctrl.cpp +++ b/src/observer/mysql/ob_query_retry_ctrl.cpp @@ -744,6 +744,7 @@ void ObQueryRetryCtrl::switch_consumer_group_retry_proc(ObRetryParam &v) retry_obj.test(switch_group_retry); } + /////// For inner SQL only /////////////// void ObQueryRetryCtrl::inner_try_lock_row_conflict_proc(ObRetryParam &v) { diff --git a/src/observer/mysql/obmp_query.cpp b/src/observer/mysql/obmp_query.cpp index 610777f36e..55acb3e92e 100644 --- a/src/observer/mysql/obmp_query.cpp +++ b/src/observer/mysql/obmp_query.cpp @@ -1001,6 +1001,13 @@ OB_INLINE int ObMPQuery::do_process(ObSQLSessionInfo &session, result.get_exec_context().get_is_evolution(), table_row_count_list); plan->update_cache_access_stat(audit_record.table_scan_stat_); + } else if (ctx_.self_add_plan_ && ctx_.plan_cache_hit_) { + // spm evolution plan first execute + plan->update_plan_stat(audit_record, + true, + result.get_exec_context().get_is_evolution(), + table_row_count_list); + plan->update_cache_access_stat(audit_record.table_scan_stat_); } } } diff --git a/src/observer/mysql/obmp_stmt_execute.cpp b/src/observer/mysql/obmp_stmt_execute.cpp index c765b269aa..2a876abd4d 100644 --- a/src/observer/mysql/obmp_stmt_execute.cpp +++ b/src/observer/mysql/obmp_stmt_execute.cpp @@ -1294,6 +1294,13 @@ int ObMPStmtExecute::do_process(ObSQLSessionInfo &session, result.get_exec_context().get_is_evolution(), table_row_count_list); plan->update_cache_access_stat(audit_record.table_scan_stat_); + } else if (ctx_.self_add_plan_ && ctx_.plan_cache_hit_) { + // spm evolution plan first execute + plan->update_plan_stat(audit_record, + true, + result.get_exec_context().get_is_evolution(), + table_row_count_list); + plan->update_cache_access_stat(audit_record.table_scan_stat_); } } } diff --git a/src/observer/virtual_table/ob_all_plan_cache_stat.cpp b/src/observer/virtual_table/ob_all_plan_cache_stat.cpp index ee67d90263..b9aaa8487d 100644 --- a/src/observer/virtual_table/ob_all_plan_cache_stat.cpp +++ b/src/observer/virtual_table/ob_all_plan_cache_stat.cpp @@ -197,7 +197,7 @@ int ObAllPlanCacheStat::fill_cells(ObPlanCache &plan_cache) break; } case ASYN_BASELINE: { - SET_REF_HANDLE_COL(ASYN_BASELINE_HANDLE); + SET_REF_HANDLE_COL(CHECK_EVOLUTION_PLAN_HANDLE); break; } case LOAD_BASELINE: { diff --git a/src/sql/engine/ob_exec_context.cpp b/src/sql/engine/ob_exec_context.cpp index d6b3199082..25a155df4f 100644 --- a/src/sql/engine/ob_exec_context.cpp +++ b/src/sql/engine/ob_exec_context.cpp @@ -495,7 +495,7 @@ int ObExecContext::check_status() if (OB_ISNULL(phy_plan_ctx_)) { ret = OB_NOT_INIT; LOG_WARN("physical plan ctx is null"); - } else if (phy_plan_ctx_->is_timeout()) { + } else if (phy_plan_ctx_->is_exec_timeout()) { ret = OB_TIMEOUT; LOG_WARN("query is timeout", K(ret)); } else if (OB_ISNULL(my_session_)) { diff --git a/src/sql/engine/ob_physical_plan.cpp b/src/sql/engine/ob_physical_plan.cpp index 50a9a0e661..62b9dd7e9b 100644 --- a/src/sql/engine/ob_physical_plan.cpp +++ b/src/sql/engine/ob_physical_plan.cpp @@ -31,6 +31,7 @@ #include "sql/engine/ob_operator_factory.h" #include "share/stat/ob_opt_stat_manager.h" #include "share/ob_truncated_string.h" +#include "sql/spm/ob_spm_evolution_plan.h" namespace oceanbase { @@ -540,9 +541,10 @@ void ObPhysicalPlan::update_plan_stat(const ObAuditRecordData &record, ATOMIC_STORE(&(stat_.last_active_time_), current_time); if (ATOMIC_LOAD(&stat_.is_evolution_)) { //for spm ATOMIC_INC(&(stat_.evolution_stat_.executions_)); - ATOMIC_AAF(&(stat_.evolution_stat_.cpu_time_), - record.get_elapsed_time() - record.exec_record_.wait_time_end_ - - (record.exec_timestamp_.run_ts_ - record.exec_timestamp_.receive_ts_)); + // ATOMIC_AAF(&(stat_.evolution_stat_.cpu_time_), + // record.get_elapsed_time() - record.exec_record_.wait_time_end_ + // - (record.exec_timestamp_.run_ts_ - record.exec_timestamp_.receive_ts_)); + ATOMIC_AAF(&(stat_.evolution_stat_.cpu_time_), record.exec_timestamp_.executor_t_); ATOMIC_AAF(&(stat_.evolution_stat_.elapsed_time_), record.get_elapsed_time()); } if (stat_.is_bind_sensitive_ && execute_count > 0) { diff --git a/src/sql/engine/ob_physical_plan.h b/src/sql/engine/ob_physical_plan.h index 01f62e502f..9c1bb7dac7 100644 --- a/src/sql/engine/ob_physical_plan.h +++ b/src/sql/engine/ob_physical_plan.h @@ -51,6 +51,7 @@ class ObTablePartitionInfo; class ObPhyOperatorMonnitorInfo; struct ObAuditRecordData; class ObOpSpec; +class ObEvolutionPlan; //class ObPhysicalPlan: public common::ObDLinkBase typedef common::ObFixedArray, common::ObIAllocator> PhyRowParamMap; @@ -355,6 +356,9 @@ public: { return ob_write_string(allocator_, rule_name, stat_.rule_name_); } + inline int64_t get_plan_error_cnt() { return stat_.evolution_stat_.error_cnt_; } + inline void update_plan_error_cnt() { ATOMIC_INC(&(stat_.evolution_stat_.error_cnt_)); } + public: int inc_concurrent_num(); void dec_concurrent_num(); diff --git a/src/sql/engine/ob_physical_plan_ctx.cpp b/src/sql/engine/ob_physical_plan_ctx.cpp index 1a8df65561..060c5fb5b4 100644 --- a/src/sql/engine/ob_physical_plan_ctx.cpp +++ b/src/sql/engine/ob_physical_plan_ctx.cpp @@ -109,7 +109,8 @@ ObPhysicalPlanCtx::ObPhysicalPlanCtx(common::ObIAllocator &allocator) field_array_(nullptr), is_ps_protocol_(false), plan_start_time_(0), - is_ps_rewrite_sql_(false) + is_ps_rewrite_sql_(false), + spm_ts_timeout_us_(0) { } diff --git a/src/sql/engine/ob_physical_plan_ctx.h b/src/sql/engine/ob_physical_plan_ctx.h index 5eb6ee073a..70edf843f9 100644 --- a/src/sql/engine/ob_physical_plan_ctx.h +++ b/src/sql/engine/ob_physical_plan_ctx.h @@ -114,6 +114,19 @@ public: } return (ts_timeout_us_ > 0 && now > ts_timeout_us_); } + inline bool is_exec_timeout(int64_t *remain_us = NULL) const + { + int64_t now = common::ObClockGenerator::getClock(); + int64_t ts_timeout_us = spm_ts_timeout_us_ > 0 ? spm_ts_timeout_us_ : ts_timeout_us_; + if (remain_us != NULL) { + if (OB_LIKELY(ts_timeout_us > 0)) { + *remain_us = ts_timeout_us - now; + } else { + *remain_us = INT64_MAX; // no timeout + } + } + return (ts_timeout_us > 0 && now > ts_timeout_us); + } // snapshot timestamp used for transaction set consistency check inline int64_t get_tsc_timestamp() const { @@ -427,6 +440,7 @@ public: } const common::ObCurTraceId::TraceId &get_last_trace_id() const { return last_trace_id_; } common::ObCurTraceId::TraceId &get_last_trace_id() { return last_trace_id_; } + void set_spm_timeout_timestamp(const int64_t timeout) { spm_ts_timeout_us_ = timeout; } private: void reset_datum_frame(char *frame, int64_t expr_cnt); @@ -560,6 +574,8 @@ private: //used for monitor operator information int64_t plan_start_time_; bool is_ps_rewrite_sql_; + // timeout use by spm, don't need to serialize + int64_t spm_ts_timeout_us_; }; } diff --git a/src/sql/plan_cache/ob_pc_ref_handle.cpp b/src/sql/plan_cache/ob_pc_ref_handle.cpp index 2d1804bb21..d68f0d4f01 100644 --- a/src/sql/plan_cache/ob_pc_ref_handle.cpp +++ b/src/sql/plan_cache/ob_pc_ref_handle.cpp @@ -37,7 +37,7 @@ const char* ObCacheRefHandleMgr::handle_name(const CacheRefHandleID handle_id) "cli_query_handle", "outline_exec_handle", "plan_explain_handle", - "asyn_baseline_handle", + "check_evolution_plan_handle", "load_baseline_handle", "ps_exec_handle", "gv_sql_handle", diff --git a/src/sql/plan_cache/ob_pc_ref_handle.h b/src/sql/plan_cache/ob_pc_ref_handle.h index d5ac8b91a4..7d3d11157e 100644 --- a/src/sql/plan_cache/ob_pc_ref_handle.h +++ b/src/sql/plan_cache/ob_pc_ref_handle.h @@ -101,7 +101,7 @@ enum CacheRefHandleID CLI_QUERY_HANDLE, OUTLINE_EXEC_HANDLE, PLAN_EXPLAIN_HANDLE, - ASYN_BASELINE_HANDLE, + CHECK_EVOLUTION_PLAN_HANDLE, LOAD_BASELINE_HANDLE, PS_EXEC_HANDLE, GV_SQL_HANDLE, diff --git a/src/sql/plan_cache/ob_pcv_set.cpp b/src/sql/plan_cache/ob_pcv_set.cpp index 1dfbb24675..da9469dc85 100644 --- a/src/sql/plan_cache/ob_pcv_set.cpp +++ b/src/sql/plan_cache/ob_pcv_set.cpp @@ -521,5 +521,6 @@ int ObPCVSet::check_contains_table(uint64_t db_id, common::ObString tab_name, bo return ret; } + } } diff --git a/src/sql/plan_cache/ob_plan_cache.cpp b/src/sql/plan_cache/ob_plan_cache.cpp index 74ef4a892f..28f747bc05 100644 --- a/src/sql/plan_cache/ob_plan_cache.cpp +++ b/src/sql/plan_cache/ob_plan_cache.cpp @@ -188,6 +188,7 @@ struct ObGetPcvSetByTabNameOp : public ObKVEntryTraverseOp common::ObString tab_name_; }; + struct ObGetTableIdOp { explicit ObGetTableIdOp(uint64_t table_id) @@ -1038,37 +1039,6 @@ int ObPlanCache::cache_evict() return ret; } -int ObPlanCache::asyn_update_baseline() -{ - int ret = OB_SUCCESS; - ObGlobalReqTimeService::check_req_timeinfo(); - SMART_VAR(PlanIdArray, plan_ids) { - ObGetAllPlanIdOp plan_id_op(&plan_ids); - if (OB_FAIL(co_mgr_.foreach_cache_obj(plan_id_op))) { - LOG_WARN("fail to traverse id2stat_map", K(ret)); - } else { - ObPhysicalPlan *plan = NULL; - for (int64_t i = 0; i < plan_ids.count(); i++) { - uint64_t plan_id= plan_ids.at(i); - ObCacheObjGuard guard(ASYN_BASELINE_HANDLE); - int tmp_ret = ref_plan(plan_id, guard); //plan引用计数加1 - plan = static_cast(guard.cache_obj_); - - if (OB_HASH_NOT_EXIST == tmp_ret) { - //do nothing; - } else if (OB_SUCCESS != tmp_ret || NULL == plan) { - if (OB_SUCCESS == tmp_ret && NULL == plan) { - LOG_DEBUG("get plan failed", K(tmp_ret), KP(plan), K(plan_id)); - } else { - LOG_WARN("get plan failed", K(tmp_ret), KP(plan), K(plan_id)); - } - } - } // for loop ends - } - } - return ret; -} - // int ObPlanCache::load_plan_baseline() // { // int ret = OB_SUCCESS; @@ -2071,9 +2041,6 @@ void ObPlanCacheEliminationTask::run_plan_cache_task() if (OB_FAIL(plan_cache_->cache_evict())) { SQL_PC_LOG(ERROR, "Plan cache evict failed, please check", K(ret)); } - if (OB_FAIL(plan_cache_->asyn_update_baseline())) { - SQL_PC_LOG(ERROR, "asyn replace plan baseline failed", K(ret)); - } } void ObPlanCacheEliminationTask::run_free_cache_obj_task() diff --git a/src/sql/plan_cache/ob_plan_cache.h b/src/sql/plan_cache/ob_plan_cache.h index d5ed07c366..4cfd4aa381 100644 --- a/src/sql/plan_cache/ob_plan_cache.h +++ b/src/sql/plan_cache/ob_plan_cache.h @@ -49,6 +49,7 @@ class ObPCVSet; class ObILibCacheObject; class ObPhysicalPlan; class ObLibCacheAtomicOp; +class ObEvolutionPlan; typedef common::hash::ObHashMap PlanCacheMap; @@ -327,8 +328,6 @@ public: int cache_evict_by_ns(ObLibCacheNameSpace ns); template int foreach_cache_evict(CallBack &cb); - //asynchronous update plan baseline - int asyn_update_baseline(); void destroy(); common::ObAddr &get_host() { return host_; } void set_host(common::ObAddr &addr) { host_ = addr; } diff --git a/src/sql/plan_cache/ob_plan_cache_manager.cpp b/src/sql/plan_cache/ob_plan_cache_manager.cpp index b5776e875c..55bb5f1fa8 100644 --- a/src/sql/plan_cache/ob_plan_cache_manager.cpp +++ b/src/sql/plan_cache/ob_plan_cache_manager.cpp @@ -353,9 +353,6 @@ void ObPlanCacheManager::ObPlanCacheEliminationTask::run_plan_cache_task() if (OB_FAIL(plan_cache->cache_evict())) { SQL_PC_LOG(ERROR, "Plan cache evict failed, please check", K(ret)); } - if (OB_FAIL(plan_cache->asyn_update_baseline())) { - SQL_PC_LOG(ERROR, "asyn replace plan baseline failed", K(ret), K(tenant_id)); - } plan_cache->dec_ref_count(); } } diff --git a/src/sql/plan_cache/ob_plan_cache_value.cpp b/src/sql/plan_cache/ob_plan_cache_value.cpp index bf92f2ca57..f78d14a5d2 100644 --- a/src/sql/plan_cache/ob_plan_cache_value.cpp +++ b/src/sql/plan_cache/ob_plan_cache_value.cpp @@ -2094,5 +2094,6 @@ int ObPlanCacheValue::check_contains_table(uint64_t db_id, common::ObString tab_ return ret; } + }//end of namespace sql }//end of namespace oceanbase diff --git a/src/sql/plan_cache/ob_plan_set.cpp b/src/sql/plan_cache/ob_plan_set.cpp index 06fa9cd51d..d9847e50fe 100644 --- a/src/sql/plan_cache/ob_plan_set.cpp +++ b/src/sql/plan_cache/ob_plan_set.cpp @@ -2144,5 +2144,6 @@ bool ObSqlPlanSet::is_sql_planset() return true; } + } } diff --git a/src/sql/spm/ob_plan_baseline_mgr.h b/src/sql/spm/ob_plan_baseline_mgr.h index 16fd0084c4..59a6b4482f 100644 --- a/src/sql/spm/ob_plan_baseline_mgr.h +++ b/src/sql/spm/ob_plan_baseline_mgr.h @@ -105,6 +105,7 @@ public: int load_baseline(ObBaselineKey &key, ObPhysicalPlan* plan, const bool fixed, const bool enabled); int purge_baselines(const uint64_t tenant_id, int64_t baseline_affected); int evict_plan_baseline(ObSpmCacheCtx& spm_ctx); + int check_evolution_task(); private: int init(uint64_t tenant_id); int init_mem_context(uint64_t tenant_id); diff --git a/src/sql/spm/ob_spm_controller.h b/src/sql/spm/ob_spm_controller.h index f525cae59c..35b97ed8fd 100644 --- a/src/sql/spm/ob_spm_controller.h +++ b/src/sql/spm/ob_spm_controller.h @@ -42,6 +42,7 @@ public: static int cancel_evolve_task(obrpc::ObModifyPlanBaselineArg& arg); static int load_baseline(const obrpc::ObLoadPlanBaselineArg& arg, ObPhysicalPlan* plan); static int deny_new_plan_as_baseline(ObSpmCacheCtx& spm_ctx); + static int64_t calc_spm_timeout_us(const int64_t normal_timeout, const int64_t baseline_exec_time); }; } // namespace sql end diff --git a/src/sql/spm/ob_spm_define.h b/src/sql/spm/ob_spm_define.h index 6fa5685021..3b01a62dac 100644 --- a/src/sql/spm/ob_spm_define.h +++ b/src/sql/spm/ob_spm_define.h @@ -267,7 +267,9 @@ struct ObSpmCacheCtx : public ObILibCacheCtx has_fixed_plan_to_check_(false), evolution_plan_type_(OB_PHY_PLAN_UNINITIALIZED), select_plan_type_(INVALID_TYPE), - cur_baseline_not_enable_(false) + cur_baseline_not_enable_(false), + need_spm_timeout_(false), + baseline_exec_time_(0) {} enum SpmMode { MODE_INVALID, @@ -288,6 +290,8 @@ struct ObSpmCacheCtx : public ObILibCacheCtx STAT_ADD_BASELINE_PLAN, // add baseline plan to plan cache evolution layer STAT_ACCEPT_EVOLUTION_PLAN, // accept evolution plan as baseline and move it from evolution layer to plan layer STAT_ACCEPT_BASELINE_PLAN, // move baeline plan from evolution layer to plan layer + STAT_FIRST_EXECUTE_PLAN, + STAT_FALLBACK_EXECUTE_PLAN, STAT_MAX }; enum SpmSelectPlanType @@ -327,6 +331,8 @@ struct ObSpmCacheCtx : public ObILibCacheCtx ObPhyPlanType evolution_plan_type_; SpmSelectPlanType select_plan_type_; // for retry bool cur_baseline_not_enable_; + bool need_spm_timeout_; + int64_t baseline_exec_time_; }; struct EvolutionTaskResult diff --git a/src/sql/spm/ob_spm_evolution_plan.h b/src/sql/spm/ob_spm_evolution_plan.h index a7d26ecb3d..52bc8e58c9 100644 --- a/src/sql/spm/ob_spm_evolution_plan.h +++ b/src/sql/spm/ob_spm_evolution_plan.h @@ -67,7 +67,14 @@ public: start_evolution_time_(0), evolution_count_ts_(DEFAULT_EVOLUTION_COUNT_THRESHOLD), evolution_timeout_ts_(DEFAULT_EVOLUTION_TIMEOUT_THRESHOLD), - evolving_plan_(NULL) + evolving_plan_(NULL), + evolving_plan_stat_(NULL), + history_exec_time_(0), + is_inited_(false), + current_stage_cnt_(0), + evolution_finish_count_(0), + lazy_finished_(false), + lazy_better_(false) { } void reset(); @@ -97,19 +104,22 @@ public: } int get_plan(ObPlanCacheCtx &ctx, ObPhysicalPlan *&plan); int add_plan(ObPlanCacheCtx &ctx, ObPhysicalPlan *plan); + void inc_evolution_finish_count(); + void check_task_need_finish(); + int compare_and_lazy_finalize_plan(); TO_STRING_KV(K_(is_evolving), K_(evolution_count), K_(start_evolution_time), K_(evolution_count_ts), K_(evolution_timeout_ts), K_(baseline_plans), - KPC_(evolving_plan), - KPC_(plan_set)); + KPC_(evolving_plan)); private: // static const EvolutionPercentage DEFAULT_EVOLUTION_PERCENTAGE = 50; - static const int64_t DEFAULT_EVOLUTION_COUNT_THRESHOLD = 100; - static const int64_t DEFAULT_EVOLUTION_TIMEOUT_THRESHOLD = 24 * 60 * 60 * 1000L * 1000L; //24 hours + static const int64_t DEFAULT_EVOLUTION_COUNT_THRESHOLD = 150; + static const int64_t DEFAULT_EVOLUTION_TIMEOUT_THRESHOLD = 3 * 60 * 60 * 1000L * 1000L; //3 hours + static const int64_t DEFAULT_ERROR_COUNT_THRESHOLD = 3; int get_plan_with_guard(ObPlanCacheCtx &ctx, ObPhysicalPlan *&plan); @@ -130,15 +140,18 @@ private: const ObPhysicalPlan *r_plan, bool &is_same) const; int is_evolving_plan_better(bool &is_better) const; - int process_plan_evolution_result(const bool is_better, - ObPlanCacheCtx &ctx, - ObPhysicalPlan *&plan); + int process_plan_evolution_result(const bool is_better); int discard_evolving_plan_add_baseline_plan_to_pc(ObPlanCacheCtx &ctx); int discard_baseline_plan_add_evolving_plan_to_pc(ObPlanCacheCtx &ctx); int discard_all_plan_by_type(EvolutionPlanType plan_type, bool evict_plan = false); int add_evolving_plan_to_pc(ObPlanCacheCtx &ctx); int add_all_baseline_plans_to_pc(ObPlanCacheCtx &ctx); void reset_evolution_plan_info(); + void get_evolution_count_and_calc_dynamic_exec_count(int64_t &evolution_count); + int get_final_plan_and_discard_other_plan(const bool need_evolving_plan, + ObPlanCacheCtx &ctx, + ObPhysicalPlan *&plan); + int64_t get_baseline_plan_error_cnt(); protected: ObSqlPlanSet *plan_set_; @@ -153,6 +166,16 @@ protected: ObPhysicalPlan *evolving_plan_; common::ObSEArray baseline_plans_; common::ObSEArray garbage_list_; + ObEvolutionStat *evolving_plan_stat_; + ObSEArray baseline_plans_stat_; + int64_t history_exec_time_; + bool is_inited_; + bool is_evo_best_plan_; + int64_t best_plan_cnt_; + int64_t current_stage_cnt_; + int64_t evolution_finish_count_; + bool lazy_finished_; + bool lazy_better_; }; } //namespace sql end diff --git a/src/sql/spm/ob_spm_struct.h b/src/sql/spm/ob_spm_struct.h index c9ca17bd54..dfb0f0920f 100644 --- a/src/sql/spm/ob_spm_struct.h +++ b/src/sql/spm/ob_spm_struct.h @@ -25,12 +25,14 @@ public: ObEvolutionStat() : executions_(0), cpu_time_(0), - elapsed_time_(0) + elapsed_time_(0), + error_cnt_(0) {} ObEvolutionStat(const ObEvolutionStat &other) : executions_(other.executions_), cpu_time_(other.cpu_time_), - elapsed_time_(other.elapsed_time_) + elapsed_time_(other.elapsed_time_), + error_cnt_(other.error_cnt_) {} virtual ~ObEvolutionStat() {} inline void reset() @@ -38,6 +40,7 @@ public: executions_ = 0; cpu_time_ = 0; elapsed_time_ = 0; + error_cnt_ = 0; } inline ObEvolutionStat& operator=(const ObEvolutionStat &other) { @@ -45,14 +48,16 @@ public: executions_ = other.executions_; cpu_time_ = other.cpu_time_; elapsed_time_ = other.elapsed_time_; + error_cnt_ = other.error_cnt_; } return *this; } - TO_STRING_KV(K_(executions), K_(cpu_time), K_(elapsed_time)); + TO_STRING_KV(K_(executions), K_(cpu_time), K_(elapsed_time), K_(error_cnt)); public: int64_t executions_; // The total number of executions in the evolution process int64_t cpu_time_; // The total CPU time consumed during the evolution process int64_t elapsed_time_; + int64_t error_cnt_; }; struct AlterPlanBaselineArg