[FEAT MERGE]4_1_sql_feature

Co-authored-by: leslieyuchen <leslieyuchen@gmail.com>
Co-authored-by: Charles0429 <xiezhenjiang@gmail.com>
Co-authored-by: raywill <hustos@gmail.com>
This commit is contained in:
obdev
2023-01-28 16:01:26 +08:00
committed by ob-robot
parent 3080f2b66f
commit 2d19a9d8f5
846 changed files with 161957 additions and 116661 deletions

View File

@ -11,7 +11,7 @@
*/
#define USING_LOG_PREFIX SQL_MONITOR
#include "sql/monitor/full_link_trace/ob_flt_control_info_mgr.h"
#include "sql/monitor/flt/ob_flt_control_info_mgr.h"
#include "observer/omt/ob_tenant_config_mgr.h"
#include "sql/session/ob_sql_session_info.h"
using namespace oceanbase::json;

View File

@ -34,16 +34,16 @@ namespace sql
static const char LEVEL[] = "level";
static const char SAM_PCT[] = "sample_pct";
static const char REC_POL[] = "record_policy";
// for record policy
static const char RP_ALL[] = "ALL";
static const char RP_ONLY_SLOW_QUERY[] = "ONLY_SLOW_QUERY";
static const char RP_SAMPLE_AND_SLOW_QUERY[] = "SAMPLE_AND_SLOW_QUERY";
static const char ID_NAME[] = "identifier_name";
static const char MOD_NAME[] = "mod_name";
static const char ACT_NAME[] = "action_name";
class ObIdentifierConInfo {
public:
ObIdentifierConInfo():
@ -53,7 +53,7 @@ namespace sql
FLTControlInfo control_info_;
TO_STRING_KV(K_(identifier_name), K_(control_info));
};
class ObModActConInfo {
public:
ObModActConInfo():

View File

@ -11,9 +11,9 @@
*/
#define USING_LOG_PREFIX LIB_UTIL
#include "sql/monitor/full_link_trace/ob_flt_extra_info.h"
#include "lib/oblog/ob_log_module.h"
#include "share/ob_errno.h"
#include "sql/monitor/flt/ob_flt_extra_info.h"
using namespace oceanbase;
using namespace oceanbase::common;
@ -448,3 +448,40 @@ int FLTQueryInfo::get_serialize_size()
return FLT_HEADER_LEN + FLT_HEADER_LEN + sizeof(int64_t) + FLT_HEADER_LEN + sizeof(int64_t);
}
int FLTShowTrace::serialize(char *buf, const int64_t len, int64_t &pos)
{
int ret = OB_SUCCESS;
// this message is written by proxy, server will do nothing
return ret;
}
int FLTShowTrace::deserialize_field(FullLinkTraceExtraInfoId extra_id, const int64_t v_len,
const char *buf, const int64_t len, int64_t &pos)
{
int ret = OB_SUCCESS;
switch(extra_id) {
case FLT_SHOW_TRACE_SPAN: {
char* ptr = NULL;
if (OB_FAIL(ObProtoTransUtil::get_str(buf, len, pos, v_len, ptr))) {
OB_LOG(WARN,"failed to resolve flt level", K(ret));
} else {
// do nothing
show_trace_span_.assign(ptr, v_len);
}
break;
}
default: {
ret = OB_NOT_SUPPORTED;
OB_LOG(WARN,"invalid extra info id", K(extra_id));
break;
}
}
return ret;
}
int FLTShowTrace::get_serialize_size()
{
// this message is written by proxy, server will do nothing
return 0;
}

View File

@ -42,6 +42,9 @@ FLT_EXTRA_INFO_DEF(FLT_TRACE_ID, 2032, EMySQLFieldType::MYSQL_TYPE_VAR_STRING)
FLT_EXTRA_INFO_DEF(FLT_REF_TYPE, 2033, EMySQLFieldType::MYSQL_TYPE_TINY)
FLT_EXTRA_INFO_DEF(FLT_SPAN_ID, 2034, EMySQLFieldType::MYSQL_TYPE_VAR_STRING)
//FLT_SHOW_TRACE
FLT_EXTRA_INFO_DEF(FLT_SHOW_TRACE_SPAN,2040,EMySQLFieldType::MYSQL_TYPE_VAR_STRING)
FLT_EXTRA_INFO_DEF(FLT_EXTRA_INFO_END, 65535, EMySQLFieldType::MYSQL_TYPE_NOT_DEFINED)
#endif /* FLT_EXTRA_INFO_DEF */
@ -58,7 +61,7 @@ using namespace obmysql;
enum FullLinkTraceExtraInfoId
{
#define FLT_EXTRA_INFO_DEF(extra_id, id, type) extra_id = id,
#include "sql/monitor/full_link_trace/ob_flt_extra_info.h"
#include "sql/monitor/flt/ob_flt_extra_info.h"
#undef FLT_EXTRA_INFO_DEF
};
@ -76,6 +79,7 @@ enum FullLinkTraceExtraInfoType
FLT_TYPE_QUERY_INFO = 2002,
FLT_TYPE_CONTROL_INFO = 2003,
FLT_TYPE_SPAN_INFO = 2004,
FLT_TYPE_SHOW_TRACE = 2005,
FLT_EXTRA_TYPE_END = 65535
};
@ -86,7 +90,7 @@ public:
FullLinkTraceExtraInfoSet()
{
#define FLT_EXTRA_INFO_DEF(extra_id, id, type) set_flt_extra_info(extra_id, type);
#include "sql/monitor/full_link_trace/ob_flt_extra_info.h"
#include "sql/monitor/flt/ob_flt_extra_info.h"
#undef FLT_EXTRA_INFO_DEF
};
@ -289,6 +293,24 @@ class FLTQueryInfo : public FLTExtraInfo
TO_STRING_KV(K_(query_start_time), K_(query_end_time));
};
class FLTShowTrace : public FLTExtraInfo
{
public:
ObString show_trace_span_;
FLTShowTrace() : show_trace_span_() {
type_ = FLT_TYPE_SHOW_TRACE;
}
~FLTShowTrace() {}
// flt_id, len, value ...
int serialize(char *buf, const int64_t len, int64_t &pos);
int deserialize_field(FullLinkTraceExtraInfoId extra_id,
const int64_t v_len, const char *buf,
const int64_t len, int64_t &pos);
int get_serialize_size();
TO_STRING_KV(K_(show_trace_span));
};
}; // end of namespace lib
}; // end of namespace oceanbase

View File

@ -0,0 +1,211 @@
// Copyright 2010-2016 Alibaba Inc. All Rights Reserved.
// Author:
// juehui.lgy@alibaba-inc.com
// Normalizer:
// juehui.lgy@alibaba-inc.com
// this file defines implementation of full link trace span manager
#define USING_LOG_PREFIX SERVER
#include "sql/monitor/flt/ob_flt_span_mgr.h"
#include "share/ob_define.h"
#include "lib/time/ob_time_utility.h"
#include "lib/allocator/ob_malloc.h"
#include "lib/allocator/ob_concurrent_fifo_allocator.h"
#include "lib/allocator/page_arena.h"
#include "lib/stat/ob_session_stat.h"
#include "lib/alloc/alloc_func.h"
#include "lib/thread/thread_mgr.h"
#include "lib/rc/ob_rc.h"
#include "share/rc/ob_context.h"
#include "observer/ob_server.h"
#include "sql/session/ob_basic_session_info.h"
#include "lib/trace/ob_trace.h"
namespace oceanbase
{
using namespace oceanbase::share::schema;
namespace sql
{
ObFLTSpanMgr* get_flt_span_manager() {
return MTL(ObFLTSpanMgr*);
}
int ObFLTSpanMgr::init(uint64_t tenant_id, const int64_t max_mem_size, const int64_t queue_size)
{
int ret = OB_SUCCESS;
if (inited_) {
ret = OB_INIT_TWICE;
} else if (OB_FAIL(queue_.init("SqlFltSpanRec", queue_size, tenant_id))) {
SERVER_LOG(WARN, "Failed to init ObMySQLRequestQueue", K(ret));
} else if (OB_FAIL(TG_CREATE_TENANT(lib::TGDefIDs::ReqMemEvict, tg_id_))) {
SERVER_LOG(WARN, "create failed", K(ret));
} else if (OB_FAIL(TG_START(tg_id_))) {
SERVER_LOG(WARN, "init timer fail", K(ret));
} else if (OB_FAIL(allocator_.init(FLT_SPAN_PAGE_SIZE,
"SqlFltSpanRec",
tenant_id,
INT64_MAX))) {
SERVER_LOG(WARN, "failed to init allocator", K(ret));
} else {
mem_limit_ = max_mem_size;
tenant_id_ = tenant_id;
inited_ = true;
destroyed_ = false;
}
if ((OB_FAIL(ret)) && (!inited_)) {
destroy();
}
return ret;
}
void ObFLTSpanMgr::destroy()
{
if (!destroyed_) {
TG_DESTROY(tg_id_);
clear_queue();
queue_.destroy();
allocator_.destroy();
inited_ = false;
destroyed_ = true;
}
}
int ObFLTSpanMgr::mtl_init(ObFLTSpanMgr* &span_mgr)
{
int ret = OB_SUCCESS;
span_mgr = OB_NEW(ObFLTSpanMgr, "SqlFltSpanRec");
if (nullptr == span_mgr) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc memory for ObMySQLRequestManager", K(ret));
} else {
uint64_t tenant_id = lib::current_resource_owner_id();
int64_t mem_limit = lib::get_tenant_memory_limit(tenant_id);
int64_t queue_size = MAX_QUEUE_SIZE;
if (OB_FAIL(span_mgr->init(tenant_id, mem_limit, queue_size))) {
LOG_WARN("failed to init request manager", K(ret));
} else {
// do nothing
}
}
if (OB_FAIL(ret) && span_mgr != nullptr) {
// cleanup
common::ob_delete(span_mgr);
span_mgr = nullptr;
}
return ret;
}
void ObFLTSpanMgr::mtl_destroy(ObFLTSpanMgr* &span_mgr)
{
common::ob_delete(span_mgr);
span_mgr = nullptr;
}
int ObFLTSpanMgr::record_span(ObFLTSpanData &span_data)
{
int ret = OB_SUCCESS;
if (!inited_) {
ret = OB_NOT_INIT;
} else {
ObFLTSpanRec *rec = NULL;
char *buf = NULL;
//alloc mem from allocator
int64_t pos = sizeof(ObFLTSpanRec);
int64_t total_sz = sizeof(ObFLTSpanRec)
+ min(span_data.trace_id_.length(), OB_MAX_SPAN_LENGTH)
+ min(span_data.span_id_.length(), OB_MAX_SPAN_LENGTH)
+ min(span_data.parent_span_id_.length(), OB_MAX_SPAN_LENGTH)
+ min(span_data.span_name_.length(), OB_MAX_SPAN_LENGTH)
+ min(span_data.tags_.length(), OB_MAX_SPAN_TAG_LENGTH)
+ min(span_data.logs_.length(), OB_MAX_SPAN_TAG_LENGTH);
if (NULL == (buf = (char*)allocator_.alloc(total_sz))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
if (REACH_TIME_INTERVAL(100 * 1000)) {
SERVER_LOG(WARN, "record concurrent fifoallocator alloc mem failed", K(sizeof(ObFLTSpanRec)), K(ret));
}
} else {
rec = new(buf)ObFLTSpanRec();
rec->allocator_ = &allocator_;
rec->data_ = span_data;
//deep copy trace id
if (!span_data.trace_id_.empty()) {
const int len = min(span_data.trace_id_.length(), OB_MAX_SPAN_LENGTH);
MEMCPY(buf + pos, span_data.trace_id_.ptr(), len);
rec->data_.trace_id_.assign_ptr(buf + pos, len);
pos += len;
}
//deep copy span id
if (!span_data.span_id_.empty()) {
const int len = min(span_data.span_id_.length(), OB_MAX_SPAN_LENGTH);
MEMCPY(buf + pos, span_data.span_id_.ptr(), len);
rec->data_.span_id_.assign_ptr(buf + pos, len);
pos += len;
}
//deep copy parent span id
if (!span_data.parent_span_id_.empty()) {
const int len = min(span_data.parent_span_id_.length(), OB_MAX_SPAN_LENGTH);
MEMCPY(buf + pos, span_data.parent_span_id_.ptr(), len);
rec->data_.parent_span_id_.assign_ptr(buf + pos, len);
pos += len;
}
//deep copy span name
if (!span_data.span_name_.empty()) {
const int len = min(span_data.span_name_.length(), OB_MAX_SPAN_LENGTH);
MEMCPY(buf + pos, span_data.span_name_.ptr(), len);
rec->data_.span_name_.assign_ptr(buf + pos, len);
pos += len;
}
//deep copy tags
if (!span_data.tags_.empty()) {
const int len = min(span_data.tags_.length(), OB_MAX_SPAN_TAG_LENGTH);
MEMCPY(buf + pos, span_data.tags_.ptr(), len);
rec->data_.tags_.assign_ptr(buf + pos, len);
pos += len;
}
//deep copy logs_
if (!span_data.logs_.empty()) {
const int len = min(span_data.logs_.length(), OB_MAX_SPAN_TAG_LENGTH);
MEMCPY(buf + pos, span_data.logs_.ptr(), len);
rec->data_.logs_.assign_ptr(buf + pos, len);
pos += len;
}
//push into queue
if (OB_SUCC(ret)) {
int64_t req_id = 0;
if (OB_FAIL(queue_.push(rec, req_id))) {
//sql audit槽位已满时会push失败, 依赖后台线程进行淘汰获得可用槽位
if (REACH_TIME_INTERVAL(2 * 1000 * 1000)) {
SERVER_LOG(WARN, "push into queue failed", K(ret));
}
if (ret == OB_ENTRY_NOT_EXIST) {
release_old(RELEASE_QUEUE_SIZE);
}
allocator_.free(rec);
rec = NULL;
} else {
rec->data_.req_id_ = req_id;
}
} else {
allocator_.free(rec);
rec = NULL;
}
}
} // end
return ret;
}
// evict old span and release memory
int ObFLTSpanMgr::release_old(int64_t limit)
{
void* span = NULL;
int64_t count = 0;
while(count++ < limit && NULL != (span = queue_.pop())) {
free(span);
}
return common::OB_SUCCESS;
}
} // end of namespace obmysql
} // end of namespace oceanbase

