init push
This commit is contained in:
229
src/sql/plan_cache/ob_cache_object_factory.cpp
Normal file
229
src/sql/plan_cache/ob_cache_object_factory.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OceanBase
|
||||
* OceanBase CE is licensed under Mulan PubL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
||||
* You may obtain a copy of Mulan PubL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPubL-2.0
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PubL v2 for more details.
|
||||
*/
|
||||
|
||||
#define USING_LOG_PREFIX SQL_PC
|
||||
|
||||
#include "sql/plan_cache/ob_cache_object_factory.h"
|
||||
#include "sql/engine/ob_physical_plan.h"
|
||||
#include "sql/ob_sql.h"
|
||||
#include "sql/plan_cache/ob_plan_cache.h"
|
||||
#include "lib/alloc/malloc_hook.h"
|
||||
#include "lib/allocator/page_arena.h"
|
||||
#include "lib/allocator/ob_malloc.h"
|
||||
#include "observer/ob_server_struct.h"
|
||||
#include "observer/ob_req_time_service.h"
|
||||
|
||||
namespace oceanbase {
|
||||
using namespace common;
|
||||
using namespace lib;
|
||||
namespace sql {
|
||||
|
||||
int ObCacheObjectFactory::alloc(ObPhysicalPlan*& plan, const CacheRefHandleID ref_handle, uint64_t tenant_id)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObCacheObject* cache_obj = NULL;
|
||||
if (OB_FAIL(alloc(cache_obj, ref_handle, T_CO_SQL_CRSR, tenant_id))) {
|
||||
LOG_WARN("alloc physical plan failed", K(ret), K(tenant_id));
|
||||
} else if (OB_ISNULL(cache_obj) || OB_UNLIKELY(!cache_obj->is_sql_crsr())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("cache object is invalid", KPC(cache_obj));
|
||||
} else {
|
||||
plan = static_cast<ObPhysicalPlan*>(cache_obj);
|
||||
}
|
||||
if (OB_FAIL(ret) && cache_obj != NULL) {
|
||||
ObCacheObjectFactory::free(cache_obj, ref_handle);
|
||||
cache_obj = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObCacheObjectFactory::alloc(
|
||||
ObCacheObject*& cache_obj, const CacheRefHandleID ref_handle, ObCacheObjType co_type, uint64_t tenant_id)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
void* buf = NULL;
|
||||
observer::ObGlobalReqTimeService::check_req_timeinfo();
|
||||
ObMemAttr mem_attr;
|
||||
mem_attr.tenant_id_ = tenant_id;
|
||||
ObPlanCache* plan_cache = get_plan_cache(tenant_id);
|
||||
if (T_CO_PRCR == co_type || T_CO_PKG == co_type || T_CO_ANON == co_type) {
|
||||
mem_attr.label_ = ObNewModIds::OB_SQL_PHY_PL_OBJ;
|
||||
} else {
|
||||
mem_attr.label_ = ObNewModIds::OB_SQL_PHY_PLAN;
|
||||
}
|
||||
mem_attr.ctx_id_ = ObCtxIds::PLAN_CACHE_CTX_ID;
|
||||
MemoryContext* entity = NULL;
|
||||
|
||||
if (OB_UNLIKELY(co_type < T_CO_SQL_CRSR) || OB_UNLIKELY(co_type >= T_CO_MAX) || OB_ISNULL(plan_cache)) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("co_type is invalid", K(co_type), K(plan_cache), K(tenant_id));
|
||||
} else if (OB_FAIL(ROOT_CONTEXT.CREATE_CONTEXT(entity, lib::ContextParam().set_mem_attr(mem_attr)))) {
|
||||
LOG_WARN("create entity failed", K(ret), K(mem_attr));
|
||||
} else if (NULL == entity) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("NULL memory entity", K(ret));
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
WITH_CONTEXT(entity)
|
||||
{
|
||||
switch (co_type) {
|
||||
case T_CO_SQL_CRSR:
|
||||
if (NULL != (buf = entity->get_arena_allocator().alloc(sizeof(ObPhysicalPlan)))) {
|
||||
cache_obj = new (buf) ObPhysicalPlan(*entity);
|
||||
}
|
||||
break;
|
||||
case T_CO_ANON:
|
||||
case T_CO_PRCR:
|
||||
case T_CO_PKG:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
if (OB_ISNULL(buf)) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
OB_LOG(ERROR, "fail to alloc cache obj", K(ret), KP(buf), K(co_type));
|
||||
} else {
|
||||
cache_obj->set_tenant_id(tenant_id);
|
||||
uint64_t cache_obj_id = plan_cache->allocate_plan_id();
|
||||
cache_obj->object_id_ = cache_obj_id;
|
||||
|
||||
cache_obj->inc_ref_count(ref_handle);
|
||||
/*
|
||||
* to deconstruct the CacheObject object, you must first remove the corresponding kv pair from the deleted_map,
|
||||
* then the atomicity of hashmap can ensure that only one thread does the removal action, and
|
||||
* only this thread gets the CacheObject pointer to do subsequent destructuring
|
||||
*/
|
||||
if (OB_FAIL(plan_cache->get_deleted_map().set_refactored(cache_obj_id, cache_obj))) {
|
||||
LOG_WARN("failed to add element to hashmap", K(ret));
|
||||
inner_free(cache_obj);
|
||||
cache_obj = NULL;
|
||||
entity = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_FAIL(ret) && NULL != entity) {
|
||||
DESTROY_CONTEXT(entity);
|
||||
entity = NULL;
|
||||
}
|
||||
if (NULL != plan_cache) {
|
||||
plan_cache->dec_ref_count();
|
||||
plan_cache = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ObCacheObjectFactory::common_free(ObCacheObject* cache_obj, const CacheRefHandleID ref_handle)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (OB_ISNULL(cache_obj)) {
|
||||
// nothing to do
|
||||
} else {
|
||||
int64_t ref_count = cache_obj->dec_ref_count(ref_handle);
|
||||
if (ref_count > 0) {
|
||||
if (!cache_obj->added_pc()) {
|
||||
cache_obj->set_logical_del_time(ObTimeUtility::current_monotonic_time());
|
||||
LOG_WARN("set logical del time",
|
||||
K(cache_obj->get_logical_del_time()),
|
||||
K(cache_obj->added_pc()),
|
||||
K(cache_obj->get_object_id()),
|
||||
K(cache_obj->get_tenant_id()),
|
||||
K(lbt()));
|
||||
}
|
||||
} else if (ref_count == 0) {
|
||||
uint64_t tenant_id = cache_obj->get_tenant_id();
|
||||
ObPlanCache* plan_cache = get_plan_cache(tenant_id);
|
||||
|
||||
if (cache_obj->get_pre_calc_expr_handler() != NULL) {
|
||||
LOG_DEBUG("dec pre calculabe expression.",
|
||||
KP(cache_obj->get_pre_calc_expr_handler()),
|
||||
KP(cache_obj),
|
||||
K(cache_obj->get_pre_expr_ref_count()));
|
||||
}
|
||||
// decrease reference and remove it when reference count is ZERO.
|
||||
cache_obj->dec_pre_expr_ref_count();
|
||||
|
||||
if (OB_FAIL(ret)) {
|
||||
// do nothing
|
||||
} else if (OB_ISNULL(plan_cache)) {
|
||||
// if plan cache is marked by destroyed_, this is not a ERROR.
|
||||
LOG_WARN("invalid null plan cache", K(ret), K(tenant_id));
|
||||
} else if (OB_FAIL(destroy_cache_obj(false, cache_obj->get_object_id(), plan_cache))) {
|
||||
LOG_WARN("failed to destroy cache obj", K(ret));
|
||||
}
|
||||
if (NULL != plan_cache) {
|
||||
plan_cache->dec_ref_count();
|
||||
plan_cache = NULL;
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("invalid plan ref count", K(ref_count), KP(cache_obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObCacheObjectFactory::inner_free(ObCacheObject* cache_obj)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
|
||||
MemoryContext& entity = cache_obj->get_mem_context();
|
||||
WITH_CONTEXT(&entity)
|
||||
{
|
||||
cache_obj->~ObCacheObject();
|
||||
}
|
||||
cache_obj = NULL;
|
||||
DESTROY_CONTEXT(&entity);
|
||||
}
|
||||
|
||||
ObPlanCache* ObCacheObjectFactory::get_plan_cache(const uint64_t tenant_id)
|
||||
{
|
||||
ObPlanCache* ret_pc = NULL;
|
||||
uint64_t used_tenant_id = tenant_id;
|
||||
ObPCMemPctConf default_conf;
|
||||
if (tenant_id > OB_SYS_TENANT_ID && tenant_id <= OB_MAX_RESERVED_TENANT_ID) {
|
||||
used_tenant_id = OB_SYS_TENANT_ID;
|
||||
}
|
||||
if (OB_ISNULL(GCTX.sql_engine_) || OB_ISNULL(GCTX.sql_engine_->get_plan_cache_manager())) {
|
||||
LOG_WARN("invalid null sql engine", K(GCTX.sql_engine_));
|
||||
} else {
|
||||
ret_pc = GCTX.sql_engine_->get_plan_cache_manager()->get_or_create_plan_cache(used_tenant_id, default_conf);
|
||||
}
|
||||
return ret_pc;
|
||||
}
|
||||
|
||||
int ObCacheObjectFactory::destroy_cache_obj(const bool is_leaked, const uint64_t obj_id, ObPlanCache* plan_cache)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObCacheObject* to_del_obj;
|
||||
if (OB_ISNULL(plan_cache)) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("invalid argument", K(ret), K(plan_cache));
|
||||
} else if (OB_FAIL(plan_cache->get_deleted_map().erase_refactored(obj_id, &to_del_obj))) {
|
||||
if (OB_HASH_NOT_EXIST == ret) {
|
||||
ret = OB_SUCCESS;
|
||||
} else {
|
||||
LOG_WARN("failed to erase element from deleted map", K(obj_id), K(ret));
|
||||
}
|
||||
} else if (OB_ISNULL(to_del_obj)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("invalid cache obj", K(to_del_obj));
|
||||
} else {
|
||||
to_del_obj->dump_deleted_log_info(!is_leaked);
|
||||
inner_free(to_del_obj);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
} // end namespace sql
|
||||
} // namespace oceanbase
|
||||
Reference in New Issue
Block a user