[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:
@ -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;
|
||||
@ -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():
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
|
||||
211
src/sql/monitor/flt/ob_flt_span_mgr.cpp
Normal file
211
src/sql/monitor/flt/ob_flt_span_mgr.cpp
Normal 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
|
||||
232
src/sql/monitor/flt/ob_flt_span_mgr.h
Normal file
232
src/sql/monitor/flt/ob_flt_span_mgr.h
Normal 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
|
||||
571
src/sql/monitor/flt/ob_flt_utils.cpp
Normal file
571
src/sql/monitor/flt/ob_flt_utils.cpp
Normal 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
|
||||
80
src/sql/monitor/flt/ob_flt_utils.h
Normal file
80
src/sql/monitor/flt/ob_flt_utils.h
Normal 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
|
||||
522
src/sql/monitor/ob_plan_real_info_manager.cpp
Normal file
522
src/sql/monitor/ob_plan_real_info_manager.cpp
Normal 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
|
||||
148
src/sql/monitor/ob_plan_real_info_manager.h
Normal file
148
src/sql/monitor/ob_plan_real_info_manager.h
Normal 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_ */
|
||||
2064
src/sql/monitor/ob_sql_plan.cpp
Normal file
2064
src/sql/monitor/ob_sql_plan.cpp
Normal file
File diff suppressed because it is too large
Load Diff
290
src/sql/monitor/ob_sql_plan.h
Normal file
290
src/sql/monitor/ob_sql_plan.h
Normal 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_ */
|
||||
730
src/sql/monitor/ob_sql_plan_manager.cpp
Normal file
730
src/sql/monitor/ob_sql_plan_manager.cpp
Normal 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
|
||||
204
src/sql/monitor/ob_sql_plan_manager.h
Normal file
204
src/sql/monitor/ob_sql_plan_manager.h
Normal 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_ */
|
||||
Reference in New Issue
Block a user