Fix the core caused by plan cache double free

This commit is contained in:
obdev
2023-04-20 11:15:53 +00:00
committed by ob-robot
parent 0dbff9d9b9
commit 2657770e7f
5 changed files with 89 additions and 84 deletions

View File

@ -469,7 +469,7 @@ int ObPlanCache::get_plan(common::ObIAllocator &allocator,
}
if (OB_SUCC(ret)) {
if (OB_FAIL(get_plan_cache(pc_ctx, guard))) {
SQL_PC_LOG(DEBUG, "failed to get plan", K(ret));
SQL_PC_LOG(TRACE, "failed to get plan", K(ret), K(pc_ctx.fp_result_.pc_key_));
} else if (OB_ISNULL(guard.cache_obj_)
|| ObLibCacheNameSpace::NS_CRSR != guard.cache_obj_->get_ns()) {
ret = OB_ERR_UNEXPECTED;
@ -671,11 +671,11 @@ int ObPlanCache::get_plan_cache(ObILibCacheCtx &ctx,
ObPlanCacheCtx &pc_ctx = static_cast<ObPlanCacheCtx&>(ctx);
pc_ctx.key_ = &(pc_ctx.fp_result_.pc_key_);
if (OB_FAIL(get_cache_obj(ctx, pc_ctx.key_, guard))) {
SQL_PC_LOG(DEBUG, "failed to get plan", K(ret));
SQL_PC_LOG(TRACE, "failed to get plan", K(ret), K(pc_ctx.key_));
}
// check the returned error code and whether the plan has expired
if (OB_FAIL(check_after_get_plan(ret, ctx, guard.cache_obj_))) {
SQL_PC_LOG(DEBUG, "failed to check after get plan", K(ret));
SQL_PC_LOG(TRACE, "failed to check after get plan", K(ret));
}
if (OB_FAIL(ret) && OB_NOT_NULL(guard.cache_obj_)) {
co_mgr_.free(guard.cache_obj_, guard.ref_handle_);
@ -699,7 +699,7 @@ int ObPlanCache::add_cache_obj(ObILibCacheCtx &ctx,
SQL_PC_LOG(ERROR, "unmatched tenant_id", K(ret), K(get_tenant_id()), K(cache_obj->get_tenant_id()));
} else if (OB_FAIL(get_value(key, cache_node, w_ref_lock /*write locked*/))) {
ret = OB_ERR_UNEXPECTED;
SQL_PC_LOG(DEBUG, "failed to get cache node from lib cache by key", K(ret));
SQL_PC_LOG(TRACE, "failed to get cache node from lib cache by key", K(ret));
} else if (NULL == cache_node) {
ObILibCacheKey *cache_key = NULL;
//create node, init node, and add cache obj
@ -730,7 +730,7 @@ int ObPlanCache::add_cache_obj(ObILibCacheCtx &ctx,
SQL_PC_LOG(TRACE, "fail to add cache obj", K(ret), K(cache_obj));
}
} else if (OB_SUCCESS == hash_err) {
SQL_PC_LOG(DEBUG, "succeed to set node to key_node_map");
SQL_PC_LOG(TRACE, "succeed to set node to key_node_map");
/* stat must be added after set_refactored is successful, otherwise the following may occur:
* Thread A Thread B
* create_node_and_add_cache_obj
@ -780,7 +780,7 @@ int ObPlanCache::add_cache_obj(ObILibCacheCtx &ctx,
} else { /* node exist, add cache obj to it */
LOG_TRACE("inner add cache obj", K(key), K(cache_node));
if (OB_FAIL(cache_node->add_cache_obj(ctx, key, cache_obj))) {
SQL_PC_LOG(DEBUG, "failed to add cache obj to lib cache node", K(ret));
SQL_PC_LOG(TRACE, "failed to add cache obj to lib cache node", K(ret));
} else if (OB_FAIL(cache_node->update_node_stat(ctx))) {
SQL_PC_LOG(WARN, "failed to update node stat", K(ret));
} else if (OB_FAIL(add_stat_for_cache_obj(ctx, cache_obj))) {
@ -807,21 +807,21 @@ int ObPlanCache::get_cache_obj(ObILibCacheCtx &ctx,
SQL_PC_LOG(WARN, "invalid null argument", K(ret), K(key));
} else if (OB_FAIL(get_value(key, cache_node, r_ref_lock /*read locked*/))) {
ret = OB_ERR_UNEXPECTED;
SQL_PC_LOG(DEBUG, "failed to get cache node from lib cache by key", K(ret));
SQL_PC_LOG(TRACE, "failed to get cache node from lib cache by key", K(ret));
} else if (OB_UNLIKELY(NULL == cache_node)) {
ret = OB_SQL_PC_NOT_EXIST;
SQL_PC_LOG(DEBUG, "cache obj does not exist!", K(key));
SQL_PC_LOG(TRACE, "cache obj does not exist!", K(key));
} else {
LOG_DEBUG("inner_get_cache_obj", K(key), K(cache_node));
LOG_TRACE("inner_get_cache_obj", K(key), K(cache_node));
if (OB_FAIL(cache_node->update_node_stat(ctx))) {
SQL_PC_LOG(WARN, "failed to update node stat", K(ret));
} else if (OB_FAIL(cache_node->get_cache_obj(ctx, key, cache_obj))) {
if (OB_SQL_PC_NOT_EXIST != ret) {
LOG_DEBUG("cache_node fail to get cache obj", K(ret));
LOG_TRACE("cache_node fail to get cache obj", K(ret));
}
} else {
guard.cache_obj_ = cache_obj;
LOG_DEBUG("succ to get cache obj", KPC(key));
LOG_TRACE("succ to get cache obj", KPC(key));
}
// release lock whatever
(void)cache_node->unlock();
@ -845,7 +845,7 @@ int ObPlanCache::cache_node_exists(ObILibCacheKey* key,
SQL_PC_LOG(WARN, "invalid null argument", K(ret), K(key));
} else if (OB_FAIL(get_value(key, cache_node, r_ref_lock /*read locked*/))) {
ret = OB_ERR_UNEXPECTED;
SQL_PC_LOG(DEBUG, "failed to get cache node from lib cache by key", K(ret));
SQL_PC_LOG(TRACE, "failed to get cache node from lib cache by key", K(ret));
} else if (OB_UNLIKELY(NULL == cache_node)) {
is_exists = false;
} else {
@ -869,12 +869,12 @@ int ObPlanCache::get_value(ObILibCacheKey *key,
case OB_SUCCESS: {
//get node and lock
if (OB_FAIL(op.get_value(node))) {
SQL_PC_LOG(DEBUG, "failed to lock cache node", K(ret), KPC(key));
SQL_PC_LOG(TRACE, "failed to lock cache node", K(ret), KPC(key));
}
break;
}
case OB_HASH_NOT_EXIST: { //返回时 node = NULL; ret = OB_SUCCESS;
SQL_PC_LOG(DEBUG, "entry does not exist.", KPC(key));
SQL_PC_LOG(TRACE, "entry does not exist.", KPC(key));
break;
}
default: {
@ -910,11 +910,13 @@ int ObPlanCache::foreach_cache_evict(CallBack &cb)
} else if (OB_FAIL(batch_remove_cache_node(*to_evict_list))) {
SQL_PC_LOG(WARN, "failed to remove lib cache node", K(ret));
}
//decrement reference count
int64_t N = to_evict_list->count();
for (int64_t i = 0; OB_SUCC(ret) && i < N; i++) {
if (NULL != to_evict_list->at(i).node_) {
to_evict_list->at(i).node_->dec_ref_count(cb.get_ref_handle());
if (OB_NOT_NULL(to_evict_list)) {
//decrement reference count
int64_t N = to_evict_list->count();
for (int64_t i = 0; OB_SUCC(ret) && i < N; i++) {
if (NULL != to_evict_list->at(i).node_) {
to_evict_list->at(i).node_->dec_ref_count(cb.get_ref_handle());
}
}
}
return ret;
@ -926,26 +928,26 @@ template int ObPlanCache::foreach_cache_evict<pl::ObGetPLKVEntryOp>(pl::ObGetPLK
int ObPlanCache::cache_evict_all_obj()
{
int ret = OB_SUCCESS;
SQL_PC_LOG(DEBUG, "cache evict all plan start");
SQL_PC_LOG(TRACE, "cache evict all plan start");
LCKeyValueArray to_evict_keys;
ObKVEntryTraverseOp get_ids_op(&to_evict_keys, PCV_GET_PLAN_KEY_HANDLE);
if (OB_FAIL(foreach_cache_evict(get_ids_op))) {
SQL_PC_LOG(WARN, "failed to foreach cache evict", K(ret));
}
SQL_PC_LOG(DEBUG, "cache evict all plan end");
SQL_PC_LOG(TRACE, "cache evict all plan end");
return ret;
}
int ObPlanCache::cache_evict_by_ns(ObLibCacheNameSpace ns)
{
int ret = OB_SUCCESS;
SQL_PC_LOG(DEBUG, "cache evict all obj by ns start");
SQL_PC_LOG(TRACE, "cache evict all obj by ns start");
LCKeyValueArray to_evict_keys;
ObGetKVEntryByNsOp get_ids_op(ns, &to_evict_keys, PCV_GET_PLAN_KEY_HANDLE);
if (OB_FAIL(foreach_cache_evict(get_ids_op))) {
SQL_PC_LOG(WARN, "failed to foreach cache evict", K(ret));
}
SQL_PC_LOG(DEBUG, "cache evict all obj by ns end");
SQL_PC_LOG(TRACE, "cache evict all obj by ns end");
return ret;
}
@ -963,13 +965,13 @@ int ObPlanCache::cache_evict_all_plan()
int ObPlanCache::cache_evict_plan_by_sql_id(uint64_t db_id, common::ObString sql_id)
{
int ret = OB_SUCCESS;
SQL_PC_LOG(DEBUG, "cache evict plan by sql id start");
SQL_PC_LOG(TRACE, "cache evict plan by sql id start");
LCKeyValueArray to_evict_keys;
ObGetKVEntryBySQLIDOp get_ids_op(db_id, sql_id, &to_evict_keys, PCV_GET_PLAN_KEY_HANDLE);
if (OB_FAIL(foreach_cache_evict(get_ids_op))) {
SQL_PC_LOG(WARN, "failed to foreach cache evict", K(ret));
}
SQL_PC_LOG(DEBUG, "cache evict plan by sql id end");
SQL_PC_LOG(TRACE, "cache evict plan by sql id end");
return ret;
}
@ -979,13 +981,13 @@ int ObPlanCache::evict_plan_by_table_name(uint64_t database_id, ObString tab_nam
int ret = OB_SUCCESS;
observer::ObReqTimeGuard req_timeinfo_guard;
ObGlobalReqTimeService::check_req_timeinfo();
SQL_PC_LOG(DEBUG, "cache evict plan by table name start");
SQL_PC_LOG(TRACE, "cache evict plan by table name start");
LCKeyValueArray to_evict_keys;
ObGetPcvSetByTabNameOp get_ids_op(database_id, tab_name, &to_evict_keys, PCV_GET_PLAN_KEY_HANDLE);
if (OB_FAIL(foreach_cache_evict(get_ids_op))) {
SQL_PC_LOG(WARN, "failed to foreach cache evict", K(ret));
}
SQL_PC_LOG(DEBUG, "cache evict plan baseline by sql id end");
SQL_PC_LOG(TRACE, "cache evict plan baseline by sql id end");
return ret;
}
@ -1253,7 +1255,7 @@ int ObPlanCache::add_cache_obj_stat(ObILibCacheCtx &ctx, ObILibCacheObject *cach
co_mgr_.free(cache_obj, LC_REF_CACHE_OBJ_STAT_HANDLE);
cache_obj = NULL;
} else {
LOG_DEBUG("succeeded to add cache object stat", K(cache_obj->get_object_id()), K(cache_obj));
LOG_TRACE("succeeded to add cache object stat", K(cache_obj->get_object_id()), K(cache_obj));
}
}
return ret;
@ -1453,7 +1455,7 @@ int ObPlanCache::add_ps_plan(T *plan, ObPlanCacheCtx &pc_ctx)
SQL_PC_LOG(WARN, "invalid physical plan", K(ret));
} else if (is_reach_memory_limit()) {
ret = OB_REACH_MEMORY_LIMIT;
SQL_PC_LOG(DEBUG, "plan cache memory used reach the high water mark",
SQL_PC_LOG(TRACE, "plan cache memory used reach the high water mark",
K(mem_used_), K(get_mem_limit()), K(ret));
} else if (plan->get_mem_size() >= get_mem_high()) {
// plan mem is too big to reach memory highwater, do not add plan
@ -1493,7 +1495,7 @@ int ObPlanCache::add_exists_cache_obj_by_sql(ObILibCacheCtx &ctx,
pc_ctx.need_add_obj_stat_ = false;
uint64_t old_stmt_id = pc_ctx.fp_result_.pc_key_.key_id_;
pc_ctx.fp_result_.pc_key_.key_id_ = OB_INVALID_ID;
SQL_PC_LOG(DEBUG, "start to add ps plan by sql", K(pc_ctx.fp_result_.pc_key_));
SQL_PC_LOG(TRACE, "start to add ps plan by sql", K(pc_ctx.fp_result_.pc_key_));
if (OB_FAIL(add_plan_cache(pc_ctx, cache_obj))) {
if (OB_FAIL(deal_add_ps_plan_result(ret, pc_ctx, *cache_obj))) {
LOG_WARN("fail to deal result code", K(ret));
@ -1515,7 +1517,7 @@ int ObPlanCache::deal_add_ps_plan_result(int add_plan_ret,
int ret = add_plan_ret;
if (OB_SQL_PC_PLAN_DUPLICATE == ret) {
ret = OB_SUCCESS;
LOG_DEBUG("this plan has been added by others, need not add again", K(cache_object));
LOG_TRACE("this plan has been added by others, need not add again", K(cache_object));
} else if (OB_REACH_MEMORY_LIMIT == ret || OB_SQL_PC_PLAN_SIZE_LIMIT == ret) {
if (REACH_TIME_INTERVAL(1000000)) { //1s, 当内存达到上限时, 该日志打印会比较频繁, 所以以1s为间隔打印
ObTruncatedString trunc_sql(pc_ctx.raw_sql_);
@ -1526,7 +1528,7 @@ int ObPlanCache::deal_add_ps_plan_result(int add_plan_ret,
ret = OB_SUCCESS;
} else if (is_not_supported_err(ret)) {
ret = OB_SUCCESS;
LOG_DEBUG("plan cache don't support add this kind of plan now", K(cache_object));
LOG_TRACE("plan cache don't support add this kind of plan now", K(cache_object));
} else if (OB_FAIL(ret)) {
if (OB_REACH_MAX_CONCURRENT_NUM != ret) { //如果是达到限流上限, 则将错误码抛出去
ret = OB_SUCCESS; //add plan出错, 覆盖错误码, 确保因plan cache失败不影响正常执行路径
@ -1534,7 +1536,7 @@ int ObPlanCache::deal_add_ps_plan_result(int add_plan_ret,
}
} else {
pc_ctx.sql_ctx_.self_add_plan_ = true;
LOG_DEBUG("Successed to add plan to ObPlanCache", K(cache_object));
LOG_TRACE("Successed to add plan to ObPlanCache", K(cache_object));
}
return ret;
@ -1559,7 +1561,7 @@ int ObPlanCache::add_exists_cache_obj_by_stmt_id(ObILibCacheCtx &ctx,
ret = OB_ERR_UNEXPECTED;
SQL_PC_LOG(WARN, "convert cache_obj to ObPhysicalPlan failed", K(ret));
} else {
SQL_PC_LOG(DEBUG, "ps_stmt_id changed", K(plan->stat_.ps_stmt_id_), K(new_stmt_id));
SQL_PC_LOG(TRACE, "ps_stmt_id changed", K(plan->stat_.ps_stmt_id_), K(new_stmt_id));
plan->stat_.ps_stmt_id_ = new_stmt_id;
}
} else {
@ -1708,13 +1710,13 @@ int ObPlanCache::get_ps_plan(ObCacheObjGuard& guard,
pc_ctx.fp_result_.pc_key_.name_ = pc_ctx.raw_sql_;
if (OB_FAIL(get_plan_cache(pc_ctx, guard))) {
if (OB_OLD_SCHEMA_VERSION == ret) {
SQL_PC_LOG(DEBUG, "get cache obj by sql failed because of old_schema_version",
SQL_PC_LOG(TRACE, "get cache obj by sql failed because of old_schema_version",
K(ret), K(pc_ctx.raw_sql_), K(new_stmt_id), K(cache_key_node_map_.size()));
} else {
SQL_PC_LOG(DEBUG, "get cache obj by sql failed",
SQL_PC_LOG(TRACE, "get cache obj by sql failed",
K(ret), K(pc_ctx.raw_sql_), K(new_stmt_id), K(cache_key_node_map_.size()));
}
SQL_PC_LOG(DEBUG, "fail to get plan", K(ret));
SQL_PC_LOG(TRACE, "fail to get plan", K(ret));
} else if (OB_ISNULL(guard.cache_obj_) || OB_UNLIKELY(!guard.cache_obj_->is_valid_cache_obj())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cache obj is invalid", K(ret), KPC(guard.cache_obj_));
@ -1797,7 +1799,7 @@ int ObPlanCache::need_late_compile(ObPhysicalPlan *plan,
need_late_compilation = false;
}
}
LOG_DEBUG("will use late compilation", K(need_late_compilation));
LOG_TRACE("will use late compilation", K(need_late_compilation));
return ret;
}