View File

@ -0,0 +1,232 @@
/**
* (C) Copyright 2014 Alibaba Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* Version:
*
* Date: 05/12/2022
*
* Authors:
* guoyun.lgy<guoyun.lgy@alibaba-inc.com>
*/
#ifndef OCEANBASE_SQL_OB_FLT_SPAN_MGR_H_
#define OCEANBASE_SQL_OB_FLT_SPAN_MGR_H_
#include "share/ob_define.h"
#include "lib/string/ob_string.h"
#include "lib/atomic/ob_atomic.h"
#include "lib/stat/ob_diagnose_info.h"
//#include "observer/mysql/ob_mysql_result_set.h"
#include "share/config/ob_server_config.h"
#include "share/schema/ob_schema_getter_guard.h"
//#include "sql/session/ob_sql_session_info.h"
#include "sql/ob_sql_define.h"
//#include "sql/ob_result_set.h"
#include "observer/mysql/ob_eliminate_task.h"
#include "observer/mysql/ob_ra_queue.h"
using namespace oceanbase::common;
namespace oceanbase
{
namespace sql
{
static const char TRACE_ID[] = "trace_id";
static const char SPAN_ID[] = "id";
static const char SPAN_NAME[] = "name";
static const char REF_TYPE[] = "is_follow";
static const char START_TS[] = "start_ts";
static const char END_TS[] = "end_ts";
static const char PARENT_SPAN_ID[] = "parent_id";
class ObFLTSpanData {
public:
int64_t tenant_id_;
ObString trace_id_;
int64_t req_id_;
ObString span_id_;
ObString parent_span_id_;
ObString span_name_;
int64_t ref_type_;
int64_t start_ts_;
int64_t end_ts_;
ObString tags_;
ObString logs_;
ObFLTSpanData()
{
reset();
}
~ObFLTSpanData()
{
}
void reset()
{
tenant_id_ = OB_INVALID_TENANT_ID;
req_id_ = OB_INVALID_ID;
ref_type_ = -1;
start_ts_ = -1;
end_ts_ = -1;
trace_id_.reset();
span_id_.reset();
parent_span_id_.reset();
span_name_.reset();
tags_.reset();
logs_.reset();
}
int64_t get_extra_size() const
{
return trace_id_.length() + span_id_.length() + parent_span_id_.length()
+ span_name_.length() + tags_.length() + logs_.length();
}
TO_STRING_KV(K_(tenant_id), K_(trace_id),
K_(req_id), K_(span_id),
K_(parent_span_id), K_(span_name),
K_(start_ts), K_(end_ts),
K_(tags), K_(logs));
};
class ObFLTShowTraceRec {
public:
/* format trace name and display */
struct trace_formatter
{
enum class LineType
{
LT_SPACE, // " "
LT_LINE, // "│"
LT_NODE, // "├"
LT_LAST_NODE, // "└"
};
struct TreeLine
{
TreeLine() : color_idx_(0), line_type_(LineType::LT_SPACE) {}
int32_t color_idx_;
LineType line_type_;
};
struct NameLeftPadding
{
NameLeftPadding() : level_(0), tree_line_(NULL)
{
}
TO_STRING_KV(K_(level), KP_(tree_line));
int64_t level_;
TreeLine *tree_line_;
};
};
public:
trace_formatter::NameLeftPadding formatter_;
sql::ObFLTSpanData data_;
ObString ipstr_;
int64_t port_;
public:
ObFLTShowTraceRec() : port_(-1) {}
~ObFLTShowTraceRec() {}
TO_STRING_KV(K_(formatter), K_(data), K_(port), K_(ipstr));
};
class ObFLTSpanRec {
public:
common::ObConcurrentFIFOAllocator *allocator_;
sql::ObFLTSpanData data_;
public:
ObFLTSpanRec()
: allocator_(nullptr) {}
~ObFLTSpanRec() {}
public:
virtual void destroy()
{
if (NULL != allocator_) {
allocator_->free(this);
}
}
public:
int64_t get_self_size() const
{
return sizeof(ObFLTSpanData) + data_.get_extra_size();
}
};
class ObFLTSpanMgr {
public:
static const int64_t FLT_SPAN_PAGE_SIZE = (1LL << 21) - ACHUNK_PRESERVE_SIZE; // 2M - 17k
static const int32_t BATCH_RELEASE_COUNT = 1000;
//初始化queue大小为1000w
static const int64_t MAX_QUEUE_SIZE = 100000; //10m
static const int64_t RELEASE_QUEUE_SIZE = 10000; //1w
ObFLTSpanMgr()
: inited_(false), destroyed_(false), request_id_(0), mem_limit_(0),
allocator_(), queue_(),
tenant_id_(OB_INVALID_TENANT_ID), tg_id_(-1)
{
}
~ObFLTSpanMgr()
{
if (inited_) {
destroy();
}
}
int64_t get_start_idx() const { return (int64_t)queue_.get_pop_idx(); }
int64_t get_end_idx() const { return (int64_t)queue_.get_push_idx(); }
int get_tenant_id() { return tenant_id_; }
int init(uint64_t tenant_id, const int64_t max_mem_size, const int64_t queue_size);
int record_span(ObFLTSpanData &span_data);
int release_old(int64_t limit = BATCH_RELEASE_COUNT); // evict old span and release memory
void destroy();
static int mtl_init(ObFLTSpanMgr* &span_mgr);
static void mtl_destroy(ObFLTSpanMgr* &span_mgr);
void clear_queue()
{
(void)release_old(INT64_MAX);
}
int get(const int64_t idx, void *&record, ObRaQueue::Ref* ref)
{
int ret = OB_SUCCESS;
if (NULL == (record = queue_.get(idx, ref))) {
ret = OB_ENTRY_NOT_EXIST;
}
return ret;
}
int revert(ObRaQueue::Ref* ref)
{
queue_.revert(ref);
return common::OB_SUCCESS;
}
void free(void *ptr) { allocator_.free(ptr); ptr = NULL;}
private:
DISALLOW_COPY_AND_ASSIGN(ObFLTSpanMgr);
private:
bool inited_;
bool destroyed_;
uint64_t request_id_;
int64_t mem_limit_;
common::ObConcurrentFIFOAllocator allocator_; //alloc mem for span info
common::ObRaQueue queue_; // store span node
//ObEliminateTask task_;
// tenant id of this request manager
uint64_t tenant_id_;
int tg_id_;
};
} // namespace sql
} // namespace oceanbase
#endif

View File

