/** * 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. */ #ifndef _OB_OPTIMIZER_TRACE_IMPL_H #define _OB_OPTIMIZER_TRACE_IMPL_H #include "lib/file/ob_file.h" #include "lib/allocator/ob_allocator.h" #include "lib/hash_func/murmur_hash.h" #include "common/storage/ob_io_device.h" #include "sql/printer/ob_raw_expr_printer.h" #include "common/ob_smart_call.h" #include "lib/container/ob_array.h" #include namespace oceanbase { namespace common { class ObObj; class ObDSResultItem; } using namespace common; namespace sql { class ObDMLStmt; class ObSelectStmt; class ObRawExpr; class ObLogPlan; class ObJoinOrder; class Path; class JoinPath; struct JoinInfo; class OptTableMetas; class TableItem; class ObSQLSessionInfo; struct CandidatePlan; class OptSystemStat; class ObSkylineDim; class ObOptimizerTraceImpl; inline ObOptimizerTraceImpl** get_local_tracer() { // use thread local for raw thread. RLOCAL_INLINE(ObOptimizerTraceImpl*, optimizer_tracer); return &optimizer_tracer; } #define TITLE_LINE "------------------------------------------------------" #define KV(x) " ", #x, " = ", x #define KV_(x) " ", #x, " = ", x##_ #define BEGIN_OPT_TRACE(session, sql_id) \ ObOptimizerTraceImpl *copy_tracer = NULL; \ do { \ ObOptimizerTraceImpl** local_tracer = get_local_tracer(); \ if (OB_ISNULL(local_tracer) || OB_ISNULL(session)) { \ } else { \ copy_tracer = *local_tracer; \ if (session->get_optimizer_tracer().enable(sql_id)) { \ session->get_optimizer_tracer().open(); \ } \ *local_tracer = &(session->get_optimizer_tracer()); \ } \ } while (0); \ #define END_OPT_TRACE(session) \ do { \ ObOptimizerTraceImpl** local_tracer = get_local_tracer(); \ if (OB_ISNULL(local_tracer) || OB_ISNULL(session)) { \ } else { \ if (session->get_optimizer_tracer().enable()) { \ session->get_optimizer_tracer().close(); \ } \ *local_tracer = copy_tracer; \ } \ } while (0); \ #define CHECK_TRACE \ ObOptimizerTraceImpl** local_tracer = get_local_tracer(); \ ObOptimizerTraceImpl *tracer = NULL; \ if (OB_ISNULL(local_tracer) || \ OB_ISNULL(tracer=*local_tracer)) { \ } else \ #define CHECK_TRACE_ENABLED \ CHECK_TRACE if (tracer->enable()) \ #define RESUME_OPT_TRACE \ do { \ CHECK_TRACE { \ tracer->resume_trace(); \ } \ } while (0); \ #define STOP_OPT_TRACE \ do { \ CHECK_TRACE_ENABLED { \ tracer->stop_trace(); \ } \ } while (0); \ #define OPT_TRACE_BEGIN_SECTION \ do { \ CHECK_TRACE_ENABLED { \ tracer->increase_section(); \ } \ } while (0); \ #define OPT_TRACE_END_SECTION \ do { \ CHECK_TRACE_ENABLED { \ tracer->decrease_section(); \ } \ } while (0); \ #define OPT_TRACE(args...) \ do { \ CHECK_TRACE_ENABLED { \ tracer->new_line(); \ SMART_CALL(tracer->append(args)); \ } \ } while (0); \ #define OPT_TRACE_TITLE(args...) \ do { \ CHECK_TRACE_ENABLED { \ tracer->append_title(args); \ } \ } while (0); \ #define OPT_TRACE_ENV \ do { \ CHECK_TRACE_ENABLED { \ tracer->append_title("SYSTEM ENVIRONMENT"); \ tracer->trace_env(); \ } \ } while (0); \ #define OPT_TRACE_SESSION_INFO \ do { \ CHECK_TRACE_ENABLED { \ tracer->append_title("SESSION INFO"); \ tracer->trace_session_info(); \ } \ } while (0); \ #define OPT_TRACE_PARAMETERS \ do { \ CHECK_TRACE_ENABLED { \ tracer->append_title("OPTIMIZER PARAMETERS");\ tracer->trace_parameters(); \ } \ } while (0); \ #define OPT_TRACE_STATIS(stmt, table_metas) \ do { \ CHECK_TRACE_ENABLED { \ tracer->trace_static(stmt, table_metas); \ } \ } while (0); \ #define OPT_TRACE_TRANSFORM_SQL(stmt) \ do { \ CHECK_TRACE_ENABLED { \ tracer->trace_trans_sql(stmt); \ } \ } while (0); \ #define OPT_TRACE_TIME_USED \ do { \ CHECK_TRACE_ENABLED { \ tracer->trace_time_used(); \ } \ } while (0); \ #define OPT_TRACE_MEM_USED \ do { \ CHECK_TRACE_ENABLED { \ tracer->trace_mem_used(); \ } \ } while (0); \ class LogFileAppender { public: LogFileAppender(); int open(); void close(); int set_identifier(const common::ObString &identifier); int append(const char* buf, int64_t buf_len); private: int check_log_file_full(bool &is_full); int generate_log_file_name(); int open_log_file(); private: static const int64_t MAX_LOG_FILE_SIZE = 256*1024*1024; common::ObArenaAllocator allocator_; common::ObFileAppender log_handle_; common::ObString identifier_; ObSqlString log_file_name_; }; class ObOptimizerTraceImpl { public: ObOptimizerTraceImpl(); ~ObOptimizerTraceImpl(); int enable_trace(const common::ObString &identifier, const common::ObString &sql_id, const int trace_level); int set_parameters(const common::ObString &identifier, const common::ObString &sql_id, const int trace_level); void reset(); int open(); void close(); inline bool enable() const { return enable_; } bool enable(const common::ObString &sql_id); inline void set_enable(bool value) { enable_ = value; } inline bool enable_trace_trans_sql() const { return trace_level_ > 1; } inline bool enable_trace_time_used() const { return trace_level_ > 0; } inline bool enable_trace_mem_used() const { return trace_level_ > 0; } inline void increase_section() { ++section_; } inline void decrease_section() { if (section_ > 0) --section_; } inline void set_session_info(ObSQLSessionInfo* info) { session_info_ = info; } void resume_trace(); void stop_trace(); /***********************************************/ ////print basic type /***********************************************/ int new_line(); int append_lower(const char* msg); int append_ptr(const void *ptr); int append(); int append(const bool &value); int append(const char* msg); int append(const common::ObString &msg); int append(const int64_t &value); int append(const uint64_t &value); int append(const uint32_t &value); int append(const double & value); int append(const ObObj& value); int append(const OpParallelRule& rule); int append(const ObTableLocationType& type); int append(const ObPhyPlanType& type); int append(const OptSystemStat& stat); /***********************************************/ ////print plan info /***********************************************/ int append(const ObLogPlan *log_plan); int append(const ObJoinOrder *join_order); int append(const Path *value); int append(const JoinPath *value); int append(const JoinInfo& info); int append(const TableItem *table); int append(const ObShardingInfo *info); int append(const CandidatePlan &plan); int append(const ObDSResultItem &ds_result); int append(const ObSkylineDim &dim); /***********************************************/ ////print template type /***********************************************/ //for class ObRawExpr template typename std::enable_if::value, int>::type append(const T* expr); //for class ObDMLStmt template typename std::enable_if::value, int>::type append(const T* value); //for ObIArray template typename std::enable_if, T>::value, int>::type append(const T& value); //for ObIArrayWrap template typename std::enable_if, T>::value, int>::type append(const T& value); //for ObIArrayWrap template typename std::enable_if, T>::value, int>::type append(const T& value); //for ObIArray template typename std::enable_if, T>::value, int>::type append(const T& value); //template for function append template int append(const T1& value1, const T2& value2, const ARGS&... args); /***********************************************/ template int append_key_value(const char* key, const ARGS&... args); template int append_title(const ARGS&... args); int trace_env(); int trace_parameters(); int trace_session_info(); int trace_static(const ObDMLStmt *stmt, OptTableMetas &table_metas); int trace_trans_sql(const ObDMLStmt *stmt); int trace_time_used(); int trace_mem_used(); private: common::ObArenaAllocator allocator_; LogFileAppender log_handle_; common::ObString sql_id_; ObSQLSessionInfo *session_info_; int64_t start_time_us_; int64_t last_time_us_; int64_t last_mem_; int section_; int trace_level_; bool enable_; bool trace_state_before_stop_; }; //for class ObRawExpr template typename std::enable_if::value, int>::type ObOptimizerTraceImpl::append(const T* expr) { int ret = OB_SUCCESS; char *buf = NULL; int64_t buf_len = OB_MAX_SQL_LENGTH; int64_t pos = 0; common::ObArenaAllocator allocator("OptimizerTrace"); if (OB_ISNULL(buf = (char*)allocator.alloc(buf_len))) { ret = OB_ERR_UNEXPECTED; //LOG_WARN("failed to alloc buffer", K(ret)); } else if (OB_NOT_NULL(expr)) { // TODO: @zhenling, use a valid schema guard in each query ObRawExprPrinter expr_printer(buf, buf_len, &pos, NULL); const ObRawExpr *raw_expr = static_cast(expr); if (OB_FAIL(expr_printer.do_print(const_cast(raw_expr), T_NONE_SCOPE))) { //LOG_WARN("failed to print expr", K(ret)); } else if (OB_FAIL(log_handle_.append(buf, pos))) { //LOG_WARN("failed to append expr", K(ret)); } } return ret; } //for class ObDMLStmt template typename std::enable_if::value, int>::type ObOptimizerTraceImpl::append(const T* value) { int ret = OB_SUCCESS; ObString sql; ObObjPrintParams print_params; common::ObArenaAllocator allocator("OptimizerTrace"); // TODO: @zhenling, use a valid schema guard in each query if (OB_FAIL(ObSQLUtils::reconstruct_sql(allocator, value, sql, NULL, print_params))) { //LOG_WARN("failed to construct sql", K(ret)); } else if (OB_FAIL(append(sql))) { //LOG_WARN("failed to append sql", K(ret)); } return ret; } //for ObIArray template typename std::enable_if, T>::value, int>::type ObOptimizerTraceImpl::append(const T& value) { int ret = OB_SUCCESS; append("["); for (int i = 0; OB_SUCC(ret) && i < value.count(); ++i) { if (i > 0) { append(", "); } ret = append(value.at(i)); } append("]"); return ret; } //for ObIArray template typename std::enable_if, T>::value, int>::type ObOptimizerTraceImpl::append(const T& value) { int ret = OB_SUCCESS; append("["); for (int i = 0; OB_SUCC(ret) && i < value.count(); ++i) { if (i > 0) { append(", "); } ret = append(value.at(i)); } append("]"); return ret; } //for ObIArray template typename std::enable_if, T>::value, int>::type ObOptimizerTraceImpl::append(const T& value) { int ret = OB_SUCCESS; append("["); for (int i = 0; OB_SUCC(ret) && i < value.count(); ++i) { if (i > 0) { append(", "); } ret = append(value.at(i)); } append("]"); return ret; } //for ObIArray template typename std::enable_if, T>::value, int>::type ObOptimizerTraceImpl::append(const T& value) { int ret = OB_SUCCESS; for (int i = 0; OB_SUCC(ret) && i < value.count(); ++i) { if (OB_FAIL(append(value.at(i)))) { } else if (OB_FAIL(new_line())) { } } return ret; } //template for function append template int ObOptimizerTraceImpl::append(const T1& value1, const T2& value2, const ARGS&... args) { int ret = OB_SUCCESS; if (OB_FAIL(append(value1))) { //LOG_WARN } else if (OB_FAIL(append(" "))) { //LOG_WARN } else if (OB_FAIL(append(value2))) { //LOG_WARN } else if (OB_FAIL(append(" "))) { //LOG_WARN } else if (OB_FAIL(append(args...))) { //LOG_WARN } return ret; } template int ObOptimizerTraceImpl::append_key_value(const char* key, const ARGS&... args) { int ret = OB_SUCCESS; if (OB_FAIL(append(key))) { //LOG_WARN } else if (OB_FAIL(append(":\t"))) { //LOG_WARN } else if (OB_FAIL(append(args...))) { //LOG_WARN } return ret; } template int ObOptimizerTraceImpl::append_title(const ARGS&... args) { int ret = OB_SUCCESS; if (OB_FAIL(new_line())) { //LOG_WARN } else if (OB_FAIL(append(TITLE_LINE))) { //LOG_WARN } else if (OB_FAIL(new_line())) { //LOG_WARN } else if (OB_FAIL(append(args...))) { //LOG_WARN } else if (OB_FAIL(new_line())) { //LOG_WARN } else if (OB_FAIL(append(TITLE_LINE))) { //LOG_WARN } return ret; } } } #endif /* _OB_OPTIMIZER_TRACE_IMPL_H */