/** * 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. */ #include #include "lib/utility/ob_print_utils.h" #include "lib/alloc/malloc_hook.h" #include "share/ob_tenant_mgr.h" #include "share/rc/ob_context.h" #include "observer/ob_server_struct.h" #include "storage/ob_partition_service.h" #include "lib/resource/ob_resource_mgr.h" #include "lib/alloc/ob_malloc_allocator.h" #include "share/ob_srv_rpc_proxy.h" #include "share/allocator/ob_memstore_allocator_mgr.h" #include "observer/ob_server_event_history_table_operator.h" #include "observer/ob_server.h" int64_t get_virtual_memory_used() { constexpr int BUFFER_SIZE = 128; char filename[BUFFER_SIZE]; int64_t page_cnt = 0; snprintf(filename, BUFFER_SIZE, "/proc/%d/statm", getpid()); FILE* statm = fopen(filename, "r"); fscanf(statm, "%ld", &page_cnt); fclose(statm); return page_cnt * sysconf(_SC_PAGESIZE); } namespace oceanbase { namespace obrpc { using namespace oceanbase::common; using namespace oceanbase::lib; using namespace oceanbase::share; typedef ObMemstoreAllocatorMgr::TAllocator ObTenantMemstoreAllocator; DEF_TO_STRING(ObTenantFreezeArg) { int64_t pos = 0; J_KV(K_(tenant_id), K_(freeze_type)); return pos; } OB_SERIALIZE_MEMBER(ObTenantFreezeArg, tenant_id_, freeze_type_, try_frozen_version_); int ObTenantMgrRpcCb::process() { int ret = OB_SUCCESS; if (OB_FAIL(ObTenantManager::get_instance().rpc_callback())) { COMMON_LOG(WARN, "rpc callback failed", K(ret)); } return ret; } void ObTenantMgrRpcCb::on_timeout() { int ret = OB_SUCCESS; COMMON_LOG(INFO, "Tenant mgr major freeze request timeout"); if (OB_FAIL(ObTenantManager::get_instance().rpc_callback())) { COMMON_LOG(WARN, "rpc callback failed", K(ret)); } } int64_t ObTenantMgrP::minor_freeze_token_ = ObTenantMgrP::MAX_CONCURRENT_MINOR_FREEZING; int ObTenantMgrP::process() { int ret = OB_SUCCESS; ObTenantManager& tenant_mgr = ObTenantManager::get_instance(); if (storage::MINOR_FREEZE == arg_.freeze_type_) { // get freeze token int64_t oldv = ATOMIC_LOAD(&minor_freeze_token_); bool finish = false; while (oldv > 0 && !finish) { int64_t newv = oldv - 1; finish = (oldv == (newv = ATOMIC_VCAS(&minor_freeze_token_, oldv, newv))); oldv = newv; } if (!finish) { COMMON_LOG( INFO, "fail to do minor freeze due to no token left", "tenant_id", arg_.tenant_id_, K_(minor_freeze_token)); } else { bool marked = false; // set freezing mark for tenant if (OB_FAIL(tenant_mgr.set_tenant_freezing(arg_.tenant_id_, marked))) { COMMON_LOG(WARN, "fail to set tenant freezing", K_(arg), K(ret)); } else if (marked) { bool rollback_freeze_cnt = false; if (OB_FAIL(partition_service_->minor_freeze(arg_.tenant_id_))) { rollback_freeze_cnt = true; COMMON_LOG(WARN, "fail to minor freeze", K_(arg), K(ret)); } else { COMMON_LOG(INFO, "finish tenant minor freeze", K_(arg), K(ret)); } // clear freezing mark for tenant int tmp_ret = OB_SUCCESS; if (OB_UNLIKELY( OB_SUCCESS != (tmp_ret = tenant_mgr.unset_tenant_freezing(arg_.tenant_id_, rollback_freeze_cnt)))) { COMMON_LOG(WARN, "unset tenant freezing mark failed", K_(arg), K(tmp_ret)); if (OB_SUCC(ret)) { ret = tmp_ret; } } } else { COMMON_LOG(WARN, "previous minor freeze exist, skip this time", K_(arg)); } // turn over freeze token ATOMIC_INC(&minor_freeze_token_); } } else if (storage::MAJOR_FREEZE == arg_.freeze_type_) { uint64_t tenant_id = arg_.tenant_id_; common::ObAddr rs_addr; Int64 frozen_version; ObRetryMajorInfo retry_major_info = tenant_mgr.get_retry_major_info(); retry_major_info.tenant_id_ = tenant_id; retry_major_info.major_version_.version_ = arg_.try_frozen_version_; if (OB_FAIL(rs_mgr_->get_master_root_server(rs_addr))) { COMMON_LOG(WARN, "get master root service address failed", K(ret)); } else if (!rs_addr.is_valid()) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(WARN, "invalid rootserver addr", K(ret), K(rs_addr)); } else if (OB_FAIL(rpc_proxy_->to(rs_addr).get_frozen_version(frozen_version))) { COMMON_LOG(WARN, "get_frozen_version failed", K(rs_addr), K(ret)); } else { bool need_major = true; if (arg_.try_frozen_version_ > 0) { if (OB_UNLIKELY(arg_.try_frozen_version_ > frozen_version + 1)) { ret = OB_ERR_UNEXPECTED; need_major = false; COMMON_LOG(WARN, "wrong frozen version", K(ret), K(tenant_id), K(rs_addr), K(frozen_version), K(arg_.try_frozen_version_)); } else if (arg_.try_frozen_version_ <= frozen_version) { need_major = false; } else { // retry_major_info.major_version_.version_ == frozen_version + 1 need_major = true; } } else if (!tenant_mgr.tenant_need_major_freeze(tenant_id)) { need_major = false; } if (!need_major) { retry_major_info.reset(); } else { ObRootMajorFreezeArg arg; arg.try_frozen_version_ = frozen_version + 1; arg.launch_new_round_ = true; arg.svr_ = MYADDR; arg.tenant_id_ = arg_.tenant_id_; retry_major_info.major_version_.version_ = arg.try_frozen_version_; COMMON_LOG(INFO, "root_major_freeze", K(rs_addr), K(arg)); if (OB_FAIL(rpc_proxy_->to(rs_addr).root_major_freeze(arg))) { COMMON_LOG(WARN, "fail to major freeze", K(arg), K(ret)); } else { retry_major_info.reset(); } } } tenant_mgr.set_retry_major_info(retry_major_info); COMMON_LOG(INFO, "finish tenant manager major freeze", K(ret), K(rs_addr)); } else { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "unknown freeze type", K(arg_), K(ret)); } return ret; } } // namespace obrpc namespace common { using namespace oceanbase::obrpc; using namespace oceanbase::storage; void get_tenant_ids(uint64_t* ids, int cap, int& cnt) { int ret = OB_SUCCESS; auto *instance = ObMallocAllocator::get_instance(); cnt = 0; for (uint64_t tenant_id = 1; tenant_id <= ObMallocAllocator::get_max_used_tenant_id() && cnt < cap; ++tenant_id) { if (nullptr != instance->get_tenant_ctx_allocator(tenant_id, 0)) { ids[cnt++] = tenant_id; } } } void ObTenantMgrTimerTask::runTimerTask() { COMMON_LOG(INFO, "====== tenant manager timer task ======"); int ret = OB_SUCCESS; ObTenantManager& tenant_mgr = ObTenantManager::get_instance(); if (OB_FAIL(tenant_mgr.check_and_do_freeze_mixed())) { COMMON_LOG(WARN, "check and do minor freeze failed", K(ret)); } } void ObPrintTenantMemstoreUsage::runTimerTask() { COMMON_LOG(INFO, "=== Run print tenant memstore usage task ==="); ObTenantManager& tenant_mgr = ObTenantManager::get_instance(); tenant_mgr.print_tenant_usage(); ObObjFreeListList::get_freelists().dump(); } ObTenantInfo::ObTenantInfo() : tenant_id_(INT64_MAX), mem_lower_limit_(0), mem_upper_limit_(0), mem_memstore_limit_(0), is_loaded_(false), is_freezing_(false), last_freeze_clock_(0), frozen_version_(0), freeze_cnt_(0), last_halt_ts_(0) { memset(disk_used_, 0, OB_MAX_MACRO_BLOCK_TYPE * sizeof(uint64_t)); } void ObTenantInfo::reset() { tenant_id_ = OB_INVALID_TENANT_ID; // i64 max as invalid. mem_memstore_limit_ = 0; mem_lower_limit_ = 0; mem_upper_limit_ = 0; is_loaded_ = false; is_freezing_ = false; frozen_version_ = 0; freeze_cnt_ = 0; last_halt_ts_ = 0; } int ObTenantInfo::update_frozen_version(int64_t frozen_version) { int ret = OB_SUCCESS; if (frozen_version > frozen_version_) { frozen_version_ = frozen_version; freeze_cnt_ = 0; } return ret; } int64_t ObTenantInfo::mem_memstore_left() const { uint64_t memstore_hold = get_tenant_memory_hold(tenant_id_, ObCtxIds::MEMSTORE_CTX_ID); return max(0, mem_memstore_limit_ - (int64_t)memstore_hold); } ObTenantManager::ObTenantManager() : tenant_map_(NULL), tenant_pool_(), allocator_(ObModIds::OB_TENANT_INFO), memattr_(default_memattr), freeze_task_(), print_task_(), rpc_proxy_(), tenant_mgr_cb_(), svr_rpc_proxy_(NULL), common_rpc_proxy_(NULL), rs_mgr_(NULL), self_(), config_(NULL), all_tenants_freeze_trigger_(INT64_MAX), all_tenants_memstore_limit_(INT64_MAX), is_inited_(false), retry_major_info_(), allocator_mgr_(NULL) {} ObTenantManager::~ObTenantManager() { destroy(); } ObTenantManager& ObTenantManager::get_instance() { static ObTenantManager instance_; return instance_; } // this init is for obproxy only int ObTenantManager::init(const int64_t tenant_cnt) { int ret = OB_SUCCESS; if (is_inited_) { ret = OB_INIT_TWICE; COMMON_LOG(WARN, "init twice", K(ret)); } else if (OB_UNLIKELY(tenant_cnt <= 0)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(tenant_cnt), K(ret)); } else if (OB_FAIL(init_tenant_map(tenant_cnt))) { COMMON_LOG(WARN, "Fail to init tenant map, ", K(ret)); } if (OB_SUCC(ret)) { allocator_mgr_ = &ObMemstoreAllocatorMgr::get_instance(); is_inited_ = true; } else if (OB_INIT_TWICE != ret) { destroy(); } return ret; } // in observer, we only use this init func int ObTenantManager::init(const ObAddr& self, obrpc::ObSrvRpcProxy& rpc_proxy, obrpc::ObCommonRpcProxy& common_rpc_proxy, const share::ObRsMgr& rs_mgr, rpc::frame::ObReqTransport* req_transport, ObServerConfig* config, const int64_t tenant_cnt) { int ret = OB_SUCCESS; if (is_inited_) { ret = OB_INIT_TWICE; COMMON_LOG(WARN, "init twice", K(ret)); } else if (OB_UNLIKELY(!self.is_valid()) || OB_UNLIKELY(NULL == req_transport) || OB_UNLIKELY(NULL == config) || OB_UNLIKELY(tenant_cnt <= 0)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(self), K(req_transport), K(config), K(tenant_cnt), K(ret)); } else if (OB_FAIL(init_tenant_map(tenant_cnt))) { COMMON_LOG(WARN, "Fail to init tenant map, ", K(ret)); } if (OB_SUCC(ret)) { if (OB_SUCCESS != (ret = rpc_proxy_.init(req_transport, self))) { COMMON_LOG(WARN, "fail to init rpc proxy", K(ret)); } else { self_ = self; svr_rpc_proxy_ = &rpc_proxy; common_rpc_proxy_ = &common_rpc_proxy; rs_mgr_ = &rs_mgr; config_ = config; ATOMIC_STORE(&all_tenants_freeze_trigger_, config_->get_server_memory_avail() * config_->get_global_freeze_trigger_percentage() / 100); ATOMIC_STORE(&all_tenants_memstore_limit_, config_->get_server_memory_avail() * config_->get_global_memstore_limit_percentage() / 100); // make sure a major freeze request can be sent the first time after start allocator_mgr_ = &ObMemstoreAllocatorMgr::get_instance(); is_inited_ = true; } } if (OB_SUCCESS != ret && !is_inited_) { destroy(); } return ret; } int ObTenantManager::init_tenant_map(const int64_t tenant_cnt) { int ret = OB_SUCCESS; char* buf = NULL; if (OB_UNLIKELY(tenant_cnt <= 0)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(tenant_cnt), K(ret)); } else if (NULL == (buf = (char*)allocator_.alloc( (sizeof(ObTenantInfo*) * tenant_cnt) + sizeof(ObTenantInfo) * tenant_cnt))) { ret = OB_ALLOCATE_MEMORY_FAILED; COMMON_LOG(ERROR, "Fail to allocate memory, ", K(ret)); } else if (OB_FAIL(tenant_pool_.init(tenant_cnt, buf))) { COMMON_LOG(WARN, "Fail to init tenant pool, ", K(ret)); } else { buf += (sizeof(ObTenantInfo*) * tenant_cnt); ObTenantInfo* info = new (buf) ObTenantInfo[tenant_cnt]; for (int64_t idx = 0; idx < tenant_cnt && OB_SUCC(ret); ++idx) { info[idx].reset(); if (OB_FAIL(tenant_pool_.push(&(info[idx])))) { COMMON_LOG(WARN, "Fail to push info to pool, ", K(ret)); } } if (OB_SUCC(ret)) { if (NULL == (buf = (char*)allocator_.alloc(sizeof(ObTenantBucket) * BUCKET_NUM))) { ret = OB_ALLOCATE_MEMORY_FAILED; COMMON_LOG(ERROR, "Fail to allocate memory, ", K(ret)); } else { tenant_map_ = new (buf) ObTenantBucket[BUCKET_NUM]; } } } return ret; } void ObTenantManager::destroy() { tenant_map_ = NULL; tenant_pool_.destroy(); allocator_.reset(); rpc_proxy_.destroy(); self_.reset(); config_ = NULL; all_tenants_freeze_trigger_ = INT64_MAX; all_tenants_memstore_limit_ = INT64_MAX; is_inited_ = false; } int ObTenantManager::print_tenant_node( ObTenantInfo& node, char* print_buf, int64_t buf_len, int64_t& pos, int64_t& total_active_memstore_hold) { int ret = OB_SUCCESS; lib::ObMallocAllocator* mallocator = lib::ObMallocAllocator::get_instance(); int64_t mem_active_memstore_used = 0; int64_t mem_total_memstore_used = 0; int64_t mem_total_memstore_hold = 0; int64_t minor_freeze_trigger_limit = 0; int64_t max_mem_memstore_can_get_now = 0; int64_t kv_cache_mem = 0; if (OB_FAIL(get_tenant_mem_usage( node.tenant_id_, mem_active_memstore_used, mem_total_memstore_used, mem_total_memstore_hold))) { COMMON_LOG(WARN, "fail to get mem usage", K(ret), K(node.tenant_id_)); } else { total_active_memstore_hold += mem_active_memstore_used; if (OB_FAIL(get_tenant_minor_freeze_trigger(node.tenant_id_, node.mem_memstore_limit_, max_mem_memstore_can_get_now, kv_cache_mem, minor_freeze_trigger_limit))) { COMMON_LOG(WARN, "get tenant minor freeze trigger error", K(ret), K(node.tenant_id_)); } else { ret = databuff_printf(print_buf, buf_len, pos, "[TENANT_MEMSTORE] " "tenant_id=% '9ld " "active_memstore_used=% '15ld " "total_memstore_used=% '15ld " "total_memstore_hold=% '15ld " "minor_freeze_trigger_limit=% '15ld " "memstore_limit=% '15ld " "mem_tenant_limit=% '15ld " "mem_tenant_hold=% '15ld " "mem_memstore_used=% '15ld " "kv_cache_mem=% '15ld " "max_mem_memstore_can_get_now=% '15ld\n", node.tenant_id_, mem_active_memstore_used, mem_total_memstore_used, mem_total_memstore_hold, minor_freeze_trigger_limit, node.mem_memstore_limit_, get_tenant_memory_limit(node.tenant_id_), get_tenant_memory_hold(node.tenant_id_), get_tenant_memory_hold(node.tenant_id_, ObCtxIds::MEMSTORE_CTX_ID), kv_cache_mem, max_mem_memstore_can_get_now); } } if (!OB_ISNULL(mallocator)) { mallocator->print_tenant_memory_usage(node.tenant_id_); mallocator->print_tenant_ctx_memory_usage(node.tenant_id_); } return ret; } int ObTenantManager::print_tenant_usage() { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_FAIL(print_mutex_.trylock())) { // Guaranteed serial printing // do-nothing } else { static const int64_t BUF_LEN = 64LL << 10; static char print_buf[BUF_LEN] = ""; int64_t pos = 0; if (OB_FAIL(databuff_printf(print_buf, BUF_LEN, pos, "=== TENANTS MEMSTORE INFO ===\n" "all_tenants_memstore_used=% '15ld " "all_tenants_memstore_limit=% '15ld\n", allocator_mgr_->get_all_tenants_memstore_used(), all_tenants_memstore_limit_))) { } else { ObTenantInfo* head = NULL; ObTenantInfo* node = NULL; int64_t total_active_memstore_hold = 0; omt::ObMultiTenant* omt = GCTX.omt_; if (OB_ISNULL(omt)) { for (int64_t i = 0; OB_SUCC(ret) && i < BUCKET_NUM; ++i) { ObTenantBucket& bucket = tenant_map_[i]; SpinRLockGuard guard(bucket.lock_); head = bucket.info_list_.get_header(); node = bucket.info_list_.get_first(); while (head != node && NULL != node && OB_SUCC(ret)) { ret = print_tenant_node(*node, print_buf, BUF_LEN, pos, total_active_memstore_hold); node = node->get_next(); } } } else { omt::TenantIdList ids(nullptr, ObModIds::OMT); omt->get_tenant_ids(ids); for (omt::TenantIdList::iterator it = ids.begin(); OB_SUCC(ret) && it != ids.end(); it++) { uint64_t id = *it; ObTenantBucket& bucket = tenant_map_[id % BUCKET_NUM]; SpinWLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(id, node))) { // tenant is not exist do nothing ret = OB_SUCCESS; lib::ObMallocAllocator* mallocator = lib::ObMallocAllocator::get_instance(); if (!OB_ISNULL(mallocator)) { mallocator->print_tenant_memory_usage(id); mallocator->print_tenant_ctx_memory_usage(id); } } else { ret = print_tenant_node(*node, print_buf, BUF_LEN, pos, total_active_memstore_hold); } } } if (OB_SUCC(ret)) { ret = databuff_printf(print_buf, BUF_LEN, pos, "[TENANT_MEMSTORE] " "total_active_memstore_hold=% '15ld " "all_tenants_freeze_trigger=% '15ld\n", total_active_memstore_hold, all_tenants_freeze_trigger_); } if (OB_SIZE_OVERFLOW == ret) { // If the buffer is not enough, truncate directly ret = OB_SUCCESS; print_buf[BUF_LEN - 2] = '\n'; print_buf[BUF_LEN - 1] = '\0'; } if (OB_SUCCESS == ret) { _COMMON_LOG(INFO, "====== tenants memstore info ======\n%s", print_buf); } // print global chunk freelist int64_t memory_used = get_virtual_memory_used(); _COMMON_LOG(INFO, "[CHUNK_MGR] free=%ld pushes=%ld pops=%ld limit=%'15ld hold=%'15ld used=%'15ld" " freelist_hold=%'15ld maps=%'15ld unmaps=%'15ld large_maps=%'15ld large_unmaps=%'15ld" " memalign=%d virtual_memory_used=%'15ld\n", CHUNK_MGR.get_free_chunk_count(), CHUNK_MGR.get_free_chunk_pushes(), CHUNK_MGR.get_free_chunk_pops(), CHUNK_MGR.get_limit(), CHUNK_MGR.get_hold(), CHUNK_MGR.get_used(), CHUNK_MGR.get_freelist_hold(), CHUNK_MGR.get_maps(), CHUNK_MGR.get_unmaps(), CHUNK_MGR.get_large_maps(), CHUNK_MGR.get_large_unmaps(), 0, memory_used); } print_mutex_.unlock(); } return ret; } int ObTenantManager::get_all_tenant_id(ObIArray& key) const { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < BUCKET_NUM; ++i) { ObTenantBucket& bucket = tenant_map_[i]; SpinRLockGuard guard(bucket.lock_); DLIST_FOREACH(iter, bucket.info_list_) { if (true == iter->is_loaded_) { if (OB_FAIL(key.push_back(iter->tenant_id_))) { COMMON_LOG(WARN, "Fail to add key to array, ", K(ret)); } } } } } return ret; } int ObTenantManager::add_tenant(const uint64_t tenant_id) { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinWLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_SUCC(bucket.get_the_node(tenant_id, node))) { // tenant is exist do nothing } else { ObTenantInfo* info = NULL; if (OB_FAIL(tenant_pool_.pop(info))) { COMMON_LOG(WARN, "Fail to pop info from pool, ", K(ret)); } else { info->reset(); info->tenant_id_ = tenant_id; if (OB_UNLIKELY(!bucket.info_list_.add_last(info))) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Fail to add proc to wait list, ", K(ret)); if (OB_SUCCESS != (tmp_ret = tenant_pool_.push(info))) { COMMON_LOG(WARN, "Fail to push collects to pool, ", K(tmp_ret)); } } } } } return ret; } int ObTenantManager::del_tenant(const uint64_t tenant_id) { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinWLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { COMMON_LOG(INFO, "This tenant has not exist", K(tenant_id), K(ret)); } else { ObTenantInfo* info = NULL; info = bucket.info_list_.remove(node); if (NULL == info) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(WARN, "The info is null, ", K(ret)); } else { if (OB_FAIL(tenant_pool_.push(info))) { COMMON_LOG(WARN, "Fail to push collect to pool, ", K(ret)); } else { COMMON_LOG(INFO, "del_tenant succeed", K(tenant_id)); } } } } return ret; } bool ObTenantManager::has_tenant(const uint64_t tenant_id) const { bool bool_ret = false; int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_INVALID_ID != tenant_id) { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_SUCC(bucket.get_the_node(tenant_id, node))) { if (NULL != node && true == node->is_loaded_) { bool_ret = true; } } } return bool_ret; } int ObTenantManager::set_tenant_freezing(const uint64_t tenant_id, bool& success) { int ret = OB_SUCCESS; ObTenantMemstoreAllocator* tenant_allocator = NULL; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else if (OB_FAIL(allocator_mgr_->get_tenant_memstore_allocator(tenant_id, tenant_allocator))) { COMMON_LOG(WARN, "failed to get_tenant_memstore_allocator", K(tenant_id), K(ret)); } else if (NULL == tenant_allocator) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "got tenant memstore allocator is NULL", K(tenant_id), K(ret)); } else { // Do not judge is_loaded_, and do minor freeze even when the tenant information is not refreshed when the machine // is restarted success = ATOMIC_BCAS(&node->is_freezing_, false, true); if (success) { node->last_freeze_clock_ = tenant_allocator->get_retire_clock(); ATOMIC_AAF(&node->freeze_cnt_, 1); } } } return ret; } int ObTenantManager::unset_tenant_freezing(uint64_t tenant_id, const bool rollback_freeze_cnt) { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else { // Do not judge is_loaded_, and do minor freeze even when the tenant information is not refreshed when the machine // is restarted if (rollback_freeze_cnt) { if (ATOMIC_AAF(&node->freeze_cnt_, -1) < 0) { node->freeze_cnt_ = 0; } } ATOMIC_SET(&node->is_freezing_, false); } } return ret; } int ObTenantManager::set_tenant_freeze_clock(const uint64_t tenant_id, const int64_t freeze_clock) { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else { node->last_freeze_clock_ = freeze_clock; COMMON_LOG(INFO, "set tenant freeze clock", K(freeze_clock), K(node->last_freeze_clock_)); } } return ret; } int ObTenantManager::set_tenant_mem_limit( const uint64_t tenant_id, const int64_t lower_limit, const int64_t upper_limit) { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id) || OB_UNLIKELY(lower_limit < 0) || OB_UNLIKELY(upper_limit < 0)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id), K(lower_limit), K(upper_limit)); } else { if ((NULL != config_) && (((int64_t)(config_->memstore_limit_percentage)) > 100 || ((int64_t)(config_->memstore_limit_percentage)) <= 0 || ((int64_t)(config_->freeze_trigger_percentage)) > 100 || ((int64_t)(config_->freeze_trigger_percentage)) <= 0)) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(WARN, "memstore limit percent in ObServerConfig is invaild", "memstore limit percent", (int64_t)config_->memstore_limit_percentage, "minor freeze trigger percent", (int64_t)config_->freeze_trigger_percentage, K(ret)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinWLockGuard guard(bucket.lock_); // It should be possible to change to a read lock here, this lock is a // structural lock, it is not appropriate to borrow ObTenantInfo* node = NULL; int64_t mem_minor_freeze_trigger_limit = 0; int64_t max_mem_memstore_can_get_now = 0; int64_t kv_cache_mem = 0; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else { node->mem_lower_limit_ = lower_limit; node->mem_upper_limit_ = upper_limit; if (NULL != config_) { int64_t tmp_var = upper_limit / 100; node->mem_memstore_limit_ = tmp_var * config_->memstore_limit_percentage; if (OB_FAIL(get_tenant_minor_freeze_trigger(tenant_id, node->mem_memstore_limit_, max_mem_memstore_can_get_now, kv_cache_mem, mem_minor_freeze_trigger_limit))) { COMMON_LOG(WARN, "fail to get minor freeze trigger", K(ret), K(tenant_id)); } } node->is_loaded_ = true; } if (OB_SUCC(ret)) { COMMON_LOG(INFO, "set tenant mem limit", "tenant id", tenant_id, "mem_lower_limit", lower_limit, "mem_upper_limit", upper_limit, "mem_memstore_limit", node->mem_memstore_limit_, "mem_minor_freeze_trigger_limit", mem_minor_freeze_trigger_limit, "mem_tenant_limit", get_tenant_memory_limit(node->tenant_id_), "mem_tenant_hold", get_tenant_memory_hold(node->tenant_id_), "mem_memstore_used", get_tenant_memory_hold(node->tenant_id_, ObCtxIds::MEMSTORE_CTX_ID), "kv_cache_mem", kv_cache_mem, "max_mem_memstore_can_get_now", max_mem_memstore_can_get_now); } } } return ret; } int ObTenantManager::get_tenant_mem_limit(const uint64_t tenant_id, int64_t& lower_limit, int64_t& upper_limit) const { int ret = OB_SUCCESS; lower_limit = 0; upper_limit = 0; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else if (false == node->is_loaded_) { ret = OB_NOT_REGISTERED; } else { lower_limit = node->mem_lower_limit_; upper_limit = node->mem_upper_limit_; } } return ret; } int ObTenantManager::get_tenant_memstore_cond(const uint64_t tenant_id, int64_t& active_memstore_used, int64_t& total_memstore_used, int64_t& minor_freeze_trigger, int64_t& memstore_limit, int64_t& freeze_cnt) { int ret = OB_SUCCESS; int64_t unused = 0; active_memstore_used = 0; total_memstore_used = 0; minor_freeze_trigger = 0; memstore_limit = 0; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else if (false == node->is_loaded_) { ret = OB_ENTRY_NOT_EXIST; COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else if (OB_FAIL(get_tenant_mem_usage(tenant_id, active_memstore_used, unused, total_memstore_used))) { COMMON_LOG(WARN, "failed to get tenant mem usage", K(ret), K(tenant_id)); } else { if (OB_FAIL(get_tenant_minor_freeze_trigger(tenant_id, node->mem_memstore_limit_, minor_freeze_trigger))) { COMMON_LOG(WARN, "fail to get minor freeze trigger", K(ret), K(tenant_id)); } memstore_limit = node->mem_memstore_limit_; freeze_cnt = node->freeze_cnt_; } } return ret; } int ObTenantManager::get_tenant_minor_freeze_trigger( const uint64_t tenant_id, const int64_t mem_memstore_limit, int64_t& minor_freeze_trigger) { int64_t not_used = 0; int64_t not_used2 = 0; return get_tenant_minor_freeze_trigger(tenant_id, mem_memstore_limit, not_used, not_used2, minor_freeze_trigger); } static inline bool is_add_overflow(int64_t first, int64_t second, int64_t& res) { if (first + second < 0) { return true; } else { res = first + second; return false; } } int ObTenantManager::get_tenant_minor_freeze_trigger(const uint64_t tenant_id, const int64_t mem_memstore_limit, /* Now the maximum memory size that the memstore module can preempt and obtain */ int64_t& max_mem_memstore_can_get_now, int64_t& kv_cache_mem, int64_t& minor_freeze_trigger) { int ret = OB_SUCCESS; ObTenantResourceMgrHandle resource_handle; if (OB_FAIL(ObResourceMgr::get_instance().get_tenant_resource_mgr(tenant_id, resource_handle))) { COMMON_LOG(WARN, "fail to get resource mgr", K(ret), K(tenant_id)); ret = OB_SUCCESS; minor_freeze_trigger = config_->freeze_trigger_percentage / 100 * mem_memstore_limit; } else if (OB_UNLIKELY(NULL == config_)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "config_ is nullptr", K(ret), K(tenant_id)); } else { int64_t tenant_mem_limit = get_tenant_memory_limit(tenant_id); int64_t tenant_mem_hold = get_tenant_memory_hold(tenant_id); int64_t tenant_memstore_hold = get_tenant_memory_hold(tenant_id, ObCtxIds::MEMSTORE_CTX_ID); kv_cache_mem = resource_handle.get_memory_mgr()->get_cache_hold(); bool is_overflow = false; if (tenant_mem_limit < tenant_mem_hold) { is_overflow = true; COMMON_LOG(WARN, "tenant_mem_limit is smaller than tenant_mem_hold", K(tenant_mem_limit), K(tenant_mem_hold), K(tenant_id)); } else if (is_add_overflow( tenant_mem_limit - tenant_mem_hold, tenant_memstore_hold, max_mem_memstore_can_get_now)) { is_overflow = true; if (REACH_TIME_INTERVAL(1 * 1000 * 1000)) { COMMON_LOG(WARN, "max memstore can get is overflow", K(tenant_mem_limit), K(tenant_mem_hold), K(tenant_memstore_hold), K(tenant_id)); } } else if (OB_SERVER_TENANT_ID != tenant_id && is_add_overflow(max_mem_memstore_can_get_now, kv_cache_mem, max_mem_memstore_can_get_now)) { is_overflow = true; if (REACH_TIME_INTERVAL(1 * 1000 * 1000)) { COMMON_LOG(WARN, "max memstore can get is overflow", K(tenant_mem_limit), K(tenant_mem_hold), K(tenant_memstore_hold), K(kv_cache_mem), K(tenant_id)); } } int64_t min = mem_memstore_limit; if (!is_overflow) { min = MIN(mem_memstore_limit, max_mem_memstore_can_get_now); } if (min < 100) { minor_freeze_trigger = config_->freeze_trigger_percentage * min / 100; } else { minor_freeze_trigger = min / 100 * config_->freeze_trigger_percentage; } } return ret; } int ObTenantManager::get_tenant_mem_usage( const uint64_t tenant_id, int64_t& active_memstore_used, int64_t& total_memstore_used, int64_t& total_memstore_hold) { int ret = OB_SUCCESS; ObTenantMemstoreAllocator* tenant_allocator = NULL; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else if (OB_FAIL(allocator_mgr_->get_tenant_memstore_allocator(tenant_id, tenant_allocator))) { COMMON_LOG(WARN, "failed to get_tenant_memstore_allocator", K(ret), K(tenant_id)); } else if (NULL == tenant_allocator) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "tenant memstore allocator is NULL", K(ret), K(tenant_id)); } else { active_memstore_used = tenant_allocator->get_mem_active_memstore_used(); total_memstore_used = tenant_allocator->get_mem_total_memstore_used(); total_memstore_hold = get_tenant_memory_hold(tenant_id, ObCtxIds::MEMSTORE_CTX_ID); } return ret; } int ObTenantManager::get_tenant_memstore_limit(const uint64_t tenant_id, int64_t& mem_limit) { int ret = OB_SUCCESS; mem_limit = INT64_MAX; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { ret = OB_SUCCESS; mem_limit = INT64_MAX; COMMON_LOG(WARN, "This tenant not exist", K(tenant_id), K(ret)); } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else if (false == node->is_loaded_) { mem_limit = INT64_MAX; COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else { mem_limit = node->mem_memstore_limit_; } } return ret; } int ObTenantManager::check_tenant_out_of_memstore_limit(const uint64_t tenant_id, bool& is_out_of_mem) { int ret = OB_SUCCESS; const int64_t check_memstore_limit_interval = 1 * 1000 * 1000; static __thread uint64_t last_tenant_id = OB_INVALID_TENANT_ID; static __thread int64_t last_check_timestamp = 0; static __thread bool last_result = false; int64_t current_time = ObTimeUtility::fast_current_time(); if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else if (!last_result && tenant_id == last_tenant_id && current_time - last_check_timestamp < check_memstore_limit_interval) { // Check once when the last memory burst or tenant_id does not match or the interval reaches the threshold is_out_of_mem = false; } else if (config_->enable_global_freeze_trigger && tenant_id >= OB_USER_TENANT_ID && allocator_mgr_->get_all_tenants_memstore_used() >= ATOMIC_LOAD(&all_tenants_memstore_limit_)) { is_out_of_mem = true; } else { int64_t mem_active_memstore_used = 0; int64_t mem_total_memstore_used = 0; int64_t mem_total_memstore_hold = 0; uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { ret = OB_SUCCESS; is_out_of_mem = false; COMMON_LOG(WARN, "This tenant not exist", K(tenant_id), K(ret)); } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else if (false == node->is_loaded_) { is_out_of_mem = false; COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else if (OB_FAIL(get_tenant_mem_usage( node->tenant_id_, mem_active_memstore_used, mem_total_memstore_used, mem_total_memstore_hold))) { COMMON_LOG(WARN, "fail to get mem usage", K(ret), K(node->tenant_id_)); } else { is_out_of_mem = (mem_total_memstore_hold > node->mem_memstore_limit_); } last_check_timestamp = current_time; } if (OB_SUCC(ret)) { last_result = is_out_of_mem; last_tenant_id = tenant_id; } return ret; } bool ObTenantManager::is_rp_pending_log_too_large(const uint64_t tenant_id, const int64_t pending_replay_mutator_size) { int ret = OB_SUCCESS; bool bool_ret = false; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else { // The limit of the tenant may not be loaded during the restart process, and the global limit is used. int64_t mem_rp_pending_log_limit = 0; int64_t all_tenants_memstore_used = allocator_mgr_->get_all_tenants_memstore_used(); if (node->mem_upper_limit_ > 0) { mem_rp_pending_log_limit = node->mem_memstore_left(); } else { mem_rp_pending_log_limit = max(0, all_tenants_memstore_limit_ - all_tenants_memstore_used); } mem_rp_pending_log_limit >>= 3; // Estimate the size of memstore based on 8 times expansion bool_ret = (pending_replay_mutator_size >= mem_rp_pending_log_limit); if (bool_ret && REACH_TIME_INTERVAL(10 * 1000 * 1000)) { COMMON_LOG(WARN, "replay engine pending log too large", K(tenant_id), K(mem_rp_pending_log_limit), K(pending_replay_mutator_size), "mem_upper_limit", node->mem_upper_limit_, K(all_tenants_memstore_limit_), K(all_tenants_memstore_used)); } } } return bool_ret; } int ObTenantManager::add_tenant_disk_used(const uint64_t tenant_id, const int64_t size, const int16_t attr) { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_SUCCESS != (tmp_ret = bucket.get_the_node(tenant_id, node))) { COMMON_LOG(WARN, "fail to get the node", K(tenant_id), K(tmp_ret)); } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else { if (attr >= OB_MAX_MACRO_BLOCK_TYPE || attr < 0) { ret = OB_INVALID_MACRO_BLOCK_TYPE; COMMON_LOG(WARN, "invalid type of macro block", K(tenant_id), K(ret)); } else { (void)ATOMIC_AAF(&node->disk_used_[attr], size); } } } if (OB_ENTRY_NOT_EXIST == tmp_ret) { AddDiskUsed adder(attr); adder.size_ = size; if (OB_FAIL(add_tenant_and_used(tenant_id, adder))) { COMMON_LOG(WARN, "fail to add disk used", K(tenant_id), K(ret)); } } } return ret; } int ObTenantManager::subtract_tenant_disk_used(const uint64_t tenant_id, const int64_t size, const int16_t attr) { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else { if (attr >= OB_MAX_MACRO_BLOCK_TYPE || attr < 0) { ret = OB_INVALID_MACRO_BLOCK_TYPE; COMMON_LOG(WARN, "invalid type of macro block", K(tenant_id), K(ret)); } else { (void)ATOMIC_SAF(&node->disk_used_[attr], size); } } } return ret; } int ObTenantManager::get_tenant_disk_used(const uint64_t tenant_id, int64_t& disk_used, int16_t attr) { int ret = OB_SUCCESS; disk_used = 0; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else if (false == node->is_loaded_) { ret = OB_ENTRY_NOT_EXIST; COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else { if (attr >= OB_MAX_MACRO_BLOCK_TYPE || attr < 0) { ret = OB_INVALID_MACRO_BLOCK_TYPE; COMMON_LOG(WARN, "invalid type of macro block", K(tenant_id), K(ret)); } else { disk_used = node->disk_used_[attr]; } } } return ret; } int ObTenantManager::get_tenant_disk_total_used(const uint64_t tenant_id, int64_t& disk_used) { int ret = OB_SUCCESS; disk_used = 0; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else if (false == node->is_loaded_) { ret = OB_ENTRY_NOT_EXIST; COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else { const int64_t max_count = OB_MAX_MACRO_BLOCK_TYPE; for (int64_t i = 0; i < max_count; i++) { disk_used += node->disk_used_[i]; } } } return ret; } bool ObTenantManager::is_major_freeze_turn(int64_t freeze_cnt) { // Major freeze can only be done after restarting the scan // Prevent multiple major freezes during restart. const int64_t minor_freeze_times = config_->minor_freeze_times; return (freeze_cnt >= minor_freeze_times && NULL != GCTX.par_ser_ && GCTX.par_ser_->is_scan_disk_finished()); } int ObTenantManager::do_major_freeze_if_previous_failure_exist(bool& triggered) { int ret = OB_SUCCESS; if (get_retry_major_info().is_valid()) { COMMON_LOG(INFO, "A major freeze is needed due to previous failure"); if (OB_FAIL(post_freeze_request( retry_major_info_.tenant_id_, MAJOR_FREEZE, get_retry_major_info().major_version_.major_))) { COMMON_LOG(WARN, "major freeze failed", K(ret)); } triggered = true; } return ret; } int ObTenantManager::do_minor_freeze(const int64_t mem_active_memstore_used, const ObTenantInfo& node, bool& triggered) { int ret = OB_SUCCESS; int64_t mem_minor_freeze_trigger = 0; int64_t max_mem_memstore_can_get_now = 0; int64_t kv_cache_mem = 0; if (OB_FAIL(get_tenant_minor_freeze_trigger(node.tenant_id_, node.mem_memstore_limit_, max_mem_memstore_can_get_now, kv_cache_mem, mem_minor_freeze_trigger))) { COMMON_LOG(WARN, "fail to get minor freeze trigger in a minor freeze", K(ret), K(node.tenant_id_)); } else { COMMON_LOG(INFO, "A minor freeze is needed", "mem_active_memstore_used_", mem_active_memstore_used, "mem_minor_freeze_trigger_limit_", mem_minor_freeze_trigger, "mem_tenant_limit", get_tenant_memory_limit(node.tenant_id_), "mem_tenant_hold", get_tenant_memory_hold(node.tenant_id_), "mem_memstore_used", get_tenant_memory_hold(node.tenant_id_, ObCtxIds::MEMSTORE_CTX_ID), "kv_cache_mem", kv_cache_mem, "max_mem_memstore_can_get_now", max_mem_memstore_can_get_now, "tenant_id", node.tenant_id_); } if (OB_FAIL(post_freeze_request(node.tenant_id_, MINOR_FREEZE, node.frozen_version_))) { COMMON_LOG(WARN, "minor freeze failed", K(node.tenant_id_), K(ret)); } else { triggered = true; } return ret; } int ObTenantManager::do_major_freeze(const uint64_t tenant_id, const int64_t try_frozen_version) { int ret = OB_SUCCESS; if (OB_FAIL(post_freeze_request(tenant_id, MAJOR_FREEZE, try_frozen_version))) { COMMON_LOG(WARN, "major freeze failed", K(ret), K(tenant_id)); } return ret; } int ObTenantManager::get_global_frozen_version(int64_t& frozen_version) { int ret = OB_SUCCESS; common::ObAddr rs_addr; Int64 tmp_frozen_version; if (OB_FAIL(rs_mgr_->get_master_root_server(rs_addr))) { COMMON_LOG(WARN, "get master root service address failed", K(ret)); } else if (!rs_addr.is_valid()) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(WARN, "invalid rootserver addr", K(ret), K(rs_addr)); } else if (OB_FAIL(common_rpc_proxy_->to(rs_addr).get_frozen_version(tmp_frozen_version))) { COMMON_LOG(WARN, "get_frozen_version failed", K(rs_addr), K(ret)); } else { frozen_version = tmp_frozen_version; } return ret; } int ObTenantManager::check_and_do_freeze_mixed() { bool upgrade_mode = GCONF.in_major_version_upgrade_mode(); int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; bool triggered = false; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(upgrade_mode)) { // skip trigger freeze while upgrading } else { if (OB_UNLIKELY(OB_SUCCESS != (tmp_ret = do_major_freeze_if_previous_failure_exist(triggered)))) { COMMON_LOG(WARN, "fail to do major freeze due to previous failure", K(tmp_ret)); } bool major_triggered = triggered; bool need_major = false; uint64_t major_tenant_id = OB_INVALID_TENANT_ID; int64_t curr_frozen_version = 0; int64_t frozen_version = 0; bool use_too_much_memory = false; if (OB_UNLIKELY(OB_SUCCESS != (tmp_ret = get_global_frozen_version(frozen_version)))) { COMMON_LOG(WARN, "fail to get global frozen version", K(tmp_ret)); } for (int64_t i = 0; i < BUCKET_NUM; ++i) { ObTenantBucket& bucket = tenant_map_[i]; SpinRLockGuard guard(bucket.lock_); DLIST_FOREACH_NORET(iter, bucket.info_list_) { if (iter->is_loaded_) { int64_t mem_active_memstore_used = 0; int64_t mem_total_memstore_used = 0; int64_t mem_total_memstore_hold = 0; int64_t mem_minor_freeze_trigger = 0; if (OB_FAIL(get_tenant_minor_freeze_trigger( iter->tenant_id_, iter->mem_memstore_limit_, mem_minor_freeze_trigger))) { COMMON_LOG(WARN, "fail to get minor freeze trigger", K(ret), K(iter->tenant_id_)); } else { if (OB_UNLIKELY(OB_SUCCESS != (tmp_ret = get_tenant_mem_usage(iter->tenant_id_, mem_active_memstore_used, mem_total_memstore_used, mem_total_memstore_hold)))) { COMMON_LOG(WARN, "fail to get mem usage", K(ret), K(iter->tenant_id_)); } else if (0 != frozen_version && OB_FAIL(iter->update_frozen_version(frozen_version))) { COMMON_LOG(WARN, "fail to update frozen version", K(ret), K(frozen_version), K(*iter)); } else if (OB_FAIL(check_memory_used(iter->tenant_id_, mem_active_memstore_used, mem_minor_freeze_trigger, iter->mem_memstore_limit_, use_too_much_memory))) { COMMON_LOG(WARN, "fail to check memory used", K(ret), K(*iter)); } else { if (mem_active_memstore_used > mem_minor_freeze_trigger || use_too_much_memory) { bool finished = false; if (!major_triggered && !need_major && is_major_freeze_turn(iter->freeze_cnt_)) { COMMON_LOG(INFO, "A major freeze is needed", "mem_active_memstore_used_", mem_active_memstore_used, "mem_minor_freeze_trigger_limit_", mem_minor_freeze_trigger, "tenant_id", iter->tenant_id_); major_tenant_id = iter->tenant_id_; curr_frozen_version = iter->frozen_version_; need_major = true; } if (OB_UNLIKELY( OB_SUCCESS != (tmp_ret = do_minor_freeze(mem_active_memstore_used, *iter, triggered)))) { COMMON_LOG(WARN, "fail to do minor freeze", K(tmp_ret), K(iter->tenant_id_)); } } if (mem_total_memstore_hold > mem_minor_freeze_trigger) { // There is an unreleased memstable COMMON_LOG(INFO, "tenant have inactive memstores", K(mem_active_memstore_used), K(mem_total_memstore_used), K(mem_total_memstore_hold), "mem_minor_freeze_trigger_limit_", mem_minor_freeze_trigger, "tenant_id", iter->tenant_id_); ObTenantMemstoreAllocator* tenant_allocator = NULL; int tmp_ret = OB_SUCCESS; if (OB_SUCCESS != (tmp_ret = allocator_mgr_->get_tenant_memstore_allocator(iter->tenant_id_, tenant_allocator))) { } else { char frozen_mt_info[DEFAULT_BUF_LENGTH]; tenant_allocator->log_frozen_memstore_info(frozen_mt_info, sizeof(frozen_mt_info)); COMMON_LOG(INFO, "oldest frozen memtable", "list", frozen_mt_info); } } // When the memory is tight, try to abort the warm-up to release memstore int64_t mem_danger_limit = iter->mem_memstore_limit_ - ((iter->mem_memstore_limit_ - mem_minor_freeze_trigger) >> 2); if (mem_total_memstore_hold > mem_danger_limit) { int64_t curr_ts = ObTimeUtility::current_time(); if (curr_ts - iter->last_halt_ts_ > 10L * 1000L * 1000L) { if (OB_UNLIKELY(OB_SUCCESS != (tmp_ret = svr_rpc_proxy_->to(self_).halt_all_prewarming_async( iter->tenant_id_, NULL)))) { COMMON_LOG(WARN, "fail to halt prewarming", K(tmp_ret), K(iter->tenant_id_)); } else { iter->last_halt_ts_ = curr_ts; } } } } } } } } if (OB_SUCC(ret)) { if (need_major && OB_INVALID_TENANT_ID != major_tenant_id) { triggered = true; if (OB_UNLIKELY(OB_SUCCESS != (tmp_ret = do_major_freeze(major_tenant_id, curr_frozen_version + 1)))) { COMMON_LOG(WARN, "fail to do major freeze", K(tmp_ret)); } } if (!triggered) { if (OB_SUCCESS != (tmp_ret = check_and_do_freeze_by_total_limit())) { COMMON_LOG(WARN, "check_and_do_freeze_by_total_limit failed", K(tmp_ret)); } } } } return ret; } // This check is triggered only if the mixed check does not trigger freeze, including two cases: // 1. The active of all tenants did not exceed their limit, but the total exceeded. // 2. During the downtime and restart, the limit of the tenant has not been loaded yet, and the total active exceeds the // total limit. int ObTenantManager::check_and_do_freeze_by_total_limit() { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; uint64_t tenant_id = OB_INVALID_TENANT_ID; int64_t freeze_cnt = 0; int64_t frozen_version = 0; int64_t total_active_memstore_used = 0; int64_t max_active_memstore_used = 0; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (NULL == GCTX.par_ser_) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "GCTX.par_ser_ is NULL", K(ret)); } else if (!config_->enable_global_freeze_trigger) { // The entire process is controlled by enable_global_freeze_trigger // If you can't start up during the downtime and restart, you need to turn on the configuration item for temporary // processing } else { for (int64_t i = 0; i < BUCKET_NUM; ++i) { ObTenantBucket& bucket = tenant_map_[i]; SpinRLockGuard guard(bucket.lock_); DLIST_FOREACH_NORET(iter, bucket.info_list_) { int64_t mem_active_memstore_used = 0; int64_t mem_total_memstore_used = 0; int64_t mem_total_memstore_hold = 0; if (OB_UNLIKELY( OB_SUCCESS != (tmp_ret = get_tenant_mem_usage( iter->tenant_id_, mem_active_memstore_used, mem_total_memstore_used, mem_total_memstore_hold)))) { COMMON_LOG(WARN, "fail to get mem usage", K(tmp_ret), K(iter->tenant_id_)); } else { total_active_memstore_used += mem_active_memstore_used; if (mem_active_memstore_used > max_active_memstore_used) { // find the max tenant to do minor freeze max_active_memstore_used = mem_active_memstore_used; tenant_id = iter->tenant_id_; frozen_version = iter->frozen_version_; freeze_cnt = iter->freeze_cnt_; } } } } if (total_active_memstore_used >= all_tenants_freeze_trigger_) { // After the overall trigger is exceeded, a dump will be triggered if it is during a downtime restart // If the downtime restart has been completed and the configuration is open to dump, the dump will be triggered, // otherwise it will trigger major freeze storage::ObFreezeType freeze_type = is_major_freeze_turn(freeze_cnt) ? MAJOR_FREEZE : MINOR_FREEZE; if (MINOR_FREEZE == freeze_type) { if (OB_INVALID_TENANT_ID != tenant_id) { COMMON_LOG(INFO, "A minor freeze is needed by total limit", K(total_active_memstore_used), "server_memory_avail", config_->get_server_memory_avail(), K_(all_tenants_freeze_trigger), K(tenant_id)); if (OB_FAIL(post_freeze_request(tenant_id, MINOR_FREEZE, frozen_version))) { COMMON_LOG(WARN, "trigger minor freeze failed", K(tenant_id), K(total_active_memstore_used), K_(all_tenants_freeze_trigger), K(ret)); } } else { ret = OB_ERR_UNEXPECTED; COMMON_LOG(WARN, "no tenant to do minor freeze", K(total_active_memstore_used), K_(all_tenants_freeze_trigger), K(ret)); } } else { COMMON_LOG(INFO, "A major freeze is needed by total limit", K(total_active_memstore_used), "server_memory_avail", config_->get_server_memory_avail(), K_(all_tenants_freeze_trigger)); if (OB_FAIL(post_freeze_request(OB_INVALID_TENANT_ID, MAJOR_FREEZE, frozen_version + 1))) { COMMON_LOG(WARN, "trigger global major freeze failed", K(ret)); } } } } return ret; } bool ObTenantManager::tenant_need_major_freeze(uint64_t tenant_id) { bool bool_ret = false; int ret = OB_SUCCESS; int64_t mem_active_memstore_used = 0; int64_t mem_total_memstore_used = 0; int64_t mem_total_memstore_hold = 0; int64_t minor_freeze_trigger_limit = 0; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_INVALID_TENANT_ID != tenant_id && ((int64_t)tenant_id < 0)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else if (OB_INVALID_TENANT_ID != tenant_id) { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinRLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_FAIL(bucket.get_the_node(tenant_id, node))) { COMMON_LOG(WARN, "This tenant not exist", K(tenant_id), K(ret)); } else if (NULL == node) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Unexpected error", K(tenant_id), K(ret)); } else if (false == node->is_loaded_) { ret = OB_ENTRY_NOT_EXIST; COMMON_LOG(INFO, "This tenant not exist", K(tenant_id), K(ret)); } else if (OB_FAIL(get_tenant_mem_usage( node->tenant_id_, mem_active_memstore_used, mem_total_memstore_used, mem_total_memstore_hold))) { COMMON_LOG(WARN, "fail to get mem usage", K(ret), K(node->tenant_id_)); } else { if (OB_FAIL(get_tenant_minor_freeze_trigger( node->tenant_id_, node->mem_memstore_limit_, minor_freeze_trigger_limit))) { COMMON_LOG(WARN, "get tenant minor freeze trigger error", K(ret), K(node->tenant_id_)); } else { if (mem_active_memstore_used > minor_freeze_trigger_limit) { COMMON_LOG(INFO, "A major freeze is needed", "mem_active_memstore_used_", mem_active_memstore_used, "mem_minor_freeze_trigger_limit_", minor_freeze_trigger_limit, "tenant_id", node->tenant_id_); bool_ret = true; } } } } else { // OB_INVALID_ID == tenant_id int64_t total_active_memstore_used = 0; for (int64_t i = 0; i < BUCKET_NUM; ++i) { ObTenantBucket& bucket = tenant_map_[i]; SpinRLockGuard guard(bucket.lock_); DLIST_FOREACH_NORET(iter, bucket.info_list_) { if (OB_FAIL(get_tenant_mem_usage( iter->tenant_id_, mem_active_memstore_used, mem_total_memstore_used, mem_total_memstore_hold))) { COMMON_LOG(WARN, "fail to get mem usage", K(ret), K(iter->tenant_id_)); } else { total_active_memstore_used += mem_active_memstore_used; } } } if (total_active_memstore_used >= all_tenants_freeze_trigger_) { COMMON_LOG(INFO, "A major freeze is needed", K(total_active_memstore_used), K_(all_tenants_freeze_trigger)); bool_ret = true; } } return bool_ret; } int ObTenantManager::register_timer_task(int tg_id) { int ret = OB_SUCCESS; const bool is_repeated = true; const int64_t trigger_interval = 2 * 1000000; // 2s const int64_t print_delay = 10 * 1000000; // 10s if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_SUCCESS != (ret = TG_SCHEDULE(tg_id, freeze_task_, trigger_interval, is_repeated))) { COMMON_LOG(WARN, "fail to schedule major freeze task of tenant manager", K(ret)); } else if (OB_SUCCESS != (ret = TG_SCHEDULE(tg_id, print_task_, print_delay, is_repeated))) { COMMON_LOG(WARN, "fail to schedule print task of tenant manager", K(ret)); } return ret; } int ObTenantManager::post_freeze_request( const uint64_t tenant_id, const storage::ObFreezeType freeze_type, const int64_t try_frozen_version) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else { ObTenantFreezeArg arg; arg.tenant_id_ = tenant_id; arg.freeze_type_ = freeze_type; arg.try_frozen_version_ = try_frozen_version; COMMON_LOG(INFO, "post major freeze in tenant manager", K(arg)); if (OB_FAIL(rpc_proxy_.to(self_).post_freeze_request(arg, &tenant_mgr_cb_))) { COMMON_LOG(WARN, "fail to post freeze request", K(arg), K(ret)); } COMMON_LOG(INFO, "after major freeze in tenant manager"); } return ret; } int ObTenantManager::rpc_callback() { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else { COMMON_LOG(INFO, "call back of tenant mgr major freeze request"); } return ret; } void ObTenantManager::reload_config() { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (NULL == config_) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(WARN, "config_ shouldn't be null here", K(ret), KP(config_)); } else if (((int64_t)(config_->memstore_limit_percentage)) > 100 || ((int64_t)(config_->memstore_limit_percentage)) <= 0 || ((int64_t)(config_->freeze_trigger_percentage)) > 100 || ((int64_t)(config_->freeze_trigger_percentage)) <= 0) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(WARN, "memstore limit percent in ObServerConfig is invalid", "memstore limit percent", (int64_t)config_->memstore_limit_percentage, "minor freeze trigger percent", (int64_t)config_->freeze_trigger_percentage, K(ret)); } else { for (int64_t i = 0; i < BUCKET_NUM; i++) { ObTenantBucket& bucket = tenant_map_[i]; SpinWLockGuard guard(bucket.lock_); // It should be possible to change to a read lock here, this lock is a // structural lock, it is not appropriate to borrow DLIST_FOREACH_NORET(iter, bucket.info_list_) { if (true == iter->is_loaded_) { int64_t tmp_var = iter->mem_upper_limit_ / 100; iter->mem_memstore_limit_ = tmp_var * config_->memstore_limit_percentage; tmp_var = iter->mem_memstore_limit_ / 100; } } } ATOMIC_STORE(&all_tenants_freeze_trigger_, config_->get_server_memory_avail() * config_->get_global_freeze_trigger_percentage() / 100); ATOMIC_STORE(&all_tenants_memstore_limit_, config_->get_server_memory_avail() * config_->get_global_memstore_limit_percentage() / 100); } if (OB_SUCCESS == ret) { COMMON_LOG(INFO, "reload config for tenant manager", "new memstore limit percent", (int64_t)config_->memstore_limit_percentage, "new minor freeze trigger percent", (int64_t)config_->freeze_trigger_percentage, "new get_global_memstore_limit_percentage()", (int64_t)config_->get_global_memstore_limit_percentage(), "new get_global_freeze_trigger_percentage()", (int64_t)config_->get_global_freeze_trigger_percentage()); } } template int ObTenantManager::add_tenant_and_used(const uint64_t tenant_id, _callback& callback) { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; COMMON_LOG(WARN, "tenant manager not init", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else { uint64_t pos = tenant_id % BUCKET_NUM; ObTenantBucket& bucket = tenant_map_[pos]; SpinWLockGuard guard(bucket.lock_); ObTenantInfo* node = NULL; if (OB_SUCCESS == (ret = bucket.get_the_node(tenant_id, node))) { COMMON_LOG(INFO, "This tenant has exist", K(tenant_id), K(ret)); callback(node); } else { ObTenantInfo* info = NULL; if (OB_FAIL(tenant_pool_.pop(info))) { COMMON_LOG(WARN, "Fail to pop info from pool, ", K(ret)); } else { info->reset(); info->tenant_id_ = tenant_id; callback(info); if (OB_UNLIKELY(!bucket.info_list_.add_last(info))) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "Fail to add proc to wait list, ", K(ret)); if (OB_SUCCESS != (tmp_ret = tenant_pool_.push(info))) { COMMON_LOG(WARN, "Fail to push collects to pool, ", K(tmp_ret)); } } } } } return ret; } int ObTenantManager::check_memory_used(const int64_t tenant_id, const double mem_active_memstore_used, const double mem_minor_freeze_trigger, const double mem_memstore_limit, bool &use_too_much_memory) { int ret = OB_SUCCESS; use_too_much_memory = false; ObTenantResourceMgrHandle resource_handle; if (OB_FAIL(ObResourceMgr::get_instance().get_tenant_resource_mgr(tenant_id, resource_handle))) { COMMON_LOG(WARN, "fail to get resource mgr", K(ret), K(tenant_id)); } else { double total_memory_hold = get_tenant_memory_hold(tenant_id); double memory_limit = get_tenant_memory_limit(tenant_id); double kv_cache_mem = resource_handle.get_memory_mgr()->get_cache_hold(); double total_freeze_trigger = mem_memstore_limit + (memory_limit - mem_memstore_limit) * 0.5; if (total_memory_hold - kv_cache_mem >= total_freeze_trigger && mem_active_memstore_used >= 1.0/3.0 * total_freeze_trigger) { use_too_much_memory = true; COMMON_LOG(INFO, "too much memory is used, need to minor freeze", K(tenant_id), K(mem_active_memstore_used), K(mem_minor_freeze_trigger), K(total_memory_hold), K(kv_cache_mem), K(memory_limit)); } } return ret; } int64_t ObTenantCpuShare::calc_px_pool_share(uint64_t tenant_id, int64_t cpu_count) { UNUSED(tenant_id); /* Follow cpu_count * concurrency * 0.1 as the default value * But make sure to allocate at least 3 threads to the px pool, * When the calculated default value is less than 3, it is forced to be set to 3 * * Why should it be at least 3? This is to make mysqltest as much as possible * Can pass. When encountering a general right deep tree in mysqltest, 3 threads * To ensure that the scheduling is successful, 2 will time out. */ return std::max( 3L, cpu_count * static_cast(static_cast(GCONF.px_workers_per_cpu_quota.get()) * 0.1)); } } // namespace common } // namespace oceanbase