@ -0,0 +1,571 @@
// Copyright 2010-2016 Alibaba Inc. All Rights Reserved.
// Author:
// juehui.lgy@alibaba-inc.com
// Normalizer:
// juehui.lgy@alibaba-inc.com
// this file defines implementation of full link trace span manager
#define USING_LOG_PREFIX SERVER
#include "sql/monitor/flt/ob_flt_utils.h"
#include "share/ob_define.h"
#include "sql/session/ob_basic_session_info.h"
#include "lib/trace/ob_trace.h"
#include "lib/trace/ob_trace_def.h"
#include "sql/monitor/flt/ob_flt_extra_info.h"
#include "sql/monitor/flt/ob_flt_control_info_mgr.h"
#include "sql/session/ob_sql_session_info.h"
namespace oceanbase
{
namespace sql
{
int ObFLTUtils::init_flt_show_trace_env(sql::ObSQLSessionInfo &session) {
int ret = OB_SUCCESS;
// if use trace log, init trace framework
if (session.is_inner()) {
// inner sql will reuse trace framework, do nothing
} else {
if (session.is_use_trace_log()) {
// query level trace
if (session.is_query_trc_granuality()) {
FLT_BEGIN_TRACE();
FLT_SET_TRACE_LEVEL(1);
FLT_SET_AUTO_FLUSH(true);
// transaction level trace
} else {
if (session.is_server_status_in_transaction()) {
// do nothing
} else {
FLT_BEGIN_TRACE();
FLT_SET_TRACE_LEVEL(1);
FLT_SET_AUTO_FLUSH(true);
}
}
} else {
FLT_SET_TRACE_LEVEL(0);
FLT_SET_AUTO_FLUSH(false);
}
}
return ret;
}
int ObFLTUtils::record_flt_last_trace_id(sql::ObSQLSessionInfo &session) {
int ret = OB_SUCCESS;
trace::UUID trc_uuid = OBTRACE->get_trace_id();
char last_trace_id[OB_MAX_UUID_STR_LENGTH + 1];
int64_t pos = 0;
trc_uuid.tostring(last_trace_id, OB_MAX_UUID_STR_LENGTH + 1, pos);
if (last_trace_id[0] == '\0') {
// do nothing
} else if (OB_FAIL(session.set_last_flt_trace_id(ObString(OB_MAX_UUID_STR_LENGTH + 1, last_trace_id)))) {
LOG_WARN("failed to set last flt trace id", K(ret), K(ObString(OB_MAX_UUID_STR_LENGTH + 1, last_trace_id)));
} else {
// do nothing
}
return ret;
}
void ObFLTUtils::clean_flt_env(sql::ObSQLSessionInfo &session) {
if (session.is_query_trc_granuality()) {
FLT_END_TRACE();
} else {
if (session.get_in_transaction()) {
// do nothing
} else {
FLT_END_TRACE();
}
}
}
int ObFLTUtils::clean_flt_show_trace_env(sql::ObSQLSessionInfo &session) {
int ret = OB_SUCCESS;
if (session.is_query_trc_granuality()) {
// record current trace id
if (OB_FAIL(record_flt_last_trace_id(session))) {
LOG_WARN("failed to record last flt trace id", K(ret));
} else {
// do nothing
}
// transaction level show trace
} else {
if (session.get_in_transaction()) {
// do nothing
} else {
// record current trace id
if (OB_FAIL(record_flt_last_trace_id(session))) {
LOG_WARN("failed to record last flt trace id", K(ret));
} else {
// do nothing
}
}
}
return ret;
}
int ObFLTUtils::init_flt_info(Ob20ExtraInfo extra_info,
sql::ObSQLSessionInfo &session,
bool is_client_support_flt)
{
int ret = OB_SUCCESS;
if (extra_info.exist_full_link_trace()) {
OZ(process_flt_extra_info(extra_info.get_full_link_trace().ptr(),
extra_info.get_full_link_trace().length(),
session));
extra_info.get_full_link_trace().reset();
}
if (session.get_control_info().is_valid()){
OZ(init_flt_log_framework(session, is_client_support_flt));
} else {
FLT_SET_TRACE_LEVEL(0);
FLT_SET_AUTO_FLUSH(false);
session.set_auto_flush_trace(false);
session.set_trace_enable(false);
}
OZ(ObFLTUtils::init_flt_show_trace_env(session));
return ret;
}
int ObFLTUtils::append_flt_extra_info(common::ObIAllocator &allocator,
ObIArray<obmysql::ObObjKV> *extra_info,
ObIArray<obmysql::Obp20Encoder*> *extra_info_ecds,
sql::ObSQLSessionInfo &sess,
bool is_new_extra_info)
{
int ret = OB_SUCCESS;
char *buf = NULL;
int size = 0;
FLTQueryInfo query_info;
// reserver memory for control info
// if sys config in control info and sys parameter has modified, resend this control info.
if (sess.get_control_info().is_valid_sys_config()
&& !((sess.get_control_info().print_sample_pct_ == ((double)(sess.get_tenant_print_sample_ppm()))/1000000)
&& (sess.get_control_info().slow_query_thres_ == GCONF.trace_log_slow_query_watermark))) {
sess.set_send_control_info(false);
}
if (!sess.is_send_control_info()) {
size += sess.get_control_info().get_serialize_size();
}
// reserver memmory for query info
if (sess.is_trace_enable()) {
query_info.query_start_time_ = sess.get_query_start_time();
query_info.query_end_time_ = ::oceanbase::common::ObTimeUtility::current_time();
size += query_info.get_serialize_size();
}
if (size == 0){
// has not flt extra info, do nothing
} else if (OB_UNLIKELY(size < 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Invalid buffer length", K(ret), K(size));
} else if (NULL == (buf = static_cast<char *>(allocator.alloc(size)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("fail to alloc mem", K(size), K(ret));
} else {
int64_t pos = 0;
// assamble control info
if (!sess.is_send_control_info()) {
FLTControlInfo con = sess.get_control_info();
if (!con.is_valid()) {
con.reset();
}
con.print_sample_pct_ = ((double)(sess.get_tenant_print_sample_ppm()))/1000000;
con.slow_query_thres_ = GCONF.trace_log_slow_query_watermark;
sess.set_flt_control_info(con);
if (OB_FAIL(con.serialize(buf, size, pos))) {
LOG_WARN("failed to serialize control info", K(pos), K(size));
} else {
sess.set_send_control_info(true);
}
}
// assamble query info
if (OB_FAIL(ret)) {
// do nothing
} else if (sess.is_trace_enable()) {
if (OB_FAIL(query_info.serialize(buf, size, pos))) {
LOG_WARN("failed to serialize query info", K(pos), K(size));
} else {
sess.set_trace_enable(false);
}
}
}
// set session info to extra info
if (OB_FAIL(ret)) {
// do nothing
} else if (size == 0) {
// nothing to write, do nothing
} else if (is_new_extra_info) {
Obp20FullTrcEncoder* full_trc_ecd = NULL;
void* ecd_buf = NULL;
if (OB_ISNULL(ecd_buf = allocator.alloc(sizeof(Obp20FullTrcEncoder)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate memory.", K(ret));
} else {
full_trc_ecd = new(ecd_buf)Obp20FullTrcEncoder();
full_trc_ecd->full_trc_.assign(buf, size);
if (OB_FAIL(extra_info_ecds->push_back(full_trc_ecd))) {
LOG_WARN("failed to add extra info kv", K(full_trc_ecd), K(ret));
}
}
} else {
ObObjKV kv;
common::ObObj key;
common::ObObj value;
ObString key_str = "full_trc";
key.set_varchar(key_str);
value.set_varchar(ObString(size, buf));
kv.key_ = key;
kv.value_ = value;
if (OB_FAIL(extra_info->push_back(kv))) {
LOG_WARN("failed to add extra info kv", K(kv), K(ret));
}
}
return ret;
}
int ObFLTUtils::process_flt_extra_info(const char *buf,
const int64_t len, sql::ObSQLSessionInfo &sess)
{
int ret = OB_SUCCESS;
int64_t pos = 0;
LOG_TRACE("recieve flt extra info", KP(buf), K(len), KPHEX(buf, len));
while (OB_SUCC(ret) && pos < len) {
FullLinkTraceExtraInfoType extra_type;
int32_t v_len = 0;
LOG_TRACE("process single flt extra info", KP(buf), K(pos), K(len), KPHEX(buf+pos, len-pos));
if (OB_FAIL(FLTExtraInfo::resolve_type_and_len(buf, len, pos, extra_type, v_len))) {
LOG_WARN("failed to resolve type and len", K(len), K(pos));
} else if (pos+v_len > len) {
ret = OB_SIZE_OVERFLOW;
LOG_WARN("buf size overflow", K(ret), K(pos), K(v_len), K(len));
} else {
switch (extra_type) {
// for drv types:
case FLT_TYPE_DRV_LOG: {
FLTDrvSpan drv_span;
if (OB_FAIL(drv_span.deserialize(buf, pos+v_len, pos))) {
LOG_WARN("failed to deserialize full link trace extra info",
KP(buf), K(ret), K(pos), K(v_len));
} else {
_OBTRACE_LOG(INFO, "%s", drv_span.span_info_.ptr());
}
break;
}
// for proxy types:
// for public types:
case FLT_TYPE_APP_INFO: {
// do nothing
FLTAppInfo app_info;
FLTControlInfo con;
ObFLTControlInfoManager mgr(sess.get_effective_tenant_id());
if (OB_FAIL(app_info.deserialize(buf, pos+v_len, pos))) {
LOG_WARN("failed to deserialize full link trace extra info",
KP(buf), K(ret), K(pos), K(v_len));
} else if (OB_FAIL(mgr.init())) {
LOG_WARN("failed to init full link trace info manager", K(ret));
} else {
if (app_info.trace_client_info_.empty()) {
// do nothing
} else if (OB_FAIL(sess.get_app_info_encoder()
.set_client_info(&sess, app_info.trace_client_info_))) {
LOG_WARN("failed to set client info name", K(ret));
}
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_FAIL(init_app_info(sess, app_info))) {
LOG_WARN("failed to init app info from session", K(ret));
} else if (OB_FAIL(mgr.find_appropriate_con_info(sess))) {
LOG_WARN("failed to find appropriate control info", K(ret));
} else {
// do nothing
}
}
break;
}
case FLT_TYPE_QUERY_INFO: {
// this extra info is written by server, and driver/proxy cannot send this to server;
ret = OB_NOT_SUPPORTED;
LOG_WARN("invalid extra_type", K(extra_type), K(ret));
break;
}
case FLT_TYPE_CONTROL_INFO: {
// this extra info is written by server, and driver/proxy cannot send this to server;
ret = OB_NOT_SUPPORTED;
LOG_WARN("invalid extra_type", K(extra_type), K(ret));
break;
}
case FLT_TYPE_SPAN_INFO: {
FLTSpanInfo span_info;
if (OB_FAIL(span_info.deserialize(buf, pos+v_len, pos))) {
LOG_WARN("failed to deserialize full link trace extra info",
KP(buf), K(ret), K(pos), K(v_len));
} else if (span_info.trace_enable_) {
if (OB_FAIL(sess.set_flt_trace_id(span_info.trace_id_))) {
LOG_WARN("failed to set trace id", K(ret));
} else if (OB_FAIL(sess.set_flt_span_id(span_info.span_id_))) {
LOG_WARN("failed to set span id", K(ret));
} else {
sess.set_trace_enable(span_info.trace_enable_);
sess.set_auto_flush_trace(span_info.force_print_);
}
}
break;
}
case FLT_TYPE_SHOW_TRACE: {
FLTShowTrace trace;
if (OB_FAIL(trace.deserialize(buf, pos+v_len, pos))) {
LOG_WARN("failed to deserialize full link trace extra info", KP(buf), K(ret), K(pos), K(v_len));
} else {
// add to span
}
break;
}
default: {
ret = OB_NOT_SUPPORTED;
LOG_WARN("invalid extra_type", K(extra_type), K(ret));
break;
}
} // switch ends
}
} // while ends
return ret;
}
int ObFLTUtils::init_flt_log_framework(sql::ObSQLSessionInfo &sess, bool is_client_support_flt)
{
// initialize log framework
int ret = OB_SUCCESS;
FLT_RESET_SPAN();
if (sess.is_query_trc_granuality()) {
// reset trace_enable and flush trace in transcation granularity
// init flush trace and trace enable
if (!is_client_support_flt) {
// reset log config
sess.set_trace_enable(false);
sess.set_auto_flush_trace(false);
OZ(update_flush_policy_by_control_info(sess));
} else {
//set by client
}
} else {
if (sess.is_server_status_in_transaction()) {
// in the trans, do nothing
} else {
// reset trace_enable and flush trace in transcation granularity
// init flush trace and trace enable
if (!is_client_support_flt) {
// reset log config
sess.set_trace_enable(false);
sess.set_auto_flush_trace(false);
OZ(update_flush_policy_by_control_info(sess));
} else {
//set by client
}
}
}
// init log frame
if (OB_FAIL(ret)) {
// do nothing
} else if (!sess.get_control_info().is_valid() || !sess.is_trace_enable()) {
FLT_SET_TRACE_LEVEL(0);
FLT_SET_AUTO_FLUSH(false);
sess.set_auto_flush_trace(false);
sess.set_trace_enable(false);
} else if (is_client_support_flt) {
trace::UUID tid, sid;
int64_t pos = 0;
ObString span_id;
ObString trace_id;
sess.get_flt_span_id(span_id);
sess.get_flt_trace_id(trace_id);
if (span_id.empty() || trace_id.empty()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid span_id or trace_id", K(span_id), K(trace_id), K(ret));
} else {
tid.deserialize(trace_id.ptr(), trace_id.length(), pos);
pos = 0;
sid.deserialize(span_id.ptr(), span_id.length(), pos);
OBTRACE->init(tid, sid);
FLT_SET_TRACE_LEVEL(sess.get_control_info().level_);
FLT_SET_AUTO_FLUSH(sess.is_auto_flush_trace());
}
// update trace_id by server self
} else {
// update trace_id in query granularity
if (sess.is_query_trc_granuality()) {
FLT_BEGIN_TRACE();
} else {
// update trace_id in transaction granularity
if (!sess.get_in_transaction()) {
// begin new trace
FLT_BEGIN_TRACE();
} else {
// do nothing
}
}
FLT_SET_TRACE_LEVEL(sess.get_control_info().level_);
FLT_SET_AUTO_FLUSH(sess.is_auto_flush_trace());
}
LOG_TRACE("flt init log", K(sess.is_trace_enable()),
K(sess.is_auto_flush_trace()), K(sess.get_control_info()));
return ret;
}
int ObFLTUtils::update_flush_policy_by_control_info(sql::ObSQLSessionInfo &sess)
{
int ret = OB_SUCCESS;
FLTControlInfo con = sess.get_control_info();
if (con.is_valid()) {
// init trace enable
con.print_sample_pct_ = ((double)(sess.get_tenant_print_sample_ppm()))/1000000;
ObRandom r;
double rand_num = 1.0 * (r.rand(0, RAND_MAX)/RAND_MAX);
if (rand_num < con.sample_pct_) {
sess.set_trace_enable(true);
} else {
sess.set_trace_enable(false);
}
// init flush trace
if (con.rp_ == FLTControlInfo::RecordPolicy::RP_ALL) {
if (sess.is_trace_enable()) {
sess.set_auto_flush_trace(true);
} else {
sess.set_auto_flush_trace(false);
}
} else if (con.rp_ == FLTControlInfo::RecordPolicy::RP_ONLY_SLOW_QUERY) {
// do nothing, slow query will must flush
} else if (con.rp_ == FLTControlInfo::RecordPolicy::RP_SAMPLE_AND_SLOW_QUERY) {
double rand_num2 = 1.0 * (r.rand(0, RAND_MAX)/RAND_MAX);
if (rand_num2 < con.print_sample_pct_) {
sess.set_auto_flush_trace(true);
} else {
sess.set_auto_flush_trace(false);
}
}
} else {
// invalid control info, do nothing
}
return ret;
}
int ObFLTUtils::init_app_info(sql::ObSQLSessionInfo &sess, FLTAppInfo &app_info)
{
int ret = OB_SUCCESS;
if (!app_info.trace_module_.empty() &&
OB_FAIL(sess.get_app_info_encoder().
set_module_name(&sess, app_info.trace_module_))) {
LOG_WARN("failed to set mod name", K(ret));
} else if (!app_info.trace_action_.empty() &&
OB_FAIL(sess.get_app_info_encoder().
set_action_name(&sess, app_info.trace_action_))) {
LOG_WARN("failed to set action name", K(ret));
} else if (!app_info.trace_client_identifier_.empty() &&
OB_FAIL(sess.set_client_id(app_info.trace_client_identifier_))) {
LOG_WARN("failed to set client id", K(ret));
} else {
// do nothing
}
return ret;
}
int handle_span_record(ObFLTSpanMgr *flt_span_manager, char* tag_buf, int64_t tag_len, ::oceanbase::trace::ObSpanCtx* span)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(flt_span_manager)) {
// failed to get flt span manager, maybe tenant has been dropped, NOT NEED TO record;
} else {
ObFLTSpanData data;
ObArenaAllocator allocator;
const int64_t len = MAX_TRACE_LOG_SIZE;
char *buf = NULL;
int64_t pos = 0;
int64_t org_pos = 0;
if (NULL == (buf = (char*)allocator.alloc(len))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
if (REACH_TIME_INTERVAL(100 * 1000)) {
SERVER_LOG(WARN, "record concurrent fifoallocator alloc mem failed", K(len), K(ret));
}
} else {
data.tenant_id_ = flt_span_manager->get_tenant_id();
// trace id
org_pos = pos;
if (OB_FAIL(OBTRACE->get_trace_id().tostring(buf, len, pos))) {
LOG_WARN ("failed to deserialize uuid", K(ret), K(buf), K(pos));
} else {
data.trace_id_.assign(buf+org_pos, pos - org_pos);
}
// span id
org_pos = pos;
if (OB_FAIL(span->span_id_.tostring(buf, len, pos))) {
LOG_WARN ("failed to deserialize uuid", K(ret), K(buf), K(pos));
} else {
data.span_id_.assign(buf+org_pos, pos - org_pos);
}
// span name
data.span_name_.assign(const_cast<char *>(trace::__span_type_mapper[span->span_type_]),
strlen(trace::__span_type_mapper[span->span_type_]));
//parent_span_id_
org_pos = pos;
if (OB_ISNULL(span->source_span_) &&
OB_FAIL(OBTRACE->get_root_span_id().tostring(buf, len, pos))) {
LOG_WARN ("failed to deserialize uuid", K(ret), K(buf), K(pos));
} else if (!OB_ISNULL(span->source_span_) &&
OB_FAIL(span->source_span_->span_id_.tostring(buf, len, pos))){
LOG_WARN ("failed to deserialize uuid", K(ret), K(buf), K(pos));
} else {
data.parent_span_id_.assign(buf+org_pos, pos - org_pos);
}
//data.parent_span_id_ = buf+org_pos;
//data.parent_span_id_ = buf+org_pos;
if (OB_NOT_NULL(tag_buf) && tag_len != 0) {
//skip "tags":[ and trim ]
data.tags_.assign(tag_buf+sizeof("\"tags\":["), tag_len-sizeof("\"tags\":[")-2);
//data.tags_.assign(tag_buf, tag_len);
}
// start ts
data.start_ts_ = span->start_ts_;
// end_ts
data.end_ts_ = span->end_ts_;
// is_follow
data.ref_type_ = span->is_follow_;
}
// record span
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_FAIL(flt_span_manager->record_span(data))) {
if (OB_SIZE_OVERFLOW == ret || OB_ALLOCATE_MEMORY_FAILED == ret) {
LOG_TRACE("cannot allocate mem for record", K(ret));
ret = OB_SUCCESS;
} else {
if (REACH_TIME_INTERVAL(100 * 1000)) { // in case logging is too frequent
LOG_WARN("failed to record request info in request manager", K(ret));
}
}
}
}
return ret;
}
} // end of namespace sql
} // end of namespace oceanbase

View File

@ -0,0 +1,80 @@
/**
* (C) Copyright 2014 Alibaba Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* Version:
*
* Date: 05/12/2022
*
* Authors:
* guoyun.lgy<guoyun.lgy@alibaba-inc.com>
*/
#ifndef OCEANBASE_SQL_OB_FLT_UTILS_H_
#define OCEANBASE_SQL_OB_FLT_UTILS_H_
#include "share/ob_define.h"
#include "lib/string/ob_string.h"
#include "lib/atomic/ob_atomic.h"
#include "lib/stat/ob_diagnose_info.h"
#include "share/config/ob_server_config.h"
#include "share/schema/ob_schema_getter_guard.h"
#include "rpc/obmysql/obp20_extra_info.h"
#include "rpc/obmysql/ob_2_0_protocol_utils.h"
#include "sql/ob_sql_define.h"
#include "sql/monitor/flt/ob_flt_extra_info.h"
namespace oceanbase
{
namespace sql
{
class ObFLTVars {
public:
ObFLTVars() : row_traceformat_(true),
trc_granuality_(ObTraceGranularity::TRANS_LEVEL)
{
flt_trace_id_[0] = '\0';
flt_span_id_[0] = '\0';
last_flt_trace_id_buf_[0] = '\0';
}
void reset() {
flt_trace_id_[0] = '\0';
flt_span_id_[0] = '\0';
last_flt_trace_id_buf_[0] = '\0';
last_flt_trace_id_.reset();
row_traceformat_ = true;
trc_granuality_ = ObTraceGranularity::TRANS_LEVEL;
}
public:
char flt_trace_id_[common::OB_MAX_UUID_LENGTH + 1];
char flt_span_id_[common::OB_MAX_UUID_LENGTH + 1];
ObString last_flt_trace_id_;
char last_flt_trace_id_buf_[OB_MAX_UUID_STR_LENGTH + 1];
bool row_traceformat_;
ObTraceGranularity trc_granuality_;
};
class ObFLTUtils {
public:
static int init_flt_info(obmysql::Ob20ExtraInfo extra_info,
sql::ObSQLSessionInfo &session,
bool is_client_support_flt);
static int append_flt_extra_info(common::ObIAllocator &allocator,
ObIArray<obmysql::ObObjKV> *extra_info,
ObIArray<obmysql::Obp20Encoder*> *extra_info_ecds,
sql::ObSQLSessionInfo &sess,
bool is_new_extra_info);
static int process_flt_extra_info(const char *buf, const int64_t len, sql::ObSQLSessionInfo &sess);
static int init_app_info(sql::ObSQLSessionInfo &sess, sql::FLTAppInfo &app_info);
static int init_flt_log_framework(sql::ObSQLSessionInfo &session, bool is_client_support_flt);
static int update_flush_policy_by_control_info(sql::ObSQLSessionInfo &sess);
static int init_flt_show_trace_env(sql::ObSQLSessionInfo &session);
static int record_flt_last_trace_id(sql::ObSQLSessionInfo &session);
static int clean_flt_show_trace_env(sql::ObSQLSessionInfo &session);
static void clean_flt_env(sql::ObSQLSessionInfo &session);
};
} // namespace sql
} // namespace oceanbase
#endif

View File

@ -0,0 +1,522 @@
// Copyright 2010-2016 Alibaba Inc. All Rights Reserved.
// Author:
// zhenling.zzg
// this file defines implementation of plan real info manager
#define USING_LOG_PREFIX SQL
#include "share/diagnosis/ob_sql_plan_monitor_node_list.h"
#include "lib/allocator/ob_concurrent_fifo_allocator.h"
#include "lib/compress/zlib/zlib_src/zlib.h"
#include "sql/session/ob_sql_session_info.h"
#include "lib/thread/thread_mgr.h"
#include "common/object/ob_object.h"
#include "ob_plan_real_info_manager.h"
#include "lib/ob_running_mode.h"
#include "util/easy_time.h"
#include "lib/rc/ob_rc.h"
namespace oceanbase
{
namespace sql
{
ObPlanRealInfo::ObPlanRealInfo()
{
reset();
}
ObPlanRealInfo::~ObPlanRealInfo()
{
}
void ObPlanRealInfo::reset()
{
plan_id_ = 0;
sql_id_ = NULL;
sql_id_len_ = 0;
plan_hash_ = 0;
id_ = 0;
real_cost_ = 0;
real_cardinality_ = 0;
cpu_cost_ = 0;
io_cost_ = 0;
}
int64_t ObPlanRealInfo::get_extra_size() const
{
return sql_id_len_;
}
ObPlanRealInfoRecord::ObPlanRealInfoRecord()
:allocator_(NULL)
{
}
ObPlanRealInfoRecord::~ObPlanRealInfoRecord()
{
destroy();
}
void ObPlanRealInfoRecord::destroy()
{
if (NULL != allocator_) {
allocator_->free(this);
}
}
ObPlanRealInfoMgr::ObPlanRealInfoMgr()
:allocator_(),
task_(),
queue_(),
destroyed_(false),
inited_(false),
tenant_id_(OB_INVALID_TENANT_ID),
tg_id_(-1)
{
}
ObPlanRealInfoMgr::~ObPlanRealInfoMgr()
{
if (inited_) {
destroy();
}
}
int ObPlanRealInfoMgr::init(uint64_t tenant_id,
const int64_t queue_size)
{
int ret = OB_SUCCESS;
if (inited_) {
ret = OB_INIT_TWICE;
} else if (OB_FAIL(queue_.init(ObModIds::OB_SQL_PLAN,
queue_size,
tenant_id))) {
SERVER_LOG(WARN, "Failed to init ObMySQLRequestQueue", K(ret));
} else if (OB_FAIL(TG_CREATE_TENANT(lib::TGDefIDs::ReqMemEvict,
tg_id_))) {
SERVER_LOG(WARN, "create failed", K(ret));
} else if (OB_FAIL(TG_START(tg_id_))) {
SERVER_LOG(WARN, "init timer fail", K(ret));
} else if (OB_FAIL(allocator_.init(SQL_PLAN_PAGE_SIZE,
ObModIds::OB_SQL_PLAN,
tenant_id,
INT64_MAX))) {
SERVER_LOG(WARN, "failed to init allocator", K(ret));
} else {
//check FIFO mem used and plan real info every 1 seconds
if (OB_FAIL(task_.init(this))) {
SERVER_LOG(WARN, "fail to init plan real info timer task", K(ret));
} else if (OB_FAIL(TG_SCHEDULE(tg_id_, task_, EVICT_INTERVAL, true))) {
SERVER_LOG(WARN, "start eliminate task failed", K(ret));
} else {
tenant_id_ = tenant_id;
inited_ = true;
destroyed_ = false;
}
}
if ((OB_FAIL(ret)) && (!inited_)) {
destroy();
}
return ret;
}
void ObPlanRealInfoMgr::destroy()
{
if (!destroyed_) {
TG_DESTROY(tg_id_);
clear_queue();
queue_.destroy();
allocator_.destroy();
inited_ = false;
destroyed_ = true;
}
}
int ObPlanRealInfoMgr::handle_plan_info(int64_t id,
const ObString& sql_id,
uint64_t plan_id,
uint64_t plan_hash,
const ObMonitorNode &plan_info)
{
int ret = OB_SUCCESS;
ObPlanRealInfoRecord *record = NULL;
if (!inited_) {
ret = OB_NOT_INIT;
} else {
char *buf = NULL;
//alloc mem from allocator
int64_t pos = sizeof(ObPlanRealInfoRecord);
int64_t total_size = sizeof(ObPlanRealInfoRecord) +
sql_id.length();
if (NULL == (buf = (char*)alloc(total_size))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
if (REACH_TIME_INTERVAL(100 * 1000)) {
SERVER_LOG(WARN, "alloc mem failed", K(total_size), K(ret));
}
} else {
int64_t row_count = plan_info.output_row_count_;
int64_t cpu_time = plan_info.db_time_*1000/get_cpufreq_khz();
int64_t io_time = plan_info.block_time_*1000/get_cpufreq_khz();
int64_t open_time = plan_info.open_time_;
int64_t last_row_time = plan_info.last_row_time_;
int64_t real_time = 0;
if (last_row_time > open_time) {
real_time = last_row_time - open_time;
}
record = new(buf)ObPlanRealInfoRecord();
record->allocator_ = &allocator_;
record->data_.id_ = id;
record->data_.plan_id_ = plan_id;
record->data_.plan_hash_ = plan_hash;
record->data_.real_cost_ = real_time;
record->data_.real_cardinality_ = row_count;
record->data_.io_cost_ = io_time;
record->data_.cpu_cost_ = cpu_time;
if ((sql_id.length() > 0) && (NULL != sql_id.ptr())) {
MEMCPY(buf + pos, sql_id.ptr(), sql_id.length());
record->data_.sql_id_ = buf + pos;
pos += sql_id.length();
record->data_.sql_id_len_ = sql_id.length();
}
}
//push into queue
if (OB_SUCC(ret)) {
int64_t req_id = 0;
if (OB_FAIL(queue_.push(record, req_id))) {
if (REACH_TIME_INTERVAL(2 * 1000 * 1000)) {
SERVER_LOG(WARN, "push into queue failed", K(ret));
}
free(record);
record = NULL;
}
}
}
return ret;
}
ObConcurrentFIFOAllocator *ObPlanRealInfoMgr::get_allocator()
{
return &allocator_;
}
void* ObPlanRealInfoMgr::alloc(const int64_t size)
{
void * ret = allocator_.alloc(size);
return ret;
}
void ObPlanRealInfoMgr::free(void *ptr)
{
allocator_.free(ptr);
ptr = NULL;
}
int ObPlanRealInfoMgr::get(const int64_t idx, void *&record, Ref* ref)
{
int ret = OB_SUCCESS;
if (NULL == (record = queue_.get(idx, ref))) {
ret = OB_ENTRY_NOT_EXIST;
}
return ret;
}
int ObPlanRealInfoMgr::revert(Ref* ref)
{
queue_.revert(ref);
return OB_SUCCESS;
}
int ObPlanRealInfoMgr::release_old(int64_t limit)
{
void* req = NULL;
int64_t count = 0;
while(count++ < limit && NULL != (req = queue_.pop())) {
free(req);
}
return OB_SUCCESS;
}
void ObPlanRealInfoMgr::clear_queue()
{
(void)release_old(INT64_MAX);
}
uint64_t ObPlanRealInfoMgr::get_tenant_id() const
{
return tenant_id_;
}
bool ObPlanRealInfoMgr::is_valid() const
{
return inited_ && !destroyed_;
}
int64_t ObPlanRealInfoMgr::get_start_idx() const
{
return (int64_t)queue_.get_pop_idx();
}
int64_t ObPlanRealInfoMgr::get_end_idx() const
{
return (int64_t)queue_.get_push_idx();
}
int64_t ObPlanRealInfoMgr::get_size_used()
{
return (int64_t)(queue_.get_push_idx() - queue_.get_pop_idx());
}
int64_t ObPlanRealInfoMgr::get_size()
{
return (int64_t)queue_.get_size();
}
int ObPlanRealInfoMgr::get_mem_limit(uint64_t tenant_id, int64_t &mem_limit)
{
int ret = OB_SUCCESS;
int64_t tenant_mem_limit = lib::get_tenant_memory_limit(tenant_id);
// default mem limit
mem_limit = static_cast<int64_t>(SQL_PLAN_MEM_FACTOR * tenant_mem_limit);
// get mem_percentage from session info
ObArenaAllocator alloc;
ObObj obj_val;
int64_t mem_pct = 0;
if (OB_FAIL(ObBasicSessionInfo::get_global_sys_variable(tenant_id,
alloc,
ObDataTypeCastParams(),
ObString(share::OB_SV_SQL_PLAN_MEMORY_PERCENTAGE),
obj_val))) {
LOG_WARN("failed to get global sys variable", K(ret));
} else if (OB_FAIL(obj_val.get_int(mem_pct))) {
LOG_WARN("failed to get int", K(ret), K(obj_val));
} else if (mem_pct < 0 || mem_pct > 100) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid value of plan real info mem percentage", K(ret), K(mem_pct));
} else {
mem_limit = static_cast<int64_t>(tenant_mem_limit * mem_pct / 100.0);
LOG_DEBUG("tenant plan real info memory limit",
K(tenant_id), K(tenant_mem_limit), K(mem_pct), K(mem_limit));
}
return ret;
}
int ObPlanRealInfoMgr::mtl_init(ObPlanRealInfoMgr* &plan_real_info_mgr)
{
int ret = OB_SUCCESS;
plan_real_info_mgr = OB_NEW(ObPlanRealInfoMgr, ObModIds::OB_SQL_PLAN);
if (nullptr == plan_real_info_mgr) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc memory for ObPlanRealInfoMgr", K(ret));
} else {
int64_t queue_size = lib::is_mini_mode() ?
MINI_MODE_MAX_QUEUE_SIZE : MAX_QUEUE_SIZE;
uint64_t tenant_id = lib::current_resource_owner_id();
if (OB_FAIL(plan_real_info_mgr->init(tenant_id,
queue_size))) {
LOG_WARN("failed to init request manager", K(ret));
}
}
if (OB_FAIL(ret) && plan_real_info_mgr != nullptr) {
// cleanup
ob_delete(plan_real_info_mgr);
plan_real_info_mgr = nullptr;
}
return ret;
}
void ObPlanRealInfoMgr::mtl_destroy(ObPlanRealInfoMgr* &plan_real_info_mgr)
{
if (plan_real_info_mgr != nullptr) {
ob_delete(plan_real_info_mgr);
plan_real_info_mgr = nullptr;
}
}
ObPlanRealInfoEliminateTask::ObPlanRealInfoEliminateTask()
:plan_real_info_manager_(NULL),
config_mem_limit_(0)
{
}
ObPlanRealInfoEliminateTask::~ObPlanRealInfoEliminateTask()
{
}
int ObPlanRealInfoEliminateTask::init(const ObPlanRealInfoMgr *plan_real_info_manager)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(plan_real_info_manager)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(plan_real_info_manager_), K(ret));
} else {
plan_real_info_manager_ = const_cast<ObPlanRealInfoMgr*>(plan_real_info_manager);
// can't call ObPlanRealInfoMgr::get_mem_limit for now, tenant not inited
// set config_mem_limit_ to 64M
config_mem_limit_ = 64 * 1024 * 1024; // 64M
disable_timeout_check();
}
return ret;
}
//mem_limit = tenant_mem_limit * ob_sql_plan_percentage
int ObPlanRealInfoEliminateTask::check_config_mem_limit(bool &is_change)
{
int ret = OB_SUCCESS;
is_change = false;
const int64_t MINIMUM_LIMIT = 64 * 1024 * 1024; // at lease 64M
const int64_t MAXIMUM_LIMIT = 1024 * 1024 * 1024; // 1G maximum
int64_t mem_limit = config_mem_limit_;
if (OB_ISNULL(plan_real_info_manager_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(plan_real_info_manager_), K(ret));
} else if (plan_real_info_manager_->get_tenant_id() > OB_SYS_TENANT_ID &&
plan_real_info_manager_->get_tenant_id() <= OB_MAX_RESERVED_TENANT_ID) {
// 50x租户在没有对应的tenant schema,查询配置一定失败
} else if (OB_FAIL(ObPlanRealInfoMgr::get_mem_limit(plan_real_info_manager_->get_tenant_id(),
mem_limit))) {
LOG_WARN("failed to get mem limit", K(ret));
// if memory limit is not retrivable
// overwrite error code, set mem config to default value
// so that total memory use of plan real info can be limited
ret = OB_SUCCESS;
mem_limit = MAXIMUM_LIMIT;
}
if (config_mem_limit_ != mem_limit) {
LOG_TRACE("before change config mem", K(config_mem_limit_));
if (mem_limit < MINIMUM_LIMIT) {
if (lib::is_mini_mode()) {
// do nothing
} else {
config_mem_limit_ = MINIMUM_LIMIT;
}
} else {
config_mem_limit_ = mem_limit;
}
is_change = true;
LOG_TRACE("after change config mem", K(config_mem_limit_));
}
return ret;
}
//剩余内存淘汰曲线图,当mem_limit在[64M, 100M]时, 内存剩余20M时淘汰;
// 当mem_limit在[100M, 5G]时, 内存甚于mem_limit*0.2时淘汰;
// 当mem_limit在[5G, +∞]时, 内存剩余1G时淘汰;
//高低水位线内存差曲线图,当mem_limit在[64M, 100M]时, 内存差为:20M;
// 当mem_limit在[100M, 5G]时,内存差:mem_limit*0.2;
// 当mem_limit在[5G, +∞]时, 内存差是:1G,
// ______
// /
// _____/
// 100M 5G
int ObPlanRealInfoEliminateTask::calc_evict_mem_level(int64_t &low, int64_t &high)
{
int ret = OB_SUCCESS;
const double HIGH_LEVEL_PRECENT = 0.80;
const double LOW_LEVEL_PRECENT = 0.60;
const double HALF_PRECENT = 0.50;
const int64_t BIG_MEMORY_LIMIT = 5368709120; //5G
const int64_t SMALL_MEMORY_LIMIT = 100*1024*1024; //100M
const int64_t LOW_CONFIG = 64*1024*1024; //64M
if (OB_ISNULL(plan_real_info_manager_) || config_mem_limit_ < 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(plan_real_info_manager_), K(config_mem_limit_), K(ret));
} else {
if (config_mem_limit_ > BIG_MEMORY_LIMIT) {
// mem_limit > 5G
high = config_mem_limit_ - static_cast<int64_t>(BIG_MEMORY_LIMIT * (1.0 - HIGH_LEVEL_PRECENT));
low = config_mem_limit_ - static_cast<int64_t>(BIG_MEMORY_LIMIT * (1.0 - LOW_LEVEL_PRECENT)) ;
} else if (config_mem_limit_ >= LOW_CONFIG && config_mem_limit_ < SMALL_MEMORY_LIMIT) {
// 64M =< mem_limit < 100M
high = config_mem_limit_ - static_cast<int64_t>(SMALL_MEMORY_LIMIT * (1.0 - HIGH_LEVEL_PRECENT));
low = config_mem_limit_ - static_cast<int64_t>(SMALL_MEMORY_LIMIT * (1.0 - LOW_LEVEL_PRECENT));
} else if (config_mem_limit_ < LOW_CONFIG) {
//mem_limit < 64M
high = static_cast<int64_t>(static_cast<double>(config_mem_limit_) * HALF_PRECENT);
low = 0;
} else {
high = static_cast<int64_t>(static_cast<double>(config_mem_limit_) * HIGH_LEVEL_PRECENT);
low = static_cast<int64_t>(static_cast<double>(config_mem_limit_) * LOW_LEVEL_PRECENT);
}
}
return ret;
}
void ObPlanRealInfoEliminateTask::runTimerTask()
{
int ret = OB_SUCCESS;
ObConcurrentFIFOAllocator *allocator = NULL;
int64_t evict_high_level = 0;
int64_t evict_low_level = 0;
bool is_change = false;
if (OB_ISNULL(plan_real_info_manager_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(plan_real_info_manager_), K(ret));
} else if (OB_FAIL(check_config_mem_limit(is_change))) {
LOG_WARN("fail to check mem limit stat", K(ret));
} else if (OB_FAIL(calc_evict_mem_level(evict_low_level, evict_high_level))) {
LOG_WARN("fail to get plan real info evict memory level", K(ret));
} else if (OB_ISNULL(allocator = plan_real_info_manager_->get_allocator())) {
ret = OB_NOT_INIT;
LOG_WARN("fail to get plan real info evict memory level", K(ret));
}
if (OB_SUCC(ret)) {
int64_t start_time = ObTimeUtility::current_time();
int64_t evict_batch_count = 0;
//按内存淘汰
if (evict_high_level < allocator->allocated()) {
LOG_INFO("plan real info evict mem start",
K(evict_low_level),
K(evict_high_level),
"size_used",plan_real_info_manager_->get_size_used(),
"mem_used", allocator->allocated());
int64_t last_time_allocated = allocator->allocated();
while (evict_low_level < allocator->allocated()) {
plan_real_info_manager_->release_old();
evict_batch_count++;
if ((evict_low_level < allocator->allocated()) &&
(last_time_allocated == allocator->allocated())) {
LOG_INFO("release old cannot free more memory");
break;
}
last_time_allocated = allocator->allocated();
}
}
//按sql plan记录数淘汰
int64_t high_level_evict_size = ObPlanRealInfoMgr::HIGH_LEVEL_EVICT_SIZE;
int64_t low_level_evict_size = ObPlanRealInfoMgr::LOW_LEVEL_EVICT_SIZE;
if (lib::is_mini_mode()) {
high_level_evict_size = ObPlanRealInfoMgr::MINI_MODE_HIGH_LEVEL_EVICT_SIZE;
low_level_evict_size = ObPlanRealInfoMgr::MINI_MODE_LOW_LEVEL_EVICT_SIZE;
}
if (plan_real_info_manager_->get_size_used() > high_level_evict_size) {
evict_batch_count = (plan_real_info_manager_->get_size_used() - low_level_evict_size)
/ ObPlanRealInfoMgr::BATCH_RELEASE_COUNT;
LOG_INFO("plan real info evict record start",
"size_used",plan_real_info_manager_->get_size_used(),
"mem_used", allocator->allocated());
for (int i = 0; i < evict_batch_count; i++) {
plan_real_info_manager_->release_old();
}
}
//如果sql_plan_memory_limit改变, 则需要将ObConcurrentFIFOAllocator中total_limit_更新;
if (true == is_change) {
allocator->set_total_limit(config_mem_limit_);
}
int64_t end_time = ObTimeUtility::current_time();
LOG_TRACE("plan real info evict task end",
K(evict_high_level),
K(evict_batch_count),
"elapse_time", end_time - start_time,
"size_used",plan_real_info_manager_->get_size_used(),
"mem_used", allocator->allocated());
}
}
} // end of namespace sql
} // end of namespace oceanbase

