/** * 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. */ #ifndef OCEANBASE_SQL_PLAN_CACHE_OB_PLAN_CACHE_ #define OCEANBASE_SQL_PLAN_CACHE_OB_PLAN_CACHE_ #include "lib/net/ob_addr.h" #include "lib/hash/ob_hashmap.h" #include "lib/alloc/alloc_func.h" #include "sql/plan_cache/ob_plan_cache_util.h" #include "sql/plan_cache/ob_id_manager_allocator.h" #include "sql/plan_cache/ob_sql_parameterization.h" #include "sql/plan_cache/ob_prepare_stmt_struct.h" #include "sql/plan_cache/ob_pc_ref_handle.h" namespace oceanbase { namespace share { class ObIPartitionLocationCache; } using common::ObPsStmtId; namespace sql { class ObPlanCacheValue; class ObPlanCacheAtomicOp; class ObPsPCVSetAtomicOp; class ObTaskExecutorCtx; class ObSqlCtx; class ObExecContext; class ObPCVSet; class ObCacheObject; class ObPhysicalPlan; enum DumpType { DUMP_SQL, DUMP_PL, DUMP_ALL }; struct ObGetAllDeletedCacheObjIdsOp { explicit ObGetAllDeletedCacheObjIdsOp( common::ObIArray* key_array, const bool dump_all, int64_t safe_timestamp, DumpType dump_type) : key_array_(key_array), dump_all_(dump_all), safe_timestamp_(safe_timestamp), dump_type_(dump_type) {} int operator()(common::hash::HashMapPair& entry); private: bool should_dump(ObCacheObjType obj_type) const { bool ret_bool = false; if (obj_type >= T_CO_MAX) { // invalid cache object should not be dumped. ret_bool = false; SQL_PC_LOG(WARN, "Invalid cache object should not be dumped"); } else if (DUMP_SQL == dump_type_) { ret_bool = (T_CO_SQL_CRSR == obj_type); } else if (DUMP_PL == dump_type_) { ret_bool = (T_CO_PRCR == obj_type || T_CO_SFC == obj_type || T_CO_PKG == obj_type || T_CO_ANON == obj_type); } else if (DUMP_ALL == dump_type_) { ret_bool = true; } else { ret_bool = false; } return ret_bool; } private: common::ObIArray* key_array_; const bool dump_all_; int64_t safe_timestamp_; DumpType dump_type_; }; class ObPlanCache { friend class ObCacheObjectFactory; public: static const int64_t MAX_PLAN_SIZE = 20 * 1024 * 1024; // 20M static const int64_t MAX_PLAN_CACHE_SIZE = 5 * 1024L * 1024L * 1024L; // 5G static const int64_t EVICT_KEY_NUM = 8; static const int64_t MAX_TENANT_MEM = ((int64_t)(1) << 40); // 1T typedef common::hash::ObHashMap PlanStatMap; typedef common::hash::ObHashMap SqlPCVSetMap; ObPlanCache(); virtual ~ObPlanCache(); int init( int64_t hash_bucket, common::ObAddr addr, share::ObIPartitionLocationCache* location_cache, uint64_t tenant_id); bool is_inited() { return inited_; } int get_plan(const CacheRefHandleID ref_handle, common::ObIAllocator& allocator, ObPlanCacheCtx& pc_ctx, ObPhysicalPlan*& plan); /** * Add new plan to PlanCache */ int add_plan(ObPhysicalPlan* plan, ObPlanCacheCtx& pc_ctx); /** * Add new ps plan to PlanCache */ template int add_ps_plan(T* plan, ObPlanCacheCtx& pc_ctx); template int get_ps_plan(const CacheRefHandleID ref_handle, const ObPsStmtId stmt_id, ObPlanCacheCtx& pc_ctx, T*& plan); /** * memory related * high water mark * low water mark * memory used */ int set_mem_conf(const ObPCMemPctConf& conf); int update_memory_conf(); int64_t get_mem_limit() const { int64_t tenant_mem = get_tenant_memory(); int64_t mem_limit = -1; if (OB_UNLIKELY(0 >= tenant_mem || tenant_mem >= MAX_TENANT_MEM)) { mem_limit = MAX_TENANT_MEM * 0.05; } else { mem_limit = get_tenant_memory() / 100 * get_mem_limit_pct(); } return mem_limit; } int64_t get_mem_high() const { return get_mem_limit() / 100 * get_mem_high_pct(); } int64_t get_mem_low() const { return get_mem_limit() / 100 * get_mem_low_pct(); } int64_t get_mem_limit_pct() const { return ATOMIC_LOAD(&mem_limit_pct_); } int64_t get_mem_high_pct() const { return ATOMIC_LOAD(&mem_high_pct_); } int64_t get_mem_low_pct() const { return ATOMIC_LOAD(&mem_low_pct_); } void set_mem_limit_pct(int64_t pct) { ATOMIC_STORE(&mem_limit_pct_, pct); } void set_mem_high_pct(int64_t pct) { ATOMIC_STORE(&mem_high_pct_, pct); } void set_mem_low_pct(int64_t pct) { ATOMIC_STORE(&mem_low_pct_, pct); } uint64_t inc_mem_used(uint64_t mem_delta) { SQL_PC_LOG(DEBUG, "before inc mem_used", K(mem_used_)); return ATOMIC_FAA((uint64_t*)&mem_used_, mem_delta); }; uint64_t dec_mem_used(uint64_t mem_delta) { SQL_PC_LOG(DEBUG, "before dec mem_used, mem_used", K(mem_used_)); return ATOMIC_FAA((uint64_t*)&mem_used_, -mem_delta); }; void inc_access_cnt() { ATOMIC_INC(&pc_stat_.access_count_); } void inc_hit_and_access_cnt() { ATOMIC_INC(&pc_stat_.hit_count_); ATOMIC_INC(&pc_stat_.access_count_); } int64_t get_mem_used() const { return mem_used_ + get_mod_hold(ObNewModIds::OB_SQL_PLAN_CACHE); } int64_t get_mem_hold() const; int64_t get_mod_hold(int mod_id) const; int64_t get_bucket_num() const { return bucket_num_; } /* * cache evict */ int cache_evict_all_plan(); int cache_evict_all_pl(); // evict plan, adjust mem between hwm and lwm int cache_evict(); // evict plan whose merged version is expired int evict_expired_plan(); bool is_valid() { return valid_; } void set_valid(bool valid) { valid_ = valid; } void destroy(); int64_t inc_ref_count(); void dec_ref_count(); common::ObAddr& get_host() { return host_; } void set_host(common::ObAddr& addr) { host_ = addr; } void set_location_cache(share::ObIPartitionLocationCache* location_cache) { location_cache_ = location_cache; } share::ObIPartitionLocationCache* get_location_cache() { return location_cache_; } int64_t get_tenant_id() const { return tenant_id_; } int64_t get_tenant_memory() const { return lib::get_tenant_memory_limit(tenant_id_); } void set_tenant_id(int64_t tenant_id) { tenant_id_ = tenant_id; } common::ObIAllocator* get_pc_allocator() { return &inner_allocator_; } common::ObIAllocator& get_pc_allocator_ref() { return inner_allocator_; } int64_t get_ref_count() const { return ref_count_; } int64_t get_sql_num() const { return sql_pcvs_map_.size(); } int64_t count() const { return sql_pcvs_map_.size(); } int64_t get_plan_num() const { return plan_stat_map_.size(); } ObPlanCacheStat& get_plan_cache_stat() { return pc_stat_; } const ObPlanCacheStat& get_plan_cache_stat() const { return pc_stat_; } PlanStatMap& get_plan_stat_map() { return plan_stat_map_; } int ref_cache_obj(const ObCacheObjID obj_id, const CacheRefHandleID ref_handle, ObCacheObject*& cache_obj); int ref_plan(const ObCacheObjID obj_id, const CacheRefHandleID ref_handle, ObPhysicalPlan*& plan); int remove_cache_obj_stat_entry(const ObCacheObjID cache_obj_id); uint64_t allocate_plan_id() { return __sync_add_and_fetch(&plan_id_, 1); } int add_exists_pcv_set_by_new_stmt_id(ObCacheObject* cache_obj, ObPlanCacheCtx& pc_ctx); int add_exists_pcv_set_by_sql(ObCacheObject* cache_obj, ObPlanCacheCtx& pc_ctx); static int construct_fast_parser_result(common::ObIAllocator& allocator, ObPlanCacheCtx& pc_ctx, const common::ObString& raw_sql, ObFastParserResult& fp_result); static int construct_multi_stmt_fast_parser_result(common::ObIAllocator& allocator, ObPlanCacheCtx& pc_ctx); PlanStatMap& get_deleted_map() { return deleted_map_; } int dump_all_objs() const; template int dump_deleted_objs(common::ObIArray& deleted_objs, const int64_t safe_timestamp) const; common::ObMemAttr get_mem_attr() { common::ObMemAttr attr; attr.label_ = ObNewModIds::OB_SQL_PLAN_CACHE; attr.tenant_id_ = tenant_id_; attr.ctx_id_ = ObCtxIds::PLAN_CACHE_CTX_ID; return attr; } TO_STRING_KV(K_(tenant_id), K_(mem_limit_pct), K_(mem_high_pct), K_(mem_low_pct)); ObCacheRefHandleMgr& get_ref_handle_mgr() { return ref_handle_mgr_; } const ObCacheRefHandleMgr& get_ref_handle_mgr() const { return ref_handle_mgr_; } private: DISALLOW_COPY_AND_ASSIGN(ObPlanCache); int add_cache_obj(ObCacheObject* plan, ObPlanCacheCtx& pc_ctx); int get_cache_obj(ObPlanCacheCtx& pc_ctx, ObCacheObject*& cache_obj); int get_value(const ObPlanCacheKey key, ObPCVSet*& pcv_set, ObPlanCacheAtomicOp& op); int add_cache_obj_stat(ObPlanCacheCtx& pc_ctx, ObCacheObject* plan); bool calc_evict_num(int64_t& plan_cache_evict_num); int calc_evict_keys(int64_t evict_num, PCKeyValueArray& to_evict_keys); int remove_pcv_set(const ObPlanCacheKey& key); int remove_pcv_sets(common::ObIArray& to_evict); bool is_reach_memory_limit() { return get_mem_hold() > get_mem_limit(); } int construct_plan_cache_key(ObPlanCacheCtx& plan_ctx, ObjNameSpace ns); static int construct_plan_cache_key(ObSQLSessionInfo& session, ObjNameSpace ns, ObPlanCacheKey& pc_key); /** * @brief wether jit compilation is needed in this sql * */ int add_stat_for_cache_obj(ObPlanCacheCtx& pc_ctx, ObCacheObject* cache_obj); int create_pcv_set_and_add_plan(ObCacheObject* cache_obj, ObPlanCacheCtx& pc_ctx, ObPCVSet*& pcv_set); int deal_add_ps_plan_result(int add_plan_ret, ObPlanCacheCtx& pc_ctx, const ObCacheObject& cache_object); int get_pl_cache(ObPlanCacheCtx& pc_ctx, ObCacheObject*& cache_obj); private: const static int64_t SLICE_SIZE = 1024; // 1k private: bool inited_; bool valid_; int64_t tenant_id_; int64_t mem_limit_pct_; int64_t mem_high_pct_; // high water mark percentage int64_t mem_low_pct_; // low water mark percentage int64_t mem_used_; // mem used now int64_t bucket_num_; // parameterized_sql --> pcv_set SqlPCVSetMap sql_pcvs_map_; common::ObMalloc inner_allocator_; // used for stmtkey and pre_calc_expr deep copy common::ObAddr host_; share::ObIPartitionLocationCache* location_cache_; ObPlanCacheStat pc_stat_; PlanStatMap deleted_map_; // use map for iterating in virtual table. PlanStatMap plan_stat_map_; // used for gen cache obj ids volatile ObCacheObjID plan_id_; volatile int64_t ref_count_; // ObSqlParameterization sql_parameterization_; // ref handle infos ObCacheRefHandleMgr ref_handle_mgr_; }; } // end namespace sql } // end namespace oceanbase #endif /* _OB_PLAN_CACHE_H */