View File

@ -0,0 +1,148 @@
// Copyright 2010-2016 Alibaba Inc. All Rights Reserved.
// Author:
// zhenling.zzg
// this file defines interface of plan real info manager
#ifndef SRC_OBSERVER_PLAN_REAL_INFO_MGR_H_
#define SRC_OBSERVER_PLAN_REAL_INFO_MGR_H_
#include "lib/allocator/ob_concurrent_fifo_allocator.h"
#include "observer/mysql/ob_ra_queue.h"
#include "lib/task/ob_timer.h"
namespace oceanbase
{
namespace common
{
class ObConcurrentFIFOAllocator;
}
namespace sql
{
class ObMonitorNode;
struct ObPlanRealInfo {
ObPlanRealInfo();
virtual ~ObPlanRealInfo();
void reset();
int64_t get_extra_size() const;
int64_t plan_id_;
char* sql_id_;
int64_t sql_id_len_;
uint64_t plan_hash_;
int id_;
int64_t real_cost_;
int64_t real_cardinality_;
int64_t cpu_cost_;
int64_t io_cost_;
TO_STRING_KV(
K_(plan_id),
K_(real_cost),
K_(real_cardinality),
K_(cpu_cost),
K_(io_cost)
);
};
struct ObPlanRealInfoRecord
{
ObPlanRealInfoRecord();
virtual ~ObPlanRealInfoRecord();
virtual void destroy();
TO_STRING_KV(
K_(data)
);
ObPlanRealInfo data_;
common::ObConcurrentFIFOAllocator *allocator_;
};
class ObPlanRealInfoMgr;
class ObPlanRealInfoEliminateTask : public common::ObTimerTask
{
public:
ObPlanRealInfoEliminateTask();
virtual ~ObPlanRealInfoEliminateTask();
void runTimerTask();
int init(const ObPlanRealInfoMgr *plan_real_info_manager);
int check_config_mem_limit(bool &is_change);
int calc_evict_mem_level(int64_t &low, int64_t &high);
private:
ObPlanRealInfoMgr *plan_real_info_manager_;
int64_t config_mem_limit_;
};
class ObPlanRealInfoMgr
{
public:
static const int64_t SQL_PLAN_PAGE_SIZE = (1LL << 17); // 128K
//进行一次release_old操作删除的记录数
static const int32_t BATCH_RELEASE_COUNT = 5000;
static const int32_t MAX_RELEASE_TIME = 5 * 1000; //5ms
static const int64_t US_PER_HOUR = 3600000000;
//初始化queue大小为1000w
static const int64_t MAX_QUEUE_SIZE = 1000000; //100w
static const int64_t MINI_MODE_MAX_QUEUE_SIZE = 100000; // 10w
//当sql_plan超过900w行记录时触发淘汰
static const int64_t HIGH_LEVEL_EVICT_SIZE = 900000; //90w
static const int64_t MINI_MODE_HIGH_LEVEL_EVICT_SIZE = 90000; // 9w
//按行淘汰的低水位线
static const int64_t LOW_LEVEL_EVICT_SIZE = 800000; //80w
static const int64_t MINI_MODE_LOW_LEVEL_EVICT_SIZE = 80000; // 8w
//启动淘汰检查的时间间隔
static const int64_t EVICT_INTERVAL = 1000000; //1s
static const int64_t PLAN_TABLE_QUEUE_SIZE = 1000;
typedef common::ObRaQueue::Ref Ref;
public:
ObPlanRealInfoMgr();
virtual ~ObPlanRealInfoMgr();
int init(uint64_t tenant_id,
const int64_t queue_size);
void destroy();
int handle_plan_info(int64_t id,
const ObString& sql_id,
uint64_t plan_id,
uint64_t plan_hash,
const ObMonitorNode &plan_info);
common::ObConcurrentFIFOAllocator *get_allocator();
void* alloc(const int64_t size);
void free(void *ptr);
int get(const int64_t idx, void *&record, Ref* ref);
int revert(Ref* ref);
int release_old(int64_t limit = BATCH_RELEASE_COUNT);
void clear_queue();
uint64_t get_tenant_id() const;
int64_t get_start_idx() const;
int64_t get_end_idx() const;
int64_t get_size_used();
int64_t get_size();
bool is_valid() const;
static int get_mem_limit(uint64_t tenant_id, int64_t &mem_limit);
static int mtl_init(ObPlanRealInfoMgr* &plan_real_info_mgr);
static void mtl_destroy(ObPlanRealInfoMgr* &plan_real_info_mgr);
private:
DISALLOW_COPY_AND_ASSIGN(ObPlanRealInfoMgr);
private:
common::ObConcurrentFIFOAllocator allocator_;//alloc mem for string buf
ObPlanRealInfoEliminateTask task_;
common::ObRaQueue queue_;
bool destroyed_;
bool inited_;
// tenant id of this manager
uint64_t tenant_id_;
int tg_id_;
};
} // end of namespace sql
} // end of namespace oceanbase
#endif /* SRC_OBSERVER_PLAN_REAL_INFO_MGR_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,290 @@
// Copyright 2010-2016 Alibaba Inc. All Rights Reserved.
// Author:
// zhenling.zzg
// this file defines interface of sql plan manager
#ifndef SRC_OBSERVER_SQL_PLAN_H_
#define SRC_OBSERVER_SQL_PLAN_H_
#include "sql/ob_sql_define.h"
#include "ob_plan_real_info_manager.h"
namespace oceanbase
{
namespace sql
{
class ObLogPlan;
class ObSQLSessionInfo;
class ObLogicalOperator;
struct ObSqlPlanItem;
struct ObQueryCtx;
struct ObExplainDisplayOpt;
#define SEPARATOR "-------------------------------------"
#define OUTPUT_PREFIX " "
#define NEW_LINE "\n"
#define COLUMN_SEPARATOR "|"
#define PLAN_WRAPPER "="
#define LINE_SEPARATOR "-"
#define BASIC_PLAN_TABLE_COLUMN_CNT 3
#define PLAN_TABLE_COLUMN_CNT 5
#define REAL_PLAN_TABLE_COLUMN_CNT 9
#define BEGIN_BUF_PRINT \
char *buf = plan_text.buf_; \
int64_t &buf_len = plan_text.buf_len_; \
int64_t &pos = plan_text.pos_; \
int64_t start_pos = pos; \
ExplainType type = plan_text.type_; \
#define END_BUF_PRINT(ptr, ptr_len) \
if (OB_SUCC(ret)) { \
ptr = plan_text.buf_ + start_pos; \
ptr_len = pos - start_pos; \
}
#define BUF_PRINT_STR(str, ptr, ptr_len) \
do { \
BEGIN_BUF_PRINT; \
if (OB_FAIL(ret)) { /* Do nothing */ \
} else if (OB_FAIL(BUF_PRINTF(str))) { /* Do nothing */ \
} else { \
END_BUF_PRINT(ptr, ptr_len) \
} \
} while (0);
#define BUF_PRINT_OB_STR(str, str_len, ptr, ptr_len) \
do { \
BEGIN_BUF_PRINT; \
if (OB_FAIL(ret)) { /* Do nothing */ \
} else if (OB_FAIL(BUF_PRINTF("%.*s", str_len, str))) { /* Do nothing */ \
} else { \
END_BUF_PRINT(ptr, ptr_len) \
} \
} while (0);
#define BUF_PRINT_CONST_STR(str, plan_text) \
do { \
char *buf = plan_text.buf_ + plan_text.pos_; \
int64_t buf_len = plan_text.buf_len_ - plan_text.pos_; \
int64_t pos = 0; \
if (OB_FAIL(ret)) { /* Do nothing */ \
} else if (OB_FAIL(BUF_PRINTF(str))) { /* Do nothing */ \
} else { \
plan_text.pos_ += pos; \
} \
} while (0);
struct PlanText
{
public:
PlanText()
: buf_(NULL),
buf_len_(0),
pos_(0),
is_oneline_(false),
is_used_hint_(false),
is_outline_data_(false),
type_(EXPLAIN_UNINITIALIZED)
{}
virtual ~PlanText() {}
char *buf_;
int64_t buf_len_;
int64_t pos_;
bool is_oneline_;
bool is_used_hint_;
bool is_outline_data_;
ExplainType type_;
};
class ObSqlPlan
{
private:
struct PlanFormatHelper {
PlanFormatHelper()
:operator_prefix_(),
column_len_(),
total_len_(0)
{}
int init();
ObSEArray<ObString, 4> operator_prefix_;
ObSEArray<int, 4> column_len_;
int64_t total_len_;
};
public:
ObSqlPlan(common::ObIAllocator &allocator);
virtual ~ObSqlPlan();
int store_sql_plan(ObLogPlan* plan,
int64_t plan_id,
uint64_t plan_hash,
ObString &sql_id);
int store_sql_plan_for_explain(ObLogPlan* plan,
ExplainType type,
const ObExplainDisplayOpt& option,
ObIArray<common::ObString> &plan_strs);
int get_sql_plan(const ObString &sql_id,
int64_t plan_id,
ExplainType type,
const ObExplainDisplayOpt& option,
ObIArray<ObPlanRealInfo> &plan_infos,
PlanText &plan_text);
int get_sql_plan_by_hash(const ObString &sql_id,
uint64_t plan_hash,
ExplainType type,
const ObExplainDisplayOpt& option,
ObIArray<ObPlanRealInfo> &plan_infos,
PlanText &plan_text);
int get_last_explain_plan(ExplainType type,
const ObExplainDisplayOpt& option,
PlanText &plan_text);
void set_session_info(ObSQLSessionInfo *session_info);
static int get_plan_outline_info_one_line(PlanText &plan_text,
ObLogPlan* plan);
static int plan_text_to_string(PlanText &plan_text,
common::ObString &plan_str);
static int plan_text_to_strings(PlanText &plan_text,
ObIArray<common::ObString> &plan_strs);
private:
int set_plan_id_for_explain(ObIArray<ObSqlPlanItem*> &sql_plan_infos);
int set_plan_id_for_excute(ObIArray<ObSqlPlanItem*> &sql_plan_infos,
int64_t plan_id,
uint64_t plan_hash,
ObString &sql_id,
PlanText &plan_text);
int get_sql_plan_infos(PlanText &plan_text,
ObLogPlan* plan,
ObIArray<ObSqlPlanItem*> &sql_plan_infos);
int get_plan_tree_infos(PlanText &plan_text,
ObLogicalOperator* op,
ObIArray<ObSqlPlanItem*> &sql_plan_infos,
int depth,
int position,
bool is_last_child);
int get_plan_used_hint_info(PlanText &plan_text,
ObLogPlan* plan,
ObSqlPlanItem* sql_plan_item);
int get_plan_tree_used_hint(PlanText &plan_text,
ObLogicalOperator* op);
int get_qb_name_trace(PlanText &plan_text,
ObLogPlan* plan,
ObSqlPlanItem* sql_plan_item);
int get_plan_outline_info(PlanText &plan_text,
ObLogPlan* plan,
ObSqlPlanItem* sql_plan_item);
static int get_plan_tree_outline(PlanText &plan_text,
ObLogicalOperator* op);
int get_plan_other_info(PlanText &plan_text,
ObLogPlan* plan,
ObSqlPlanItem* sql_plan_item);
int get_constraint_info(char *buf,
int64_t buf_len,
int64_t &pos,
const ObQueryCtx &ctx);
int print_constraint_info(char *buf,
int64_t buf_len,
int64_t &pos,
const ObPCConstParamInfo &info);
int print_constraint_info(char *buf,
int64_t buf_len,
int64_t &pos,
const ObPCParamEqualInfo &info);
int print_constraint_info(char *buf,
int64_t buf_len,
int64_t &pos,
const ObExprConstraint &info);
int inner_store_sql_plan(ObIArray<ObSqlPlanItem*> &sql_plan_infos, bool for_explain);
int format_sql_plan(ObIArray<ObSqlPlanItem*> &sql_plan_infos,
ExplainType type,
const ObExplainDisplayOpt& option,
ObIArray<ObPlanRealInfo> &plan_infos,
PlanText &plan_text);
int get_plan_table_formatter(ObIArray<ObSqlPlanItem*> &sql_plan_infos,
const ObExplainDisplayOpt& option,
PlanFormatHelper &format_helper);
int get_real_plan_table_formatter(ObIArray<ObSqlPlanItem*> &sql_plan_infos,
const ObExplainDisplayOpt& option,
ObIArray<ObPlanRealInfo> &plan_infos,
PlanFormatHelper &format_helper);
int get_operator_prefix(ObIArray<ObSqlPlanItem*> &sql_plan_infos,
const ObExplainDisplayOpt& option,
PlanFormatHelper &format_helper);
int format_basic_plan_table(ObIArray<ObSqlPlanItem*> &sql_plan_infos,
const ObExplainDisplayOpt& option,
PlanText &plan_text);
int format_plan_table(ObIArray<ObSqlPlanItem*> &sql_plan_infos,
const ObExplainDisplayOpt& option,
PlanText &plan_text);
int format_real_plan_table(ObIArray<ObSqlPlanItem*> &sql_plan_infos,
const ObExplainDisplayOpt& option,
ObIArray<ObPlanRealInfo> &plan_infos,
PlanText &plan_text);
int format_plan_output(ObIArray<ObSqlPlanItem*> &sql_plan_infos, PlanText &plan_text);
int format_used_hint(ObIArray<ObSqlPlanItem*> &sql_plan_infos, PlanText &plan_text);
int format_qb_name_trace(ObIArray<ObSqlPlanItem*> &sql_plan_infos, PlanText &plan_text);
int format_outline(ObIArray<ObSqlPlanItem*> &sql_plan_infos, PlanText &plan_text);
int format_optimizer_info(ObIArray<ObSqlPlanItem*> &sql_plan_infos, PlanText &plan_text);
int format_other_info(ObIArray<ObSqlPlanItem*> &sql_plan_infos, PlanText &plan_text);
int format_plan_to_json(ObIArray<ObSqlPlanItem*> &sql_plan_infos, PlanText &plan_text);
int inner_format_plan_to_json(ObIArray<ObSqlPlanItem*> &sql_plan_infos,
int64_t info_idx,
json::Value *&ret_val);
int init_buffer(PlanText &plan_text);
void destroy_buffer(PlanText &plan_text);
int refine_buffer(PlanText &plan_text);
DISALLOW_COPY_AND_ASSIGN(ObSqlPlan);
private:
common::ObIAllocator &allocator_;
ObSQLSessionInfo *session_info_;
};
} // end of namespace sql
} // end of namespace oceanbase
#endif /* SRC_OBSERVER_SQL_PLAN_H_ */

View File

@ -0,0 +1,730 @@
// Copyright 2010-2016 Alibaba Inc. All Rights Reserved.
// Author:
// zhenling.zzg
// this file defines implementation of sql plan manager
#define USING_LOG_PREFIX SQL
#include "lib/allocator/ob_concurrent_fifo_allocator.h"
#include "lib/compress/zlib/zlib_src/zlib.h"
#include "sql/session/ob_sql_session_info.h"
#include "common/object/ob_object.h"
#include "lib/thread/thread_mgr.h"
#include "ob_sql_plan_manager.h"
#include "lib/ob_running_mode.h"
#include "util/easy_time.h"
#include "lib/rc/ob_rc.h"
namespace oceanbase
{
namespace sql
{
ObSqlPlanItem::ObSqlPlanItem()
{
reset();
}
ObSqlPlanItem::~ObSqlPlanItem()
{
}
void ObSqlPlanItem::reset()
{
plan_id_ = 0;
db_id_ = 0;
sql_id_ = NULL;
sql_id_len_ = 0;
plan_hash_ = 0;
gmt_create_ = 0;
operation_ = NULL;
operation_len_ = 0;
options_ = NULL;
options_len_ = 0;
object_node_ = NULL;
object_node_len_ = 0;
object_id_ = 0;
object_owner_ = NULL;
object_owner_len_ = 0;
object_name_ = NULL;
object_name_len_ = 0;
object_alias_ = NULL;
object_alias_len_ = 0;
object_type_ = NULL;
object_type_len_ = 0;
optimizer_ = NULL;
optimizer_len_ = 0;
id_ = 0;
parent_id_ = 0;
depth_ = 0;
position_ = 0;
is_last_child_ = false;
search_columns_ = 0;
cost_ = 0;
cardinality_ = 0;
bytes_ = 0;
rowset_ = 1;
other_tag_ = NULL;
other_tag_len_ = 0;
partition_start_ = NULL;
partition_start_len_ = 0;
partition_stop_ = NULL;
partition_stop_len_ = 0;
partition_id_ = 0;
other_ = NULL;
other_len_ = 0;
distribution_ = NULL;
distribution_len_ = 0;
cpu_cost_ = 0;
io_cost_ = 0;
temp_space_ = 0;
access_predicates_ = NULL;
access_predicates_len_ = 0;
filter_predicates_ = NULL;
filter_predicates_len_ = 0;
startup_predicates_ = NULL;
startup_predicates_len_ = 0;
projection_ = NULL;
projection_len_ = 0;
special_predicates_ = NULL;
special_predicates_len_ = 0;
time_ = 0;
qblock_name_ = NULL;
qblock_name_len_ = 0;
remarks_ = NULL;
remarks_len_ = 0;
other_xml_ = NULL;
other_xml_len_ = 0;
}
int64_t ObSqlPlanItem::get_extra_size() const
{
return sql_id_len_ +
operation_len_ +
options_len_ +
object_node_len_ +
object_owner_len_ +
object_name_len_ +
object_alias_len_ +
object_type_len_ +
optimizer_len_ +
other_tag_len_ +
partition_start_len_ +
partition_stop_len_ +
other_len_ +
distribution_len_ +
access_predicates_len_ +
filter_predicates_len_ +
startup_predicates_len_ +
projection_len_ +
special_predicates_len_ +
qblock_name_len_ +
remarks_len_ +
other_xml_len_;
}
ObSqlPlanItemRecord::ObSqlPlanItemRecord()
:allocator_(NULL)
{
}
ObSqlPlanItemRecord::~ObSqlPlanItemRecord()
{
destroy();
}
void ObSqlPlanItemRecord::destroy()
{
if (NULL != allocator_) {
allocator_->free(this);
}
}
ObSqlPlanMgr::ObSqlPlanMgr()
:allocator_(),
task_(),
queue_(),
plan_id_increment_(0),
destroyed_(false),
inited_(false),
tenant_id_(OB_INVALID_TENANT_ID),
tg_id_(-1)
{
}
ObSqlPlanMgr::~ObSqlPlanMgr()
{
if (inited_) {
destroy();
}
}
int ObSqlPlanMgr::init(uint64_t tenant_id,
const int64_t queue_size)
{
int ret = OB_SUCCESS;
if (inited_) {
ret = OB_INIT_TWICE;
} else if (OB_FAIL(queue_.init(ObModIds::OB_SQL_PLAN,
queue_size,
tenant_id))) {
SERVER_LOG(WARN, "Failed to init ObMySQLRequestQueue", K(ret));
} else if (OB_FAIL(TG_CREATE_TENANT(lib::TGDefIDs::ReqMemEvict,
tg_id_))) {
SERVER_LOG(WARN, "create failed", K(ret));
} else if (OB_FAIL(TG_START(tg_id_))) {
SERVER_LOG(WARN, "init timer fail", K(ret));
} else if (OB_FAIL(allocator_.init(SQL_PLAN_PAGE_SIZE,
ObModIds::OB_SQL_PLAN,
tenant_id,
INT64_MAX))) {
SERVER_LOG(WARN, "failed to init allocator", K(ret));
} else {
//check FIFO mem used and sql plan every 1 seconds
if (OB_FAIL(task_.init(this))) {
SERVER_LOG(WARN, "fail to init sql plan timer task", K(ret));
} else if (OB_FAIL(TG_SCHEDULE(tg_id_, task_, EVICT_INTERVAL, true))) {
SERVER_LOG(WARN, "start eliminate task failed", K(ret));
} else {
tenant_id_ = tenant_id;
inited_ = true;
destroyed_ = false;
}
}
if ((OB_FAIL(ret)) && (!inited_)) {
destroy();
}
return ret;
}
void ObSqlPlanMgr::destroy()
{
if (!destroyed_) {
TG_DESTROY(tg_id_);
clear_queue();
queue_.destroy();
allocator_.destroy();
inited_ = false;
destroyed_ = true;
}
}
int ObSqlPlanMgr::handle_plan_item(const ObSqlPlanItem &plan_item)
{
int ret = OB_SUCCESS;
ObSqlPlanItemRecord *record = NULL;
if (!inited_) {
ret = OB_NOT_INIT;
} else {
char *buf = NULL;
//alloc mem from allocator
int64_t pos = sizeof(ObSqlPlanItemRecord);
int64_t total_size = sizeof(ObSqlPlanItemRecord) +
plan_item.get_extra_size();
if (NULL == (buf = (char*)alloc(total_size))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
if (REACH_TIME_INTERVAL(100 * 1000)) {
SERVER_LOG(WARN, "alloc mem failed", K(total_size), K(ret));
}
} else {
record = new(buf)ObSqlPlanItemRecord();
record->allocator_ = &allocator_;
record->data_ = plan_item;
#define DEEP_COPY_DATA(value) \
do { \
if (pos + plan_item.value##len_ > total_size) { \
ret = OB_ERR_UNEXPECTED; \
LOG_WARN("unexpect record size", K(pos), K(plan_item.value##len_), \
K(total_size), K(ret)); \
} else if ((plan_item.value##len_ > 0) && (NULL != plan_item.value)) { \
MEMCPY(buf + pos, plan_item.value, plan_item.value##len_); \
record->data_.value = buf + pos; \
pos += plan_item.value##len_; \
} else { \
record->data_.value = buf + pos; \
} \
} while(0);
DEEP_COPY_DATA(sql_id_);
DEEP_COPY_DATA(operation_);
DEEP_COPY_DATA(options_);
DEEP_COPY_DATA(object_node_);
DEEP_COPY_DATA(object_owner_);
DEEP_COPY_DATA(object_name_);
DEEP_COPY_DATA(object_alias_);
DEEP_COPY_DATA(object_type_);
DEEP_COPY_DATA(optimizer_);
DEEP_COPY_DATA(other_tag_);
DEEP_COPY_DATA(partition_start_);
DEEP_COPY_DATA(partition_stop_);
DEEP_COPY_DATA(other_);
DEEP_COPY_DATA(distribution_);
DEEP_COPY_DATA(access_predicates_);
DEEP_COPY_DATA(filter_predicates_);
DEEP_COPY_DATA(startup_predicates_);
DEEP_COPY_DATA(projection_);
DEEP_COPY_DATA(special_predicates_);
DEEP_COPY_DATA(qblock_name_);
DEEP_COPY_DATA(remarks_);
DEEP_COPY_DATA(other_xml_);
}
//push into queue
if (OB_SUCC(ret)) {
int64_t req_id = 0;
if (OB_FAIL(queue_.push(record, req_id))) {
if (REACH_TIME_INTERVAL(2 * 1000 * 1000)) {
SERVER_LOG(WARN, "push into queue failed", K(ret));
}
free(record);
record = NULL;
}
}
}
return ret;
}
int ObSqlPlanMgr::get_plan(int64_t plan_id,
ObIArray<ObSqlPlanItem*> &plan)
{
int ret = OB_SUCCESS;
plan.reuse();
int64_t start_idx = get_start_idx();
int64_t end_idx = get_end_idx();
void *rec = NULL;
Ref ref;
for (int64_t cur_id=start_idx;
(OB_ENTRY_NOT_EXIST == ret || OB_SUCCESS == ret) && cur_id < end_idx;
++cur_id) {
ref.reset();
ret = get(cur_id, rec, &ref);
if (OB_SUCC(ret) && NULL != rec) {
ObSqlPlanItemRecord *record = static_cast<ObSqlPlanItemRecord*>(rec);
if (record->data_.plan_id_ != plan_id) {
//do nothing
} else if (OB_FAIL(plan.push_back(&record->data_))) {
LOG_WARN("failed to push back plan item", K(ret));
}
}
if (ref.idx_ != -1) {
revert(&ref);
}
}
return ret;
}
int ObSqlPlanMgr::get_plan(const ObString &sql_id,
int64_t plan_id,
ObIArray<ObSqlPlanItem*> &plan)
{
int ret = OB_SUCCESS;
plan.reuse();
int64_t start_idx = get_start_idx();
int64_t end_idx = get_end_idx();
void *rec = NULL;
Ref ref;
for (int64_t cur_id=start_idx;
(OB_ENTRY_NOT_EXIST == ret || OB_SUCCESS == ret) && cur_id < end_idx;
++cur_id) {
ref.reset();
ret = get(cur_id, rec, &ref);
if (OB_SUCC(ret) && NULL != rec) {
ObSqlPlanItemRecord *record = static_cast<ObSqlPlanItemRecord*>(rec);
if (record->data_.plan_id_ != plan_id ||
sql_id.case_compare(ObString(record->data_.sql_id_len_,record->data_.sql_id_)) != 0) {
//do nothing
} else if (OB_FAIL(plan.push_back(&record->data_))) {
LOG_WARN("failed to push back plan item", K(ret));
}
}
if (ref.idx_ != -1) {
revert(&ref);
}
}
return ret;
}
int ObSqlPlanMgr::get_plan_by_hash(const ObString &sql_id,
uint64_t plan_hash,
ObIArray<ObSqlPlanItem*> &plan)
{
int ret = OB_SUCCESS;
plan.reuse();
int64_t start_idx = get_start_idx();
int64_t end_idx = get_end_idx();
void *rec = NULL;
Ref ref;
for (int64_t cur_id=start_idx;
(OB_ENTRY_NOT_EXIST == ret || OB_SUCCESS == ret) && cur_id < end_idx;
++cur_id) {
ref.reset();
ret = get(cur_id, rec, &ref);
if (OB_SUCC(ret) && NULL != rec) {
ObSqlPlanItemRecord *record = static_cast<ObSqlPlanItemRecord*>(rec);
if (record->data_.plan_hash_ != plan_hash ||
sql_id.case_compare(ObString(record->data_.sql_id_len_,record->data_.sql_id_)) != 0) {
//do nothing
} else if (OB_FAIL(plan.push_back(&record->data_))) {
LOG_WARN("failed to push back plan item", K(ret));
}
}
if (ref.idx_ != -1) {
revert(&ref);
}
}
return ret;
}
ObConcurrentFIFOAllocator *ObSqlPlanMgr::get_allocator()
{
return &allocator_;
}
void* ObSqlPlanMgr::alloc(const int64_t size)
{
void * ret = allocator_.alloc(size);
return ret;
}
void ObSqlPlanMgr::free(void *ptr)
{
allocator_.free(ptr);
ptr = NULL;
}
int ObSqlPlanMgr::get(const int64_t idx, void *&record, Ref* ref)
{
int ret = OB_SUCCESS;
if (NULL == (record = queue_.get(idx, ref))) {
ret = OB_ENTRY_NOT_EXIST;
}
return ret;
}
int ObSqlPlanMgr::revert(Ref* ref)
{
queue_.revert(ref);
return OB_SUCCESS;
}
int ObSqlPlanMgr::release_old(int64_t limit)
{
void* req = NULL;
int64_t count = 0;
while(count++ < limit && NULL != (req = queue_.pop())) {
free(req);
}
return OB_SUCCESS;
}
void ObSqlPlanMgr::clear_queue()
{
(void)release_old(INT64_MAX);
}
uint64_t ObSqlPlanMgr::get_tenant_id() const
{
return tenant_id_;
}
bool ObSqlPlanMgr::is_valid() const
{
return inited_ && !destroyed_;
}
int64_t ObSqlPlanMgr::get_start_idx() const
{
return (int64_t)queue_.get_pop_idx();
}
int64_t ObSqlPlanMgr::get_end_idx() const
{
return (int64_t)queue_.get_push_idx();
}
int64_t ObSqlPlanMgr::get_size_used()
{
return (int64_t)queue_.get_size();
}
int64_t ObSqlPlanMgr::get_capacity()
{
return (int64_t)queue_.get_capacity();
}
int64_t ObSqlPlanMgr::get_next_plan_id()
{
return ++plan_id_increment_;
}
int64_t ObSqlPlanMgr::get_last_plan_id()
{
return plan_id_increment_;
}
int ObSqlPlanMgr::get_mem_limit(uint64_t tenant_id, int64_t &mem_limit)
{
int ret = OB_SUCCESS;
int64_t tenant_mem_limit = lib::get_tenant_memory_limit(tenant_id);
// default mem limit
mem_limit = static_cast<int64_t>(SQL_PLAN_MEM_FACTOR * tenant_mem_limit);
// get mem_percentage from session info
ObArenaAllocator alloc;
ObObj obj_val;
int64_t mem_pct = 0;
if (OB_FAIL(ObBasicSessionInfo::get_global_sys_variable(tenant_id,
alloc,
ObDataTypeCastParams(),
ObString(share::OB_SV_SQL_PLAN_MEMORY_PERCENTAGE),
obj_val))) {
LOG_WARN("failed to get global sys variable", K(ret));
} else if (OB_FAIL(obj_val.get_int(mem_pct))) {
LOG_WARN("failed to get int", K(ret), K(obj_val));
} else if (mem_pct < 0 || mem_pct > 100) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid value of sql plan mem percentage", K(ret), K(mem_pct));
} else {
mem_limit = static_cast<int64_t>(tenant_mem_limit * mem_pct / 100.0);
LOG_DEBUG("tenant sql plan memory limit",
K(tenant_id), K(tenant_mem_limit), K(mem_pct), K(mem_limit));
}
return ret;
}
int ObSqlPlanMgr::init_plan_manager(uint64_t tenant_id, ObSqlPlanMgr* &sql_plan_mgr)
{
int ret = OB_SUCCESS;
sql_plan_mgr = OB_NEW(ObSqlPlanMgr, ObModIds::OB_SQL_PLAN);
if (nullptr == sql_plan_mgr) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc memory for ObSqlPlanMgr", K(ret));
} else {
int64_t queue_size = PLAN_TABLE_QUEUE_SIZE;
if (OB_FAIL(sql_plan_mgr->init(tenant_id,
queue_size))) {
LOG_WARN("failed to init request manager", K(ret));
}
}
if (OB_FAIL(ret) && sql_plan_mgr != nullptr) {
// cleanup
ob_delete(sql_plan_mgr);
sql_plan_mgr = nullptr;
}
return ret;
}
int ObSqlPlanMgr::mtl_init(ObSqlPlanMgr* &sql_plan_mgr)
{
int ret = OB_SUCCESS;
sql_plan_mgr = OB_NEW(ObSqlPlanMgr, ObModIds::OB_SQL_PLAN);
if (nullptr == sql_plan_mgr) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc memory for ObSqlPlanMgr", K(ret));
} else {
int64_t queue_size = lib::is_mini_mode() ?
MINI_MODE_MAX_QUEUE_SIZE : MAX_QUEUE_SIZE;
uint64_t tenant_id = lib::current_resource_owner_id();
if (OB_FAIL(sql_plan_mgr->init(tenant_id,
queue_size))) {
LOG_WARN("failed to init request manager", K(ret));
}
}
if (OB_FAIL(ret) && sql_plan_mgr != nullptr) {
// cleanup
ob_delete(sql_plan_mgr);
sql_plan_mgr = nullptr;
}
return ret;
}
void ObSqlPlanMgr::mtl_destroy(ObSqlPlanMgr* &sql_plan_mgr)
{
if (sql_plan_mgr != nullptr) {
ob_delete(sql_plan_mgr);
sql_plan_mgr = nullptr;
}
}
ObSqlPlanEliminateTask::ObSqlPlanEliminateTask()
:sql_plan_manager_(NULL),
config_mem_limit_(0)
{
}
ObSqlPlanEliminateTask::~ObSqlPlanEliminateTask()
{
}
int ObSqlPlanEliminateTask::init(const ObSqlPlanMgr *sql_plan_manager)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(sql_plan_manager)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(sql_plan_manager_), K(ret));
} else {
sql_plan_manager_ = const_cast<ObSqlPlanMgr*>(sql_plan_manager);
// can't call ObSqlPlanMgr::get_mem_limit for now, tenant not inited
// set config_mem_limit_ to 64M
config_mem_limit_ = 64 * 1024 * 1024; // 64M
disable_timeout_check();
}
return ret;
}
//mem_limit = tenant_mem_limit * ob_sql_plan_percentage
int ObSqlPlanEliminateTask::check_config_mem_limit(bool &is_change)
{
int ret = OB_SUCCESS;
is_change = false;
const int64_t MINIMUM_LIMIT = 64 * 1024 * 1024; // at lease 64M
const int64_t MAXIMUM_LIMIT = 1024 * 1024 * 1024; // 1G maximum
int64_t mem_limit = config_mem_limit_;
if (OB_ISNULL(sql_plan_manager_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(sql_plan_manager_), K(ret));
} else if (sql_plan_manager_->get_tenant_id() > OB_SYS_TENANT_ID &&
sql_plan_manager_->get_tenant_id() <= OB_MAX_RESERVED_TENANT_ID) {
// 50x租户在没有对应的tenant schema,查询配置一定失败
} else if (OB_FAIL(ObSqlPlanMgr::get_mem_limit(sql_plan_manager_->get_tenant_id(),
mem_limit))) {
LOG_WARN("failed to get mem limit", K(ret));
// if memory limit is not retrivable
// overwrite error code, set mem config to default value
// so that total memory use of sql plan can be limited
ret = OB_SUCCESS;
mem_limit = MAXIMUM_LIMIT;
}
if (config_mem_limit_ != mem_limit) {
LOG_TRACE("before change config mem", K(config_mem_limit_));
if (mem_limit < MINIMUM_LIMIT) {
if (lib::is_mini_mode()) {
// do nothing
} else {
config_mem_limit_ = MINIMUM_LIMIT;
}
} else {
config_mem_limit_ = mem_limit;
}
is_change = true;
LOG_TRACE("after change config mem", K(config_mem_limit_));
}
return ret;
}
//剩余内存淘汰曲线图,当mem_limit在[64M, 100M]时, 内存剩余20M时淘汰;
// 当mem_limit在[100M, 5G]时, 内存剩余mem_limit*0.2时淘汰;
// 当mem_limit在[5G, +∞]时, 内存剩余1G时淘汰;
//高低水位线内存差曲线图,当mem_limit在[64M, 100M]时, 内存差为:20M;
// 当mem_limit在[100M, 5G]时,内存差:mem_limit*0.2;
// 当mem_limit在[5G, +∞]时, 内存差是:1G,
// ______
// /
// _____/
// 100M 5G
int ObSqlPlanEliminateTask::calc_evict_mem_level(int64_t &low, int64_t &high)
{
int ret = OB_SUCCESS;
const double HIGH_LEVEL_PRECENT = 0.80;
const double LOW_LEVEL_PRECENT = 0.60;
const double HALF_PRECENT = 0.50;
const int64_t BIG_MEMORY_LIMIT = 5368709120; //5G
const int64_t SMALL_MEMORY_LIMIT = 100*1024*1024; //100M
const int64_t LOW_CONFIG = 64*1024*1024; //64M
if (OB_ISNULL(sql_plan_manager_) || config_mem_limit_ < 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(sql_plan_manager_), K(config_mem_limit_), K(ret));
} else {
if (config_mem_limit_ > BIG_MEMORY_LIMIT) {
// mem_limit > 5G
high = config_mem_limit_ - static_cast<int64_t>(BIG_MEMORY_LIMIT * (1.0 - HIGH_LEVEL_PRECENT));
low = config_mem_limit_ - static_cast<int64_t>(BIG_MEMORY_LIMIT * (1.0 - LOW_LEVEL_PRECENT)) ;
} else if (config_mem_limit_ >= LOW_CONFIG && config_mem_limit_ < SMALL_MEMORY_LIMIT) {
// 64M =< mem_limit < 100M
high = config_mem_limit_ - static_cast<int64_t>(SMALL_MEMORY_LIMIT * (1.0 - HIGH_LEVEL_PRECENT));
low = config_mem_limit_ - static_cast<int64_t>(SMALL_MEMORY_LIMIT * (1.0 - LOW_LEVEL_PRECENT));
} else if (config_mem_limit_ < LOW_CONFIG) {
//mem_limit < 64M
high = static_cast<int64_t>(static_cast<double>(config_mem_limit_) * HALF_PRECENT);
low = 0;
} else {
high = static_cast<int64_t>(static_cast<double>(config_mem_limit_) * HIGH_LEVEL_PRECENT);
low = static_cast<int64_t>(static_cast<double>(config_mem_limit_) * LOW_LEVEL_PRECENT);
}
}
return ret;
}
void ObSqlPlanEliminateTask::runTimerTask()
{
int ret = OB_SUCCESS;
ObConcurrentFIFOAllocator *allocator = NULL;
int64_t evict_high_level = 0;
int64_t evict_low_level = 0;
bool is_change = false;
if (OB_ISNULL(sql_plan_manager_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(sql_plan_manager_), K(ret));
} else if (OB_FAIL(check_config_mem_limit(is_change))) {
LOG_WARN("fail to check mem limit stat", K(ret));
} else if (OB_FAIL(calc_evict_mem_level(evict_low_level, evict_high_level))) {
LOG_WARN("fail to get sql plan evict memory level", K(ret));
} else if (OB_ISNULL(allocator = sql_plan_manager_->get_allocator())) {
ret = OB_NOT_INIT;
LOG_WARN("fail to get sql plan evict memory level", K(ret));
}
if (OB_SUCC(ret)) {
int64_t start_time = ObTimeUtility::current_time();
int64_t evict_batch_count = 0;
//按内存淘汰
if (evict_high_level < allocator->allocated()) {
LOG_INFO("sql plan evict mem start",
K(evict_low_level),
K(evict_high_level),
"size_used",sql_plan_manager_->get_size_used(),
"mem_used", allocator->allocated());
int64_t last_time_allocated = allocator->allocated();
while (evict_low_level < allocator->allocated()) {
sql_plan_manager_->release_old();
evict_batch_count++;
if ((evict_low_level < allocator->allocated()) &&
(last_time_allocated == allocator->allocated())) {
LOG_INFO("release old cannot free more memory");
break;
}
last_time_allocated = allocator->allocated();
}
}
//按sql plan记录数淘汰
int64_t max_queue_size = sql_plan_manager_->get_capacity();
int64_t high_level_evict_size = max_queue_size * ObSqlPlanMgr::HIGH_LEVEL_EVICT_SIZE_PERCENT;
int64_t low_level_evict_size = max_queue_size * ObSqlPlanMgr::LOW_LEVEL_EVICT_SIZE_PERCENT;
if (sql_plan_manager_->get_size_used() > high_level_evict_size) {
evict_batch_count = (sql_plan_manager_->get_size_used() - low_level_evict_size)
/ ObSqlPlanMgr::BATCH_RELEASE_COUNT;
LOG_INFO("sql plan evict record start",
"size_used",sql_plan_manager_->get_size_used(),
"mem_used", allocator->allocated());
for (int i = 0; i < evict_batch_count; i++) {
sql_plan_manager_->release_old();
}
}
//如果sql_plan_memory_limit改变, 则需要将ObConcurrentFIFOAllocator中total_limit_更新;
if (true == is_change) {
allocator->set_total_limit(config_mem_limit_);
}
int64_t end_time = ObTimeUtility::current_time();
LOG_TRACE("sql plan evict task end",
K(evict_high_level),
K(evict_batch_count),
"elapse_time", end_time - start_time,
"size_used",sql_plan_manager_->get_size_used(),
"mem_used", allocator->allocated());
}
}
} // end of namespace sql
} // end of namespace oceanbase

View File

@ -0,0 +1,204 @@
// Copyright 2010-2016 Alibaba Inc. All Rights Reserved.
// Author:
// zhenling.zzg
// this file defines interface of sql plan manager
#ifndef SRC_OBSERVER_SQL_PLAN_MGR_H_
#define SRC_OBSERVER_SQL_PLAN_MGR_H_
#include "lib/allocator/ob_concurrent_fifo_allocator.h"
#include "observer/mysql/ob_ra_queue.h"
#include "lib/task/ob_timer.h"
namespace oceanbase
{
namespace sql
{
struct ObSqlPlanItem {
ObSqlPlanItem();
virtual ~ObSqlPlanItem();
void reset();
int64_t get_extra_size() const;
int64_t plan_id_;
char* sql_id_;
int64_t sql_id_len_;
int64_t db_id_;
uint64_t plan_hash_;
int64_t gmt_create_;
char* operation_;
int64_t operation_len_;
char* options_;
int64_t options_len_;
char* object_node_;
int64_t object_node_len_;
int64_t object_id_;
char* object_owner_;
int64_t object_owner_len_;
char* object_name_;
int64_t object_name_len_;
char* object_alias_;
int64_t object_alias_len_;
char* object_type_;
int64_t object_type_len_;
char* optimizer_;
int64_t optimizer_len_;
int id_;
int parent_id_;
int depth_;
int position_;
int search_columns_;
bool is_last_child_;
int64_t cost_;
int64_t cardinality_;
int64_t bytes_;
int64_t rowset_;
char* other_tag_;
int64_t other_tag_len_;
char* partition_start_;
int64_t partition_start_len_;
char* partition_stop_;
int64_t partition_stop_len_;
int64_t partition_id_;
char* other_;
int64_t other_len_;
char* distribution_;
int64_t distribution_len_;
int64_t cpu_cost_;
int64_t io_cost_;
int64_t temp_space_;
char* access_predicates_;
int64_t access_predicates_len_;
char* filter_predicates_;
int64_t filter_predicates_len_;
char* startup_predicates_;
int64_t startup_predicates_len_;
char* projection_;
int64_t projection_len_;
char* special_predicates_;
int64_t special_predicates_len_;
int64_t time_;
char* qblock_name_;
int64_t qblock_name_len_;
char* remarks_;
int64_t remarks_len_;
char* other_xml_;
int64_t other_xml_len_;
TO_STRING_KV(
K_(plan_id)
);
};
struct ObSqlPlanItemRecord
{
ObSqlPlanItemRecord();
virtual ~ObSqlPlanItemRecord();
virtual void destroy();
TO_STRING_KV(
K_(data)
);
ObSqlPlanItem data_;
common::ObConcurrentFIFOAllocator *allocator_;
};
struct ObSqlPlanItemRecords {
void reset() { records_.reuse(); }
ObSEArray<ObSqlPlanItemRecord*, 4> records_;
};
class ObSqlPlanMgr;
class ObSqlPlanEliminateTask : public common::ObTimerTask
{
public:
ObSqlPlanEliminateTask();
virtual ~ObSqlPlanEliminateTask();
void runTimerTask();
int init(const ObSqlPlanMgr *sql_plan_manager);
int check_config_mem_limit(bool &is_change);
int calc_evict_mem_level(int64_t &low, int64_t &high);
private:
ObSqlPlanMgr *sql_plan_manager_;
int64_t config_mem_limit_;
};
class ObSqlPlanMgr
{
public:
static const int64_t SQL_PLAN_PAGE_SIZE = (1LL << 17); // 128K
//进行一次release_old操作删除的记录数
static const int32_t BATCH_RELEASE_COUNT = 5000;
static const int32_t MAX_RELEASE_TIME = 5 * 1000; //5ms
static const int64_t US_PER_HOUR = 3600000000;
//初始化queue大小为100w
static const int64_t MAX_QUEUE_SIZE = 1000000; //100w
static const int64_t MINI_MODE_MAX_QUEUE_SIZE = 100000; // 10w
//当sql_plan超过90w行记录时触发淘汰
static constexpr const double HIGH_LEVEL_EVICT_SIZE_PERCENT = 0.9;
//按行淘汰的低水位线
static constexpr const double LOW_LEVEL_EVICT_SIZE_PERCENT = 0.8;
//启动淘汰检查的时间间隔
static const int64_t EVICT_INTERVAL = 1000000; //1s
static const int64_t PLAN_TABLE_QUEUE_SIZE = 100000;
typedef common::ObRaQueue::Ref Ref;
public:
ObSqlPlanMgr();
virtual ~ObSqlPlanMgr();
int init(uint64_t tenant_id,
const int64_t queue_size);
void destroy();
int handle_plan_item(const ObSqlPlanItem &plan_item);
int get_plan(int64_t plan_id,
ObIArray<ObSqlPlanItem*> &plan);
int get_plan(const ObString &sql_id,
int64_t plan_id,
ObIArray<ObSqlPlanItem*> &plan);
int get_plan_by_hash(const ObString &sql_id,
uint64_t plan_hash,
ObIArray<ObSqlPlanItem*> &plan);
common::ObConcurrentFIFOAllocator *get_allocator();
void* alloc(const int64_t size);
void free(void *ptr);
int get(const int64_t idx, void *&record, Ref* ref);
int revert(Ref* ref);
int release_old(int64_t limit = BATCH_RELEASE_COUNT);
void clear_queue();
uint64_t get_tenant_id() const;
int64_t get_start_idx() const;
int64_t get_end_idx() const;
int64_t get_size_used();
int64_t get_capacity();
int64_t get_next_plan_id();
int64_t get_last_plan_id();
bool is_valid() const;
static int get_mem_limit(uint64_t tenant_id, int64_t &mem_limit);
static int init_plan_manager(uint64_t tenant_id, ObSqlPlanMgr* &sql_plan_mgr);
static int mtl_init(ObSqlPlanMgr* &sql_plan_mgr);
static void mtl_destroy(ObSqlPlanMgr* &sql_plan_mgr);
private:
DISALLOW_COPY_AND_ASSIGN(ObSqlPlanMgr);
private:
common::ObConcurrentFIFOAllocator allocator_;//alloc mem for string buf
ObSqlPlanEliminateTask task_;
common::ObRaQueue queue_;
int64_t plan_id_increment_;
bool destroyed_;
bool inited_;
// tenant id of this manager
uint64_t tenant_id_;
int tg_id_;
};
} // end of namespace sql
} // end of namespace oceanbase
#endif /* SRC_OBSERVER_SQL_PLAN_MGR_H_ */