/**
 * 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 RS

#include "ob_unit_manager.h"

#include <cmath>
#include <float.h>

#include "lib/string/ob_sql_string.h"
#include "lib/allocator/ob_mod_define.h"
#include "lib/time/ob_time_utility.h"
#include "lib/container/ob_array_iterator.h"
#include "lib/mysqlclient/ob_mysql_proxy.h"
#include "lib/mysqlclient/ob_mysql_transaction.h"
#include "lib/utility/ob_tracepoint.h"
#include "share/ob_unit_getter.h"
#include "share/ob_debug_sync.h"
#include "share/ob_srv_rpc_proxy.h"
#include "share/config/ob_server_config.h"
#include "share/ob_schema_status_proxy.h"
#include "share/ob_dml_sql_splicer.h"
#include "share/ob_max_id_fetcher.h"
#include "share/inner_table/ob_inner_table_schema.h"
#include "share/ob_tenant_memstore_info_operator.h"
#include "observer/ob_server_struct.h"
#include "rootserver/ob_balance_info.h"
#include "rootserver/ob_zone_manager.h"
#include "rootserver/ob_rs_event_history_table_operator.h"
#include "rootserver/ob_leader_coordinator.h"
#include "rootserver/ob_unit_placement_strategy.h"
#include "rootserver/ob_rs_job_table_operator.h"
#include "rootserver/ob_root_service.h"
#include "rootserver/ob_root_balancer.h"
#include "rootserver/ob_rebalance_task_mgr.h"

namespace oceanbase {
using namespace common;
using namespace common::sqlclient;
using namespace common::hash;
using namespace share;
using namespace share::schema;
namespace rootserver {

int ObUnitManager::ZoneUnitPtr::assign(const ZoneUnitPtr& other)
{
  int ret = OB_SUCCESS;
  zone_ = other.zone_;
  if (OB_FAIL(copy_assign(unit_ptrs_, other.unit_ptrs_))) {
    LOG_WARN("fail to assign unit_ptrs", K(ret));
  }
  return ret;
}

int ObUnitManager::ZoneUnitPtr::sort_by_unit_id_desc()
{
  UnitGroupIdCmp cmp;
  std::sort(unit_ptrs_.begin(), unit_ptrs_.end(), cmp);
  return cmp.get_ret();
}

int ObUnitManager::ZoneUnit::assign(const ZoneUnit& other)
{
  int ret = OB_SUCCESS;
  zone_ = other.zone_;
  if (OB_FAIL(copy_assign(unit_infos_, other.unit_infos_))) {
    LOG_WARN("failed to assign unit_infos_", K(ret));
  }
  return ret;
}
////////////////////////////////////////////////////////////////
double ObUnitManager::ObUnitLoad::get_demand(ObResourceType resource_type) const
{
  double ret = -1;
  if (resource_type < RES_MAX && resource_type >= 0) {
    switch (resource_type) {
      case RES_CPU:
        ret = unit_config_->min_cpu_;
        break;
      case RES_MEM:
        ret = static_cast<double>(unit_config_->min_memory_);
        break;
      case RES_DISK:
        ret = static_cast<double>(unit_config_->max_disk_size_);
        break;
      default:
        ret = -1;
        break;
    }
  }
  return ret;
}

// sort asc
bool ObUnitManager::ObUnitLoadOrder::operator()(const ObUnitLoad& left, const ObUnitLoad& right)
{
  bool less = false;
  double left_load = 0;
  double right_load = 0;
  if (OB_SUCCESS != ret_) {
  } else if (!left.is_valid() || !right.is_valid()) {
    ret_ = OB_INVALID_ARGUMENT;
    RS_LOG(WARN, "invalid argument", K(left), K(right), K_(ret));
  } else if (OB_SUCCESS !=
             (ret_ = ObResourceUtils::calc_load(left, server_load_, weights_, weights_count_, left_load))) {
  } else if (OB_SUCCESS !=
             (ret_ = ObResourceUtils::calc_load(right, server_load_, weights_, weights_count_, right_load))) {
  } else {
    less = left_load < right_load;
  }
  return less;
}

////////////////////////////////////////////////////////////////
double ObUnitManager::ObServerLoad::get_assigned(ObResourceType resource_type) const
{
  double ret = -1;
  if (resource_type < RES_MAX && resource_type >= 0) {
    switch (resource_type) {
      case RES_CPU:
        ret = sum_load_.min_cpu_;
        break;
      case RES_MEM:
        ret = static_cast<double>(sum_load_.min_memory_);
        break;
      case RES_DISK:
        ret = static_cast<double>(sum_load_.max_disk_size_);
        break;
      default:
        ret = -1;
        break;
    }
  }
  return ret;
}

double ObUnitManager::ObServerLoad::get_max_assigned(ObResourceType resource_type) const
{
  double ret = -1;
  if (resource_type < RES_MAX && resource_type >= 0) {
    switch (resource_type) {
      case RES_CPU:
        ret = sum_load_.max_cpu_;
        break;
      case RES_MEM:
        ret = static_cast<double>(sum_load_.max_memory_);
        break;
      case RES_DISK:
        ret = static_cast<double>(sum_load_.max_disk_size_);
        break;
      default:
        ret = -1;
        break;
    }
  }
  return ret;
}

double ObUnitManager::ObServerLoad::get_capacity(ObResourceType resource_type) const
{
  double ret = -1;
  if (resource_type < RES_MAX && resource_type >= 0) {
    switch (resource_type) {
      case RES_CPU:
        ret = status_.resource_info_.cpu_;
        break;
      case RES_MEM:
        ret = static_cast<double>(status_.resource_info_.mem_total_);
        break;
      case RES_DISK:
        ret = static_cast<double>(status_.resource_info_.disk_total_);
        break;
      default:
        ret = -1;
        break;
    }
  }
  return ret;
}

int ObUnitManager::ObServerLoad::assign(const ObServerLoad& other)
{
  int ret = OB_SUCCESS;
  sum_load_ = other.sum_load_;
  status_ = other.status_;
  all_normal_unit_ = other.all_normal_unit_;
  if (OB_FAIL(copy_assign(unit_loads_, other.unit_loads_))) {
    LOG_WARN("failed to assign unit_loads_", K(ret));
  } else if (OB_FAIL(copy_assign(mark_delete_indexes_, other.mark_delete_indexes_))) {
    LOG_WARN("failed to assign mark_delete_indexes_", K(ret));
  }
  return ret;
}

bool ObUnitManager::ObServerLoad::is_valid() const
{
  // sum_load_ config_name is empty, don't check it
  return status_.is_valid();
}

void ObUnitManager::ObServerLoad::reset()
{
  sum_load_.reset();
  status_.reset();
  unit_loads_.reset();
  all_normal_unit_ = true;
  mark_delete_indexes_.reset();
}

int ObUnitManager::ObServerLoad::get_load(double* weights, int64_t weights_count, double& load) const
{
  int ret = common::OB_SUCCESS;
  if (!is_valid() || weights_count != RES_MAX) {
    ret = OB_INVALID_ARGUMENT;
    RS_LOG(WARN, "invalid server load", "server_load", *this, K(ret), K(weights_count));
  } else if (OB_FAIL(ObResourceUtils::calc_load(*this, weights, weights_count, load))) {
    RS_LOG(WARN, "failed to calc load");
  }
  return ret;
}

int ObUnitManager::ObServerLoad::get_load_if_add(
    double* weights, int64_t weights_count, const share::ObUnitConfig& config, double& load) const
{
  int ret = OB_SUCCESS;
  if (!is_valid() || !config.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    RS_LOG(WARN, "invalid server load", "server_load", *this, K(config), K(ret));
  } else {
    ObServerLoad new_load;
    new_load.sum_load_ = this->sum_load_;
    new_load.status_ = this->status_;
    new_load.sum_load_ += config;
    if (OB_FAIL(ObResourceUtils::calc_load(new_load, weights, weights_count, load))) {
      RS_LOG(WARN, "failed to calc load");
    }
  }
  return ret;
}

int ObUnitManager::ObServerLoad::build(const ObArray<ObUnitLoad>* unit_loads, const ObServerStatus& status)
{
  int ret = OB_SUCCESS;
  reset();
  // if not unit on server, unit_loads is NULL, so don't check unit_loads here
  if (!status.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid status", K(status), K(ret));
  } else if (OB_FAIL(ObUnitManager::calc_sum_load(unit_loads, sum_load_))) {
    LOG_WARN("calc_sum_load failed", KP(unit_loads), K(ret));
  } else {
    status_ = status;
    if (NULL == unit_loads) {
      // do nothing
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < unit_loads->count(); ++i) {
        if (!unit_loads->at(i).is_valid()) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unit_load is null", "unit_load", unit_loads->at(i), K(ret));
        } else if (unit_loads->at(i).unit_->migrate_from_server_ == status.server_ ||
                   ObUnit::UNIT_STATUS_ACTIVE != unit_loads->at(i).unit_->status_) {
          all_normal_unit_ = false;
        }
      }
      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(unit_loads_.assign(*unit_loads))) {
        LOG_WARN("assign failed", K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::ObServerLoad::mark_delete(const int64_t index)
{
  int ret = OB_SUCCESS;
  if (!is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid server_load", "server_load", *this, K(ret));
  } else if (index < 0 || index >= unit_loads_.count()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid index", K(index), "unit_load count", unit_loads_.count(), K(ret));
  } else if (!unit_loads_.at(index).is_valid()) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid unit_load", "unit_load", unit_loads_.at(index), K(ret));
  } else if (has_exist_in_array(mark_delete_indexes_, index)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("unit_load already marked deleted", K_(mark_delete_indexes), K(index), K(ret));
  } else if (OB_FAIL(mark_delete_indexes_.push_back(index))) {
    LOG_WARN("push_back failed", K(ret));
  } else {
    sum_load_ -= *unit_loads_.at(index).unit_config_;
  }
  return ret;
}

int ObUnitManager::ObServerLoad::add_load(const ObUnitLoad& load)
{
  int ret = OB_SUCCESS;
  if (!is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid server_load", "server_load", *this, K(ret));
  } else if (!load.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid load", K(load), K(ret));
  } else {
    sum_load_ += *load.unit_config_;
    if (OB_FAIL(unit_loads_.push_back(load))) {
      LOG_WARN("push_back failed", K(ret));
    }
  }
  return ret;
}

// sorted desc
bool ObUnitManager::ObServerLoadOrder::operator()(const ObServerLoad* left, const ObServerLoad* right)
{
  bool greater = false;
  double left_load = 0;
  double right_load = 0;
  if (OB_SUCCESS != ret_) {
  } else if (OB_ISNULL(left) || OB_ISNULL(right) || !left->is_valid() || !right->is_valid()) {
    ret_ = OB_INVALID_ARGUMENT;
    RS_LOG(WARN, "invalid argument", K(left), K(right), K_(ret));
  } else if (OB_SUCCESS != (ret_ = left->get_load(weights_, weights_count_, left_load))) {
  } else if (OB_SUCCESS != (ret_ = right->get_load(weights_, weights_count_, right_load))) {
  } else {
    greater = left_load > right_load;
  }
  return greater;
}
////////////////////////////////////////////////////////////////
ObUnitManager::ObUnitManager(ObServerManager& server_mgr, ObZoneManager& zone_mgr)
    : inited_(false),
      loaded_(false),
      proxy_(NULL),
      server_config_(NULL),
      leader_coordinator_(NULL),
      server_mgr_(server_mgr),
      zone_mgr_(zone_mgr),
      ut_operator_(),
      id_config_map_(),
      name_config_map_(),
      config_ref_count_map_(),
      config_pools_map_(),
      config_pools_allocator_(OB_MALLOC_NORMAL_BLOCK_SIZE, ObMalloc(ObModIds::OB_RS_UNIT_MANAGER)),
      config_allocator_(OB_MALLOC_NORMAL_BLOCK_SIZE, ObMalloc(ObModIds::OB_RS_UNIT_MANAGER)),
      id_pool_map_(),
      name_pool_map_(),
      pool_allocator_(OB_MALLOC_NORMAL_BLOCK_SIZE, ObMalloc(ObModIds::OB_RS_UNIT_MANAGER)),
      pool_unit_map_(),
      pool_unit_allocator_(OB_MALLOC_NORMAL_BLOCK_SIZE, ObMalloc(ObModIds::OB_RS_UNIT_MANAGER)),
      id_unit_map_(),
      allocator_(OB_MALLOC_NORMAL_BLOCK_SIZE, ObMalloc(ObModIds::OB_RS_UNIT_MANAGER)),
      server_loads_(),
      load_allocator_(OB_MALLOC_NORMAL_BLOCK_SIZE, ObMalloc(ObModIds::OB_RS_UNIT_MANAGER)),
      tenant_pools_map_(),
      tenant_pools_allocator_(OB_MALLOC_NORMAL_BLOCK_SIZE, ObMalloc(ObModIds::OB_RS_UNIT_MANAGER)),
      server_migrate_units_map_(),
      migrate_units_allocator_(OB_MALLOC_NORMAL_BLOCK_SIZE, ObMalloc(ObModIds::OB_RS_UNIT_MANAGER)),
      lock_(ObLatchIds::UNIT_MANAGER_LOCK),
      unit_placement_strategy_(NULL),
      schema_service_(NULL),
      root_balance_(NULL)
{}

ObUnitManager::~ObUnitManager()
{
  ObHashMap<uint64_t, ObArray<share::ObResourcePool*>*>::iterator iter1;
  for (iter1 = config_pools_map_.begin(); iter1 != config_pools_map_.end(); ++iter1) {
    ObArray<share::ObResourcePool*>* ptr = iter1->second;
    if (NULL != ptr) {
      ptr->reset();
      ptr = NULL;
    }
  }
  ObHashMap<uint64_t, ObArray<ObUnit*>*>::iterator iter2;
  for (iter2 = pool_unit_map_.begin(); iter2 != pool_unit_map_.end(); ++iter2) {
    ObArray<share::ObUnit*>* ptr = iter2->second;
    if (NULL != ptr) {
      ptr->reset();
      ptr = NULL;
    }
  }
  ObHashMap<ObAddr, ObArray<ObUnitLoad>*>::iterator iter3;
  for (iter3 = server_loads_.begin(); iter3 != server_loads_.end(); ++iter3) {
    ObArray<ObUnitLoad>* ptr = iter3->second;
    if (NULL != ptr) {
      ptr->reset();
      ptr = NULL;
    }
  }
  TenantPoolsMap::iterator iter4;
  for (iter4 = tenant_pools_map_.begin(); iter4 != tenant_pools_map_.end(); ++iter4) {
    common::ObArray<share::ObResourcePool*>* ptr = iter4->second;
    if (NULL != ptr) {
      ptr->reset();
      ptr = NULL;
    }
  }
  ObHashMap<ObAddr, ObArray<uint64_t>*>::iterator iter5;
  for (iter5 = server_migrate_units_map_.begin(); iter5 != server_migrate_units_map_.end(); ++iter5) {
    common::ObArray<uint64_t>* ptr = iter5->second;
    if (NULL != ptr) {
      ptr->reset();
      ptr = NULL;
    }
  }
}

void ObUnitManager::dump()
{
  ObHashMap<ObAddr, ObArray<uint64_t>*>::iterator iter5;
  for (iter5 = server_migrate_units_map_.begin(); iter5 != server_migrate_units_map_.end(); ++iter5) {
    common::ObArray<uint64_t>* ptr = iter5->second;
    ObAddr server = iter5->first;
    if (OB_ISNULL(ptr)) {
      LOG_WARN("DUMP get invalid unit info", K(server));
    } else {
      LOG_INFO("DUMP SERVER_MIGRATE_UNIT_MAP", K(server), K(*ptr));
    }
  }
}

int ObUnitManager::init(ObMySQLProxy& proxy, ObServerConfig& server_config, ObILeaderCoordinator& leader_coordinator,
    share::schema::ObMultiVersionSchemaService& schema_service, ObRootBalancer& root_balance)
{
  int ret = OB_SUCCESS;
  if (inited_) {
    ret = OB_INIT_TWICE;
    LOG_WARN("init twice", K(ret));
  } else if (OB_FAIL(ut_operator_.init(proxy, NULL))) {
    LOG_WARN("init unit table operator failed", K(ret));
  } else if (OB_FAIL(pool_unit_map_.create(POOL_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_POOL_UNIT_MAP))) {
    LOG_WARN("pool_unit_map_ create failed", LITERAL_K(POOL_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(id_unit_map_.create(UNIT_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_ID_UNIT_MAP))) {
    LOG_WARN("id_unit_map_ create failed", LITERAL_K(UNIT_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(id_config_map_.create(CONFIG_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_ID_CONFIG_MAP))) {
    LOG_WARN("id_config_map_ create failed", LITERAL_K(CONFIG_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(name_config_map_.create(CONFIG_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_NAME_CONFIG_MAP))) {
    LOG_WARN("name_config_map_ create failed", LITERAL_K(CONFIG_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(config_ref_count_map_.create(
                 CONFIG_REF_COUNT_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_CONFIG_REF_COUNT_MAP))) {
    LOG_WARN("config_ref_count_map_ create failed", LITERAL_K(CONFIG_REF_COUNT_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(
                 config_pools_map_.create(CONFIG_POOLS_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_CONFIG_POOLS_MAP))) {
    LOG_WARN("create config_pools_map failed", LITERAL_K(CONFIG_POOLS_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(id_pool_map_.create(POOL_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_ID_POOL_MAP))) {
    LOG_WARN("id_pool_map_ create failed", LITERAL_K(POOL_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(name_pool_map_.create(POOL_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_NAME_POOL_MAP))) {
    LOG_WARN("name_pool_map_ create failed", LITERAL_K(POOL_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(server_loads_.create(UNITLOAD_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_SERVER_UNITLOAD_MAP))) {
    LOG_WARN("server_loads_ create failed", LITERAL_K(UNITLOAD_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(
                 tenant_pools_map_.create(TENANT_POOLS_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_TENANT_POOLS_MAP))) {
    LOG_WARN("tenant_pools_map_ create failed", LITERAL_K(TENANT_POOLS_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(server_migrate_units_map_.create(
                 SERVER_MIGRATE_UNITS_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_SERVER_MIGRATE_UNIT_MAP))) {
    LOG_WARN("server_migrate_units_map_ create failed", LITERAL_K(SERVER_MIGRATE_UNITS_MAP_BUCKET_NUM), K(ret));
  } else {
    proxy_ = &proxy;
    server_config_ = &server_config;
    leader_coordinator_ = &leader_coordinator;
    schema_service_ = &schema_service;
    root_balance_ = &root_balance;
    loaded_ = false;
    inited_ = true;
  }
  return ret;
}

int ObUnitManager::load()
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else {
    loaded_ = false;
    ObHashMap<uint64_t, ObArray<share::ObResourcePool*>*>::iterator iter1;
    for (iter1 = config_pools_map_.begin(); iter1 != config_pools_map_.end(); ++iter1) {
      ObArray<share::ObResourcePool*>* ptr = iter1->second;
      if (NULL != ptr) {
        ptr->reset();
        ptr = NULL;
      }
    }
    ObHashMap<uint64_t, ObArray<ObUnit*>*>::iterator iter2;
    for (iter2 = pool_unit_map_.begin(); iter2 != pool_unit_map_.end(); ++iter2) {
      ObArray<share::ObUnit*>* ptr = iter2->second;
      if (NULL != ptr) {
        ptr->reset();
        ptr = NULL;
      }
    }
    ObHashMap<ObAddr, ObArray<ObUnitLoad>*>::iterator iter3;
    for (iter3 = server_loads_.begin(); iter3 != server_loads_.end(); ++iter3) {
      ObArray<ObUnitLoad>* ptr = iter3->second;
      if (NULL != ptr) {
        ptr->reset();
        ptr = NULL;
      }
    }
    TenantPoolsMap::iterator iter4;
    for (iter4 = tenant_pools_map_.begin(); iter4 != tenant_pools_map_.end(); ++iter4) {
      common::ObArray<share::ObResourcePool*>* ptr = iter4->second;
      if (NULL != ptr) {
        ptr->reset();
        ptr = NULL;
      }
    }
    ObHashMap<ObAddr, ObArray<uint64_t>*>::iterator iter5;
    for (iter5 = server_migrate_units_map_.begin(); iter5 != server_migrate_units_map_.end(); ++iter5) {
      common::ObArray<uint64_t>* ptr = iter5->second;
      if (NULL != ptr) {
        ptr->reset();
        ptr = NULL;
      }
    }
    if (OB_FAIL(id_config_map_.clear())) {
      LOG_WARN("id_config_map_ clear failed", K(ret));
    } else if (OB_FAIL(name_config_map_.clear())) {
      LOG_WARN("name_pool_map_  clear failed", K(ret));
    } else if (OB_FAIL(config_ref_count_map_.clear())) {
      LOG_WARN("config_ref_count_map_ clear failed", K(ret));
    } else if (OB_FAIL(config_pools_map_.clear())) {
      LOG_WARN("config_pools_map_ clear failed", K(ret));
    } else if (OB_FAIL(id_pool_map_.clear())) {
      LOG_WARN("id_pool_map_ clear failed", K(ret));
    } else if (OB_FAIL(name_pool_map_.clear())) {
      LOG_WARN("name_pool_map_ clear failed", K(ret));
    } else if (OB_FAIL(pool_unit_map_.clear())) {
      LOG_WARN("pool_unit_map_ clear failed", K(ret));
    } else if (OB_FAIL(id_unit_map_.clear())) {
      LOG_WARN("id_unit_map_ clear failed", K(ret));
    } else if (OB_FAIL(server_loads_.clear())) {
      LOG_WARN("server_loads_ clear failed", K(ret));
    } else if (OB_FAIL(tenant_pools_map_.clear())) {
      LOG_WARN("tenant_pools_map_ clear failed", K(ret));
    } else if (OB_FAIL(server_migrate_units_map_.clear())) {
      LOG_WARN("server_migrate_units_map_ clear failed", K(ret));
    }

    // free all memory
    if (OB_FAIL(ret)) {
    } else {
      config_allocator_.reset();
      config_pools_allocator_.reset();
      pool_allocator_.reset();
      pool_unit_allocator_.reset();
      allocator_.reset();
      load_allocator_.reset();
      tenant_pools_allocator_.reset();
      migrate_units_allocator_.reset();
    }

    // load unit config
    ObArray<ObUnitConfig> configs;
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(ut_operator_.get_unit_configs(configs))) {
      LOG_WARN("get_unit_configs failed", K(ret));
    } else if (OB_FAIL(build_config_map(configs))) {
      LOG_WARN("build_config_map failed", K(ret));
    }

    // load resource pool
    ObArray<share::ObResourcePool> pools;
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(ut_operator_.get_resource_pools(pools))) {
      LOG_WARN("get_resource_pools failed", K(ret));
    } else if (OB_FAIL(build_pool_map(pools))) {
      LOG_WARN("build_pool_map failed", K(ret));
    }

    // load unit
    ObArray<ObUnit> units;
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(ut_operator_.get_units(units))) {
      LOG_WARN("get_units failed", K(ret));
    } else {
      if (OB_FAIL(build_unit_map(units))) {
        LOG_WARN("build_unit_map failed", K(ret));
      }
    }

    // build tenant pools
    if (OB_FAIL(ret)) {
    } else {
      for (ObHashMap<uint64_t, share::ObResourcePool*>::iterator it = id_pool_map_.begin();
           OB_SUCCESS == ret && it != id_pool_map_.end();
           ++it) {
        // pool not grant to tenant don't add to tenant_pools_map
        if (NULL == it->second) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("it->second is null", KP(it->second), K(ret));
        } else if (OB_INVALID_ID != it->second->tenant_id_) {
          if (OB_FAIL(insert_tenant_pool(it->second->tenant_id_, it->second))) {
            LOG_WARN("insert_tenant_pool failed", "tenant_id", it->second->tenant_id_, "pool", *(it->second), K(ret));
          }
        }
      }
    }

    // build server migrate units
    if (OB_FAIL(ret)) {
    } else {
      FOREACH_CNT_X(unit, units, OB_SUCCESS == ret)
      {
        if (unit->migrate_from_server_.is_valid()) {
          if (OB_FAIL(insert_migrate_unit(unit->migrate_from_server_, unit->unit_id_))) {
            LOG_WARN(
                "insert_migrate_unit failed", "server", unit->migrate_from_server_, "unit_id", unit->unit_id_, K(ret));
          }
        }
      }
    }

    if (OB_SUCC(ret)) {
      loaded_ = true;
    }
  }
  LOG_INFO("unit manager load finish", K(ret));
  return ret;
}

int ObUnitManager::create_unit_config(ObUnitConfig& config, const bool if_not_exist)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  if (OB_FAIL(inner_create_unit_config(config, if_not_exist))) {
    LOG_WARN("fail to create unit config", K(ret));
  }
  return ret;
}

int ObUnitManager::inner_create_unit_config(ObUnitConfig& config, const bool if_not_exist)
{
  int ret = OB_SUCCESS;
  LOG_INFO("start create unit config", K(config));
  ObUnitConfig* temp_config = NULL;
  const ObUnitConfig rpc_config = config;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (!config.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid config", K(config), K(ret));
  } else if (OB_FAIL(check_unit_config(rpc_config, config))) {
    LOG_WARN("check_unit_config failed", K(rpc_config), K(config), K(ret));
  } else if (OB_SUCCESS == (ret = get_unit_config_by_name(config.name_, temp_config))) {
    if (NULL == temp_config) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("temp_config is null", KP(temp_config), K(ret));
    } else if (if_not_exist) {
      LOG_USER_NOTE(OB_RESOURCE_UNIT_EXIST, to_cstring(config.name_));
      LOG_INFO("unit config already exist", K(config));
    } else {
      ret = OB_RESOURCE_UNIT_EXIST;
      LOG_USER_ERROR(OB_RESOURCE_UNIT_EXIST, to_cstring(config.name_));
      LOG_WARN("unit config already exist", K(config), K(ret));
    }
  } else if (OB_ENTRY_NOT_EXIST != ret) {
    LOG_WARN("get_unit_config_by_name failed", "config_name", config.name_, K(ret));
  } else {
    ret = OB_SUCCESS;
    ObUnitConfig* new_config = NULL;
    if (NULL == (new_config = config_allocator_.alloc())) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_ERROR("alloc memory failed", K(ret));
    } else {
      *new_config = config;
      if (OB_INVALID_ID == new_config->unit_config_id_) {
        if (OB_FAIL(fetch_new_unit_config_id(new_config->unit_config_id_))) {
          LOG_WARN("fetch_new_unit_config_id failed", K(ret));
        }
      }

      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(ut_operator_.update_unit_config(*proxy_, *new_config))) {
        LOG_WARN("update_unit_config failed", "unit config", *new_config, K(ret));
      } else if (OB_FAIL(insert_unit_config(new_config))) {
        LOG_WARN("insert_unit_config failed", "unit config", *new_config, K(ret));
      }

      // avoid memory leak
      if (OB_FAIL(ret)) {
        config_allocator_.free(new_config);
        new_config = NULL;
      }
      if (OB_SUCC(ret)) {
        ROOTSERVICE_EVENT_ADD("unit", "create_resource_unit", "name", new_config->name_);
      }
    }
  }
  LOG_INFO("finish create unit config", K(config), K(ret));
  return ret;
}

int ObUnitManager::alter_unit_config(ObUnitConfig& unit_config)
{
  int ret = OB_SUCCESS;
  ObUnitConfig* old_config = NULL;
  ObArray<share::ObResourcePool*>* pools = NULL;
  SpinWLockGuard guard(lock_);
  // don't check unit_config valid here, max_xxx == 0 if not change, will not
  // pass valid check
  const ObUnitConfig rpc_config = unit_config;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_FAIL(get_unit_config_by_name(unit_config.name_, old_config))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_unit_config_by_name failed", "name", unit_config.name_, K(ret));
    } else {
      // overwrite ret on purpose
      ret = OB_RESOURCE_UNIT_NOT_EXIST;
      LOG_WARN("config does not exist", "config name", unit_config.name_, K(ret));
    }
  } else if (NULL == old_config) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("old_config is null", KP(old_config), K(ret));
  } else if (OB_FAIL(copy_config_options(*old_config, unit_config))) {
    LOG_WARN("copy_config_options failed", "old_config", *old_config, K(ret));
  } else {
    if (OB_FAIL(check_unit_config(rpc_config, unit_config))) {
      LOG_WARN("check_unit_config failed", K(rpc_config), K(unit_config), K(ret));
    } else {
      if (OB_FAIL(get_pools_by_config(old_config->unit_config_id_, pools))) {
        if (OB_ENTRY_NOT_EXIST != ret) {
          LOG_WARN("get_pools_by_config failed", "config_id", old_config->unit_config_id_, K(ret));
        } else {
          ret = OB_SUCCESS;
          // this unit config is not used by any resource pools
          // update the config directly
        }
      } else if (NULL == pools) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pools is null", KP(pools), K(ret));
      } else {
        if (OB_FAIL(check_expand_config(*pools, *old_config, unit_config))) {
          LOG_WARN("check expand config failed", "old config", *old_config, "new config", unit_config, K(ret));
        } else if (OB_FAIL(check_shrink_config(*pools, *old_config, unit_config))) {
          LOG_WARN("check_shrink_config failed", "old config", *old_config, "new config", unit_config, K(ret));
        } else if (OB_FAIL(check_full_resource_pool_memory_condition(*pools, unit_config))) {
          LOG_WARN(
              "fail to check full resource pool memory condition", K(ret), "new_config", unit_config, "pools", *pools);
        }
      }
    }

    if (OB_SUCC(ret)) {
      unit_config.unit_config_id_ = old_config->unit_config_id_;
      if (OB_FAIL(ut_operator_.update_unit_config(*proxy_, unit_config))) {
        LOG_WARN("update_unit_config failed", K(unit_config), K(ret));
      } else {
        *old_config = unit_config;
      }
    }
    if (OB_SUCC(ret)) {
      ROOTSERVICE_EVENT_ADD("unit",
          "alter_resource_unit",
          "name",
          unit_config.name_,
          "old_config",
          *old_config,
          "new_config",
          unit_config);
    }
  }
  return ret;
}

int ObUnitManager::drop_unit_config(const ObUnitConfigName& name, const bool if_exist)
{
  int ret = OB_SUCCESS;
  LOG_INFO("start drop unit config", K(name));
  SpinWLockGuard guard(lock_);
  ObUnitConfig* config = NULL;
  int64_t ref_count = 0;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (name.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource unit name");
    LOG_WARN("invalid argument", K(name), K(ret));
  } else if (OB_FAIL(get_unit_config_by_name(name, config))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_unit_config_by_name failed", K(name), K(ret));
    } else {
      if (if_exist) {
        ret = OB_SUCCESS;
        LOG_USER_NOTE(OB_RESOURCE_UNIT_NOT_EXIST, to_cstring(name));
        LOG_INFO("unit config not exist, no need to delete it", K(name));
      } else {
        ret = OB_RESOURCE_UNIT_NOT_EXIST;
        LOG_USER_ERROR(OB_RESOURCE_UNIT_NOT_EXIST, to_cstring(name));
        LOG_WARN("unit config not exist", K(name), K(ret));
      }
    }
  } else if (NULL == config) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("config is null", KP(config), K(ret));
  } else if (OB_FAIL(get_config_ref_count(config->unit_config_id_, ref_count))) {
    LOG_WARN("get_config_ref_count failed", "config_id", config->unit_config_id_, K(ret));
  } else if (0 != ref_count) {
    ret = OB_RESOURCE_UNIT_IS_REFERENCED;
    LOG_USER_ERROR(OB_RESOURCE_UNIT_IS_REFERENCED, to_cstring(name));
    LOG_WARN("some resource pool is using this unit config, can not delete it", K(ref_count), K(ret));
  } else if (OB_FAIL(ut_operator_.remove_unit_config(*proxy_, config->unit_config_id_))) {
    LOG_WARN("remove_unit_config failed", "config_id", config->unit_config_id_, K(ret));
  } else if (OB_FAIL(delete_unit_config(config->unit_config_id_, config->name_))) {
    LOG_WARN("delete_unit_config failed", "config id", config->unit_config_id_, "name", config->name_, K(ret));
  } else {
    ROOTSERVICE_EVENT_ADD("unit", "drop_resource_unit", "name", config->name_);
    // free memory
    config_allocator_.free(config);
    config = NULL;
  }
  LOG_INFO("finish drop unit config", K(name), K(ret));
  return ret;
}

int ObUnitManager::check_tenant_pools_in_shrinking(const uint64_t tenant_id, bool& is_shrinking)
{
  int ret = OB_SUCCESS;
  common::ObArray<share::ObResourcePool*>* pools = NULL;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(OB_INVALID_ID == tenant_id)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret));
  } else if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
    LOG_WARN("fail to get pools by tenant", K(ret), K(tenant_id));
  } else if (OB_UNLIKELY(NULL == pools)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pools ptr is null", K(ret), KP(pools));
  } else {
    is_shrinking = false;
    for (int64_t i = 0; !is_shrinking && OB_SUCC(ret) && i < pools->count(); ++i) {
      common::ObArray<share::ObUnit*>* units = NULL;
      const share::ObResourcePool* pool = pools->at(i);
      if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret), KP(pool));
      } else if (OB_FAIL(get_units_by_pool(pool->resource_pool_id_, units))) {
        LOG_WARN("fail to get units by pool", K(ret), "pool_id", pool->resource_pool_id_);
      } else if (NULL == units) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("units ptrs is null", K(ret), KP(units));
      } else {
        is_shrinking = false;
        for (int64_t j = 0; !is_shrinking && OB_SUCC(ret) && j < units->count(); ++j) {
          const ObUnit* unit = units->at(j);
          if (OB_UNLIKELY(NULL == unit)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unit ptr si null", K(ret));
          } else if (ObUnit::UNIT_STATUS_DELETING == unit->status_) {
            is_shrinking = true;
          } else if (ObUnit::UNIT_STATUS_ACTIVE == unit->status_) {
            // a normal unit, go on and check next
          } else {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unit status unexpected", K(ret), "unit_status", unit->status_);
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::check_pool_in_shrinking(const uint64_t pool_id, bool& is_shrinking)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(OB_INVALID_ID == pool_id)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(pool_id));
  } else {
    common::ObArray<share::ObUnit*>* units = NULL;
    SpinRLockGuard guard(lock_);
    if (OB_FAIL(get_units_by_pool(pool_id, units))) {
      LOG_WARN("fail to get units by pool", K(ret), K(pool_id));
    } else if (NULL == units) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("units ptr is null", K(ret), KP(units));
    } else {
      is_shrinking = false;
      for (int64_t i = 0; !is_shrinking && OB_SUCC(ret) && i < units->count(); ++i) {
        const ObUnit* unit = units->at(i);
        if (OB_UNLIKELY(NULL == unit)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unit ptr is null", K(ret));
        } else if (ObUnit::UNIT_STATUS_DELETING == unit->status_) {
          is_shrinking = true;
        } else if (ObUnit::UNIT_STATUS_ACTIVE == unit->status_) {
          // a normal unit, go on and check next
        } else {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unit status unexpected", K(ret), "unit_status", unit->status_);
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::upgrade_cluster_create_ha_gts_util()
{
  int ret = OB_SUCCESS;
  LOG_INFO("start upgrade cluster create ha gts util");
  SpinWLockGuard guard(lock_);

  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("fail to check inner stat", K(ret), K(inited_), K(loaded_));
  } else if (OB_FAIL(try_upgrade_cluster_create_gts_unit_config())) {
    LOG_WARN("fail to try create gts unit config", K(ret));
  } else if (OB_FAIL(try_upgrade_cluster_create_gts_resource_pool())) {
    LOG_WARN("fail to try create gts resource pool", K(ret));
  }
  return ret;
}

int ObUnitManager::do_upgrade_cluster_create_gts_unit_config()
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("fail to check inner stat", K(ret), K(inited_), K(loaded_));
  } else {
    share::ObUnitConfig gts_unit_cfg;
    gts_unit_cfg.unit_config_id_ = OB_GTS_UNIT_CONFIG_ID;
    gts_unit_cfg.name_ = OB_GTS_UNIT_CONFIG_NAME;
    gts_unit_cfg.max_cpu_ = 0.5;
    gts_unit_cfg.min_cpu_ = 0.5;
    gts_unit_cfg.max_memory_ = GCONF.__min_full_resource_pool_memory;
    gts_unit_cfg.min_memory_ = gts_unit_cfg.max_memory_;
    gts_unit_cfg.max_disk_size_ = 1024 * 1024 * 1024;  // no use;
    gts_unit_cfg.max_iops_ = 128;                      // no use;
    gts_unit_cfg.min_iops_ = 128;                      // no use;
    gts_unit_cfg.max_session_num_ = INT64_MAX;
    if (OB_FAIL(inner_create_unit_config(gts_unit_cfg, false /*if not exist*/))) {
      LOG_WARN("fail to inner create unit config", K(ret));
    }
  }
  return ret;
}

int ObUnitManager::try_upgrade_cluster_create_gts_unit_config()
{
  int ret = OB_SUCCESS;
  const share::ObUnitConfigName unit_cfg_name(OB_GTS_UNIT_CONFIG_NAME);
  share::ObUnitConfig* unit_cfg = nullptr;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("fail to check inner stat", K(ret), K(inited_), K(loaded_));
  } else {
    bool gts_cfg_exist = false;
    int tmp_ret = get_unit_config_by_name(unit_cfg_name, unit_cfg);
    if (OB_ENTRY_NOT_EXIST == tmp_ret) {
      gts_cfg_exist = false;
    } else if (OB_SUCCESS == tmp_ret) {
      gts_cfg_exist = true;
    } else {
      ret = tmp_ret;
      LOG_WARN("fail to get unit config", K(ret));
    }
    if (OB_SUCC(ret) && !gts_cfg_exist) {
      if (OB_FAIL(do_upgrade_cluster_create_gts_unit_config())) {
        LOG_WARN("fail to do create gts unit config", K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::init_upgrade_cluster_gts_resource_pool(const common::ObZone& zone, share::ObResourcePool& pool)
{
  int ret = OB_SUCCESS;
  pool.reset();
  pool.unit_count_ = 1;
  pool.unit_config_id_ = OB_GTS_UNIT_CONFIG_ID;
  pool.tenant_id_ = OB_INVALID_ID;
  pool.replica_type_ = REPLICA_TYPE_FULL;
  if (OB_FAIL(databuff_printf(pool.name_.ptr(), common::MAX_RESOURCE_POOL_LENGTH, "gts_pool_%s", zone.ptr()))) {
    LOG_WARN("fail to do data buff print", K(ret));
  } else if (OB_FAIL(pool.zone_list_.push_back(zone))) {
    LOG_WARN("fail to push back", K(ret));
  }
  return ret;
}

int ObUnitManager::try_upgrade_cluster_create_gts_resource_pool()
{
  int ret = OB_SUCCESS;
  common::ObArray<common::ObZone> all_zone_list;
  common::ObArray<common::ObZone> pool_zone_list;
  const uint64_t tenant_id = OB_GTS_TENANT_ID;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("fail to check inner stat", K(ret), K(inited_), K(loaded_));
  } else if (nullptr == proxy_) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret));
  } else if (OB_FAIL(zone_mgr_.get_zone(all_zone_list))) {
    LOG_WARN("fail to get zone list", K(ret));
  } else if (OB_FAIL(inner_get_tenant_pool_zone_list(tenant_id, pool_zone_list))) {
    if (OB_ENTRY_NOT_EXIST == ret) {
      ret = OB_SUCCESS;
    } else {
      LOG_WARN("fail to get pools by tenant", K(ret), K(tenant_id));
    }
  }
  if (OB_SUCC(ret)) {
    ObArray<ObResourcePoolName> pool_names;
    for (int64_t i = 0; OB_SUCC(ret) && i < all_zone_list.count(); ++i) {
      share::ObResourcePool pool;
      const common::ObZone& this_zone = all_zone_list.at(i);
      if (has_exist_in_array(pool_zone_list, this_zone)) {
        // bypass, resource pool already exist on this zone
      } else if (OB_FAIL(init_upgrade_cluster_gts_resource_pool(this_zone, pool))) {
        LOG_WARN("fail to init update cluster gts resource pool", K(ret));
      } else if (OB_FAIL(inner_create_resource_pool(pool, OB_GTS_UNIT_CONFIG_NAME, false /*if not exist*/))) {
        LOG_WARN("fail to inner create resource pool", K(ret));
      } else if (OB_FAIL(pool_names.push_back(pool.name_))) {
        LOG_WARN("fail to push back", K(ret));
      }
    }
    if (OB_SUCC(ret)) {
      if (OB_FAIL(change_pool_owner(*proxy_,
              share::ObWorker::CompatMode::MYSQL,
              true /*grant*/,
              pool_names,
              OB_GTS_TENANT_ID,
              false /*is_bootstrap*/,
              false /*if_not_grant*/))) {
        LOG_WARN("fail to change pool owner", K(ret));
      } else if (OB_FAIL(inner_commit_change_pool_owner(true /*grant*/, pool_names, OB_GTS_TENANT_ID))) {
        LOG_WARN("fail to inner commit change pool owner", K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::create_resource_pool(
    share::ObResourcePool& resource_pool, const ObUnitConfigName& config_name, const bool if_not_exist)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  if (OB_FAIL(inner_create_resource_pool(resource_pool, config_name, if_not_exist))) {
    LOG_WARN("fail to inner create resource pool", K(ret));
  }
  return ret;
}

int ObUnitManager::inner_create_resource_pool(
    share::ObResourcePool& resource_pool, const ObUnitConfigName& config_name, const bool if_not_exist)
{
  int ret = OB_SUCCESS;
  LOG_INFO("start create resource pool", K(resource_pool), K(config_name));
  ObUnitConfig* config = NULL;
  share::ObResourcePool* pool = NULL;
  bool is_bootstrap_pool = (OB_SYS_UNIT_CONFIG_ID == resource_pool.unit_config_id_ ||
                            OB_GTS_UNIT_CONFIG_ID == resource_pool.unit_config_id_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (is_bootstrap_pool && OB_FAIL(check_bootstrap_pool(resource_pool))) {
    LOG_WARN("check bootstrap pool failed", K(resource_pool), K(ret));
  } else if (!is_bootstrap_pool && OB_FAIL(check_resource_pool(resource_pool))) {
    LOG_WARN("check_resource_pool failed", K(resource_pool), K(ret));
  } else if (config_name.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource unit name");
    LOG_WARN("invalid config_name", K(config_name), K(ret));
  } else if (OB_FAIL(get_unit_config_by_name(config_name, config))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_unit_config_by_name failed", K(config_name), K(ret));
    } else {
      ret = OB_RESOURCE_UNIT_NOT_EXIST;
      LOG_USER_ERROR(OB_RESOURCE_UNIT_NOT_EXIST, to_cstring(config_name));
      LOG_WARN("config not exist", K(config_name), K(ret));
    }
  } else if (NULL == config) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("config is null", KP(config), K(ret));
  } else if (OB_SUCCESS == (ret = inner_get_resource_pool_by_name(resource_pool.name_, pool))) {
    if (NULL == pool) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pool is null", K_(resource_pool.name), KP(pool), K(ret));
    } else if (if_not_exist) {
      LOG_USER_NOTE(OB_RESOURCE_POOL_EXIST, to_cstring(resource_pool.name_));
      LOG_INFO("resource_pool already exist, no need to create", K(resource_pool.name_));
    } else {
      ret = OB_RESOURCE_POOL_EXIST;
      LOG_USER_ERROR(OB_RESOURCE_POOL_EXIST, to_cstring(resource_pool.name_));
      LOG_WARN("resource_pool already exist", "name", resource_pool.name_, K(ret));
    }
  } else if (OB_ENTRY_NOT_EXIST != ret) {
    LOG_WARN("get resource pool by name failed", "name", resource_pool.name_, K(ret));
  } else {
    ret = OB_SUCCESS;
    common::ObMySQLTransaction trans;
    share::ObResourcePool* new_pool = NULL;
    if (NULL == (new_pool = pool_allocator_.alloc())) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_ERROR("alloc memory failed", K(ret));
    } else if (REPLICA_TYPE_FULL == resource_pool.replica_type_ &&
               config->min_memory_ < GCONF.__min_full_resource_pool_memory) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN("full resource pool min memory illegal", K(ret));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "unit min memory less than __min_full_resource_pool_memory");
    } else {
      if (OB_FAIL(trans.start(proxy_))) {
        LOG_WARN("start transaction failed", K(ret));
      } else {
        if (OB_FAIL(new_pool->assign(resource_pool))) {
          LOG_WARN("failed to assign new_pool", K(ret));
        } else {
          new_pool->unit_config_id_ = config->unit_config_id_;
          if (OB_INVALID_ID == new_pool->resource_pool_id_) {
            if (OB_FAIL(fetch_new_resource_pool_id(new_pool->resource_pool_id_))) {
              LOG_WARN("fetch_new_resource_pool_id failed", K(ret));
            }
          } else {
            // sys resource pool with pool_id set
          }
        }
        if (OB_FAIL(ret)) {
        } else if (OB_FAIL(ut_operator_.update_resource_pool(trans, *new_pool))) {
          LOG_WARN("update_resource_pool failed", "resource_pool", *new_pool, K(ret));
        } else if (OB_FAIL(update_pool_map(new_pool))) {
          LOG_WARN("update pool map failed", "resource_pool", *new_pool, K(ret));
        }

        if (OB_SUCCESS == ret && !is_bootstrap_resource_pool(new_pool->resource_pool_id_)) {
          if (OB_FAIL(allocate_pool_units(trans, *new_pool))) {
            LOG_WARN("arrange pool units failed", "resource_pool", *new_pool, K(ret));
          }
        }
      }

      if (trans.is_started()) {
        const bool commit = (OB_SUCC(ret));
        int temp_ret = OB_SUCCESS;
        if (OB_SUCCESS != (temp_ret = trans.end(commit))) {
          LOG_WARN("trans end failed", K(commit), K(temp_ret));
          ret = (OB_SUCCESS == ret) ? temp_ret : ret;
        }
      }
      if (OB_SUCC(ret)) {
        ret = E(EventTable::EN_UNIT_MANAGER) OB_SUCCESS;
        DEBUG_SYNC(UNIT_MANAGER_WAIT_FOR_TIMEOUT);
      }

      if (OB_FAIL(ret)) {
        if (OB_INVALID_ID == new_pool->resource_pool_id_) {
          // do nothing, fetch new resource pool id failed
        } else {
          int temp_ret = OB_SUCCESS;  // avoid ret overwritten
          // some error occur during doing the transaction, rollback change occur in memory
          ObArray<ObUnit*>* units = NULL;
          if (OB_SUCCESS == (temp_ret = get_units_by_pool(new_pool->resource_pool_id_, units))) {
            if (NULL == units) {
              temp_ret = OB_ERR_UNEXPECTED;
              LOG_WARN("units is null", KP(units), K(temp_ret));
            } else if (OB_SUCCESS != (temp_ret = delete_units_of_pool(new_pool->resource_pool_id_))) {
              LOG_WARN("delete_units_of_pool failed", "resource_pool_id", new_pool->resource_pool_id_, K(temp_ret));
            }
          } else if (OB_ENTRY_NOT_EXIST != temp_ret) {
            LOG_WARN("get_units_by_pool failed", "resource_pool_id", new_pool->resource_pool_id_, K(temp_ret));
          } else {
            temp_ret = OB_SUCCESS;
          }

          share::ObResourcePool* temp_pool = NULL;
          if (OB_SUCCESS != temp_ret) {
          } else if (OB_SUCCESS != (temp_ret = get_resource_pool_by_id(new_pool->resource_pool_id_, temp_pool))) {
            if (OB_ENTRY_NOT_EXIST != temp_ret) {
              LOG_WARN("get_resource_pool_by_id failed", "pool_id", new_pool->resource_pool_id_, K(temp_ret));
            } else {
              temp_ret = OB_SUCCESS;
              // do nothing, no need to delete from id_map and name_map
            }
          } else if (NULL == temp_pool) {
            temp_ret = OB_ERR_UNEXPECTED;
            LOG_WARN("temp_pool is null", KP(temp_pool), K(temp_ret));
          } else if (OB_SUCCESS != (temp_ret = delete_resource_pool(new_pool->resource_pool_id_, new_pool->name_))) {
            LOG_WARN("delete_resource_pool failed", "new pool", *new_pool, K(temp_ret));
          }
        }
        // avoid memory leak
        pool_allocator_.free(new_pool);
        new_pool = NULL;
      } else {
        // inc unit config ref count at last
        if (OB_FAIL(inc_config_ref_count(config->unit_config_id_))) {
          LOG_WARN("inc_config_ref_count failed", "config id", config->unit_config_id_, K(ret));
        } else if (OB_FAIL(insert_config_pool(config->unit_config_id_, new_pool))) {
          LOG_WARN("insert config pool failed", "config id", config->unit_config_id_, K(ret));
        } else {
          ROOTSERVICE_EVENT_ADD("unit",
              "create_resource_pool",
              "name",
              new_pool->name_,
              "unit",
              config_name,
              "zone_list",
              new_pool->zone_list_);
        }
      }
    }
  }
  LOG_INFO("finish create resource pool", K(resource_pool), K(config_name), K(ret));
  return ret;
}

int ObUnitManager::convert_pool_name_list(const common::ObIArray<common::ObString>& split_pool_list,
    common::ObIArray<share::ObResourcePoolName>& split_pool_name_list)
{
  int ret = OB_SUCCESS;
  split_pool_name_list.reset();
  for (int64_t i = 0; OB_SUCC(ret) && i < split_pool_list.count(); ++i) {
    share::ObResourcePoolName pool_name;
    if (OB_FAIL(pool_name.assign(split_pool_list.at(i).ptr()))) {
      LOG_WARN("fail to assign pool name", K(ret));
    } else if (OB_FAIL(split_pool_name_list.push_back(pool_name))) {
      LOG_WARN("fail to push back", K(ret));
    }
  }
  return ret;
}

int ObUnitManager::check_split_pool_name_condition(
    const common::ObIArray<share::ObResourcePoolName>& split_pool_name_list)
{
  int ret = OB_SUCCESS;
  // Check whether the pool name already exists,
  // and check whether the pool name is duplicate
  const int64_t POOL_NAME_SET_BUCKET_NUM = 16;
  ObHashSet<share::ObResourcePoolName> pool_name_set;
  if (OB_FAIL(pool_name_set.create(POOL_NAME_SET_BUCKET_NUM))) {
    LOG_WARN("fail to create hash set", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < split_pool_name_list.count(); ++i) {
      const share::ObResourcePoolName& pool_name = split_pool_name_list.at(i);
      share::ObResourcePool* pool = NULL;
      int tmp_ret = inner_get_resource_pool_by_name(pool_name, pool);
      if (OB_ENTRY_NOT_EXIST == tmp_ret) {
        // good, go on next, this pool name not exist
      } else if (OB_SUCCESS == tmp_ret) {
        if (NULL == pool) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("pool is null", K(ret), KP(pool), K(pool_name));
        } else {
          ret = OB_RESOURCE_POOL_EXIST;
          LOG_WARN("resource pool already exist", K(ret), K(pool_name));
          LOG_USER_ERROR(OB_RESOURCE_POOL_EXIST, to_cstring(pool_name));
        }
      } else {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unexpected error when get pool by name", K(ret), K(pool_name));
      }
      if (OB_SUCC(ret)) {
        int tmp_ret = pool_name_set.exist_refactored(pool_name);
        if (OB_HASH_NOT_EXIST == tmp_ret) {
          if (OB_FAIL(pool_name_set.set_refactored(pool_name))) {
            LOG_WARN("fail to set", K(ret), K(pool_name));
          }
        } else if (OB_HASH_EXIST == tmp_ret) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("invalid argument to split resource pool with duplicated name");
          LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource pool name");
        } else {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unexpected error when set hashset", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::check_split_pool_zone_condition(
    const common::ObIArray<common::ObZone>& split_zone_list, const share::ObResourcePool& pool)
{
  int ret = OB_SUCCESS;
  const common::ObIArray<common::ObZone>& pool_zone_list = pool.zone_list_;
  // Check whether the zone is included in the pool zone list,
  // and check whether the zone is duplicated
  const int64_t ZONE_SET_BUCKET_NUM = 16;
  ObHashSet<common::ObZone> zone_set;
  if (pool_zone_list.count() != split_zone_list.count()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument to split zone list", K(ret));
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "corresponding zone vector");
  } else if (OB_FAIL(zone_set.create(ZONE_SET_BUCKET_NUM))) {
    LOG_WARN("fail to create hash set", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < split_zone_list.count(); ++i) {
      const common::ObZone& this_zone = split_zone_list.at(i);
      if (!has_exist_in_array(pool_zone_list, this_zone)) {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("invalid argument to non-exist zone in splitting zone vector", K(ret));
        LOG_USER_ERROR(OB_INVALID_ARGUMENT, "non-exist zone in corresponding zone vector");
      } else {
        int tmp_ret = zone_set.exist_refactored(this_zone);
        if (OB_HASH_NOT_EXIST == tmp_ret) {
          if (OB_FAIL(zone_set.set_refactored(this_zone))) {
            LOG_WARN("fail to set", K(ret), K(this_zone));
          }
        } else if (OB_HASH_EXIST == tmp_ret) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("invalid argument to duplicate zones in splitting zone vector", K(ret));
          LOG_USER_ERROR(OB_INVALID_ARGUMENT, "duplidate zones in corresponding zone vector");
        } else {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unexpected error when set hashset", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::split_resource_pool(const share::ObResourcePoolName& pool_name,
    const common::ObIArray<common::ObString>& split_pool_list, const common::ObIArray<common::ObZone>& split_zone_list)
{
  int ret = OB_SUCCESS;
  LOG_INFO("start split resource pool", K(pool_name), K(split_pool_list), K(split_zone_list));
  SpinWLockGuard guard(lock_);
  share::ObResourcePool* pool = NULL;
  common::ObArray<share::ObResourcePoolName> split_pool_name_list;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (pool_name.is_empty() || split_pool_list.count() <= 0 || split_zone_list.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("resource pool name is empty", K(ret), K(split_zone_list), K(split_pool_list));
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource pool");
  } else if (OB_FAIL(inner_get_resource_pool_by_name(pool_name, pool))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get resource pool by name failed", K(ret), K(pool_name));
    } else {
      ret = OB_RESOURCE_POOL_NOT_EXIST;
      LOG_WARN("resource pool not exist", K(ret), K(pool_name));
      LOG_USER_ERROR(OB_RESOURCE_POOL_NOT_EXIST, to_cstring(pool_name));
    }
  } else if (OB_UNLIKELY(NULL == pool)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool ptr is null", K(ret));
  } else if (OB_FAIL(convert_pool_name_list(split_pool_list, split_pool_name_list))) {
    LOG_WARN("fail to convert pool name list", K(ret));
  } else if (OB_FAIL(check_split_pool_name_condition(split_pool_name_list))) {
    LOG_WARN("fail to check pool list name duplicate", K(ret));
  } else if (split_pool_name_list.count() != split_zone_list.count()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument to split pool and zone count", K(ret));
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "split pool and zone count");
  } else if (OB_FAIL(check_split_pool_zone_condition(split_zone_list, *pool))) {
    LOG_WARN("fail to check split pool zone condition", K(ret));
  } else if (OB_FAIL(do_split_resource_pool(pool, split_pool_name_list, split_zone_list))) {
    LOG_WARN("fail to do split resource pool", K(ret));
  } else {
    LOG_INFO("succeed to split resource pool",
        K(pool_name),
        "new_pool_name",
        split_pool_list,
        "corresponding_zone",
        split_zone_list);
  }
  return ret;
}

int ObUnitManager::do_split_pool_persistent_info(share::ObResourcePool* pool,
    const common::ObIArray<share::ObResourcePoolName>& split_pool_name_list,
    const common::ObIArray<common::ObZone>& split_zone_list,
    common::ObIArray<share::ObResourcePool*>& allocate_pool_ptrs)
{
  int ret = OB_SUCCESS;
  common::ObMySQLTransaction trans;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_FAIL(trans.start(proxy_))) {
    LOG_WARN("fail to start transaction", K(ret));
  } else if (OB_UNLIKELY(split_zone_list.count() != split_pool_name_list.count() || NULL == pool)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret));
  } else {
    // Write down the resource pool allocated during execution
    allocate_pool_ptrs.reset();
    for (int64_t i = 0; OB_SUCC(ret) && i < split_pool_name_list.count(); ++i) {
      const share::ObResourcePoolName& new_pool_name = split_pool_name_list.at(i);
      const common::ObZone& zone = split_zone_list.at(i);
      share::ObResourcePool* new_pool = NULL;
      if (NULL == (new_pool = pool_allocator_.alloc())) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_ERROR("fail to alloc memory", K(ret));
      } else if (OB_FAIL(allocate_pool_ptrs.push_back(new_pool))) {
        LOG_WARN("fail to push back", K(ret));
      } else if (OB_FAIL(fill_splitting_pool_basic_info(new_pool_name, new_pool, zone, pool))) {
        LOG_WARN("fail to fill splitting pool basic info", K(ret));
      }
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < allocate_pool_ptrs.count(); ++i) {
      share::ObResourcePool* new_pool = allocate_pool_ptrs.at(i);
      if (OB_UNLIKELY(NULL == new_pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret));
      } else if (new_pool->zone_list_.count() != 1) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("zone list count unexpected", K(ret), "zone_list", new_pool->zone_list_);
      } else if (OB_FAIL(ut_operator_.update_resource_pool(trans, *new_pool))) {
        LOG_WARN("fail to update resource pool", K(ret));
      } else if (OB_FAIL(split_pool_unit_persistent_info(trans, new_pool->zone_list_.at(0), new_pool, pool))) {
        LOG_WARN("fail to split pool unit persistent info", K(ret));
      }
    }
    if (OB_FAIL(ret)) {
    } else if (ut_operator_.remove_resource_pool(trans, pool->resource_pool_id_)) {
      LOG_WARN("fail to remove resource pool persistent info", K(ret), "pool_id", pool->resource_pool_id_);
    } else {
    }  // all persistent infos update finished
    const bool commit = (OB_SUCCESS == ret);
    int tmp_ret = OB_SUCCESS;
    if (OB_SUCCESS != (tmp_ret = trans.end(commit))) {
      LOG_WARN("fail to end trans", K(tmp_ret), K(commit));
      ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
    }
    if (OB_FAIL(ret)) {
      // 1. The transaction did fail to commit.
      //    the internal table and the memory state remain the same,
      //    as long as the memory of allocate_pool_ptrs is released.
      //
      // 2. The transaction submission timed out, but the final submission was successful.
      //    The internal table and memory state are inconsistent,
      //    and the outer layer will call the reload unit manager.
      //    Still need to release the memory of allocate_pool_ptrs
      for (int64_t i = 0; i < allocate_pool_ptrs.count(); ++i) {
        share::ObResourcePool* new_pool = allocate_pool_ptrs.at(i);
        if (NULL != new_pool) {
          pool_allocator_.free(new_pool);
          new_pool = NULL;
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::do_split_pool_inmemory_info(
    share::ObResourcePool* pool, common::ObIArray<share::ObResourcePool*>& allocate_pool_ptrs)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (NULL == pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < allocate_pool_ptrs.count(); ++i) {
      share::ObResourcePool* new_pool = allocate_pool_ptrs.at(i);
      if (OB_UNLIKELY(NULL == new_pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret));
      } else if (new_pool->zone_list_.count() != 1) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("zone list count unexpected", K(ret), "zone_list", new_pool->zone_list_);
      } else if (OB_FAIL(inc_config_ref_count(new_pool->unit_config_id_))) {
        LOG_WARN("fail to inc config ref count", K(ret), "unit_config_id", new_pool->unit_config_id_);
      } else if (OB_FAIL(insert_config_pool(new_pool->unit_config_id_, new_pool))) {
        LOG_WARN("fail to insert config pool", K(ret), "unit_config_id", new_pool->unit_config_id_);
      } else if (OB_FAIL(update_pool_map(new_pool))) {
        LOG_WARN("fail to update pool map", K(ret), "resource_pool_id", new_pool->resource_pool_id_);
      } else if (OB_INVALID_ID == new_pool->tenant_id_) {
        // bypass
      } else if (OB_FAIL(insert_tenant_pool(new_pool->tenant_id_, new_pool))) {
        LOG_WARN("fail to insert tenant pool", K(ret), "tenant_id", new_pool->tenant_id_);
      }
      if (OB_FAIL(ret)) {
        // failed
      } else if (OB_FAIL(split_pool_unit_inmemory_info(new_pool->zone_list_.at(0), new_pool, pool))) {
        LOG_WARN("fail to split pool unit inmemory info", K(ret));
      } else {
      }  // no more
    }
    common::ObArray<share::ObUnit*>* pool_units = NULL;
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(dec_config_ref_count(pool->unit_config_id_))) {
      LOG_WARN("fail to dec config ref count", K(ret));
    } else if (OB_FAIL(delete_config_pool(pool->unit_config_id_, pool))) {
      LOG_WARN("fail to delete config pool", K(ret));
    } else if (OB_FAIL(delete_resource_pool(pool->resource_pool_id_, pool->name_))) {
      LOG_WARN("fail to delete resource pool", K(ret));
    } else if (OB_INVALID_ID == pool->tenant_id_) {
      // bypass
    } else if (OB_FAIL(delete_tenant_pool(pool->tenant_id_, pool))) {
      LOG_WARN("fail to delete tenant pool", K(ret), "tenant_id", pool->tenant_id_);
    }
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(get_units_by_pool(pool->resource_pool_id_, pool_units))) {
      LOG_WARN("fail to get units by pool", K(ret), "pool_id", pool->resource_pool_id_);
    } else if (OB_UNLIKELY(NULL == pool_units)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pool units ptr is null", K(ret));
    } else if (OB_FAIL(pool_unit_map_.erase_refactored(pool->resource_pool_id_))) {
      LOG_WARN("fail to erase map", K(ret), "pool_id", pool->resource_pool_id_);
    } else {
      pool_unit_allocator_.free(pool_units);
      pool_units = NULL;
      pool_allocator_.free(pool);
      pool = NULL;
    }
    if (OB_FAIL(ret)) {
      // reload
      rootserver::ObRootService* root_service = NULL;
      if (OB_UNLIKELY(NULL == (root_service = GCTX.root_service_))) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("rootservice is null", K(ret));
      } else {
        int tmp_ret = root_service->submit_reload_unit_manager_task();
        if (OB_SUCCESS != tmp_ret) {
          LOG_ERROR("fail to reload unit manager", K(tmp_ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::do_split_resource_pool(share::ObResourcePool* pool,
    const common::ObIArray<share::ObResourcePoolName>& split_pool_name_list,
    const common::ObIArray<common::ObZone>& split_zone_list)
{
  int ret = OB_SUCCESS;
  common::ObArray<share::ObResourcePool*> allocate_pool_ptrs;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(NULL == pool)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret));
  } else if (split_pool_name_list.count() != split_zone_list.count()) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("split pool name and zone count not match", K(ret), K(split_pool_name_list), K(split_zone_list));
  } else if (OB_FAIL(do_split_pool_persistent_info(pool, split_pool_name_list, split_zone_list, allocate_pool_ptrs))) {
    LOG_WARN("fail to do split pool persistent info", K(ret));
  } else if (OB_FAIL(do_split_pool_inmemory_info(pool, allocate_pool_ptrs))) {
    LOG_WARN("fail to do split pool inmemory info", K(ret));
  } else {
  }  // no more
  return ret;
}

int ObUnitManager::fill_splitting_pool_basic_info(const share::ObResourcePoolName& new_pool_name,
    share::ObResourcePool* new_pool, const common::ObZone& zone, share::ObResourcePool* orig_pool)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(new_pool_name.is_empty() || NULL == new_pool || zone.is_empty() || NULL == orig_pool)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(new_pool_name), KP(new_pool), K(zone), K(orig_pool));
  } else {
    new_pool->name_ = new_pool_name;
    new_pool->unit_count_ = orig_pool->unit_count_;
    new_pool->unit_config_id_ = orig_pool->unit_config_id_;
    new_pool->tenant_id_ = orig_pool->tenant_id_;
    new_pool->replica_type_ = orig_pool->replica_type_;
    if (OB_FAIL(new_pool->zone_list_.push_back(zone))) {
      LOG_WARN("fail to push back to zone list", K(ret));
    } else if (OB_FAIL(fetch_new_resource_pool_id(new_pool->resource_pool_id_))) {
      LOG_WARN("fail to fetch new resource pool id", K(ret));
    } else {
    }  // finish fill splitting pool basic info
  }
  return ret;
}

int ObUnitManager::split_pool_unit_inmemory_info(
    const common::ObZone& zone, share::ObResourcePool* new_pool, share::ObResourcePool* orig_pool)
{
  int ret = OB_SUCCESS;
  common::ObArray<share::ObUnit*>* new_units = NULL;
  common::ObArray<share::ObUnit*>* orig_units = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(NULL == new_pool || NULL == orig_pool || zone.is_empty())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(new_pool), K(orig_pool), K(zone));
  } else if (OB_FAIL(get_units_by_pool(orig_pool->resource_pool_id_, orig_units))) {
    LOG_WARN("fail to get units by pool", K(ret));
  } else if (OB_UNLIKELY(NULL == orig_units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units ptr is null", K(ret));
  } else {
    ret = get_units_by_pool(new_pool->resource_pool_id_, new_units);
    if (OB_SUCCESS == ret) {
      // got new units
    } else if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("fail to get units by pool", K(ret));
    } else {
      if (NULL == (new_units = pool_unit_allocator_.alloc())) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_ERROR("fail to alloc memory", K(ret));
      } else if (OB_FAIL(pool_unit_map_.set_refactored(new_pool->resource_pool_id_, new_units))) {
        LOG_WARN("fail to set refactored", K(ret), "pool_id", new_pool->resource_pool_id_);
      }
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < orig_units->count(); ++i) {
      share::ObUnit* unit = orig_units->at(i);
      if (OB_UNLIKELY(NULL == unit)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit ptr is null", K(ret));
      } else if (zone != unit->zone_) {
        // bypass
      } else if (NULL == new_units) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("new units ptr is null", K(ret));
      } else {
        unit->resource_pool_id_ = new_pool->resource_pool_id_;
        if (OB_FAIL(new_units->push_back(unit))) {
          LOG_WARN("fail to push back", K(ret));
        } else if (OB_FAIL(update_unit_load(unit, new_pool))) {
          LOG_WARN("fail to update unit load", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::split_pool_unit_persistent_info(common::ObMySQLTransaction& trans, const common::ObZone& zone,
    share::ObResourcePool* new_pool, share::ObResourcePool* orig_pool)
{
  int ret = OB_SUCCESS;
  common::ObArray<share::ObUnit*>* units = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(NULL == new_pool || NULL == orig_pool || zone.is_empty())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(new_pool), KP(orig_pool), K(zone));
  } else if (OB_FAIL(get_units_by_pool(orig_pool->resource_pool_id_, units))) {
    LOG_WARN("fail to get units by pool", K(ret));
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units ptr is null", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
      const share::ObUnit* unit = units->at(i);
      if (OB_UNLIKELY(NULL == unit)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit ptr is null", K(ret));
      } else if (unit->zone_ != zone) {
        // bypass
      } else {
        share::ObUnit new_unit = *unit;
        new_unit.resource_pool_id_ = new_pool->resource_pool_id_;
        if (OB_FAIL(ut_operator_.update_unit(trans, new_unit))) {
          LOG_WARN("fail to update unit", K(ret), K(new_unit));
        } else {
          ROOTSERVICE_EVENT_ADD("unit",
              "split_pool",
              "unit_id",
              unit->unit_id_,
              "server",
              unit->server_,
              "prev_pool_id",
              orig_pool->resource_pool_id_,
              "curr_pool_id",
              new_pool->resource_pool_id_);
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::merge_resource_pool(
    const common::ObIArray<common::ObString>& old_pool_list, const common::ObIArray<common::ObString>& new_pool_list)
{
  int ret = OB_SUCCESS;
  LOG_INFO("start merge resource pool", K(old_pool_list), K(new_pool_list));
  SpinWLockGuard guard(lock_);
  common::ObArray<share::ObResourcePoolName> old_pool_name_list;
  share::ObResourcePoolName merge_pool_name;
  common::ObArray<share::ObResourcePool*> old_pool;  // Pool to be merged
  common::ObArray<common::ObZone> merge_zone_list;   // zone list to be merged
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (new_pool_list.count() <= 0 || old_pool_list.count() <= 0 ||
             old_pool_list.count() < 2
             // Preventing only one pool from being merged is meaningless
             || new_pool_list.count() > 1) {
    // Can only be merged into one resource pool
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("resource pool zone list is illeagle", K(old_pool_list), K(new_pool_list));
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource pool");
  } else if (OB_FAIL(convert_pool_name_list(
                 old_pool_list, old_pool_name_list, new_pool_list, merge_pool_name))) {  // 1.parse pool name
    LOG_WARN("fail to convert pool name list", K(ret));
  } else if (OB_FAIL(check_old_pool_name_condition(old_pool_name_list, merge_zone_list, old_pool))) {
    // 2. check the pool that in old_pool_list is whether valid
    LOG_WARN("fail to check old pool name condition", K(ret));
  } else if (OB_FAIL(check_merge_pool_name_condition(merge_pool_name))) {
    // 3. check the merge_pool_name is whether the new pool
    LOG_WARN("fail to check merge pool name condition", K(ret));
  } else if (OB_FAIL(do_merge_resource_pool(merge_pool_name, merge_zone_list, old_pool))) {
    LOG_WARN("fail to do merge resource pool", K(ret));
  } else {
    LOG_INFO("success to merge resource pool", K(merge_pool_name), "old_pool_name", old_pool_list);
  }
  return ret;
}

int ObUnitManager::convert_pool_name_list(const common::ObIArray<common::ObString>& old_pool_list,
    common::ObIArray<share::ObResourcePoolName>& old_pool_name_list,
    const common::ObIArray<common::ObString>& new_pool_list, share::ObResourcePoolName& merge_pool_name)
{
  int ret = OB_SUCCESS;
  old_pool_name_list.reset();
  for (int64_t i = 0; OB_SUCC(ret) && i < old_pool_list.count(); ++i) {
    share::ObResourcePoolName pool_name;
    if (OB_FAIL(pool_name.assign(old_pool_list.at(i).ptr()))) {
      LOG_WARN("fail to assign pool name", K(ret));
    } else if (has_exist_in_array(old_pool_name_list, pool_name)) {  // Check for duplication
      ret = OB_OP_NOT_ALLOW;
      LOG_WARN("not allow merge resource pool repeat", K(ret));
      LOG_USER_ERROR(OB_OP_NOT_ALLOW, "merge resource pool repeat");
    } else if (OB_FAIL(old_pool_name_list.push_back(pool_name))) {
      LOG_WARN("fail to push back", K(ret));
    }
  }
  if (OB_SUCC(ret)) {
    if (OB_FAIL(merge_pool_name.assign(new_pool_list.at(0).ptr()))) {
      LOG_WARN("fail to assign pool name", K(ret));
    }
  }
  return ret;
}

int ObUnitManager::check_merge_pool_name_condition(const share::ObResourcePoolName& merge_pool_name)
{
  int ret = OB_SUCCESS;
  // check the pool name is whether exist,
  // and check the pool name is whether duplication.
  share::ObResourcePool* pool = NULL;
  int tmp_ret = inner_get_resource_pool_by_name(merge_pool_name, pool);
  if (OB_ENTRY_NOT_EXIST == tmp_ret) {
    // good, go on next, this pool name not exist
  } else if (OB_SUCCESS == tmp_ret) {
    if (NULL == pool) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pool is null", K(ret), KP(pool), K(merge_pool_name));
    } else {
      ret = OB_RESOURCE_POOL_EXIST;
      LOG_WARN("resource pool already exist", K(ret), K(merge_pool_name));
      LOG_USER_ERROR(OB_RESOURCE_POOL_EXIST, to_cstring(merge_pool_name));
    }
  } else {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected error when get pool by name", K(ret), K(merge_pool_name));
  }
  return ret;
}

int ObUnitManager::check_old_pool_name_condition(common::ObIArray<share::ObResourcePoolName>& old_pool_name_list,
    common::ObIArray<common::ObZone>& merge_zone_list, common::ObIArray<share::ObResourcePool*>& old_pool)
{
  int ret = OB_SUCCESS;
  common::ObReplicaType replica_type = REPLICA_TYPE_MAX;
  uint64_t tenant_id = OB_INVALID_ID;
  share::ObUnitConfig* unit_config = NULL;
  int64_t unit_count = 0;
  const int64_t POOL_NAME_SET_BUCKET_NUM = 16;
  ObHashSet<share::ObResourcePoolName> pool_name_set;
  if (OB_FAIL(pool_name_set.create(POOL_NAME_SET_BUCKET_NUM))) {
    LOG_WARN("fail to create hash set", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < old_pool_name_list.count(); ++i) {
      const share::ObResourcePoolName& pool_name = old_pool_name_list.at(i);
      share::ObUnitConfig* this_unit_config = NULL;
      share::ObResourcePool* pool = NULL;
      if (OB_FAIL(inner_get_resource_pool_by_name(pool_name, pool))) {
        LOG_WARN("fail to get resource pool by name", K(ret));
      } else if (OB_ISNULL(pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", K(ret), K(pool), K(pool_name));
      } else {
        if (0 == i) {
          replica_type = pool->replica_type_;
          tenant_id = pool->tenant_id_;
          unit_count = pool->unit_count_;
          if (OB_FAIL(get_unit_config_by_id(pool->unit_config_id_, unit_config))) {
            if (OB_ENTRY_NOT_EXIST == ret) {
              ret = OB_RESOURCE_UNIT_NOT_EXIST;
            }
            LOG_WARN("can not find config for unit", "unit_config_id", pool->unit_config_id_, K(ret));
          } else if (NULL == unit_config) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("config is null", K(*unit_config), K(ret));
          } else {
          }  // no more
        } else {
          if (replica_type != pool->replica_type_) {
            // Determine whether the replica_type is the same
            ret = OB_OP_NOT_ALLOW;
            LOG_WARN("not allow pool replica type different", K(ret), K(replica_type), K(pool->replica_type_));
            LOG_USER_ERROR(OB_OP_NOT_ALLOW, "pool replica type different");
          } else if (tenant_id != pool->tenant_id_) {
            // Determine whether the tenant_id is the same
            ret = OB_OP_NOT_ALLOW;
            LOG_WARN("not allow pool tenant id different", K(ret), K(tenant_id), K(pool->tenant_id_));
            LOG_USER_ERROR(OB_OP_NOT_ALLOW, "pool tenant id different");
          } else if (unit_count != pool->unit_count_) {
            // Determine whether the unit_count is the same
            ret = OB_OP_NOT_ALLOW;
            LOG_WARN("not allow pool unit count different", K(ret), K(unit_count), K(pool->unit_count_));
            LOG_USER_ERROR(OB_OP_NOT_ALLOW, "pool unit count different");
          } else if (OB_FAIL(get_unit_config_by_id(pool->unit_config_id_, this_unit_config))) {
            if (OB_ENTRY_NOT_EXIST == ret) {
              ret = OB_RESOURCE_UNIT_NOT_EXIST;
            }
            LOG_WARN("can not find config for unit", "unit_config_id", pool->unit_config_id_, K(ret));
          } else if (NULL == this_unit_config) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("config is null", KP(this_unit_config), K(ret));
          } else {  // Determine whether the unit config is the same
            if (unit_config->unit_config_id_ == this_unit_config->unit_config_id_) {  // nothing todo
            } else {
              ret = OB_OP_NOT_ALLOW;
              LOG_WARN("not allow pool unit config different", K(ret), K(*this_unit_config), K(*unit_config));
              LOG_USER_ERROR(OB_OP_NOT_ALLOW, "pool unit config different");
            }
          }
        }
        if (OB_SUCC(ret)) {
          int tmp_ret = pool_name_set.exist_refactored(pool_name);
          if (OB_HASH_NOT_EXIST == tmp_ret) {
            if (OB_FAIL(pool_name_set.set_refactored(pool_name))) {
              LOG_WARN("fail to set", K(ret), K(pool_name));
            }
          } else if (OB_HASH_EXIST == tmp_ret) {
            ret = OB_INVALID_ARGUMENT;
            LOG_WARN("invalid argument to merge resource pool duplicate");
            LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource pool name duplicate");
          } else {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unexpected error when set hashset", K(ret));
          }
        }
        if (OB_SUCC(ret)) {
          // Judge whether the zone has crossover,
          // it is implicitly judged whether the pool_name is repeated, no need to repeat the judgment
          for (int64_t j = 0; OB_SUCC(ret) && j < pool->zone_list_.count(); ++j) {
            const common::ObZone& this_zone = pool->zone_list_.at(j);
            if (has_exist_in_array(merge_zone_list, this_zone)) {
              ret = OB_OP_NOT_ALLOW;
              LOG_WARN("not allow to merge resource pool with duplicated zone");
              LOG_USER_ERROR(OB_OP_NOT_ALLOW, "resource pool with duplicated zone");
            } else if (OB_FAIL(merge_zone_list.push_back(this_zone))) {
              LOG_WARN("fail to push back", K(ret));
            }
          }
        }
        if (OB_SUCC(ret)) {
          if (OB_FAIL(old_pool.push_back(pool))) {
            LOG_WARN("fail to push back", K(ret));
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::do_merge_resource_pool(const share::ObResourcePoolName& merge_pool_name,
    const common::ObIArray<common::ObZone>& merge_zone_list, common::ObIArray<share::ObResourcePool*>& old_pool)
{
  int ret = OB_SUCCESS;
  share::ObResourcePool* allocate_pool_ptr = nullptr;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_FAIL(do_merge_pool_persistent_info(allocate_pool_ptr, merge_pool_name, merge_zone_list, old_pool))) {
    LOG_WARN("fail to do merge pool persistent info", K(ret));
  } else if (OB_FAIL(do_merge_pool_inmemory_info(allocate_pool_ptr, old_pool))) {
    LOG_WARN("fail to do merge pool inmemory info", K(ret));
  } else {
  }  // no more
  return ret;
}

int ObUnitManager::do_merge_pool_persistent_info(share::ObResourcePool*& allocate_pool_ptr,
    const share::ObResourcePoolName& merge_pool_name, const common::ObIArray<common::ObZone>& merge_zone_list,
    const common::ObIArray<share::ObResourcePool*>& old_pool)
{
  int ret = OB_SUCCESS;
  common::ObMySQLTransaction trans;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_FAIL(trans.start(proxy_))) {
    LOG_WARN("fail to start transaction", K(ret));
  } else {
    if (NULL == (allocate_pool_ptr = pool_allocator_.alloc())) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_ERROR("fail to alloc memory", K(ret));
    } else if (OB_FAIL(fill_merging_pool_basic_info(allocate_pool_ptr, merge_pool_name, merge_zone_list, old_pool))) {
      // The specifications of the pools to be merged are the same, so select the first pool here
      LOG_WARN("fail to fill merging pool basic info", K(ret));
    } else if (OB_FAIL(ut_operator_.update_resource_pool(trans, *allocate_pool_ptr))) {
      LOG_WARN("fail to update resource pool", K(ret));
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < old_pool.count(); ++i) {
        if (OB_FAIL(merge_pool_unit_persistent_info(trans, allocate_pool_ptr, old_pool.at(i)))) {
          LOG_WARN("fail to split pool unit persistent info", K(ret));
        }
      }
    }
    if (OB_SUCC(ret)) {
      for (int64_t i = 0; i < old_pool.count() && OB_SUCC(ret); ++i) {
        if (OB_FAIL(ut_operator_.remove_resource_pool(trans, old_pool.at(i)->resource_pool_id_))) {
          LOG_WARN(
              "fail to remove resource pool persistent info", K(ret), "pool_id", old_pool.at(i)->resource_pool_id_);
        } else {
        }  // all persistent infos update finished
      }
    }
    const bool commit = (OB_SUCCESS == ret);
    int tmp_ret = OB_SUCCESS;
    if (OB_SUCCESS != (tmp_ret = trans.end(commit))) {
      LOG_WARN("fail to end trans", K(tmp_ret), K(commit));
      ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
    }
    if (OB_FAIL(ret)) {
      // 1. The transaction did fail to commit.
      //    the internal table and the memory state remain the same,
      //    as long as the memory of allocate_pool_ptrs is released.
      //
      // 2. The transaction submission timed out, but the final submission was successful.
      //    The internal table and memory state are inconsistent,
      //    and the outer layer will call the reload unit manager.
      //    Still need to release the memory of allocate_pool_ptrs
      if (NULL != allocate_pool_ptr) {
        pool_allocator_.free(allocate_pool_ptr);
        allocate_pool_ptr = NULL;
      }
    }
  }
  return ret;
}

int ObUnitManager::fill_merging_pool_basic_info(share::ObResourcePool*& allocate_pool_ptr,
    const share::ObResourcePoolName& merge_pool_name, const common::ObIArray<common::ObZone>& merge_zone_list,
    const common::ObIArray<share::ObResourcePool*>& old_pool)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(old_pool.count() <= 1)) {
    // It doesn't make sense to merge only one pool
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret));
  }
  if (OB_SUCC(ret)) {
    share::ObResourcePool* orig_pool = old_pool.at(0);
    if (OB_UNLIKELY(merge_pool_name.is_empty() || NULL == allocate_pool_ptr || NULL == orig_pool)) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("invalid argument", K(ret), K(merge_pool_name), KP(allocate_pool_ptr), K(orig_pool));
    } else {
      allocate_pool_ptr->name_ = merge_pool_name;
      allocate_pool_ptr->unit_count_ = orig_pool->unit_count_;
      allocate_pool_ptr->unit_config_id_ = orig_pool->unit_config_id_;
      allocate_pool_ptr->tenant_id_ = orig_pool->tenant_id_;
      allocate_pool_ptr->replica_type_ = orig_pool->replica_type_;
      if (OB_FAIL(fetch_new_resource_pool_id(allocate_pool_ptr->resource_pool_id_))) {
        LOG_WARN("fail to fetch new resource pool id", K(ret));
      } else {
        for (int64_t i = 0; i < merge_zone_list.count() && OB_SUCC(ret); ++i) {
          if (OB_UNLIKELY(merge_zone_list.at(i).is_empty())) {
            ret = OB_INVALID_ARGUMENT;
            LOG_WARN("invalid argument", K(ret), K(merge_zone_list.at(i)));
          } else if (OB_FAIL(allocate_pool_ptr->zone_list_.push_back(merge_zone_list.at(i)))) {
            LOG_WARN("fail to push back to zone list", K(ret));
          }
        }
      }  // finish fill splitting pool basic info
    }
  }
  return ret;
}

int ObUnitManager::merge_pool_unit_persistent_info(
    common::ObMySQLTransaction& trans, share::ObResourcePool* new_pool, share::ObResourcePool* orig_pool)
{
  int ret = OB_SUCCESS;
  common::ObArray<share::ObUnit*>* units = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(NULL == new_pool || NULL == orig_pool)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(new_pool), KP(orig_pool));
  } else if (OB_FAIL(get_units_by_pool(orig_pool->resource_pool_id_, units))) {
    LOG_WARN("fail to get units by pool", K(ret));
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units ptr is null", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
      const share::ObUnit* unit = units->at(i);
      if (OB_UNLIKELY(NULL == unit)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit ptr is null", K(ret));
      } else {
        share::ObUnit new_unit = *unit;
        new_unit.resource_pool_id_ = new_pool->resource_pool_id_;
        if (OB_FAIL(ut_operator_.update_unit(trans, new_unit))) {
          LOG_WARN("fail to update unit", K(ret), K(new_unit));
        }
        ROOTSERVICE_EVENT_ADD("unit",
            "merge_pool",
            "unit_id",
            unit->unit_id_,
            "server",
            unit->server_,
            "prev_pool_id",
            orig_pool->resource_pool_id_,
            "curr_pool_id",
            new_pool->resource_pool_id_,
            K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::do_merge_pool_inmemory_info(
    share::ObResourcePool* new_pool /*allocate_pool_ptr*/, common::ObIArray<share::ObResourcePool*>& old_pool)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (NULL == new_pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret));
  } else {
    if (OB_FAIL(inc_config_ref_count(new_pool->unit_config_id_))) {
      LOG_WARN("fail to inc config ref count", K(ret), "unit_config_id", new_pool->unit_config_id_);
    } else if (OB_FAIL(insert_config_pool(new_pool->unit_config_id_, new_pool))) {
      LOG_WARN("fail to insert config pool", K(ret), "unit_config_id", new_pool->unit_config_id_);
    } else if (OB_FAIL(update_pool_map(new_pool))) {
      LOG_WARN("fail to update pool map", K(ret), "resource_pool_id", new_pool->resource_pool_id_);
    } else if (OB_INVALID_ID == new_pool->tenant_id_) {
      // bypass
    } else if (OB_FAIL(insert_tenant_pool(new_pool->tenant_id_, new_pool))) {
      LOG_WARN("fail to insert tenant pool", K(ret), "tenant_id", new_pool->tenant_id_);
    }
    if (OB_FAIL(ret)) {
      // failed
    } else if (OB_FAIL(merge_pool_unit_inmemory_info(new_pool, old_pool))) {
      LOG_WARN("fail to split pool unit inmemory info", K(ret));
    } else {
    }  // no more
    for (int64_t i = 0; i < old_pool.count() && OB_SUCC(ret); ++i) {
      common::ObArray<share::ObUnit*>* pool_units = NULL;
      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(dec_config_ref_count(old_pool.at(i)->unit_config_id_))) {
        LOG_WARN("fail to dec config ref count", K(ret));
      } else if (OB_FAIL(delete_config_pool(old_pool.at(i)->unit_config_id_, old_pool.at(i)))) {
        LOG_WARN("fail to delete config pool", K(ret));
      } else if (OB_FAIL(delete_resource_pool(old_pool.at(i)->resource_pool_id_, old_pool.at(i)->name_))) {
        LOG_WARN("fail to delete resource pool", K(ret));
      } else if (OB_INVALID_ID == old_pool.at(i)->tenant_id_) {
        // bypass
      } else if (OB_FAIL(delete_tenant_pool(old_pool.at(i)->tenant_id_, old_pool.at(i)))) {
        LOG_WARN("fail to delete tenant pool", K(ret), "tenant_id", old_pool.at(i)->tenant_id_);
      }
      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(get_units_by_pool(old_pool.at(i)->resource_pool_id_, pool_units))) {
        LOG_WARN("fail to get units by pool", K(ret), "pool_id", old_pool.at(i)->resource_pool_id_);
      } else if (OB_UNLIKELY(NULL == pool_units)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool units ptr is null", K(ret));
      } else if (OB_FAIL(pool_unit_map_.erase_refactored(old_pool.at(i)->resource_pool_id_))) {
        LOG_WARN("fail to erase map", K(ret), "pool_id", old_pool.at(i)->resource_pool_id_);
      } else {
        pool_unit_allocator_.free(pool_units);
        pool_units = NULL;
        pool_allocator_.free(old_pool.at(i));
        old_pool.at(i) = NULL;
      }
    }
    if (OB_FAIL(ret)) {
      // reload
      rootserver::ObRootService* root_service = NULL;
      if (OB_UNLIKELY(NULL == (root_service = GCTX.root_service_))) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("rootservice is null", K(ret));
      } else {
        int tmp_ret = root_service->submit_reload_unit_manager_task();
        if (OB_SUCCESS != tmp_ret) {
          LOG_ERROR("fail to reload unit manager", K(tmp_ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::merge_pool_unit_inmemory_info(
    share::ObResourcePool* new_pool /*allocate_pool_ptr*/, common::ObIArray<share::ObResourcePool*>& old_pool)
{
  int ret = OB_SUCCESS;
  common::ObArray<share::ObUnit*>* new_units = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(NULL == new_pool)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(new_pool));
  } else {
    ret = get_units_by_pool(new_pool->resource_pool_id_, new_units);
    if (OB_SUCCESS == ret) {
      // got new units
    } else if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("fail to get units by pool", K(ret));
    } else {
      if (NULL == (new_units = pool_unit_allocator_.alloc())) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_ERROR("fail to alloc memory", K(ret));
      } else if (OB_FAIL(pool_unit_map_.set_refactored(new_pool->resource_pool_id_, new_units))) {
        LOG_WARN("fail to set refactored", K(ret), "pool_id", new_pool->resource_pool_id_);
      }
    }
    for (int64_t i = 0; i < old_pool.count() && OB_SUCC(ret); ++i) {
      common::ObArray<share::ObUnit*>* orig_units = NULL;
      if (OB_ISNULL(old_pool.at(i))) {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("invalid argument", K(ret), KP(old_pool.at(i)));
      } else if (OB_FAIL(get_units_by_pool(old_pool.at(i)->resource_pool_id_, orig_units))) {
        LOG_WARN("fail to get units by pool", K(ret));
      } else if (OB_UNLIKELY(NULL == orig_units)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("units ptr is null", K(ret));
      } else {
        for (int64_t i = 0; OB_SUCC(ret) && i < orig_units->count(); ++i) {
          share::ObUnit* unit = orig_units->at(i);
          if (OB_UNLIKELY(NULL == unit)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unit ptr is null", K(ret));
          } else if (NULL == new_units) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("new units ptr is null", K(ret));
          } else {
            unit->resource_pool_id_ = new_pool->resource_pool_id_;
            if (OB_FAIL(new_units->push_back(unit))) {
              LOG_WARN("fail to push back", K(ret));
            } else if (OB_FAIL(update_unit_load(unit, new_pool))) {
              LOG_WARN("fail to update unit load", K(ret));
            }
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::alter_resource_pool(const share::ObResourcePool& alter_pool, const ObUnitConfigName& config_name,
    const common::ObIArray<uint64_t>& delete_unit_id_array)
{
  int ret = OB_SUCCESS;
  LOG_INFO("start alter resource pool", K(alter_pool), K(config_name));
  SpinWLockGuard guard(lock_);
  share::ObResourcePool* pool = NULL;
  share::ObResourcePool pool_bak;
  // don't invoke alter_pool.is_valid() here, alter_pool.unit_count may be 0
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (alter_pool.name_.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource pool name");
    LOG_WARN("resource pool name is empty", "resource pool name", alter_pool.name_, K(ret));
  } else if (alter_pool.unit_count_ < 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource unit num");
    LOG_WARN("invalid resource pool unit num", "unit num", alter_pool.unit_count_, K(ret));
  } else if (OB_FAIL(inner_get_resource_pool_by_name(alter_pool.name_, pool))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get resource pool by name failed", "resource_pool name", alter_pool.name_, K(ret));
    } else {
      ret = OB_RESOURCE_POOL_NOT_EXIST;
      LOG_USER_ERROR(OB_RESOURCE_POOL_NOT_EXIST, to_cstring(alter_pool.name_));
      LOG_WARN("resource pool not exist", "resource pool name", alter_pool.name_, K(ret));
    }
  } else if (NULL == pool) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool is null", KP(pool), K(ret));
  } else if (REPLICA_TYPE_LOGONLY == pool->replica_type_ && alter_pool.unit_count_ > 1) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("logonly resource pool should only have one unit on one zone", K(ret), K(alter_pool));
  } else {
    int64_t alter_count = 0;
    if (!config_name.is_empty()) {
      ++alter_count;
    }
    if (0 != alter_pool.unit_count_) {
      ++alter_count;
    }
    if (alter_pool.zone_list_.count() > 0) {
      ++alter_count;
    }
    if (alter_count > 1) {
      ret = OB_NOT_SUPPORTED;
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "alter unit_num, resource_unit, zone_list in one cmd");
      LOG_WARN("only support alter one item one time", K(alter_pool), K(config_name), K(ret));
    }

    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(pool_bak.assign(*pool))) {
      LOG_WARN("failed to assign pool_bak", K(ret));
    }

    // TODO: modiry replica_type not support;
    // alter unit config
    if (OB_FAIL(ret)) {
    } else if (config_name.is_empty()) {
      // config not change
    } else if (OB_FAIL(alter_pool_unit_config(pool, config_name))) {
      LOG_WARN("alter_pool_unit_config failed", "pool", *pool, K(config_name), K(ret));
    }

    // alter unit num
    if (OB_FAIL(ret)) {
    } else if (0 == alter_pool.unit_count_) {
      // unit num not change
    } else if (OB_FAIL(alter_pool_unit_num(pool, alter_pool.unit_count_, delete_unit_id_array))) {
      LOG_WARN("alter_pool_unit_num failed", "pool", *pool, "unit_num", alter_pool.unit_count_, K(ret));
    }

    // alter zone list
    if (OB_FAIL(ret)) {
    } else if (alter_pool.zone_list_.count() <= 0) {
      // zone list not change
    } else if (OB_FAIL(alter_pool_zone_list(pool, alter_pool.zone_list_))) {
      LOG_WARN("alter_pool_zone_list failed", "pool", *pool, "zone_list", alter_pool.zone_list_, K(ret));
    }
  }
  if (OB_SUCC(ret)) {
    ROOTSERVICE_EVENT_ADD("unit", "alter_resource_pool", "name", pool_bak.name_);
  }
  LOG_INFO("finish alter resource pool", K(alter_pool), K(config_name), K(ret));
  return ret;
}

int ObUnitManager::drop_resource_pool(const ObResourcePoolName& name, const bool if_exist)
{
  int ret = OB_SUCCESS;
  LOG_INFO("start drop resource pool", K(name));
  SpinWLockGuard guard(lock_);
  share::ObResourcePool* pool = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (name.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource pool name");
    LOG_WARN("invalid argument", K(name), K(ret));
  } else if (OB_FAIL(inner_get_resource_pool_by_name(name, pool))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get resource pool by name failed", K(name), K(ret));
    } else {
      if (if_exist) {
        ret = OB_SUCCESS;
        LOG_USER_NOTE(OB_RESOURCE_POOL_NOT_EXIST, to_cstring(name));
        LOG_INFO("resource_pool not exist, but no need drop it", K(name));
      } else {
        ret = OB_RESOURCE_POOL_NOT_EXIST;
        LOG_USER_ERROR(OB_RESOURCE_POOL_NOT_EXIST, to_cstring(name));
        LOG_WARN("resource_pool not exist", K(name), K(ret));
      }
    }
  } else if (NULL == pool) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool is null", KP(pool), K(ret));
  } else if (OB_INVALID_ID != pool->tenant_id_) {
    ret = OB_RESOURCE_POOL_ALREADY_GRANTED;
    LOG_USER_ERROR(OB_RESOURCE_POOL_ALREADY_GRANTED, to_cstring(name));
    LOG_WARN("resource pool is granted to tenant, can't not delete it", "tenant_id", pool->tenant_id_, K(ret));
  } else {
    common::ObMySQLTransaction trans;
    if (OB_FAIL(trans.start(proxy_))) {
      LOG_WARN("start transaction failed", K(ret));
    } else if (OB_FAIL(remove_resource_pool_unit_in_trans(pool->resource_pool_id_, trans))) {
      LOG_WARN("failed to remove reource pool and unit", K(ret), K(pool));
    }
    if (trans.is_started()) {
      const bool commit = (OB_SUCC(ret));
      int temp_ret = OB_SUCCESS;
      if (OB_SUCCESS != (temp_ret = trans.end(commit))) {
        LOG_WARN("trans end failed", K(commit), K(temp_ret));
        ret = (OB_SUCCESS == ret) ? temp_ret : ret;
      }
    }

    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(delete_resource_pool_unit(pool))) {
      LOG_WARN("failed to delete resource pool or unit", K(ret), K(pool));
    }
  }
  LOG_INFO("finish drop resource pool", K(name), K(ret));
  return ret;
}
int ObUnitManager::remove_resource_pool_unit_in_trans(const int64_t resource_pool_id, ObMySQLTransaction& trans)
{
  int ret = OB_SUCCESS;
  int migrate_unit_ret = OB_CANCELED;
  if (OB_INVALID_ID == resource_pool_id || !trans.is_started()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(resource_pool_id), "is_started", trans.is_started());
  } else if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_FAIL(ut_operator_.remove_units(trans, resource_pool_id))) {
    LOG_WARN("remove_units failed", K(ret), K(resource_pool_id));
  } else if (OB_FAIL(ut_operator_.remove_resource_pool(trans, resource_pool_id))) {
    LOG_WARN("remove_resource_pool failed", K(ret), K(resource_pool_id));
  } else if (OB_FAIL(complete_migrate_unit_rs_job_in_pool(resource_pool_id, migrate_unit_ret, trans))) {
    LOG_WARN("failed to complete migrate unit in pool", K(ret), K(resource_pool_id));
  }
  return ret;
}
// site lock at the call
int ObUnitManager::delete_resource_pool_unit(share::ObResourcePool* pool)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(pool)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool is null or invalid", K(ret), K(pool));
  } else if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else {
    if (OB_FAIL(delete_units_of_pool(pool->resource_pool_id_))) {
      LOG_WARN("delete_units_of_pool failed", "pool id", pool->resource_pool_id_, K(ret));
    } else if (OB_FAIL(delete_resource_pool(pool->resource_pool_id_, pool->name_))) {
      LOG_WARN("delete_resource_pool failed", "pool", *pool, K(ret));
    } else {
      const uint64_t config_id = pool->unit_config_id_;
      if (OB_FAIL(dec_config_ref_count(config_id))) {
        LOG_WARN("dec_config_ref_count failed", K(config_id), K(ret));
      } else if (OB_FAIL(delete_config_pool(config_id, pool))) {
        LOG_WARN("delete config pool failed", K(config_id), "pool", *pool, K(ret));
      } else {
        ROOTSERVICE_EVENT_ADD("unit", "drop_resource_pool", "name", pool->name_);
      }
      pool_allocator_.free(pool);
      pool = NULL;
    }
  }
  return ret;
}
int ObUnitManager::drop_standby_resource_pool(
    const common::ObIArray<ObResourcePoolName>& pool_names, ObMySQLTransaction& trans)
{
  int ret = OB_SUCCESS;
  if (0 == pool_names.count() || !trans.is_started()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool names is empty or trans not start", K(ret), K(pool_names), "started", trans.is_started());
  } else if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else {
    SpinRLockGuard guard(lock_);
    // When the standby database deletes a tenant, it needs to delete resource_pool
    for (int64_t i = 0; i < pool_names.count() && OB_SUCC(ret); ++i) {
      share::ObResourcePool* pool = NULL;
      if (OB_FAIL(inner_get_resource_pool_by_name(pool_names.at(i), pool))) {
        LOG_WARN("failed to get reource pool by name", K(ret), K(i), K(pool_names));
      } else if (OB_ISNULL(pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", K(ret), K(pool));
      } else if (OB_FAIL(remove_resource_pool_unit_in_trans(pool->resource_pool_id_, trans))) {
        LOG_WARN("failed to remove resource pool and unit", K(ret), K(pool));
      }
    }
  }
  return ret;
}
int ObUnitManager::commit_drop_standby_resource_pool(const common::ObIArray<ObResourcePoolName>& pool_names)
{
  int ret = OB_SUCCESS;
  if (0 == pool_names.count()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool names is empty or trans not start", K(ret), K(pool_names));
  } else if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else {
    SpinWLockGuard guard(lock_);
    // When the standby database deletes a tenant, it needs to delete resource_pool
    for (int64_t i = 0; i < pool_names.count() && OB_SUCC(ret); ++i) {
      share::ObResourcePool* pool = NULL;
      if (OB_FAIL(inner_get_resource_pool_by_name(pool_names.at(i), pool))) {
        LOG_WARN("failed to get reource pool by name", K(ret), K(i), K(pool_names));
      } else if (OB_ISNULL(pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", K(ret), K(pool));
      } else if (OB_FAIL(delete_resource_pool_unit(pool))) {
        LOG_WARN("failed to remove resource pool and unit", K(ret), K(pool));
      }
    }
  }
  return ret;
}
// After the 14x version,
// the same tenant is allowed to have multiple unit specifications in a zone,
// but it is necessary to ensure that these units can be scattered on each server in the zone,
// and multiple units of the same tenant cannot be located on the same machine;
int ObUnitManager::check_server_enough(
    const uint64_t tenant_id, const ObIArray<ObResourcePoolName>& pool_names, bool& enough)
{
  int ret = OB_SUCCESS;
  enough = true;
  share::ObResourcePool* pool = NULL;
  ObArray<ObUnitInfo> unit_infos;
  ObArray<ObUnitInfo> total_unit_infos;
  common::ObArray<share::ObResourcePool*>* pools = NULL;
  ;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (pool_names.count() <= 0 || OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(pool_names), K(tenant_id), K(ret));
  } else {
    // Count the number of newly added units
    for (int64_t i = 0; i < pool_names.count() && OB_SUCC(ret); i++) {
      unit_infos.reset();
      if (OB_FAIL(inner_get_resource_pool_by_name(pool_names.at(i), pool))) {
        LOG_WARN("fail to get resource pool by name", K(ret), "pool_name", pool_names.at(i));
      } else if (OB_ISNULL(pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get invalid pool", K(ret), K(pool));
      } else if (OB_FAIL(inner_get_unit_infos_of_pool(pool->resource_pool_id_, unit_infos))) {
        LOG_WARN("fail to get unit infos", K(ret), K(*pool));
      } else {
        for (int64_t j = 0; j < unit_infos.count() && OB_SUCC(ret); j++) {
          if (OB_FAIL(total_unit_infos.push_back(unit_infos.at(j)))) {
            LOG_WARN("fail to push back unit", K(ret), K(total_unit_infos), K(j), K(unit_infos));
          } else {
            LOG_DEBUG("add unit infos", K(ret), K(total_unit_infos), K(unit_infos));
          }
        }
      }  // end else
    }    // end for
  }
  // Count the number of existing units
  if (OB_FAIL(ret)) {
    // nothing todo
  } else if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
    if (OB_ENTRY_NOT_EXIST == ret) {
      // a new tenant, without resource pool already granted
      ret = OB_SUCCESS;
    } else {
      LOG_WARN("fail to get pools by tenant", K(ret), K(tenant_id));
    }
  } else if (OB_UNLIKELY(NULL == pools)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pools is null", K(ret), KP(pools));
  } else {
    for (int64_t i = 0; i < pools->count() && OB_SUCC(ret); i++) {
      unit_infos.reset();
      const share::ObResourcePool* pool = pools->at(i);
      if (OB_UNLIKELY(NULL == pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret), KP(pool));
      } else if (OB_FAIL(inner_get_unit_infos_of_pool(pool->resource_pool_id_, unit_infos))) {
        LOG_WARN("fail to get unit infos", K(ret), K(*pool));
      } else {
        for (int64_t j = 0; j < unit_infos.count() && OB_SUCC(ret); j++) {
          if (OB_FAIL(total_unit_infos.push_back(unit_infos.at(j)))) {
            LOG_WARN("fail to push back unit", K(ret), K(total_unit_infos), K(j), K(unit_infos));
          } else {
            LOG_WARN("add unit infos", K(ret), K(total_unit_infos), K(unit_infos));
          }
        }
      }
    }
  }
  ObArray<ObZoneInfo> zone_infos;
  if (OB_FAIL(ret)) {
  } else if (OB_FAIL(zone_mgr_.get_zone(zone_infos))) {
    LOG_WARN("fail to get zone infos", K(ret));
  } else {
    // Count the number of units in zone
    for (int64_t i = 0; i < zone_infos.count() && OB_SUCC(ret) && enough; i++) {
      ObZone zone = zone_infos.at(i).zone_;
      int64_t unit_count = 0;
      int64_t alive_server_count = 0;
      for (int64_t j = 0; j < total_unit_infos.count() && OB_SUCC(ret); j++) {
        if (total_unit_infos.at(j).unit_.zone_ == zone) {
          unit_count++;
        }
      }
      if (unit_count > 0) {
        if (OB_FAIL(server_mgr_.get_alive_server_count(zone, alive_server_count))) {
          LOG_WARN("fail to get alive server count", K(ret), K(zone));
        } else if (alive_server_count < unit_count) {
          // ret = OB_UNIT_NUM_OVER_SERVER_COUNT;
          enough = false;
          LOG_WARN("resource pool unit num over zone server count",
              K(ret),
              K(unit_count),
              K(alive_server_count),
              K(total_unit_infos));
        }
      }
    }
  }
  return ret;
}

// The F/L scheme has new restrictions.
// If the logonly replica exists in the locality before adding the Logonly pool, the change is not allowed
int ObUnitManager::check_locality_for_logonly_unit(const share::schema::ObTenantSchema& tenant_schema,
    const ObIArray<ObResourcePoolName>& pool_names, bool& is_permitted)
{
  int ret = OB_SUCCESS;
  is_permitted = true;
  ObArray<ObZone> zone_with_logonly_unit;
  ObArray<share::ObZoneReplicaNumSet> zone_locality;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (pool_names.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(pool_names), K(ret));
  } else {
    FOREACH_CNT_X(pool_name, pool_names, OB_SUCCESS == ret)
    {
      share::ObResourcePool* pool = NULL;
      if (OB_FAIL(inner_get_resource_pool_by_name(*pool_name, pool))) {
        LOG_WARN("get resource pool by name failed", "pool_name", *pool_name, K(ret));
      } else if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", KP(pool), K(ret));
      } else if (REPLICA_TYPE_LOGONLY != pool->replica_type_) {
        // nothing todo
      } else {
        for (int64_t i = 0; i < pool->zone_list_.count() && OB_SUCC(ret); i++) {
          if (OB_FAIL(zone_with_logonly_unit.push_back(pool->zone_list_.at(i)))) {
            LOG_WARN("fail to push back", K(ret));
          }
        }
      }
    }
  }
  if (OB_FAIL(ret)) {
  } else if (OB_FAIL(tenant_schema.get_zone_replica_attr_array(zone_locality))) {
    LOG_WARN("fail to get zone replica attr array", K(ret));
  } else {
    for (int64_t i = 0; i < zone_locality.count() && OB_SUCC(ret); i++) {
      if (zone_locality.at(i).replica_attr_set_.get_logonly_replica_num() == 1 &&
          has_exist_in_array(zone_with_logonly_unit, zone_locality.at(i).zone_)) {
        is_permitted = false;
        ret = OB_NOT_SUPPORTED;
        LOG_WARN("logonly replica already exist before logonly pool create",
            K(ret),
            K(zone_locality),
            K(zone_with_logonly_unit));
      }
    }
  }
  return ret;
}

int ObUnitManager::grant_pools_for_standby(common::ObISQLClient& client,
    const common::ObIArray<share::ObResourcePoolName>& pool_names, const uint64_t tenant_id)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K(ret), K(inited_), K(loaded_));
  } else if (common::STANDBY_CLUSTER != ObClusterInfoGetter::get_cluster_type_v2()) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("not standby cluster", K(ret), "cluster_type", ObClusterInfoGetter::get_cluster_type_v2());
  } else {
    SpinWLockGuard guard(lock_);
    // If the grant pool has been successful, you only need to modify the table next time
    share::ObResourcePool new_pool;
    for (int64_t i = 0; OB_SUCC(ret) && i < pool_names.count(); ++i) {
      share::ObResourcePool* pool = NULL;
      if (OB_FAIL(inner_get_resource_pool_by_name(pool_names.at(i), pool))) {
        LOG_WARN("get resource pool by name failed", "pool_name", pool_names.at(i), K(ret));
      } else if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", KP(pool), K(ret));
      } else if (OB_INVALID_ID != pool->tenant_id_) {
        ret = OB_RESOURCE_POOL_ALREADY_GRANTED;
        LOG_USER_ERROR(OB_RESOURCE_POOL_ALREADY_GRANTED, to_cstring(pool_names.at(i)));
        LOG_WARN("pool has already granted to other tenant, can't grant again", K(ret), K(tenant_id), "pool", *pool);
      } else if (OB_FAIL(new_pool.assign(*pool))) {
        LOG_WARN("failed to assign new_pool", K(ret));
      } else {
        new_pool.tenant_id_ = tenant_id;
        if (OB_FAIL(ut_operator_.update_resource_pool(client, new_pool))) {
          LOG_WARN("update_resource_pool failed", K(new_pool), K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::grant_pools(ObISQLClient& client, const share::ObWorker::CompatMode compat_mode,
    const ObIArray<ObResourcePoolName>& pool_names, const uint64_t tenant_id, const bool is_bootstrap,
    const bool if_not_grant, const bool skip_offline_server)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  const bool grant = true;
  bool intersect = false;
  bool enough = true;
  const bool skip_check_enough = is_bootstrap || skip_offline_server;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (pool_names.count() <= 0 || OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(pool_names), K(tenant_id), K(ret));
  } else if (OB_FAIL(check_pool_intersect(tenant_id, pool_names, intersect))) {
    LOG_WARN("check pool intersect failed", K(pool_names), K(ret));
  } else if (intersect) {
    ret = OB_POOL_SERVER_INTERSECT;
    LOG_USER_ERROR(OB_POOL_SERVER_INTERSECT, to_cstring(pool_names));
    LOG_WARN("resource pool unit server intersect", K(pool_names), K(ret));
  } else if (!skip_check_enough && OB_FAIL(check_server_enough(tenant_id, pool_names, enough))) {
    LOG_WARN("fail to check server enough", K(tenant_id), K(pool_names));
  } else if (!enough) {
    ret = OB_UNIT_NUM_OVER_SERVER_COUNT;
    LOG_WARN("resource pool unit num over zone server count", K(ret), K(pool_names), K(tenant_id));
  } else if (OB_FAIL(change_pool_owner(
                 client, compat_mode, grant, pool_names, tenant_id, is_bootstrap, if_not_grant, skip_offline_server))) {
    LOG_WARN("change pool owner failed",
        KR(ret),
        K(grant),
        K(pool_names),
        K(tenant_id),
        K(compat_mode),
        K(is_bootstrap),
        K(if_not_grant),
        K(skip_offline_server));
  }
  LOG_INFO("grant resource pools to tenant",
      K(pool_names),
      K(tenant_id),
      K(ret),
      K(is_bootstrap),
      K(if_not_grant),
      K(skip_offline_server));
  return ret;
}

int ObUnitManager::revoke_pools(
    ObISQLClient& client, const ObIArray<ObResourcePoolName>& pool_names, const uint64_t tenant_id)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  const bool grant = false;
  const share::ObWorker::CompatMode dummy_mode = share::ObWorker::CompatMode::INVALID;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (pool_names.count() <= 0 || OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(pool_names), K(tenant_id), K(ret));
  } else if (OB_FAIL(change_pool_owner(client, dummy_mode, grant, pool_names, tenant_id, false /*is_bootstrap*/))) {
    LOG_WARN("change pool owner failed", K(grant), K(pool_names), K(tenant_id), K(ret));
  }
  LOG_INFO("revoke resource pools from tenant", K(pool_names), K(ret));
  return ret;
}

int ObUnitManager::commit_change_pool_owner(
    const bool grant, const ObIArray<ObResourcePoolName>& pool_names, const uint64_t tenant_id)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  if (OB_FAIL(inner_commit_change_pool_owner(grant, pool_names, tenant_id))) {
    LOG_WARN("fail to inner commit change pool owner", K(ret));
  }
  return ret;
}

int ObUnitManager::inner_commit_change_pool_owner(
    const bool grant, const ObIArray<ObResourcePoolName>& pool_names, const uint64_t tenant_id)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (pool_names.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool_names is empty", K(pool_names), K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid tenant_id", K(tenant_id), K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < pool_names.count(); ++i) {
      share::ObResourcePool* pool = NULL;
      if (OB_FAIL(inner_get_resource_pool_by_name(pool_names.at(i), pool))) {
        LOG_WARN("resource pool expected to exist", "pool_name", pool_names.at(i), K(ret));
      } else if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", KP(pool), K(ret));
      } else if (OB_INVALID_ID != pool->tenant_id_ && pool->tenant_id_ != tenant_id) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("find pool already grant to other tenant", "pool", *pool, K(tenant_id), K(ret));
      } else {
        if (grant) {
          if (pool->tenant_id_ == tenant_id) {
            // possible if alter system reload unit before invoke this function
          } else {
            if (OB_FAIL(insert_tenant_pool(tenant_id, pool))) {
              LOG_WARN("insert_tenant_pool failed", K(tenant_id), K(ret));
            } else {
              pool->tenant_id_ = tenant_id;
            }
          }
        } else {
          if (OB_INVALID_ID == pool->tenant_id_) {
            // possible if alter system reload unit before invoke this function
          } else {
            if (OB_FAIL(delete_tenant_pool(pool->tenant_id_, pool))) {
              LOG_WARN("delete_tenant_pool failed", "pool tenant_id", pool->tenant_id_, K(ret));
            } else {
              pool->tenant_id_ = OB_INVALID_ID;
            }
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::inner_get_pool_ids_of_tenant(const uint64_t tenant_id, ObIArray<uint64_t>& pool_ids) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(tenant_id), K(ret));
  } else {
    pool_ids.reuse();
    ObArray<share::ObResourcePool*>* pools = NULL;
    if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
      if (OB_ENTRY_NOT_EXIST != ret) {
        LOG_DEBUG("get_pools_by_tenant failed", K(tenant_id), K(ret));
      } else {
        // just return empty pool_ids
        if (OB_GTS_TENANT_ID != tenant_id) {
          LOG_INFO("tenant doesn't own any pool", K(tenant_id), KR(ret));
        }
        ret = OB_SUCCESS;
      }
    } else if (NULL == pools) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pools is null", KP(pools), K(ret));
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < pools->count(); ++i) {
        if (NULL == pools->at(i)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("pool is null", "pool", OB_P(pools->at(i)), K(ret));
        } else if (OB_FAIL(pool_ids.push_back(pools->at(i)->resource_pool_id_))) {
          LOG_WARN("push_back failed", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::get_pool_ids_of_tenant(const uint64_t tenant_id, ObIArray<uint64_t>& pool_ids) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(tenant_id), K(ret));
  } else if (OB_FAIL(inner_get_pool_ids_of_tenant(tenant_id, pool_ids))) {
    LOG_WARN("fail to inner get pool ids of tenant", K(ret));
  }
  return ret;
}

int ObUnitManager::get_pool_names_of_tenant(const uint64_t tenant_id, ObIArray<ObResourcePoolName>& pool_names) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(tenant_id), K(ret));
  } else {
    ObArray<share::ObResourcePool*>* pools = NULL;
    if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
      if (OB_ENTRY_NOT_EXIST != ret) {
        LOG_WARN("get_pools_by_tenant failed", K(tenant_id), K(ret));
      } else {
        // just return empty pool_ids
        ret = OB_SUCCESS;
        LOG_WARN("tenant doesn't own any pool", K(tenant_id), K(ret));
      }
    } else if (NULL == pools) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pools is null", KP(pools), K(ret));
    } else {
      pool_names.reuse();
      for (int64_t i = 0; OB_SUCC(ret) && i < pools->count(); ++i) {
        if (NULL == pools->at(i)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("pool is null", "pool", OB_P(pools->at(i)), K(ret));
        } else if (OB_FAIL(pool_names.push_back(pools->at(i)->name_))) {
          LOG_WARN("push_back failed", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::get_unit_config_by_pool_name(const ObString& pool_name, share::ObUnitConfig& unit_config) const
{
  int ret = OB_SUCCESS;
  share::ObResourcePool* pool = NULL;
  ObUnitConfig* config = NULL;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_FAIL(inner_get_resource_pool_by_name(pool_name, pool))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get resource pool by name failed", K(pool_name), K(ret));
    } else {
      ret = OB_RESOURCE_POOL_NOT_EXIST;
      LOG_WARN("pool not exist", K(ret), K(pool_name));
    }
  } else if (NULL == pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool is null", KP(pool), K(ret));
  } else if (OB_FAIL(get_unit_config_by_id(pool->unit_config_id_, config))) {
    if (OB_ENTRY_NOT_EXIST == ret) {
      ret = OB_RESOURCE_UNIT_NOT_EXIST;
    }
    LOG_WARN("can not find config for unit", "unit_config_id", pool->unit_config_id_, K(ret));
  } else if (NULL == config) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("config is null", KP(config), K(ret));
  } else {
    unit_config = *config;
  }
  return ret;
}

int ObUnitManager::get_pools_of_tenant(const uint64_t tenant_id, ObIArray<share::ObResourcePool>& pools) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(tenant_id), K(ret));
  } else {
    ObArray<share::ObResourcePool*>* inner_pools = NULL;
    if (OB_FAIL(get_pools_by_tenant(tenant_id, inner_pools))) {
      if (OB_ENTRY_NOT_EXIST != ret) {
        LOG_WARN("get_pools_by_tenant failed", K(tenant_id), K(ret));
      } else {
        // just return empty pool_ids
        ret = OB_SUCCESS;
        LOG_WARN("tenant doesn't own any pool", K(tenant_id), K(ret));
      }
    } else if (NULL == inner_pools) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("inner_pools is null", KP(inner_pools), K(ret));
    } else {
      pools.reuse();
      for (int64_t i = 0; OB_SUCC(ret) && i < inner_pools->count(); ++i) {
        if (NULL == inner_pools->at(i)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("inner_pool is null", "inner_pool", OB_P(inner_pools->at(i)), K(ret));
        } else if (OB_FAIL(pools.push_back(*inner_pools->at(i)))) {
          LOG_WARN("push_back failed", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::get_zones_of_pools(const ObIArray<ObResourcePoolName>& pool_names, ObIArray<ObZone>& zones) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (pool_names.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool_names is empty", K(pool_names), K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < pool_names.count(); ++i) {
      share::ObResourcePool* pool = NULL;
      if (pool_names.at(i).is_empty()) {
        ret = OB_INVALID_ARGUMENT;
        LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource pool name");
        LOG_WARN("invalid pool name", "pool name", pool_names.at(i), K(ret));
      } else if (OB_FAIL(inner_get_resource_pool_by_name(pool_names.at(i), pool))) {
        if (OB_ENTRY_NOT_EXIST != ret) {
          LOG_WARN("get resource pool by name failed", "name", pool_names.at(i), K(ret));
        } else {
          ret = OB_RESOURCE_POOL_NOT_EXIST;
          LOG_USER_ERROR(OB_RESOURCE_POOL_NOT_EXIST, to_cstring(pool_names.at(i)));
          LOG_WARN("pool not exist", "pool_name", pool_names.at(i), K(ret));
        }
      } else if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", KP(pool), K(ret));
      } else if (OB_FAIL(append(zones, pool->zone_list_))) {
        LOG_WARN("append failed", "zone_list", pool->zone_list_, K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::get_pool_id(const share::ObResourcePoolName& pool_name, uint64_t& pool_id) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (pool_name.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid pool_name", K(pool_name), K(ret));
  } else {
    share::ObResourcePool* pool = NULL;
    if (OB_FAIL(inner_get_resource_pool_by_name(pool_name, pool))) {
      if (OB_ENTRY_NOT_EXIST != ret) {
        LOG_WARN("get resource pool by name failed", K(pool_name), K(ret));
      } else {
        ret = OB_RESOURCE_POOL_NOT_EXIST;
        LOG_WARN("pool not exist", K(ret), K(pool_name));
      }
    } else if (NULL == pool) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("pool is null", KP(pool), K(ret));
    } else {
      pool_id = pool->resource_pool_id_;
    }
  }
  return ret;
}

int ObUnitManager::get_pools(common::ObIArray<share::ObResourcePool>& pools) const
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else {
    ObHashMap<uint64_t, share::ObResourcePool*>::const_iterator iter = id_pool_map_.begin();
    for (; OB_SUCC(ret) && iter != id_pool_map_.end(); ++iter) {
      if (NULL == iter->second) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("iter->second is null", KP(iter->second), K(ret));
      } else if (OB_FAIL(pools.push_back(*(iter->second)))) {
        LOG_WARN("push_back failed", K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::create_gts_units(const ObIArray<ObUnit>& gts_units)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (gts_units.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("gts_units is empty", K(gts_units), K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < gts_units.count(); ++i) {
      if (OB_FAIL(add_unit(*proxy_, gts_units.at(i)))) {
        LOG_WARN("add_unit failed", "unit", gts_units.at(i), K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::create_sys_units(const ObIArray<ObUnit>& sys_units)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (sys_units.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("sys_units is empty", K(sys_units), K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < sys_units.count(); ++i) {
      if (OB_FAIL(add_unit(*proxy_, sys_units.at(i)))) {
        LOG_WARN("add_unit failed", "unit", sys_units.at(i), K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::inner_get_tenant_pool_zone_list(
    const uint64_t tenant_id, common::ObIArray<common::ObZone>& zone_list) const
{
  int ret = OB_SUCCESS;
  ObArray<share::ObResourcePool*>* pools = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(OB_INVALID_ID == tenant_id)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id));
  } else if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
    LOG_WARN("fail to get pools by tenant", K(ret), K(tenant_id));
  } else if (OB_UNLIKELY(NULL == pools)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pools ptr is null", K(ret), K(tenant_id));
  } else if (pools->count() <= 0) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pools array is empty", K(ret), K(*pools));
  } else {
    zone_list.reset();
    for (int64_t i = 0; OB_SUCC(ret) && i < pools->count(); ++i) {
      const share::ObResourcePool* pool = pools->at(i);
      if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", K(ret), KP(pool));
      } else if (OB_FAIL(append(zone_list, pool->zone_list_))) {
        LOG_WARN("fail to append", K(ret));
      } else {
      }  // no more to do
    }
  }
  return ret;
}

int ObUnitManager::get_tenant_pool_zone_list(
    const uint64_t tenant_id, common::ObIArray<common::ObZone>& zone_list) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (OB_FAIL(inner_get_tenant_pool_zone_list(tenant_id, zone_list))) {
    LOG_WARN("fail to inner get tenant pool zone list", K(ret));
  }
  return ret;
}

// Units in the deleting state will no longer be migrated
// int ObUnitManager::migrate_out_units(const ObAddr &server,
//    const ObIArray<ObAddr> &excluded_servers, bool &empty)
//{
//  int ret = OB_SUCCESS;
//  ObArray<ObUnitLoad> *loads = NULL;
//  SpinWLockGuard guard(lock_);
//  empty = false;
//  if (!check_inner_stat()) {
//    ret = OB_INNER_STAT_ERROR;
//    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
//  } else if (!server.is_valid()) {
//    ret = OB_INVALID_ARGUMENT;
//    LOG_WARN("invalid argument", K(server), K(ret));
//  } else if (OB_FAIL(get_loads_by_server(server, loads))) {
//    if (OB_ENTRY_NOT_EXIST != ret) {
//      LOG_WARN("get_loads_by_server failed", K(server), K(ret));
//    } else {
//      ret = OB_SUCCESS;
//      empty = true;
//    }
//  } else if (NULL == loads) {
//    ret = OB_ERR_UNEXPECTED;
//    LOG_WARN("loads is null", KP(loads), K(ret));
//  } else if (OB_FAIL(make_server_empty(server, excluded_servers, loads))) {
//    LOG_WARN("make_server_empty failed", K(server), K(excluded_servers), K(ret));
//  }
//  LOG_INFO("migrate out units", K(server), K(empty), K(ret));
//  return ret;
//}

int ObUnitManager::cancel_migrate_out_units(const ObAddr& server)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  ObArray<uint64_t> migrate_units;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (!server.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(server), K(ret));
  } else if (OB_FAIL(get_migrate_units_by_server(server, migrate_units))) {
    LOG_WARN("get_migrate_units_by_server failed", K(server), K(ret));
  } else {
    const EndMigrateOp op = REVERSE;
    for (int64_t i = 0; OB_SUCC(ret) && i < migrate_units.count(); ++i) {
      if (OB_FAIL(end_migrate_unit(migrate_units.at(i), op))) {
        LOG_WARN("end_migrate_unit failed", "unit_id", migrate_units.at(i), K(op), K(ret));
      }
    }
  }
  LOG_INFO("cancel migrate out units", K(server), K(ret));
  return ret;
}

int ObUnitManager::check_server_empty(const ObAddr& server, bool& empty) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  ObArray<ObUnitLoad>* loads = NULL;
  empty = false;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (!server.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid server", K(server), K(ret));
  } else if (OB_FAIL(get_loads_by_server(server, loads))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_loads_by_server failed", K(server), K(ret));
    } else {
      ret = OB_SUCCESS;
      empty = true;
    }
  } else if (NULL == loads) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("loads is null", KP(loads), K(ret));
  } else {
    empty = false;
  }
  return ret;
}

int ObUnitManager::finish_migrate_unit_not_in_tenant(share::ObResourcePool* pool, int64_t& total_task_cnt)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  // Not in tenant unit
  // Using pool, take the unit corresponding to the pool whose tenant_id is -1
  if (-1 != pool->tenant_id_) {
    // in tenant
    // ignore in tenant unit
  } else {
    ObArray<ObUnitInfo> unit_infos;
    if (OB_FAIL(inner_get_unit_infos_of_pool(pool->resource_pool_id_, unit_infos))) {
      LOG_WARN("fail to get units by pool", K(ret));
    } else {
      FOREACH_CNT_X(unit_info, unit_infos, OB_SUCC(ret))
      {
        if ((*unit_info).unit_.migrate_from_server_.is_valid()) {
          total_task_cnt++;
          if (OB_INVALID_ID == (*unit_info).unit_.unit_id_) {
            ret = OB_INVALID_ARGUMENT;
            LOG_WARN("invalid argument", K((*unit_info).unit_.unit_id_), K(ret));
          } else {
            const EndMigrateOp op = COMMIT;
            if (OB_FAIL(end_migrate_unit((*unit_info).unit_.unit_id_, op))) {
              LOG_WARN("end migrate unit failed", K(ret), K((*unit_info).unit_.unit_id_), K(op));
            } else {
              LOG_INFO("finish migrate unit not in tenant", K(ret), "unit_id", (*unit_info).unit_.unit_id_);
            }
          }
        } else {
        }  // ignore not in migrate unit
      }
    }
  }
  return ret;
}

int ObUnitManager::finish_migrate_unit_not_in_locality(uint64_t tenant_id,
    share::schema::ObSchemaGetterGuard* schema_guard, ObArray<common::ObZone> zone_list, int64_t& task_cnt)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  const ObTenantSchema* tenant_schema = NULL;
  ObArray<ObUnitInfo> unit_infos;
  ObArray<common::ObZone> zone_locality_list;
  if (OB_FAIL((*schema_guard).get_tenant_info(tenant_id, tenant_schema))) {
    LOG_WARN("fail to get tenant schema", K(ret), K(tenant_id));
  } else if (OB_ISNULL(tenant_schema)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("tenant schema is null", K(ret));
  } else if (OB_FAIL(tenant_schema->get_zone_list(zone_locality_list))) {
    LOG_WARN("fail to get zone replica attr array", K(ret));
  } else {
    for (int64_t i = 0; i < zone_list.count() && OB_SUCC(ret); i++) {
      if (!has_exist_in_array(zone_locality_list, zone_list.at(i))) {
        // Get the unit that is in the zone locality but not in the zone_list,
        // the zone that is not in the locality
        if (OB_FAIL(inner_get_zone_alive_unit_infos_by_tenant(tenant_id, zone_list.at(i), unit_infos))) {
          LOG_WARN("fail to get zone alive unit infos by tenant", K(ret));
        } else {
          FOREACH_CNT_X(unit_info, unit_infos, OB_SUCC(ret))
          {
            if ((*unit_info).unit_.migrate_from_server_.is_valid()) {
              task_cnt++;
              if (OB_INVALID_ID == (*unit_info).unit_.unit_id_) {
                ret = OB_INVALID_ARGUMENT;
                LOG_WARN("invalid argument", K((*unit_info).unit_.unit_id_), K(ret));
              } else {
                const EndMigrateOp op = COMMIT;
                if (OB_FAIL(end_migrate_unit((*unit_info).unit_.unit_id_, op))) {
                  LOG_WARN("end migrate unit failed", K(ret), K((*unit_info).unit_.unit_id_), K(op));
                } else {
                  LOG_INFO("finish migrate unit not in locality", K(ret), "unit_id", (*unit_info).unit_.unit_id_);
                }
              }
            } else {
            }  // ignore not in migrate unit
          }    // end FOREACH
        }
      } else {
      }  // ignore in locality unit
    }    // end for
  }
  return ret;
}

int ObUnitManager::finish_migrate_unit(const uint64_t unit_id)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == unit_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(unit_id), K(ret));
  } else {
    const EndMigrateOp op = COMMIT;
    if (OB_FAIL(end_migrate_unit(unit_id, op))) {
      LOG_WARN("end_migrate_unit failed", K(unit_id), K(op), K(ret));
    }
  }
  LOG_INFO("finish migrate unit", K(unit_id), K(ret));
  return ret;
}

int ObUnitManager::get_zone_active_unit_infos_by_tenant(
    const uint64_t tenant_id, const common::ObZone& zone, common::ObIArray<share::ObUnitInfo>& unit_infos) const
{
  int ret = OB_SUCCESS;
  ObArray<uint64_t> rs_pool;
  ObArray<ObUnitInfo> unit_array;
  unit_infos.reset();
  if (OB_UNLIKELY(OB_INVALID_ID == tenant_id) || OB_UNLIKELY(zone.is_empty())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id), K(zone));
  } else if (OB_FAIL(get_pool_ids_of_tenant(tenant_id, rs_pool))) {
    LOG_WARN("fail to get pool ids by tennat", K(ret), K(tenant_id));
  } else {
    FOREACH_X(pool, rs_pool, OB_SUCCESS == ret)
    {
      unit_array.reuse();
      if (!check_inner_stat()) {
        ret = OB_INNER_STAT_ERROR;
        LOG_WARN("check inner stat failed", K(ret), K(inited_), K(loaded_));
      } else if (OB_UNLIKELY(NULL == pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", K(ret));
      } else if (OB_FAIL(get_unit_infos_of_pool(*pool, unit_array))) {
        LOG_WARN("fail to get unit infos of pool", K(ret));
      } else if (unit_array.count() > 0) {
        FOREACH_X(u, unit_array, OB_SUCCESS == ret)
        {
          if (OB_UNLIKELY(NULL == u)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unit is empty", K(ret));
          } else if (zone != u->unit_.zone_) {
            // do not belong to this zone
          } else if (ObUnit::UNIT_STATUS_ACTIVE != u->unit_.status_) {
            // ignore the unit which is in deleting status
          } else if (OB_FAIL(unit_infos.push_back(*u))) {
            LOG_WARN("fail to push back", K(ret));
          } else {
          }  // no more to do
        }
      } else {
      }  // empty array
    }
  }
  return ret;
}

int ObUnitManager::inner_get_zone_alive_unit_infos_by_tenant(
    const uint64_t tenant_id, const common::ObZone& zone, common::ObIArray<share::ObUnitInfo>& unit_infos) const
{
  int ret = OB_SUCCESS;
  ObArray<uint64_t> rs_pool;
  ObArray<ObUnitInfo> unit_array;
  unit_infos.reset();
  if (OB_UNLIKELY(OB_INVALID_ID == tenant_id) || OB_UNLIKELY(zone.is_empty())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id), K(zone));
  } else if (OB_FAIL(inner_get_pool_ids_of_tenant(tenant_id, rs_pool))) {
    LOG_WARN("fail to get pool ids by tennat", K(ret), K(tenant_id));
  } else {
    FOREACH_X(pool, rs_pool, OB_SUCCESS == ret)
    {
      unit_array.reuse();
      if (!check_inner_stat()) {
        ret = OB_INNER_STAT_ERROR;
        LOG_WARN("check inner stat failed", K(ret), K(inited_), K(loaded_));
      } else if (OB_UNLIKELY(NULL == pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", K(ret));
      } else if (OB_FAIL(inner_get_unit_infos_of_pool(*pool, unit_array))) {
        LOG_WARN("fail to get unit infos of pool", K(ret));
      } else if (unit_array.count() > 0) {
        FOREACH_X(u, unit_array, OB_SUCCESS == ret)
        {
          bool is_alive = false;
          bool is_in_service = false;
          if (OB_UNLIKELY(NULL == u)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unit is empty", K(ret));
          } else if (zone != u->unit_.zone_) {
            // do not belong to this zone
          } else if (OB_FAIL(server_mgr_.check_server_alive(u->unit_.server_, is_alive))) {
            LOG_WARN("check_server_alive failed", "server", u->unit_.server_, K(ret));
          } else if (OB_FAIL(server_mgr_.check_in_service(u->unit_.server_, is_in_service))) {
            LOG_WARN("check server in service failed", "server", u->unit_.server_, K(ret));
          } else if (!is_alive || !is_in_service) {
            // ignore unit on not-alive server
          } else if (ObUnit::UNIT_STATUS_ACTIVE != u->unit_.status_) {
            // ignore the unit which is in deleting status
          } else if (OB_FAIL(unit_infos.push_back(*u))) {
            LOG_WARN("fail to push back", K(ret));
          } else {
          }  // no more to do
        }
      } else {
      }  // empty array
    }
  }
  return ret;
}

int ObUnitManager::get_zone_alive_unit_infos_by_tenant(
    const uint64_t tenant_id, const common::ObZone& zone, common::ObIArray<share::ObUnitInfo>& unit_infos) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(tenant_id), K(ret));
  } else if (OB_FAIL(inner_get_zone_alive_unit_infos_by_tenant(tenant_id, zone, unit_infos))) {
    LOG_WARN("fail to inner get zone alive unit infos by tenant", K(ret));
  }
  return ret;
}

int ObUnitManager::get_all_gts_unit_infos(ObIArray<ObUnitInfo>& unit_infos)
{
  int ret = OB_SUCCESS;
  unit_infos.reset();
  ObArray<uint64_t> rs_pool;
  ObArray<ObUnitInfo> unit_array;

  if (OB_FAIL(get_pool_ids_of_tenant(OB_GTS_TENANT_ID, rs_pool))) {
    LOG_WARN("fail to get pool ids of tenant", K(ret));
  } else {
    FOREACH_X(pool, rs_pool, OB_SUCCESS == ret)
    {
      unit_array.reuse();
      if (!check_inner_stat()) {
        ret = OB_INNER_STAT_ERROR;
        LOG_WARN("check inner stat failed", K(ret), K(inited_), K(loaded_));
      } else if (OB_UNLIKELY(NULL == pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", K(ret));
      } else if (OB_FAIL(get_unit_infos_of_pool(*pool, unit_array))) {
        LOG_WARN("fail to get unit infos of pool", K(ret));
      } else if (unit_array.count() > 0) {
        FOREACH_X(u, unit_array, OB_SUCCESS == ret)
        {
          if (OB_UNLIKELY(NULL == u)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("empty is null", K(ret));
          } else if (OB_FAIL(unit_infos.push_back(*u))) {
            LOG_WARN("fail to push back", K(ret));
          } else {
          }  // no more to do
        }
      } else {
      }  // do nothing
    }
  }
  return ret;
}

int ObUnitManager::get_all_unit_infos_by_tenant(const uint64_t tenant_id, ObIArray<ObUnitInfo>& unit_infos)
{
  int ret = OB_SUCCESS;
  share::schema::ObSchemaGetterGuard schema_guard;
  const share::schema::ObTenantSchema* tenant_schema = NULL;
  unit_infos.reset();
  common::ObArray<common::ObZone> tenant_zone_list;
  ObArray<uint64_t> rs_pool;
  ObArray<ObUnitInfo> unit_array;

  if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id));
  } else if (OB_FAIL(get_newest_schema_guard_in_inner_table(tenant_id, schema_guard))) {
    LOG_WARN("fail to get schema guard", K(ret));
  } else if (OB_FAIL(schema_guard.get_tenant_info(tenant_id, tenant_schema))) {
    LOG_WARN("fail to get tenant info", K(ret), K(tenant_id));
  } else if (OB_UNLIKELY(NULL == tenant_schema)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("tenant schema is null", K(ret), KP(tenant_schema));
  } else if (OB_FAIL(tenant_schema->get_zone_list(tenant_zone_list))) {
    LOG_WARN("fail to get zone list", K(ret));
  } else if (OB_FAIL(get_pool_ids_of_tenant(tenant_id, rs_pool))) {
    LOG_WARN("fail to get pool ids of tenant", K(ret), K(tenant_id));
  } else {
    FOREACH_X(pool, rs_pool, OB_SUCCESS == ret)
    {
      unit_array.reuse();
      if (!check_inner_stat()) {
        ret = OB_INNER_STAT_ERROR;
        LOG_WARN("check inner stat failed", K(ret), K(inited_), K(loaded_));
      } else if (OB_UNLIKELY(NULL == pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", K(ret));
      } else if (OB_FAIL(get_unit_infos_of_pool(*pool, unit_array))) {
        LOG_WARN("fail to get unit infos of pool", K(ret));
      } else if (unit_array.count() > 0) {
        FOREACH_X(u, unit_array, OB_SUCCESS == ret)
        {
          if (OB_UNLIKELY(NULL == u)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("empty is null", K(ret));
          } else if (!has_exist_in_array(tenant_zone_list, u->unit_.zone_)) {
            // this unit do not in tenant zone list, ignore
          } else if (OB_FAIL(unit_infos.push_back(*u))) {
            LOG_WARN("fail to push back", K(ret));
          } else {
          }  // no more to do
        }
      } else {
      }  // do nothing
    }
  }
  return ret;
}

int ObUnitManager::get_active_unit_infos_by_tenant(const uint64_t tenant_id, ObIArray<ObUnitInfo>& unit_infos)
{
  int ret = OB_SUCCESS;
  share::schema::ObSchemaGetterGuard schema_guard;
  const share::schema::ObTenantSchema* tenant_schema = NULL;
  unit_infos.reset();
  if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id));
  } else if (OB_UNLIKELY(nullptr == schema_service_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("schema service ptr is null", K(ret));
  } else if (OB_FAIL(schema_service_->get_tenant_schema_guard(OB_SYS_TENANT_ID, schema_guard))) {
    LOG_WARN("fail to get schema guard", K(ret));
  } else if (OB_FAIL(schema_guard.get_tenant_info(tenant_id, tenant_schema))) {
    LOG_WARN("fail to get tenant info", K(ret), K(tenant_id));
  } else if (OB_UNLIKELY(NULL == tenant_schema)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("tenant schema is null", K(ret), KP(tenant_schema));
  } else if (OB_FAIL(get_active_unit_infos_by_tenant(*tenant_schema, unit_infos))) {
    LOG_WARN("fail to get active unit infos", K(ret), K(tenant_id));
  }
  return ret;
}

int ObUnitManager::get_active_unit_infos_by_tenant(
    const share::schema::ObTenantSchema& tenant_schema, ObIArray<ObUnitInfo>& unit_infos) const
{
  int ret = OB_SUCCESS;
  const uint64_t tenant_id = tenant_schema.get_tenant_id();
  common::ObArray<common::ObZone> tenant_zone_list;
  ObArray<uint64_t> rs_pool;
  ObArray<ObUnitInfo> unit_array;
  unit_infos.reset();
  if (OB_FAIL(tenant_schema.get_zone_list(tenant_zone_list))) {
    LOG_WARN("fail to get zone list", K(ret));
  } else if (OB_FAIL(get_pool_ids_of_tenant(tenant_id, rs_pool))) {
    LOG_WARN("fail to get pool ids of tenant", K(ret), K(tenant_id));
  } else {
    FOREACH_X(pool, rs_pool, OB_SUCCESS == ret)
    {
      unit_array.reuse();
      if (!check_inner_stat()) {
        ret = OB_INNER_STAT_ERROR;
        LOG_WARN("check inner stat failed", K(ret), K(inited_), K(loaded_));
      } else if (OB_UNLIKELY(NULL == pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", K(ret));
      } else if (OB_FAIL(get_unit_infos_of_pool(*pool, unit_array))) {
        LOG_WARN("fail to get unit infos of pool", K(ret));
      } else if (unit_array.count() > 0) {
        FOREACH_X(u, unit_array, OB_SUCCESS == ret)
        {
          if (OB_UNLIKELY(NULL == u)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("empty is null", K(ret));
          } else if (!has_exist_in_array(tenant_zone_list, u->unit_.zone_)) {
            // this unit do not in tenant zone list, ignore
          } else if (ObUnit::UNIT_STATUS_ACTIVE != u->unit_.status_) {
            // ignore the unit which is not in active status
          } else if (OB_FAIL(unit_infos.push_back(*u))) {
            LOG_WARN("fail to push back", K(ret));
          } else {
          }  // no more to do
        }
      } else {
      }  // do nothing
    }
  }
  return ret;
}

int ObUnitManager::get_zone_active_unit_infos_by_tenant(const uint64_t tenant_id,
    const common::ObIArray<common::ObZone>& tenant_zone_list, ObIArray<ObUnitInfo>& unit_info) const
{
  int ret = OB_SUCCESS;
  ObArray<uint64_t> pool_ids;
  ObArray<share::ObResourcePool*>* pools = NULL;
  share::schema::ObSchemaGetterGuard schema_guard;
  unit_info.reset();
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (0 >= tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("tenant_id is invalid", K(ret), K(tenant_id));
  } else if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_pools_by_tenant failed", K(tenant_id), K(ret));
    } else {
      // just return empty pool_ids
      ret = OB_SUCCESS;
      LOG_WARN("tenant doesn't own any pool", K(tenant_id), K(ret));
    }
  } else if (NULL == pools) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pools is null", KP(pools), K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < pools->count(); ++i) {
      if (NULL == pools->at(i)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", "pool", OB_P(pools->at(i)), K(ret));
      } else if (OB_FAIL(pool_ids.push_back(pools->at(i)->resource_pool_id_))) {
        LOG_WARN("push_back failed", K(ret));
      }
    }
  }
  if (OB_SUCC(ret)) {
    ObArray<ObUnitInfo> unit_in_pool;
    for (int64_t i = 0; i < pool_ids.count() && OB_SUCC(ret); i++) {
      uint64_t pool_id = pool_ids.at(i);
      unit_in_pool.reset();
      if (OB_FAIL(inner_get_unit_infos_of_pool(pool_id, unit_in_pool))) {
        LOG_WARN("fail to inner get unit infos", K(ret), K(pool_id));
      } else {
        for (int64_t j = 0; j < unit_in_pool.count() && OB_SUCC(ret); j++) {
          if (ObUnit::UNIT_STATUS_ACTIVE != unit_in_pool.at(j).unit_.status_) {
            // nothing todo
          } else if (!has_exist_in_array(tenant_zone_list, unit_in_pool.at(j).unit_.zone_)) {
            // nothing todo
          } else if (OB_FAIL(unit_info.push_back(unit_in_pool.at(j)))) {
            LOG_WARN("fail to push back", K(ret), K(unit_in_pool), K(j));
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::commit_shrink_resource_pool(const uint64_t resource_pool_id)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  common::ObMySQLTransaction trans;
  share::ObResourcePool* pool = NULL;
  ObArray<ObUnit*>* units = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(loaded_), K(inited_));
  } else if (OB_UNLIKELY(OB_INVALID_ID == resource_pool_id)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(resource_pool_id));
  } else if (OB_FAIL(get_resource_pool_by_id(resource_pool_id, pool))) {
    LOG_WARN("fail to get resource pool", K(ret), K(resource_pool_id));
  } else if (OB_UNLIKELY(NULL == pool)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool ptr is null", K(ret), KP(pool));
  } else if (OB_FAIL(get_units_by_pool(resource_pool_id, units))) {
    LOG_WARN("fail to get units by pool", K(ret), K(resource_pool_id));
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool ptr is null", K(ret), KP(units));
  } else if (OB_FAIL(trans.start(proxy_))) {
    LOG_WARN("start transaction failed", K(ret));
  } else if (OB_FAIL(complete_shrink_pool_unit_num_rs_job(pool->resource_pool_id_, pool->tenant_id_, trans))) {
    LOG_WARN("do rs_job failed", K(ret));
  } else {
    // Commit shrink resource pool only needs to change the state of the unit,
    // the state of the resource pool itself has been changed before,
    // and there is no need to adjust it again.
    common::ObArray<uint64_t> unit_ids;
    int64_t unit_count = pool->unit_count_;
    if (unit_count <= 0) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unit count unexpected", K(ret), K(unit_count));
    } else if (units->count() <= 0) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("zone unit ptrs has no element", K(ret), "unit_cnt", units->count());
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
        const ObUnit* unit = units->at(i);
        if (OB_UNLIKELY(NULL == unit)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unit ptr is null", K(ret), KP(unit), K(i));
        } else if (ObUnit::UNIT_STATUS_DELETING == unit->status_) {
          if (OB_FAIL(ut_operator_.remove_unit(trans, *unit))) {
            LOG_WARN("fail to remove unit", K(ret), "unit", *unit);
          } else if (OB_FAIL(unit_ids.push_back(unit->unit_id_))) {
            LOG_WARN("fail to push back", K(ret));
          } else {
          }  // no more to do
        } else {
        }  // active unit, do nothing
      }
    }
    // however, we need to end this transaction
    const bool commit = (OB_SUCCESS == ret);
    int tmp_ret = OB_SUCCESS;
    if (OB_SUCCESS != (tmp_ret = trans.end(commit))) {
      LOG_WARN("trans end failed", K(tmp_ret), K(commit));
      ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
    }
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(delete_inmemory_units(pool->resource_pool_id_, unit_ids))) {
      LOG_WARN("fail to delete unit groups", K(ret));
    } else {
    }  // no more to do
  }
  return ret;
}

int ObUnitManager::get_deleting_units_of_pool(const uint64_t resource_pool_id, ObIArray<share::ObUnit>& units) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  ObArray<ObUnit*>* inner_units = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(loaded_), K(inited_));
  } else if (OB_UNLIKELY(OB_INVALID_ID == resource_pool_id)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(resource_pool_id));
  } else if (OB_FAIL(get_units_by_pool(resource_pool_id, inner_units))) {
    LOG_WARN("fail to get units by pool", K(ret), K(resource_pool_id));
  } else if (NULL == inner_units) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("inner_units ptr is null", K(ret), KP(inner_units));
  } else {
    units.reset();
    for (int64_t i = 0; OB_SUCC(ret) && i < inner_units->count(); ++i) {
      const share::ObUnit* this_unit = inner_units->at(i);
      if (NULL == this_unit) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit ptr is null", K(ret), KP(this_unit));
      } else if (ObUnit::UNIT_STATUS_DELETING == this_unit->status_) {
        if (OB_FAIL(units.push_back(*this_unit))) {
          LOG_WARN("fail to push back", K(ret));
        } else {
        }  // no more to do
      } else if (ObUnit::UNIT_STATUS_ACTIVE == this_unit->status_) {
        // a normal unit, ignore
      } else {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unexpected unit status", K(ret), "unit_status", this_unit->status_);
      }
    }
    LOG_INFO("get deleting units of pool", K(ret), K(resource_pool_id), K(units));
  }
  return ret;
}

int ObUnitManager::get_unit_infos_of_pool(const uint64_t resource_pool_id, ObIArray<ObUnitInfo>& unit_infos) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == resource_pool_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(resource_pool_id), K(ret));
  } else if (OB_FAIL(inner_get_unit_infos_of_pool(resource_pool_id, unit_infos))) {
    LOG_WARN("inner_get_unit_infos_of_pool failed", K(resource_pool_id), K(ret));
  }
  return ret;
}

int ObUnitManager::get_active_unit_infos_of_pool(
    const uint64_t resource_pool_id, common::ObIArray<share::ObUnitInfo>& unit_infos) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  common::ObArray<share::ObUnitInfo> tmp_unit_infos;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == resource_pool_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(resource_pool_id));
  } else if (OB_FAIL(inner_get_unit_infos_of_pool(resource_pool_id, tmp_unit_infos))) {
    LOG_WARN("inner_get_unit_infos_of_pool failed", K(ret), K(resource_pool_id));
  } else {
    for (int64_t i = 0; i < tmp_unit_infos.count() && OB_SUCC(ret); ++i) {
      const share::ObUnitInfo& this_unit_info = tmp_unit_infos.at(i);
      if (ObUnit::UNIT_STATUS_ACTIVE == this_unit_info.unit_.status_) {
        if (OB_FAIL(unit_infos.push_back(this_unit_info))) {
          LOG_WARN("fail to push back", K(ret));
        } else {
        }  // no more to do
      } else {
      }  // ignore unit whose status is not active
    }
  }
  return ret;
}

int ObUnitManager::inner_get_unit_infos_of_pool(const uint64_t resource_pool_id, ObIArray<ObUnitInfo>& unit_infos) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == resource_pool_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(resource_pool_id), K(ret));
  } else {
    unit_infos.reuse();
    ObUnitInfo unit_info;
    share::ObResourcePool* pool = NULL;
    ObUnitConfig* config = NULL;
    if (OB_FAIL(get_resource_pool_by_id(resource_pool_id, pool))) {
      if (OB_ENTRY_NOT_EXIST == ret) {
        ret = OB_RESOURCE_POOL_NOT_EXIST;
      }
      LOG_WARN("get_resource_pool_by_id failed", K(resource_pool_id), K(ret));
    } else if (NULL == pool) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pool is null", KP(pool), K(ret));
    } else if (OB_FAIL(get_unit_config_by_id(pool->unit_config_id_, config))) {
      if (OB_ENTRY_NOT_EXIST == ret) {
        ret = OB_RESOURCE_UNIT_NOT_EXIST;
      }
      LOG_WARN("get_unit_config_by_id failed", "unit config id", pool->unit_config_id_, K(ret));
    } else if (NULL == config) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("config is null", KP(config), K(ret));
    } else {
      unit_info.reset();
      if (OB_FAIL(unit_info.pool_.assign(*pool))) {
        LOG_WARN("failed to assign unit_info.pool_", K(ret));
      } else {
        unit_info.config_ = *config;
        ObArray<ObUnit*>* units = NULL;
        if (OB_FAIL(get_units_by_pool(resource_pool_id, units))) {
          LOG_WARN("get_units_by_pool failed", K(resource_pool_id), K(ret));
        } else if (NULL == units) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("units is null", KP(units), K(ret));
        } else if (units->count() <= 0) {
          ret = OB_ENTRY_NOT_EXIST;
          LOG_WARN("units of resource pool not exist", K(resource_pool_id), K(ret));
        } else {
          for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
            if (NULL == units->at(i)) {
              ret = OB_ERR_UNEXPECTED;
              LOG_WARN("unit is null", "unit", OB_P(units->at(i)), K(ret));
            } else {
              unit_info.unit_ = *units->at(i);
              if (OB_FAIL(unit_infos.push_back(unit_info))) {
                LOG_WARN("push_back failed", K(ret));
              }
            }
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::inner_get_unit_info_by_id(const uint64_t unit_id, ObUnitInfo& unit_info) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == unit_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(unit_id), K(ret));
  } else {
    ObUnit* unit = NULL;
    ObUnitConfig* config = NULL;
    share::ObResourcePool* pool = NULL;
    if (OB_FAIL(get_unit_by_id(unit_id, unit))) {
      LOG_WARN("get_unit_by_id failed", K(unit_id), K(ret));
    } else if (NULL == unit) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unit is null", KP(unit), K(ret));
    } else if (OB_FAIL(get_resource_pool_by_id(unit->resource_pool_id_, pool))) {
      if (OB_ENTRY_NOT_EXIST == ret) {
        ret = OB_RESOURCE_POOL_NOT_EXIST;
      }
      LOG_WARN("get_resource_pool_by_id failed", "pool id", unit->resource_pool_id_, K(ret));
    } else if (NULL == pool) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pool is null", KP(pool), K(ret));
    } else if (OB_FAIL(get_unit_config_by_id(pool->unit_config_id_, config))) {
      if (OB_ENTRY_NOT_EXIST == ret) {
        ret = OB_RESOURCE_UNIT_NOT_EXIST;
      }
      LOG_WARN("get_unit_config_by_id failed", "unit config id", pool->unit_config_id_, K(ret));
    } else if (NULL == config) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("config is null", KP(config), K(ret));
    } else {
      if (OB_FAIL(unit_info.pool_.assign(*pool))) {
        LOG_WARN("failed to assign unit_info.pool_", K(ret));
      } else {
        unit_info.unit_ = *unit;
        unit_info.config_ = *config;
      }
    }
  }
  return ret;
}

int ObUnitManager::get_unit(const uint64_t tenant_id, const ObAddr& server, share::ObUnit& unit) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == tenant_id || !server.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid tenant_id or invalid server", K(tenant_id), K(server), K(ret));
  } else {
    ObArray<share::ObResourcePool*>* pools = NULL;
    if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
      LOG_WARN("get_pools_by_tenant failed", K(tenant_id), K(ret));
    } else if (NULL == pools) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pools is null", KP(pools), K(ret));
    } else if (pools->count() <= 0) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pools is empty", "pools", *pools, K(ret));
    } else {
      bool find = false;
      FOREACH_CNT_X(pool, *pools, OB_SUCCESS == ret && !find)
      {
        if (NULL == *pool) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("entry in pools is null", K(ret));
        } else {
          ObArray<ObUnit*>* units = NULL;
          if (OB_FAIL(get_units_by_pool((*pool)->resource_pool_id_, units))) {
            LOG_WARN("get_units_by_pool failed", "pool id", (*pool)->resource_pool_id_, K(ret));
          } else if (NULL == units) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("units is null", KP(units), K(ret));
          } else if (units->count() <= 0) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("units is empty", "units", *units, K(ret));
          } else {
            FOREACH_CNT_X(inner_unit, *units, OB_SUCCESS == ret && !find)
            {
              if (NULL == *inner_unit) {
                ret = OB_ERR_UNEXPECTED;
                LOG_WARN("entry in units is null", "unit", OB_P(*inner_unit), K(ret));
              } else if ((*inner_unit)->server_ == server || (*inner_unit)->migrate_from_server_ == server) {
                unit = *(*inner_unit);
                find = true;
              }
            }
          }
        }
      }
      if (OB_SUCCESS == ret && !find) {
        ret = OB_ENTRY_NOT_EXIST;
        LOG_WARN("unit not exist", K(tenant_id), K(server), K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::extract_unit_ids(const common::ObIArray<share::ObUnit*>& units, common::ObIArray<uint64_t>& unit_ids)
{
  int ret = OB_SUCCESS;
  unit_ids.reset();
  for (int64_t i = 0; OB_SUCC(ret) && i < units.count(); ++i) {
    if (OB_UNLIKELY(NULL == units.at(i))) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unit ptr is null", K(ret));
    } else if (OB_FAIL(unit_ids.push_back(units.at(i)->unit_id_))) {
      LOG_WARN("fail to push back", K(ret));
    } else {
    }  // no more to do
  }
  return ret;
}

int ObUnitManager::inner_get_unit_ids(ObIArray<uint64_t>& unit_ids) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  }
  for (ObHashMap<uint64_t, ObArray<ObUnit*>*>::const_iterator it = pool_unit_map_.begin();
       OB_SUCCESS == ret && it != pool_unit_map_.end();
       ++it) {
    if (NULL == it->second) {
      ret = OB_ERR_UNEXPECTED;
      LOG_ERROR("pointer of ObArray<ObUnit *> is null", "pool_id", it->first, K(ret));
    } else if (it->second->count() <= 0) {
      ret = OB_ERR_UNEXPECTED;
      LOG_ERROR("array of unit is empty", "pool_id", it->first, K(ret));
    } else {
      const ObArray<ObUnit*> units = *it->second;
      for (int64_t i = 0; OB_SUCC(ret) && i < units.count(); ++i) {
        uint64_t unit_id = units.at(i)->unit_id_;
        if (OB_FAIL(unit_ids.push_back(unit_id))) {
          LOG_WARN("fail push back it", K(unit_id), K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::get_unit_ids(ObIArray<uint64_t>& unit_ids) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (OB_FAIL(inner_get_unit_ids(unit_ids))) {
    LOG_WARN("fail to inner get unit ids", K(ret));
  }
  return ret;
}

int ObUnitManager::calc_sum_load(const ObArray<ObUnitLoad>* unit_loads, ObUnitConfig& sum_load)
{
  int ret = OB_SUCCESS;
  sum_load.reset();
  if (NULL == unit_loads) {
    // all be zero
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < unit_loads->count(); ++i) {
      if (!unit_loads->at(i).is_valid()) {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("invalid unit_load", "unit_load", unit_loads->at(i), K(ret));
      } else {
        sum_load += *unit_loads->at(i).unit_config_;
      }
    }
  }
  return ret;
}

int ObUnitManager::check_unit_config(const ObUnitConfig& rpc_config, ObUnitConfig& config) const
{
  int ret = OB_SUCCESS;
  // rpc_config is used to indicate which property is changed, don't check
  // rpc_config's validation, config is generated from rpc_config, check
  // config can cover rpc_config
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (config.name_.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource unit name");
    LOG_WARN("invalid resource unit name", "resource unit name", config.name_, K(ret));
  }

  if (OB_SUCC(ret)) {
    if (std::fabs(config.min_cpu_) < ObUnitConfig::CPU_EPSILON) {
      config.min_cpu_ = config.max_cpu_;
    }
    if (0 == config.min_memory_) {
      config.min_memory_ = config.max_memory_;
    }
    if (0 == config.min_iops_) {
      config.min_iops_ = config.max_iops_;
    }
  }

  if (OB_FAIL(ret)) {
  } else if (config.max_cpu_ < 0 || std::fabs(config.max_cpu_) < ObUnitConfig::CPU_EPSILON ||
             (std::fabs(rpc_config.max_cpu_) >= ObUnitConfig::CPU_EPSILON && config.max_cpu_ < config.min_cpu_)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "max cpu");
    LOG_WARN("invalid max cpu", K(ret), "max cpu", config.max_cpu_, "min cpu", config.min_cpu_);
  } else if (config.min_cpu_ < 0 || config.min_cpu_ > config.max_cpu_) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "min cpu");
    LOG_WARN("invalid min cpu", K(ret), "min cpu", config.min_cpu_, "max cpu", config.max_cpu_);
  } else if (config.max_memory_ <= 0 || (0 != rpc_config.max_memory_ && config.max_memory_ < config.min_memory_)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "max memory");
    LOG_WARN("invalid max memory", "max memory", config.max_memory_, K(ret));
  } else if (config.min_memory_ < 0 || config.min_memory_ > config.max_memory_) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "min memory");
    LOG_WARN("invalid min memory", "min memory", config.min_memory_, "max memory", config.max_memory_, K(ret));
  } else if (config.max_iops_ <= 0 || (0 != rpc_config.max_iops_ && config.max_iops_ < config.min_iops_)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "max iops");
    LOG_WARN("invalid max iops", "max iops", config.max_iops_, K(ret));
  } else if (config.min_iops_ < 0 || config.min_iops_ > config.max_iops_) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "min iops");
    LOG_WARN("invalid min iops", "min iops", config.min_iops_, K(ret));
  } else if (config.max_disk_size_ <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "max disk size");
    LOG_WARN("invalid max disk size", "max disk size", config.max_disk_size_, K(ret));
  } else if (config.max_session_num_ <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "max session num");
    LOG_WARN("invalid max session num", "max session num", config.max_session_num_, K(ret));
  } else if (config.max_cpu_ < OB_UNIT_MIN_CPU) {
    ret = OB_INVALID_RESOURCE_UNIT;
    LOG_USER_ERROR(OB_INVALID_RESOURCE_UNIT, "max_cpu", to_cstring(OB_UNIT_MIN_CPU));
    LOG_WARN("invalid max cpu", "max_cpu", config.max_cpu_, "max_cpu min value", OB_UNIT_MIN_CPU, K(ret));
  } else if (config.min_cpu_ < OB_UNIT_MIN_CPU) {
    ret = OB_INVALID_RESOURCE_UNIT;
    LOG_USER_ERROR(OB_INVALID_RESOURCE_UNIT, "min_cpu", to_cstring(OB_UNIT_MIN_CPU));
    LOG_WARN("invalid min cpu", "min_cpu", config.max_cpu_, "min_cpu min value", OB_UNIT_MIN_CPU, K(ret));
  } else if (config.max_memory_ < get_unit_min_memory()) {
    ret = OB_INVALID_RESOURCE_UNIT;
    LOG_USER_ERROR(OB_INVALID_RESOURCE_UNIT, "max_memory", to_cstring(get_unit_min_memory()));
    LOG_WARN(
        "invalid max memory", "max_memory", config.max_memory_, "max_memory min value", get_unit_min_memory(), K(ret));
  } else if (config.min_memory_ < get_unit_min_memory()) {
    ret = OB_INVALID_RESOURCE_UNIT;
    LOG_USER_ERROR(OB_INVALID_RESOURCE_UNIT, "min_memory", to_cstring(get_unit_min_memory()));
    LOG_WARN(
        "invalid min memory", "min_memory", config.min_memory_, "min_memory min value", get_unit_min_memory(), K(ret));
  } else if (config.max_disk_size_ < OB_UNIT_MIN_DISK_SIZE) {
    ret = OB_INVALID_RESOURCE_UNIT;
    LOG_USER_ERROR(OB_INVALID_RESOURCE_UNIT, "max_disk_size", to_cstring(OB_UNIT_MIN_DISK_SIZE));
    LOG_WARN("invalid max disk size",
        "max_disk_size",
        config.max_disk_size_,
        "max_disk_size min value",
        OB_UNIT_MIN_DISK_SIZE,
        K(ret));
  } else if (config.max_iops_ < OB_UNIT_MIN_IOPS) {
    ret = OB_INVALID_RESOURCE_UNIT;
    LOG_USER_ERROR(OB_INVALID_RESOURCE_UNIT, "max_iops", to_cstring(OB_UNIT_MIN_IOPS));
    LOG_WARN("invalid max iops", "max_iops", config.max_iops_, "max_iops min value", OB_UNIT_MIN_IOPS, K(ret));
  } else if (config.min_iops_ < OB_UNIT_MIN_IOPS) {
    ret = OB_INVALID_RESOURCE_UNIT;
    LOG_USER_ERROR(OB_INVALID_RESOURCE_UNIT, "min_iops", to_cstring(OB_UNIT_MIN_IOPS));
    LOG_WARN("invalid min iops", "min_iops", config.min_iops_, "min_iops min value", OB_UNIT_MIN_IOPS, K(ret));
  } else if (config.max_session_num_ < OB_UNIT_MIN_SESSION_NUM) {
    ret = OB_INVALID_RESOURCE_UNIT;
    LOG_USER_ERROR(OB_INVALID_RESOURCE_UNIT, "max_session_num", to_cstring(OB_UNIT_MIN_SESSION_NUM));
    LOG_WARN("invalid max session num",
        "max_session_num",
        config.max_session_num_,
        "max_session_num min value",
        OB_UNIT_MIN_SESSION_NUM,
        K(ret));
  }

  return ret;
}

int ObUnitManager::check_resource_pool(share::ObResourcePool& resource_pool) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (resource_pool.name_.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "resource pool name");
    LOG_WARN("invalid resource pool name", "resource pool name", resource_pool.name_, K(ret));
  } else if (resource_pool.unit_count_ <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "unit num");
    LOG_WARN("invalid resource unit num", "unit num", resource_pool.unit_count_, K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < resource_pool.zone_list_.count(); ++i) {
      for (int64_t j = i + 1; OB_SUCC(ret) && j < resource_pool.zone_list_.count(); ++j) {
        if (resource_pool.zone_list_[i] == resource_pool.zone_list_[j]) {
          ret = OB_ZONE_DUPLICATED;
          LOG_USER_ERROR(
              OB_ZONE_DUPLICATED, to_cstring(resource_pool.zone_list_[i]), to_cstring(resource_pool.zone_list_));
          LOG_WARN("duplicate zone in zone list", "zone_list", resource_pool.zone_list_, K(ret));
        }
      }
    }
    if (OB_SUCC(ret)) {
      FOREACH_CNT_X(zone, resource_pool.zone_list_, OB_SUCCESS == ret)
      {
        bool zone_exist = false;
        if (OB_FAIL(zone_mgr_.check_zone_exist(*zone, zone_exist))) {
          LOG_WARN("check_zone_exist failed", K(zone), K(ret));
        } else if (!zone_exist) {
          ret = OB_ZONE_INFO_NOT_EXIST;
          LOG_USER_ERROR(OB_ZONE_INFO_NOT_EXIST, to_cstring(*zone));
          LOG_WARN("zone not exist", "zone", *zone, K(ret));
        }
      }
    }
    if (OB_SUCCESS == ret && 0 == resource_pool.zone_list_.count()) {
      ObArray<ObZoneInfo> zone_infos;
      if (OB_FAIL(zone_mgr_.get_zone(zone_infos))) {
        LOG_WARN("get_zone failed", K(ret));
      } else {
        FOREACH_CNT_X(zone_info, zone_infos, OB_SUCCESS == ret)
        {
          if (OB_FAIL(resource_pool.zone_list_.push_back(zone_info->zone_))) {
            LOG_WARN("push_back failed", K(ret));
          }
        }
        if (OB_SUCCESS == ret && resource_pool.zone_list_.count() <= 0) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("not active zone found", K(ret));
        }
      }
    }
    FOREACH_CNT_X(zone, resource_pool.zone_list_, OB_SUCCESS == ret)
    {
      int64_t alive_server_count = 0;
      if (OB_FAIL(server_mgr_.get_alive_server_count(*zone, alive_server_count))) {
        LOG_WARN("get_alive_servers failed", "zone", *zone, K(ret));
      } else if (alive_server_count < resource_pool.unit_count_) {
        ret = OB_UNIT_NUM_OVER_SERVER_COUNT;
        LOG_WARN("resource pool unit num over zone server count",
            "unit_count",
            resource_pool.unit_count_,
            K(alive_server_count),
            K(ret),
            "zone",
            *zone);
      }
    }
  }
  return ret;
}

int ObUnitManager::allocate_pool_units(ObISQLClient& client, const share::ObResourcePool& pool)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (!pool.is_valid() || pool.zone_list_.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid pool", K(pool), K(ret));
  } else {
    const bool new_allocate_pool = true;
    const int64_t delta_unit_num = pool.unit_count_;
    ObArray<ObAddr> new_servers;
    if (OB_FAIL(allocate_unit_groups(client, pool, new_allocate_pool, delta_unit_num, new_servers))) {
      LOG_WARN("arrange units failed", K(pool), K(ret));
    }
  }
  return ret;
}

int ObUnitManager::try_notify_tenant_server_unit_resource(const uint64_t tenant_id, const bool is_delete,
    ObNotifyTenantServerResourceProxy& notify_proxy, const share::ObResourcePool& new_pool,
    const share::ObWorker::CompatMode compat_mode, const share::ObUnit& unit, const bool if_not_grant,
    const bool skip_offline_server)
{
  int ret = OB_SUCCESS;
  bool is_server_alive = false;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(nullptr == leader_coordinator_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("leader coordinator ptr is null", K(ret));
  } else if (OB_FAIL(server_mgr_.check_server_alive(unit.server_, is_server_alive))) {
    LOG_WARN("fail to check server alive", K(ret), "server", unit.server_);
  } else if (!is_server_alive && (is_delete || skip_offline_server)) {
    LOG_INFO("server not alive when delete unit, ignore", "server", unit.server_);
  } else {
    share::ObUnitConfig* unit_config = nullptr;
    if (OB_INVALID_ID == new_pool.tenant_id_ && !is_delete) {
      // bypass
    } else if (OB_FAIL(get_unit_config_by_id(new_pool.unit_config_id_, unit_config))) {
      LOG_WARN("fail to get unit config by id", K(ret));
    } else if (OB_UNLIKELY(nullptr == unit_config)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unit config is null", K(ret), "unit_config_id", new_pool.unit_config_id_);
    } else {
      int64_t start = ObTimeUtility::current_time();
      obrpc::TenantServerUnitConfig tenant_unit_server_config;
      tenant_unit_server_config.tenant_id_ = tenant_id;
      tenant_unit_server_config.compat_mode_ = compat_mode;
      tenant_unit_server_config.unit_config_ = *unit_config;
      tenant_unit_server_config.replica_type_ = unit.replica_type_;
      tenant_unit_server_config.if_not_grant_ = if_not_grant;
      tenant_unit_server_config.is_delete_ = is_delete;
      int64_t rpc_timeout = NOTIFY_RESOURCE_RPC_TIMEOUT;
      if (INT64_MAX != THIS_WORKER.get_timeout_ts()) {
        rpc_timeout = max(rpc_timeout, THIS_WORKER.get_timeout_remain());
      }
      if (OB_FAIL(notify_proxy.call(unit.server_, rpc_timeout, tenant_unit_server_config))) {
        LOG_WARN("fail to call notify resource to server", K(ret), K(rpc_timeout), "dst", unit.server_);
        if (OB_TENANT_EXIST == ret) {
          ret = OB_TENANT_RESOURCE_UNIT_EXIST;
          LOG_USER_ERROR(OB_TENANT_RESOURCE_UNIT_EXIST, tenant_id, to_cstring(unit.server_));
        }
      }
      LOG_INFO(
          "call notify resource to server", K(ret), "dst", unit.server_, "cost", ObTimeUtility::current_time() - start);
    }
  }
  return ret;
}

int ObUnitManager::get_tenant_unit_servers(const uint64_t tenant_id, const common::ObZone& zone,
    const common::ObIArray<uint64_t>& processed_pool_id_array, common::ObIArray<common::ObAddr>& server_array)
{
  int ret = OB_SUCCESS;
  ObArray<share::ObResourcePool*>* pools = nullptr;
  if (OB_UNLIKELY(OB_INVALID_ID == tenant_id)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id));
  } else {
    server_array.reset();
    int tmp_ret = get_pools_by_tenant(tenant_id, pools);
    if (OB_ENTRY_NOT_EXIST == tmp_ret) {
      // pass, and return empty server array
    } else if (OB_SUCCESS != tmp_ret) {
      ret = tmp_ret;
      LOG_WARN("fail to get pools by tenant", K(ret), K(tenant_id));
    } else if (nullptr == pools) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pools ptr is null, unexpected", K(ret), K(tenant_id));
    } else {
      common::ObArray<common::ObAddr> this_server_array;
      for (int64_t i = 0; OB_SUCC(ret) && i < pools->count(); ++i) {
        this_server_array.reset();
        const share::ObResourcePool* pool = pools->at(i);
        if (OB_UNLIKELY(nullptr == pool)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("pool ptr is null", K(ret), K(tenant_id));
        } else if (has_exist_in_array(processed_pool_id_array, pool->resource_pool_id_)) {
          // already processed
        } else if (OB_FAIL(get_pool_servers(pool->resource_pool_id_, zone, this_server_array))) {
          LOG_WARN("fail to get pool server", K(ret), "pool_id", pool->resource_pool_id_, K(zone));
        } else if (OB_FAIL(append(server_array, this_server_array))) {
          LOG_WARN("fail to append", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::allocate_unit_groups(ObISQLClient& client, const share::ObResourcePool& pool,
    const bool new_allocate_pool, const int64_t increase_delta_unit_num, ObIArray<ObAddr>& new_servers)
{
  int ret = OB_SUCCESS;
  share::ObWorker::CompatMode compat_mode = share::ObWorker::CompatMode::INVALID;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (!pool.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid resource pool", K(pool), K(ret));
  } else if (increase_delta_unit_num <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(increase_delta_unit_num), K(ret));
  } else if (nullptr == schema_service_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("schema service ptr is null", K(ret));
  } else if (OB_UNLIKELY(nullptr == leader_coordinator_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("leader coordinator ptr is null", K(ret));
  } else if (OB_INVALID_ID == pool.tenant_id_) {
    // by pass
  } else if (OB_FAIL(ObCompatModeGetter::get_tenant_mode(pool.tenant_id_, compat_mode))) {
    LOG_WARN("fail to get tenant compat mode", K(ret));
  }
  ObNotifyTenantServerResourceProxy notify_proxy(
      leader_coordinator_->get_rpc_proxy(), &obrpc::ObSrvRpcProxy::notify_tenant_server_unit_resource);
  if (OB_SUCC(ret)) {
    ObArray<ObAddr> excluded_servers;
    ObAddr server;
    ObUnit unit;
    for (int64_t i = 0; OB_SUCC(ret) && i < pool.zone_list_.count(); ++i) {  // for each zone
      excluded_servers.reuse();
      if (new_allocate_pool) {
        // do nothing
      } else if (OB_FAIL(get_pool_servers(pool.resource_pool_id_, pool.zone_list_.at(i), excluded_servers))) {
        LOG_WARN("get_pool_servers failed",
            "resource pool id",
            pool.resource_pool_id_,
            "zone",
            pool.zone_list_.at(i),
            K(ret));
      } else if (OB_INVALID_ID == pool.tenant_id_) {
        // The pool does not belong to any tenant, no other processing is required
      } else {
        // The pool grant is given to a tenant,
        // and the server where the unit of the other pool of the tenant in the same zone
        // is located should also be regarded as excluded servers
        common::ObArray<uint64_t> processed_pool_id_array;
        common::ObArray<common::ObAddr> other_excluded_servers;
        if (OB_FAIL(processed_pool_id_array.push_back(pool.resource_pool_id_))) {
          LOG_WARN("fail to push back", K(ret));
        } else if (OB_FAIL(get_tenant_unit_servers(
                       pool.tenant_id_, pool.zone_list_.at(i), processed_pool_id_array, other_excluded_servers))) {
          LOG_WARN(
              "fail to get tenant unit servers", K(ret), "tenant_id", pool.tenant_id_, "zone", pool.zone_list_.at(i));
        } else if (OB_FAIL(append(excluded_servers, other_excluded_servers))) {
          LOG_WARN("fail to append other excluded servers", K(ret));
        }
      }
      if (OB_SUCC(ret) && GCONF.enable_sys_unit_standalone) {
        // When the system tenant is deployed independently,
        // the server where the unit of the system tenant is located is also required as the executed servers
        common::ObArray<uint64_t> processed_pool_id_array;
        common::ObArray<common::ObAddr> other_excluded_servers;
        if (OB_FAIL(get_tenant_unit_servers(
                OB_SYS_TENANT_ID, pool.zone_list_.at(i), processed_pool_id_array, other_excluded_servers))) {
          LOG_WARN("fail to get tenant unit servers", K(ret), "zone", pool.zone_list_.at(i));
        } else if (OB_FAIL(append(excluded_servers, other_excluded_servers))) {
          LOG_WARN("fail to append other excluded servers", K(ret));
        }
      }
      for (int64_t j = 0; OB_SUCC(ret) && j < increase_delta_unit_num; ++j) {
        ObUnitConfig* config = NULL;
        uint64_t unit_id = OB_INVALID_ID;
        server.reset();
        if (OB_FAIL(get_unit_config_by_id(pool.unit_config_id_, config))) {
          LOG_WARN("get_unit_config_by_id failed", "unit_config_id", pool.unit_config_id_, K(ret));
        } else if (NULL == config) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("config is null", KP(config), K(ret));
        } else if (OB_FAIL(choose_server_for_unit(*config, pool.zone_list_.at(i), excluded_servers, server))) {
          LOG_WARN("choose_unit_server failed",
              "config",
              *config,
              "zone",
              pool.zone_list_.at(i),
              K(excluded_servers),
              K(ret));
        } else if (OB_FAIL(excluded_servers.push_back(server))) {
          LOG_WARN("push_back failed", K(ret));
        } else if (OB_FAIL(fetch_new_unit_id(unit_id))) {
          LOG_WARN("fetch_new_unit_id failed", K(ret));
        } else {
          const bool is_delete = false;  // is_delete is false when allocate new unit
          unit.reset();
          unit.unit_id_ = unit_id;
          unit.resource_pool_id_ = pool.resource_pool_id_;
          unit.group_id_ = 0;  // group_id has no meaning, just fill it in as 0
          unit.zone_ = pool.zone_list_.at(i);
          unit.server_ = server;
          unit.status_ = ObUnit::UNIT_STATUS_ACTIVE;
          unit.replica_type_ = pool.replica_type_;
          if (OB_FAIL(try_notify_tenant_server_unit_resource(pool.tenant_id_,
                  is_delete,
                  notify_proxy,
                  pool,
                  compat_mode,
                  unit,
                  false /*if not grant*/,
                  false /*skip offline server*/))) {
            LOG_WARN("fail to try notify server unit resource", K(ret));
          } else if (OB_FAIL(add_unit(client, unit))) {
            LOG_WARN("add_unit failed", K(unit), K(ret));
          } else if (OB_FAIL(new_servers.push_back(server))) {
            LOG_WARN("push_back failed", K(ret));
          }
        }
      }
    }
    int tmp_ret = OB_SUCCESS;
    if (OB_SUCCESS != (tmp_ret = notify_proxy.wait())) {
      LOG_WARN("fail to wait notify resource", K(ret), K(tmp_ret));
      ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
    }
  }
  return ret;
}

// Before 14x, there is no intersection zone between two resource_pools of the same tenant
// After 14x, there may be intersection,
// so need to filter out the server where all units of the tenant are located
int ObUnitManager::get_excluded_servers(
    const ObUnit& unit, const ObUnitStat& unit_stat, ObIArray<ObAddr>& servers) const
{
  int ret = OB_SUCCESS;
  // Add all OBS whose disks do not meet the requirements
  ObArray<share::ObServerStatus> server_list;
  if (OB_FAIL(get_excluded_servers(unit, servers))) {
    LOG_WARN("fail to get excluded_servers", K(ret), K(unit));
  } else if (OB_FAIL(server_mgr_.get_server_statuses(unit.zone_, server_list))) {
    LOG_WARN("fail to get server of zone", K(ret), K(unit));
  } else {
    for (int64_t i = 0; i < server_list.count() && OB_SUCC(ret); i++) {
      ObServerStatus& status = server_list.at(i);
      bool is_exclude = false;
      if (!status.can_migrate_in()) {
        is_exclude = true;
        LOG_INFO("server can't migrate in, push into excluded_array", K(status));
      } else {
        int64_t required_size = unit_stat.required_size_ + status.resource_info_.disk_in_use_;
        int64_t total_size = status.resource_info_.disk_total_;
        if (total_size <= required_size || total_size <= 0) {
          is_exclude = true;
          LOG_INFO("server total size no bigger than required size",
              K(required_size),
              K(total_size),
              K(unit_stat),
              K(status.resource_info_));
        } else if (required_size <= 0) {
          // nothing todo
        } else {
          int64_t required_percent = (100 * required_size) / total_size;
          int64_t limit_percent = GCONF.data_disk_usage_limit_percentage;
          if (required_percent > limit_percent) {
            is_exclude = true;
            LOG_INFO("server disk percent will out of control;",
                K(required_percent),
                K(limit_percent),
                K(required_size),
                K(total_size));
          }
        }
      }
      if (!is_exclude) {
        // nothing todo
      } else if (has_exist_in_array(servers, status.server_)) {
        // nothing todo
      } else if (OB_FAIL(servers.push_back(status.server_))) {
        LOG_WARN("fail to push back", K(ret), K(status));
      }
    }
  }
  return ret;
}

int ObUnitManager::get_excluded_servers(const ObUnit& unit, ObIArray<ObAddr>& servers) const
{
  int ret = OB_SUCCESS;
  common::ObArray<share::ObResourcePool*>* all_pools = NULL;
  int64_t resource_pool_id = unit.resource_pool_id_;
  int64_t tenant_id = OB_INVALID_ID;
  servers.reset();
  share::ObResourcePool* pool = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (!unit.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid unit", K(unit), K(ret));
  } else if (OB_FAIL(get_resource_pool_by_id(resource_pool_id, pool))) {
    LOG_WARN("fail to get resource pool by id", K(ret), K(resource_pool_id));
  } else if (FALSE_IT(tenant_id = pool->tenant_id_)) {
    // nothing todo
  } else if (OB_INVALID_ID == tenant_id) {
    // nothing todo
    // The unit is not assigned to the tenant
  } else if (OB_FAIL(get_pools_by_tenant(tenant_id, all_pools))) {
    if (OB_ENTRY_NOT_EXIST == ret) {
      ret = OB_SUCCESS;
    } else {
      LOG_WARN("fail to get pools by tenant", K(ret), K(tenant_id));
    }
  } else {
    ObArray<ObAddr> pool_servers;
    for (int64_t i = 0; i < all_pools->count() && OB_SUCC(ret); i++) {
      pool_servers.reset();
      resource_pool_id = all_pools->at(i)->resource_pool_id_;
      if (OB_FAIL(get_pool_servers(resource_pool_id, unit.zone_, pool_servers))) {
        LOG_WARN("get_pool_servers failed", "resource_pool_id", unit.resource_pool_id_, "zone", unit.zone_, K(ret));
      } else {
        for (int64_t j = 0; j < pool_servers.count() && OB_SUCC(ret); j++) {
          if (has_exist_in_array(servers, pool_servers.at(j))) {
            // nothing todo
          } else if (OB_FAIL(servers.push_back(pool_servers.at(j)))) {
            LOG_WARN("fail to push back server", K(ret), K(servers), K(pool_servers));
          }
        }  // end for
      }
    }  // end for
  }
  return ret;
}

int ObUnitManager::get_pools_servers(const common::ObIArray<share::ObResourcePool*>& pools,
    common::hash::ObHashMap<common::ObAddr, int64_t>& server_ref_count_map) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (pools.count() <= 0 || !server_ref_count_map.created()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pools is empty", K(pools), "server_ref_count_map created", server_ref_count_map.created(), K(ret));
  } else {
    ObArray<ObAddr> servers;
    const ObZone all_zone;
    FOREACH_CNT_X(pool, pools, OB_SUCCESS == ret)
    {
      servers.reuse();
      if (NULL == *pool) {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("pool is null", "pool", *pool, K(ret));
      } else if (OB_FAIL(get_pool_servers((*pool)->resource_pool_id_, all_zone, servers))) {
        LOG_WARN("get pool servers failed", "pool id", (*pool)->resource_pool_id_, K(all_zone), K(ret));
      } else {
        FOREACH_CNT_X(server, servers, OB_SUCCESS == ret)
        {
          int64_t server_ref_count = 0;
          if (OB_FAIL(get_server_ref_count(server_ref_count_map, *server, server_ref_count))) {
            if (OB_ENTRY_NOT_EXIST == ret) {
              server_ref_count = 1;
              ret = OB_SUCCESS;
            } else {
              LOG_WARN("get server ref count failed", "server", *server, K(ret));
            }
          } else {
            ++server_ref_count;
          }
          if (OB_SUCC(ret)) {
            if (OB_FAIL(set_server_ref_count(server_ref_count_map, *server, server_ref_count))) {
              LOG_WARN("set server ref count failed", "server", *server, K(server_ref_count), K(ret));
            }
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::get_pool_servers(
    const uint64_t resource_pool_id, const ObZone& zone, ObIArray<ObAddr>& servers) const
{
  int ret = OB_SUCCESS;
  ObArray<ObUnit*>* units = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == resource_pool_id) {
    // don't need to check zone, can be empty
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid resource_pool_id", K(resource_pool_id), K(ret));
  } else if (OB_FAIL(get_units_by_pool(resource_pool_id, units))) {
    LOG_WARN("get_units_by_pool failed", K(resource_pool_id), K(ret));
  } else if (NULL == units) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units is null", KP(units), K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
      if (NULL == units->at(i)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit is null", "unit", OB_P(units->at(i)), K(ret));
      } else if (!zone.is_empty() && zone != units->at(i)->zone_) {
        continue;
      } else {
        if (OB_SUCCESS == ret && units->at(i)->migrate_from_server_.is_valid()) {
          if (OB_FAIL(servers.push_back(units->at(i)->migrate_from_server_))) {
            LOG_WARN("push_back failed", K(ret));
          }
        }

        if (OB_SUCCESS == ret && units->at(i)->server_.is_valid()) {
          if (OB_FAIL(servers.push_back(units->at(i)->server_))) {
            LOG_WARN("push_back failed", K(ret));
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::choose_server_for_unit(
    const ObUnitConfig& config, const ObZone& zone, const ObArray<ObAddr>& excluded_servers, ObAddr& server) const
{
  int ret = OB_SUCCESS;
  server.reset();
  double hard_limit = 1.0;
  double soft_limit = 1.0;
  ObArray<ObServerStatus> statuses;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (!config.is_valid() || zone.is_empty()) {
    // excluded_servers can be empty
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid config", K(config), K(zone), K(ret));
  } else if (OB_FAIL(get_hard_limit(hard_limit))) {
    LOG_WARN("get_hard_limit failed", K(ret));
  } else if (OB_FAIL(get_soft_limit(soft_limit))) {
    LOG_WARN("get_soft_limit failed", K(ret));
  } else if (OB_FAIL(server_mgr_.get_server_statuses(zone, statuses))) {
    LOG_WARN("get_server_statuses failed", K(zone), K(ret));
  } else {
    // 1. construct servers resource
    ObUnitPlacementStrategy::ObServerResource server_resource;
    ObArray<ObUnitPlacementStrategy::ObServerResource> servers_resources;
    ObArray<ObUnitLoad>* unit_loads = NULL;
    ObUnitConfig sum_load;
    for (int64_t i = 0; OB_SUCC(ret) && i < statuses.count(); ++i) {  // for each active servers
      sum_load.reset();
      const ObServerStatus& server_status = statuses[i];
      if (has_exist_in_array(excluded_servers, server_status.server_)) {
        continue;
      } else if (!server_status.can_migrate_in()) {
        LOG_WARN("server can not migrate in", "status", server_status);
        continue;
      } else if (OB_FAIL(get_loads_by_server(server_status.server_, unit_loads))) {
        // the server is empty yet
        // all assigned resources are zero
        ret = OB_SUCCESS;
      } else if (NULL == unit_loads) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit_loads is null", KP(unit_loads), K(ret));
      } else if (OB_FAIL(calc_sum_load(unit_loads, sum_load))) {
        LOG_WARN("calc_sum_load failed", KP(unit_loads), K(ret));
      }
      if (OB_SUCC(ret)) {
        // Unit resource information is persisted on the observer side,
        // The unit_load seen on the rs side is only the resource view managed by rs itself,
        // It is actually inaccurate to judge whether the resources are sufficient based on the resource view of rs
        // itself, Need to consider the persistent resources of the unit resource information on the observer side. The
        // persistent information of the unit on the observer side is regularly reported to rs by the observer through
        // the heartbeat. When performing allocation, rs reports the maximum value of resource information from its own
        // resource view and observer side as a reference for unit resource allocation
        const ObServerResourceInfo& report_resource = server_status.resource_info_;
        LOG_INFO("server load", K(i), "server", server_status, "load", sum_load, "unit_load", unit_loads);
        server_resource.addr_ = server_status.server_;
        server_resource.assigned_[RES_CPU] = sum_load.min_cpu_ > report_resource.report_cpu_assigned_
                                                 ? sum_load.min_cpu_
                                                 : report_resource.report_cpu_assigned_;
        server_resource.max_assigned_[RES_CPU] = sum_load.max_cpu_ > report_resource.report_cpu_max_assigned_
                                                     ? sum_load.max_cpu_
                                                     : report_resource.report_cpu_max_assigned_;
        server_resource.capacity_[RES_CPU] = server_status.resource_info_.cpu_;
        server_resource.assigned_[RES_MEM] = sum_load.min_memory_ > report_resource.report_mem_assigned_
                                                 ? static_cast<double>(sum_load.min_memory_)
                                                 : static_cast<double>(report_resource.report_mem_assigned_);
        server_resource.max_assigned_[RES_MEM] = sum_load.max_memory_ > report_resource.report_mem_max_assigned_
                                                     ? static_cast<double>(sum_load.max_memory_)
                                                     : static_cast<double>(report_resource.report_mem_max_assigned_);
        server_resource.capacity_[RES_MEM] = static_cast<double>(server_status.resource_info_.mem_total_);
        server_resource.assigned_[RES_DISK] = static_cast<double>(sum_load.max_disk_size_);
        server_resource.max_assigned_[RES_DISK] = static_cast<double>(sum_load.max_disk_size_);
        server_resource.capacity_[RES_DISK] = static_cast<double>(server_status.resource_info_.disk_total_);
        if (OB_FAIL(servers_resources.push_back(server_resource))) {
          LOG_WARN("failed to push into array", K(ret), K(server_resource));
        }
      }
    }  // end for
    if (OB_SUCC(ret)) {
      // 2. choose the server
      ObUnitPlacementStrategy* placement_strategy = unit_placement_strategy_;
      ObUnitPlacementHybridStrategy old_unit_placement(soft_limit, hard_limit);
      ObUnitPlacementDPStrategy unit_placement(hard_limit);
      int64_t find_idx = -1;
      UNUSED(old_unit_placement);
      if (NULL == placement_strategy) {
        placement_strategy = &unit_placement;
      }
      if (OB_FAIL(placement_strategy->choose_server(servers_resources, config, server, zone, find_idx))) {
        LOG_DEBUG("failed to choose server for unit", K(ret), K(config));
      } else {
        LOG_INFO("chosen server for unit", K(config), K(server));
      }
    }
  }
  return ret;
}

int ObUnitManager::have_enough_resource(const ObServerStatus& server_status, const ObUnitConfig& unit_config,
    const double hard_limit, bool& is_enough, AlterResourceErr& err_index) const
{
  int ret = OB_SUCCESS;
  ObArray<ObUnitLoad>* unit_loads = NULL;
  ObUnitConfig sum_load;
  sum_load.reset();
  double min_cpu_assigned = 0.0;
  double max_cpu_assigned = 0.0;
  int64_t min_mem_assigned = 0;
  int64_t max_mem_assigned = 0;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (!server_status.is_valid() || hard_limit <= 0) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid argument", K(server_status), K(hard_limit), K(ret));
  } else if (OB_FAIL(get_loads_by_server(server_status.server_, unit_loads))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_loads_by_server failed", "server", server_status.server_, K(ret));
    } else {
      ret = OB_SUCCESS;
    }
  } else if (NULL == unit_loads) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unit_loads is null", KP(unit_loads), K(ret));
  } else if (OB_FAIL(calc_sum_load(unit_loads, sum_load))) {
    LOG_WARN("calc_sum_load failed", KP(unit_loads), K(ret));
  }
  if (OB_SUCC(ret)) {
    const ObServerResourceInfo& report_resource = server_status.resource_info_;
    min_cpu_assigned = sum_load.min_cpu_ > report_resource.report_cpu_assigned_ ? sum_load.min_cpu_
                                                                                : report_resource.report_cpu_assigned_;
    max_cpu_assigned = sum_load.max_cpu_ > report_resource.report_cpu_max_assigned_
                           ? sum_load.max_cpu_
                           : report_resource.report_cpu_max_assigned_;
    min_mem_assigned = sum_load.min_memory_ > report_resource.report_mem_assigned_
                           ? sum_load.min_memory_
                           : report_resource.report_mem_assigned_;
    max_mem_assigned = sum_load.max_memory_ > report_resource.report_mem_max_assigned_
                           ? sum_load.max_memory_
                           : report_resource.report_mem_max_assigned_;
  }
  if (OB_SUCC(ret)) {
    is_enough = true;
    // bool temp_value = true;
    if (server_status.resource_info_.cpu_ * hard_limit < max_cpu_assigned + unit_config.max_cpu_) {
      is_enough = false;
      err_index = MAX_CPU;
    } else if (server_status.resource_info_.cpu_ < min_cpu_assigned + unit_config.min_cpu_) {
      is_enough = false;
      err_index = MIN_CPU;
    } else if (static_cast<double>(server_status.resource_info_.mem_total_) * hard_limit <
               static_cast<double>(max_mem_assigned + unit_config.max_memory_)) {
      is_enough = false;
      err_index = MAX_MEM;
    } else if (server_status.resource_info_.mem_total_ < min_mem_assigned + unit_config.min_memory_) {
      is_enough = false;
      err_index = MIN_MEM;
    } else {
      err_index = ALT_ERR;
    }
  }
  return ret;
}

int ObUnitManager::check_enough_resource_for_delete_server(const ObAddr& server, const ObZone& zone)
{
  int ret = OB_SUCCESS;
  ObArray<ObUnitManager::ObUnitLoad>* unit_loads = NULL;
  ObArray<ObUnitPlacementStrategy::ObServerResource> initial_servers_resources;
  ObArray<ObServerStatus> statuses;
  SpinRLockGuard guard(lock_);
  bool empty = false;
  if (OB_FAIL(check_server_empty(server, empty))) {
    LOG_WARN("fail to check server empty", K(ret));
  } else if (empty) {
    // nothing todo
  } else {
    if (OB_FAIL(get_loads_by_server(server, unit_loads))) {
      LOG_WARN("fail to get loads by server", K(ret));
    } else if (OB_FAIL(server_mgr_.get_server_statuses(zone, statuses))) {
      LOG_WARN("get_server_statuses failed", K(zone), K(ret));
    } else if (OB_FAIL(build_initial_servers_resources(statuses, initial_servers_resources))) {
      LOG_WARN("fail to get unit config", K(ret));
    } else {
      for (int64_t i = 0; i < unit_loads->count() && OB_SUCC(ret); ++i) {
        if (OB_FAIL(check_server_have_enough_resource_for_delete_server(
                unit_loads->at(i), statuses, zone, initial_servers_resources))) {
          LOG_WARN("fail to check server have enough resource", K(ret), K(zone));
        }
      }  // end for unit_loads
    }
  }
  return ret;
}

int ObUnitManager::check_server_have_enough_resource_for_delete_server(const ObUnitLoad& unit_load,
    const ObIArray<ObServerStatus>& statuses, const common::ObZone& zone,
    ObIArray<ObUnitPlacementStrategy::ObServerResource>& initial_servers_resources)
{
  int ret = OB_SUCCESS;
  double hard_limit = 1.0;
  ObArray<ObUnitPlacementStrategy::ObServerResource> servers_resources;
  ObArray<ObAddr> excluded_servers;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_ISNULL(unit_load.unit_config_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unit config ptr is null", K(ret));
  } else if (!unit_load.unit_config_->is_valid()) {
    // excluded_servers can be empty
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid config", K(*(unit_load.unit_config_)), K(ret));
  } else if (OB_ISNULL(unit_load.unit_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unit ptr is null", K(ret));
  } else if (unit_load.unit_->migrate_from_server_.is_valid()) {
    // In a state of migration, there must be a place to migrate
  } else if (OB_FAIL(get_hard_limit(hard_limit))) {
    LOG_WARN("get_hard_limit failed", K(ret));
  } else if (OB_FAIL(get_excluded_servers(*(unit_load.unit_), excluded_servers))) {
    LOG_WARN("fail to get excluded server", K(ret));
  } else {
    if (OB_SUCC(ret)) {
      for (int64_t i = 0; OB_SUCC(ret) && i < statuses.count(); ++i) {  // for each active servers
        const ObServerStatus& server_status = statuses.at(i);
        if (has_exist_in_array(excluded_servers, server_status.server_)) {
          // nothing todo
        } else if (server_status.can_migrate_in() && i < initial_servers_resources.count()) {
          if (OB_FAIL(servers_resources.push_back(initial_servers_resources.at(i)))) {
            LOG_WARN("fail to push_back servers resources", K(ret));
          }
        }
      }  // end for
    }
    if (OB_SUCC(ret)) {
      // 2. choose the server
      ObUnitPlacementStrategy* placement_strategy = unit_placement_strategy_;
      ObUnitPlacementDPStrategy unit_placement(hard_limit);
      ObAddr server;
      int64_t index = -1;
      if (NULL == placement_strategy) {
        placement_strategy = &unit_placement;
      }
      if (OB_FAIL(
              placement_strategy->choose_server(servers_resources, *(unit_load.unit_config_), server, zone, index))) {
        LOG_DEBUG("failed to choose server for unit", K(ret), K(*(unit_load.unit_config_)));
      } else if (index < initial_servers_resources.count() && index >= 0) {
        if (OB_FAIL(sum_servers_resources(initial_servers_resources.at(index), *(unit_load.unit_config_)))) {
          LOG_WARN("fail to sum servers resources", K(ret));
        }
      } else {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("choose wrong server", K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::build_initial_servers_resources(const ObIArray<ObServerStatus>& statuses,
    ObIArray<ObUnitPlacementStrategy::ObServerResource>& initial_servers_resources)
{
  int ret = OB_SUCCESS;
  ObArray<ObUnitLoad>* unit_loads = NULL;
  ObUnitConfig sum_load;
  for (int64_t i = 0; OB_SUCC(ret) && i < statuses.count(); ++i) {
    sum_load.reset();
    const ObServerStatus& server_status = statuses.at(i);
    if (OB_FAIL(get_loads_by_server(server_status.server_, unit_loads))) {
      // the server is empty yet
      // all assigned resources are zero
      if (ret == OB_ENTRY_NOT_EXIST) {
        ret = OB_SUCCESS;
      } else {
        LOG_WARN("fail to get loads by server", K(ret));
      }
    } else if (NULL == unit_loads) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unit_loads is null", KP(unit_loads), K(ret));
    } else if (OB_FAIL(calc_sum_load(unit_loads, sum_load))) {
      LOG_WARN("calc_sum_load failed", KP(unit_loads), K(ret));
    }
    if (OB_SUCC(ret)) {
      ObUnitPlacementStrategy::ObServerResource server_resource;
      if (OB_FAIL(get_server_resource(server_status, sum_load, server_resource))) {
        LOG_WARN("fail to get server resource", K(ret));
      } else if (OB_FAIL(initial_servers_resources.push_back(server_resource))) {
        LOG_WARN("fail to push back", K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::get_server_resource(const ObServerStatus& status, const share::ObUnitConfig& unit_config,
    ObUnitPlacementStrategy::ObServerResource& server_resource)
{
  int ret = OB_SUCCESS;
  const ObServerResourceInfo& report_resource = status.resource_info_;
  LOG_INFO("server load", "server", status, "load", unit_config);
  server_resource.addr_ = status.server_;
  server_resource.assigned_[RES_CPU] = unit_config.min_cpu_ > report_resource.report_cpu_assigned_
                                           ? unit_config.min_cpu_
                                           : report_resource.report_cpu_assigned_;
  server_resource.max_assigned_[RES_CPU] = unit_config.max_cpu_ > report_resource.report_cpu_max_assigned_
                                               ? unit_config.max_cpu_
                                               : report_resource.report_cpu_max_assigned_;
  server_resource.capacity_[RES_CPU] = report_resource.cpu_;
  server_resource.assigned_[RES_MEM] = unit_config.min_memory_ > report_resource.report_mem_assigned_
                                           ? static_cast<double>(unit_config.min_memory_)
                                           : static_cast<double>(report_resource.report_mem_assigned_);
  server_resource.max_assigned_[RES_MEM] = unit_config.max_memory_ > report_resource.report_mem_max_assigned_
                                               ? static_cast<double>(unit_config.max_memory_)
                                               : static_cast<double>(report_resource.report_mem_max_assigned_);
  server_resource.capacity_[RES_MEM] = static_cast<double>(report_resource.mem_total_);
  server_resource.assigned_[RES_DISK] = static_cast<double>(unit_config.max_disk_size_);
  server_resource.max_assigned_[RES_DISK] = static_cast<double>(unit_config.max_disk_size_);
  server_resource.capacity_[RES_DISK] = static_cast<double>(report_resource.disk_total_);
  return ret;
}

int ObUnitManager::sum_servers_resources(
    ObUnitPlacementStrategy::ObServerResource& server_resource, const share::ObUnitConfig& unit_config)
{
  int ret = OB_SUCCESS;
  server_resource.assigned_[RES_CPU] = server_resource.assigned_[RES_CPU] + unit_config.min_cpu_;
  server_resource.max_assigned_[RES_CPU] = server_resource.max_assigned_[RES_CPU] + unit_config.max_cpu_;
  server_resource.assigned_[RES_MEM] =
      server_resource.assigned_[RES_MEM] + static_cast<double>(unit_config.min_memory_);
  server_resource.max_assigned_[RES_MEM] =
      server_resource.max_assigned_[RES_MEM] + static_cast<double>(unit_config.max_memory_);
  server_resource.assigned_[RES_DISK] =
      server_resource.assigned_[RES_DISK] + static_cast<double>(unit_config.max_disk_size_);
  server_resource.max_assigned_[RES_DISK] =
      server_resource.max_assigned_[RES_DISK] + static_cast<double>(unit_config.max_disk_size_);
  return ret;
}

int ObUnitManager::add_unit(ObISQLClient& client, const ObUnit& unit)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (!unit.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(unit), K(ret));
  } else {
    ObUnit* new_unit = NULL;
    if (OB_SUCCESS == (ret = get_unit_by_id(unit.unit_id_, new_unit))) {
      ret = OB_ENTRY_EXIST;
      LOG_WARN("unit already exist, can't add", K(unit), K(ret));
    } else if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_unit_by_id failed", "unit_id", unit.unit_id_, K(ret));
    } else {
      ret = OB_SUCCESS;
    }

    if (OB_FAIL(ret)) {
    } else if (NULL == (new_unit = allocator_.alloc())) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_ERROR("alloc unit failed", K(ret));
    } else {
      if (OB_FAIL(ut_operator_.update_unit(client, unit))) {
        LOG_WARN("update_unit failed", K(unit), K(ret));
      } else {
        *new_unit = unit;
        if (OB_FAIL(insert_unit(new_unit))) {
          LOG_WARN("insert_unit failed", "new unit", *new_unit, K(ret));
        } else {
          ROOTSERVICE_EVENT_ADD("unit", "create_unit", "unit_id", unit.unit_id_, "server", unit.server_);
        }
      }
      if (OB_FAIL(ret)) {
        // avoid memory leak
        allocator_.free(new_unit);
        new_unit = NULL;
      }
    }
  }
  return ret;
}

int ObUnitManager::alter_pool_unit_config(share::ObResourcePool* pool, const ObUnitConfigName& config_name)
{
  int ret = OB_SUCCESS;
  ObUnitConfig* config = NULL;
  ObUnitConfig* alter_config = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (NULL == pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool is null", K(ret));
  } else if (config_name.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("config_name is empty", K(config_name), K(ret));
  } else if (OB_FAIL(get_unit_config_by_id(pool->unit_config_id_, config))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_unit_config_by_id failed", "unit_config_id", pool->unit_config_id_, K(ret));
    } else {
      ret = OB_RESOURCE_UNIT_NOT_EXIST;
      LOG_WARN("unit config not exist", "config_id", pool->unit_config_id_, K(ret));
    }
  } else if (NULL == config) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("config is null", KP(config), K(ret));
  } else if (OB_FAIL(get_unit_config_by_name(config_name, alter_config))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_unit_config_by_name failed", K(config_name), K(ret));
    } else {
      ret = OB_RESOURCE_UNIT_NOT_EXIST;
      LOG_USER_ERROR(OB_RESOURCE_UNIT_NOT_EXIST, to_cstring(config_name));
      LOG_WARN("unit config not exist", K(config_name), K(ret));
    }
  } else if (NULL == alter_config) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("alter_config is null", KP(alter_config), K(ret));
  } else if (config_name == config->name_) {
    // do nothing
  } else if (REPLICA_TYPE_FULL == pool->replica_type_ &&
             alter_config->min_memory_ < GCONF.__min_full_resource_pool_memory) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("full resource pool min memory illegal", K(ret));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "unit min memory less than __min_full_resource_pool_memory");
  } else if (OB_FAIL(check_expand_config(*pool, *config, *alter_config))) {
    LOG_WARN("check_expand_config failed", "pool", *pool, "config", *config, "alter_config", *alter_config, K(ret));
  } else if (OB_FAIL(check_shrink_config(*pool, *config, *alter_config))) {
    LOG_WARN("check_shrink_config failed", "pool", *pool, "config", *config, "alter_config", *alter_config, K(ret));
  } else if (OB_FAIL(change_pool_config(pool, config, alter_config))) {
    LOG_WARN("change_pool_config failed", "pool", *pool, "config", *config, "alter_config", *alter_config, K(ret));
  }
  return ret;
}

// There are two situations to consider in the shrinkage of the resource pool:
// 1. There is no resource pool granted to tenants
//    the specified number of units can be directly deleted when the resource pool shrinks.
// 2. Resource pool that has been granted to tenants
//    It is necessary to select the specified units from the resource pool,
//    mark these units as the deleting state,
//    and wait for all the replicas to be moved from such units before the whole process can be considered complete.
//    The unit num of the pool that has been granted to the tenant needs to be scaled down.
//    Preconditions:
//    2.1 The reduced unit num cannot be less than the number of replicas of locality in the corresponding zone
//    2.2 At present, the shrinking operation is performed when the unit is in a steady state,
//        the shrinking is allowed when all units are not migrated.
//        We avoid the unit being in both the migration and the deleting state, thereby reducing the complexity
int ObUnitManager::shrink_pool_unit_num(
    share::ObResourcePool* pool, const int64_t alter_unit_num, const common::ObIArray<uint64_t>& delete_unit_id_array)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(NULL == pool || alter_unit_num <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(alter_unit_num));
  } else {
    ObArray<uint64_t> sort_unit_id_array;
    for (int64_t i = 0; OB_SUCC(ret) && i < delete_unit_id_array.count(); ++i) {
      if (OB_FAIL(sort_unit_id_array.push_back(delete_unit_id_array.at(i)))) {
        LOG_WARN("fail to push back", K(ret));
      }
    }
    std::sort(sort_unit_id_array.begin(), sort_unit_id_array.end());
    for (int64_t i = 0; OB_SUCC(ret) && i < sort_unit_id_array.count() - 1; ++i) {
      if (sort_unit_id_array.at(i) == sort_unit_id_array.at(i + 1)) {
        ret = OB_NOT_SUPPORTED;
        LOG_WARN("delete same unit more than once not supported", K(ret));
        LOG_USER_ERROR(OB_NOT_SUPPORTED, "delete same unit more than once");
      }
    }
    if (OB_SUCC(ret)) {
      uint64_t tenant_id = pool->tenant_id_;
      if (OB_INVALID_ID == tenant_id) {
        if (OB_FAIL(shrink_not_granted_pool(pool, alter_unit_num, delete_unit_id_array))) {
          LOG_WARN("fail to shrink not granted pool", K(ret));
        }
      } else {
        if (OB_FAIL(shrink_granted_pool(pool, alter_unit_num, delete_unit_id_array))) {
          LOG_WARN("fail to shrink granted pool", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::build_sorted_zone_unit_ptr_array(
    share::ObResourcePool* pool, common::ObIArray<ZoneUnitPtr>& zone_unit_ptrs)
{
  int ret = OB_SUCCESS;
  common::ObArray<share::ObUnit*>* units = NULL;
  zone_unit_ptrs.reset();
  if (OB_UNLIKELY(NULL == pool)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool));
  } else if (OB_FAIL(get_units_by_pool(pool->resource_pool_id_, units))) {
    LOG_WARN("fail to get units by pool", K(ret), "pool_id", pool->resource_pool_id_);
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units ptr is null", K(ret), KP(units));
  } else {
    // traverse all unit in units
    for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
      ObUnit* this_unit = units->at(i);
      if (OB_UNLIKELY(NULL == this_unit)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit ptr is null", K(ret), KP(this_unit));
      } else {
        // aggregate units with the same zone
        int64_t index = 0;
        for (; OB_SUCC(ret) && index < zone_unit_ptrs.count(); ++index) {
          if (this_unit->zone_ == zone_unit_ptrs.at(index).zone_) {
            break;
          }
        }
        if (OB_FAIL(ret)) {
        } else if (index >= zone_unit_ptrs.count()) {
          ZoneUnitPtr zone_unit_ptr;
          zone_unit_ptr.zone_ = this_unit->zone_;
          if (OB_FAIL(zone_unit_ptrs.push_back(zone_unit_ptr))) {
            LOG_WARN("fail to push back", K(ret));
          }
        }
        if (OB_FAIL(ret)) {
        } else if (index >= zone_unit_ptrs.count()) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unexpected index", K(ret), K(index), "zone_unit_count", zone_unit_ptrs.count());
        } else if (this_unit->zone_ != zone_unit_ptrs.at(index).zone_) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN(
              "zone not match", K(ret), "left_zone", this_unit->zone_, "right_zone", zone_unit_ptrs.at(index).zone_);
        } else if (OB_FAIL(zone_unit_ptrs.at(index).unit_ptrs_.push_back(this_unit))) {
          LOG_WARN("fail to push back", K(ret), K(index));
        } else {
        }  // good, no more to do
      }
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < zone_unit_ptrs.count(); ++i) {
      // sort each zone unit ptr using group id
      ZoneUnitPtr& zone_unit_ptr = zone_unit_ptrs.at(i);
      if (OB_FAIL(zone_unit_ptr.sort_by_unit_id_desc())) {
        LOG_WARN("fail to sort unit", K(ret));
      } else {
      }  // good, unit num match
    }
  }
  return ret;
}

int ObUnitManager::check_shrink_unit_num_zone_condition(
    share::ObResourcePool* pool, const int64_t alter_unit_num, const common::ObIArray<uint64_t>& delete_unit_id_array)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(NULL == pool || alter_unit_num <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(alter_unit_num));
  } else if (delete_unit_id_array.count() <= 0) {
    // good, we choose deleting set all by ourselves
  } else if (pool->unit_count_ <= alter_unit_num) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN(
        "should be a shrink pool operation", K(ret), "cur_unit_num", pool->unit_count_, "new_unit_num", alter_unit_num);
  } else {
    int64_t delta = pool->unit_count_ - alter_unit_num;
    const common::ObIArray<common::ObZone>& zone_list = pool->zone_list_;
    common::ObArray<ZoneUnitPtr> delete_zone_unit_ptrs;
    for (int64_t i = 0; OB_SUCC(ret) && i < delete_unit_id_array.count(); ++i) {
      ObUnit* this_unit = NULL;
      if (OB_FAIL(get_unit_by_id(delete_unit_id_array.at(i), this_unit))) {
        LOG_WARN("fail to get unit by id", K(ret));
      } else if (OB_UNLIKELY(NULL == this_unit)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit ptr is null", K(ret), KP(this_unit));
      } else if (this_unit->resource_pool_id_ != pool->resource_pool_id_) {
        ret = OB_NOT_SUPPORTED;
        LOG_WARN("do not support shrink unit belonging to other pool");
        LOG_USER_ERROR(OB_NOT_SUPPORTED, "shrink unit belonging to other pool");
      } else if (!has_exist_in_array(zone_list, this_unit->zone_)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit zone not match", K(ret), K(zone_list), "unit_zone", this_unit->zone_);
      } else {
        int64_t index = 0;
        for (; OB_SUCC(ret) && index < delete_zone_unit_ptrs.count(); ++index) {
          if (this_unit->zone_ == delete_zone_unit_ptrs.at(index).zone_) {
            break;
          }
        }
        if (OB_FAIL(ret)) {
        } else if (index >= delete_zone_unit_ptrs.count()) {
          ZoneUnitPtr delete_zone_unit_ptr;
          delete_zone_unit_ptr.zone_ = this_unit->zone_;
          if (OB_FAIL(delete_zone_unit_ptrs.push_back(delete_zone_unit_ptr))) {
            LOG_WARN("fail to push back", K(ret));
          }
        }
        if (OB_FAIL(ret)) {
        } else if (index >= delete_zone_unit_ptrs.count()) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unexpected index", K(ret), K(index), "delete_zone_unit_count", delete_zone_unit_ptrs.count());
        } else if (this_unit->zone_ != delete_zone_unit_ptrs.at(index).zone_) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("zone not match",
              K(ret),
              "left_zone",
              this_unit->zone_,
              "right_zone",
              delete_zone_unit_ptrs.at(index).zone_);
        } else if (OB_FAIL(delete_zone_unit_ptrs.at(index).unit_ptrs_.push_back(this_unit))) {
          LOG_WARN("fail to push back", K(ret), K(index));
        } else {
        }  // good, no more to do
      }
    }
    if (OB_SUCC(ret)) {
      if (delete_zone_unit_ptrs.count() != zone_list.count()) {
        ret = OB_NOT_SUPPORTED;
        LOG_WARN("do not support shrink unit num to different value on different zone", K(ret));
        LOG_USER_ERROR(OB_NOT_SUPPORTED, "shrink unit num to different value on different zone");
      }
    }
    if (OB_SUCC(ret)) {
      for (int64_t i = 0; OB_SUCC(ret) && i < delete_zone_unit_ptrs.count(); ++i) {
        if (delta != delete_zone_unit_ptrs.at(i).unit_ptrs_.count()) {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("shrink mismatching unit num and unit id list not support", K(ret));
          LOG_USER_ERROR(OB_NOT_SUPPORTED, "shrink mismatching unit num and unit id list");
        } else {
        }  // good, go on to check next
      }
    }
  }
  return ret;
}

int ObUnitManager::fill_delete_unit_ptr_array(share::ObResourcePool* pool,
    const common::ObIArray<uint64_t>& delete_unit_id_array, const int64_t alter_unit_num,
    common::ObIArray<ObUnit*>& output_delete_unit_ptr_array)
{
  int ret = OB_SUCCESS;
  output_delete_unit_ptr_array.reset();
  if (delete_unit_id_array.count() > 0) {
    // The alter resource pool shrinkage specifies the deleted unit, just fill it in directly
    for (int64_t i = 0; OB_SUCC(ret) && i < delete_unit_id_array.count(); ++i) {
      ObUnit* unit = NULL;
      if (OB_FAIL(get_unit_by_id(delete_unit_id_array.at(i), unit))) {
        LOG_WARN("fail to get unit by id", K(ret));
      } else if (NULL == unit) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit ptr is null", K(ret), KP(unit));
      } else if (OB_FAIL(output_delete_unit_ptr_array.push_back(unit))) {
        LOG_WARN("fail to push back", K(ret));
      } else {
      }  // no more to do
    }
  } else {
    common::ObArray<ZoneUnitPtr> zone_unit_ptrs;
    if (OB_UNLIKELY(NULL == pool)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("invalid argument", K(ret), KP(pool));
    } else if (OB_FAIL(build_sorted_zone_unit_ptr_array(pool, zone_unit_ptrs))) {
      LOG_WARN("fail to build sorted zone unit ptr array", K(ret));
    } else if (zone_unit_ptrs.count() <= 0) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("zone unit ptrs has no element", K(ret), "zone_unit_cnt", zone_unit_ptrs.count());
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < zone_unit_ptrs.count(); ++i) {
        const ZoneUnitPtr& zone_unit_ptr = zone_unit_ptrs.at(i);
        for (int64_t j = alter_unit_num; OB_SUCC(ret) && j < zone_unit_ptr.unit_ptrs_.count(); ++j) {
          ObUnit* unit = zone_unit_ptr.unit_ptrs_.at(j);
          if (OB_UNLIKELY(NULL == unit)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unit ptr is null", K(ret), KP(unit), K(i), K(j));
          } else if (OB_FAIL(output_delete_unit_ptr_array.push_back(unit))) {
            LOG_WARN("fail to push back", K(ret));
          } else {
          }  // no more to do
        }
      }
    }
  }
  return ret;
}

// the resource pool don't grant any tenants shrink directly.
// step:
// 1. clear __all_unit, change the unit num in __all_resouce_pool
// 2. clear the unit info in memory structure, change the unit_num in memroy structure resource pool
int ObUnitManager::shrink_not_granted_pool(
    share::ObResourcePool* pool, const int64_t alter_unit_num, const common::ObIArray<uint64_t>& delete_unit_id_array)
{
  int ret = OB_SUCCESS;
  common::ObMySQLTransaction trans;
  if (OB_UNLIKELY(NULL == pool || alter_unit_num <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(alter_unit_num));
  } else if (OB_INVALID_ID != pool->tenant_id_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool already grant to some tenant", K(ret), "tenant_id", pool->tenant_id_);
  } else if (pool->unit_count_ <= alter_unit_num) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN(
        "should be a shrink pool operation", K(ret), "cur_unit_num", pool->unit_count_, "new_unit_num", alter_unit_num);
  } else if (OB_FAIL(trans.start(proxy_))) {
    LOG_WARN("start transaction failed", K(ret));
  } else {
    common::ObArray<ObUnit*> output_delete_unit_ptr_array;
    common::ObArray<uint64_t> output_delete_unit_id_array;
    share::ObResourcePool new_pool;
    if (OB_FAIL(new_pool.assign(*pool))) {
      LOG_WARN("fail to assign new pool", K(ret));
    } else {
      new_pool.unit_count_ = alter_unit_num;
    }
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(ut_operator_.update_resource_pool(trans, new_pool))) {
      LOG_WARN("fail to update resource pool", K(ret));
    } else if (OB_FAIL(check_shrink_unit_num_zone_condition(pool, alter_unit_num, delete_unit_id_array))) {
      LOG_WARN("fail to check shrink unit num zone condition", K(ret));
    } else if (OB_FAIL(fill_delete_unit_ptr_array(
                   pool, delete_unit_id_array, alter_unit_num, output_delete_unit_ptr_array))) {
      LOG_WARN("fail to fill delete unit id array", K(ret));
    } else if (output_delete_unit_ptr_array.count() <= 0) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("zone unit ptrs has no element", K(ret), "zone_unit_cnt", output_delete_unit_ptr_array.count());
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < output_delete_unit_ptr_array.count(); ++i) {
        const ObUnit* unit = output_delete_unit_ptr_array.at(i);
        if (OB_UNLIKELY(NULL == unit)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unit ptr is null", K(ret), KP(unit));
        } else if (OB_FAIL(ut_operator_.remove_unit(trans, *unit))) {
          LOG_WARN("fail to remove unit", K(ret), "unit", *unit);
        } else if (OB_FAIL(output_delete_unit_id_array.push_back(unit->unit_id_))) {
          LOG_WARN("fail to push back", K(ret));
        } else {
        }  // no more to do
      }
    }
    // however, we need to end this transaction
    const bool commit = (OB_SUCCESS == ret);
    int tmp_ret = OB_SUCCESS;
    if (OB_SUCCESS != (tmp_ret = trans.end(commit))) {
      LOG_WARN("trans end failed", K(tmp_ret), K(commit));
      ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
    }
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(delete_inmemory_units(pool->resource_pool_id_, output_delete_unit_id_array))) {
      LOG_WARN("fail to delete unit groups", K(ret));
    } else {
      pool->unit_count_ = alter_unit_num;
    }
  }
  return ret;
}

int ObUnitManager::check_shrink_granted_pool_allowed_by_migrate_unit(
    share::ObResourcePool* pool, const int64_t alter_unit_num, bool& is_allowed)
{
  int ret = OB_SUCCESS;
  UNUSED(alter_unit_num);
  is_allowed = true;
  common::ObArray<share::ObUnit*>* units = NULL;
  if (OB_UNLIKELY(NULL == pool || alter_unit_num <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(alter_unit_num));
  } else if (OB_FAIL(get_units_by_pool(pool->resource_pool_id_, units))) {
    LOG_WARN("fail to get units by pool", K(ret));
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unit ptr is null", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && is_allowed && i < units->count(); ++i) {
      const ObUnit* unit = units->at(i);
      if (OB_UNLIKELY(NULL == unit)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit ptr is null", K(ret), KP(unit));
      } else if (unit->migrate_from_server_.is_valid()) {
        is_allowed = false;
      } else {
      }  // unit not in migrating, check next
    }
  }
  return ret;
}

int ObUnitManager::check_all_pools_granted(const common::ObIArray<share::ObResourcePool*>& pools, bool& all_granted)
{
  int ret = OB_SUCCESS;
  all_granted = true;
  for (int64_t i = 0; all_granted && OB_SUCC(ret) && i < pools.count(); ++i) {
    if (NULL == pools.at(i)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pool ptr is null", K(ret), K(i));
    } else if (OB_INVALID_ID == pools.at(i)->tenant_id_) {
      all_granted = false;
    } else {
    }  // go on check next
  }
  return ret;
}

// alter 14x add the new locality F/L@ZONE;
// temporarily logonly_unit = 1 does not support scaling,
// so only the unit num of non-logonly_unit can be reduced;
// Here it is only judged whether the number of units on non-logonly_unit satisfies locality;
// The goal of this function is to determine whether the distribution of the current unit meets the requirements of
// locality check in two parts:
// 1. First check whether the logonly unit meets the requirements
// 2. second check whether the non-logonly unit meets the requirements
int ObUnitManager::do_check_shrink_granted_pool_allowed_by_locality(
    const common::ObIArray<share::ObResourcePool*>& pools, const common::ObIArray<common::ObZone>& schema_zone_list,
    const ZoneLocalityIArray& zone_locality, const ObIArray<int64_t>& new_unit_nums, bool& is_allowed)
{
  int ret = OB_SUCCESS;
  UNUSED(schema_zone_list);
  is_allowed = true;
  common::hash::ObHashMap<common::ObZone, UnitNum> zone_unit_num_map;
  const int64_t BUCKET_SIZE = 2 * MAX_ZONE_NUM;
  if (OB_UNLIKELY(pools.count() <= 0 || new_unit_nums.count() <= 0 || new_unit_nums.count() != pools.count())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(pools.count()), K(new_unit_nums.count()));
  } else if (OB_FAIL(zone_unit_num_map.create(BUCKET_SIZE, ObModIds::OB_RS_UNIT_MANAGER))) {
    LOG_WARN("fail to create map", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < pools.count(); ++i) {
      const int64_t pool_unit_num = new_unit_nums.at(i);
      const share::ObResourcePool* pool = pools.at(i);
      if (OB_UNLIKELY(nullptr == pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret));
      } else {
        const common::ObIArray<common::ObZone>& pool_zone_list = pool->zone_list_;
        for (int64_t j = 0; OB_SUCC(ret) && j < pool_zone_list.count(); ++j) {
          const common::ObZone& zone = pool_zone_list.at(j);
          const int32_t overwrite = 1;
          UnitNum unit_num_set;
          int tmp_ret = zone_unit_num_map.get_refactored(zone, unit_num_set);
          if (OB_SUCCESS == tmp_ret) {
            // bypass
          } else if (OB_HASH_NOT_EXIST == tmp_ret) {
            unit_num_set.reset();
          } else {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("fail to get from map", K(ret));
          }
          if (OB_FAIL(ret)) {
          } else if (REPLICA_TYPE_FULL == pool->replica_type_) {
            unit_num_set.full_unit_num_ += pool_unit_num;
          } else if (REPLICA_TYPE_LOGONLY == pool->replica_type_) {
            unit_num_set.logonly_unit_num_ += pool_unit_num;
          } else {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("pool replica type unexpected", K(ret), "pool", *pool);
          }
          if (OB_FAIL(ret)) {
          } else if (OB_FAIL(zone_unit_num_map.set_refactored(zone, unit_num_set, overwrite))) {
            LOG_WARN("fail to set map", K(ret));
          }
        }
      }
    }
    for (int64_t i = 0; is_allowed && OB_SUCC(ret) && i < zone_locality.count(); ++i) {
      const share::ObZoneReplicaAttrSet& zone_replica_attr = zone_locality.at(i);
      int64_t full_unit_num = 0;
      int64_t logonly_unit_num = 0;
      for (int64_t j = 0; OB_SUCC(ret) && j < zone_replica_attr.zone_set_.count(); ++j) {
        const common::ObZone& zone = zone_replica_attr.zone_set_.at(j);
        UnitNum unit_num_set;
        if (OB_FAIL(zone_unit_num_map.get_refactored(zone, unit_num_set))) {
          LOG_WARN("fail to get refactored", K(ret));
        } else {
          full_unit_num += unit_num_set.full_unit_num_;
          logonly_unit_num += unit_num_set.logonly_unit_num_;
        }
      }
      if (OB_SUCC(ret)) {
        const int64_t specific_num = zone_replica_attr.get_specific_replica_num();
        const int64_t except_l_specific_num = specific_num - zone_replica_attr.get_logonly_replica_num();
        const int64_t total_unit_num = full_unit_num + logonly_unit_num;
        is_allowed = (total_unit_num >= specific_num && full_unit_num >= except_l_specific_num);
      }
    }
  }
  return ret;
}

// Scaling also needs to consider the locality of the tenant or table under the tenant.
// There are several situations that need to be considered:
// 1 Although the resource pool has been granted to a tenant,
//   but the zone of the resource pool may not be in the tenant's zone list.
//   For example: tenant has two pools : pool1(z1,z2,z3),pool2(z4,z5,z6),
//                The locality of tenant is F@z1,F@z2,F@z3,F@z4,
//                tenant the zone_list is (z1, z2, z3, z4). In this case,
//                only z4 needs to be considered when shrinkg pool2 unit num.
// 2 The locality of the tenant may include zone locality and region locality.
//   For zone locality, it is only necessary to consider that
//   the unit num of the zone after scaling is not less than the number of copies of the locality in this zone.
// 3 For region locality,
//   it is necessary to satisfy that the sum of unit num of all zones in the region under
//   this tenant is not less than the number of locality replicas on the region.
//   For example: tenant has two pools, pool1(z1,z2) and pool2(z3,z4),
//                the current pool1_unit_num = 2, pool2_unit_num = 2,
//                where z1, z4 belong to region SH, z2, z3 belong to region HZ, and locality is
//                F{2},R{2}@SH,F{2},R{2}@HZ.
//   We try to compress the unit_num of pool2 to 1,
//   the total number of units in region SH after compression is 3,
//   and the total number of units in region HZ is 3,
//   which is not enough to accommodate the number of copies of locality.
//   Therefore, compressing the unit num of pool2 to 1 is not allowed.
// The specific implementation is to traverse each zone in the zone list of the resource pool:
// 1 The zone does not exist in the tenant's zone list, skip it directly;
// 2 The zone exists in the tenant's zone locality.
//  It is necessary to compare whether the compressed unit num is enough to accommodate
//  the number of locality replicas in the zone;
// 3 If the zone does not exist in the tenant's zone locality, save the unit num in the region_unit_num_container.
// 4 Save the zones of other resource pools under the tenant to the region zone container,
//  and compare whether the unit num is sufficient
int ObUnitManager::check_shrink_granted_pool_allowed_by_tenant_locality(
    share::schema::ObSchemaGetterGuard& schema_guard, const uint64_t tenant_id,
    const common::ObIArray<share::ObResourcePool*>& pools, const common::ObIArray<int64_t>& new_unit_nums,
    bool& is_allowed)
{
  int ret = OB_SUCCESS;
  const share::schema::ObTenantSchema* tenant_schema = NULL;
  common::ObArray<common::ObZone> tenant_zone_list;
  if (OB_UNLIKELY(OB_INVALID_ID == tenant_id)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id));
  } else if (OB_FAIL(schema_guard.get_tenant_info(tenant_id, tenant_schema))) {
    LOG_WARN("fail to get tenant info", K(ret), K(tenant_id));
  } else if (NULL == tenant_schema) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("tenant schema is null", K(ret), KP(tenant_schema));
  } else if (OB_FAIL(tenant_schema->get_zone_list(tenant_zone_list))) {
    LOG_WARN("fail to get zone list", K(ret));
  } else {
    ObArray<ObZoneReplicaNumSet> zone_locality;
    if (OB_FAIL(tenant_schema->get_zone_replica_attr_array(zone_locality))) {
      LOG_WARN("fail to assign", K(ret));
    } else if (OB_FAIL(do_check_shrink_granted_pool_allowed_by_locality(
                   pools, tenant_zone_list, zone_locality, new_unit_nums, is_allowed))) {
      LOG_WARN("fail to do check shrink by locality", K(ret));
    } else {
    }  // no more to do
  }
  return ret;
}

int ObUnitManager::filter_logonly_task(
    const common::ObIArray<share::ObResourcePool*>& pools, ObIArray<share::ObZoneReplicaNumSet>& zone_locality)
{
  int ret = OB_SUCCESS;
  ObArray<ObUnitInfo> unit_info;
  ObArray<ObZone> logonly_zone;
  ObArray<ObUnitInfo> tmp_unit_info;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  }

  for (int64_t i = 0; i < pools.count() && OB_SUCC(ret); i++) {
    tmp_unit_info.reset();
    if (REPLICA_TYPE_LOGONLY != pools.at(i)->replica_type_) {
      // nothing todo
    } else if (OB_FAIL(inner_get_unit_infos_of_pool(pools.at(i)->resource_pool_id_, tmp_unit_info))) {
      LOG_WARN("fail to get unit info", K(ret), K(i));
    } else {
      for (int64_t j = 0; j < tmp_unit_info.count() && OB_SUCC(ret); j++) {
        if (OB_FAIL(logonly_zone.push_back(tmp_unit_info.at(j).unit_.zone_))) {
          LOG_WARN("fail to push back", K(ret));
        }
      }
    }
  }

  for (int64_t i = 0; i < zone_locality.count() && OB_SUCC(ret); ++i) {
    share::ObZoneReplicaAttrSet& zone_replica_attr_set = zone_locality.at(i);
    if (zone_replica_attr_set.get_logonly_replica_num() <= 0) {
      // nothing todo
    } else if (zone_replica_attr_set.zone_set_.count() <= 0) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("zone set unexpected", K(ret), K(zone_replica_attr_set));
    } else {
      for (int64_t j = 0; j < logonly_zone.count(); j++) {
        const ObZone& zone = logonly_zone.at(j);
        if (!has_exist_in_array(zone_replica_attr_set.zone_set_, zone)) {
          // bypass
        } else if (zone_replica_attr_set.get_logonly_replica_num() <= 0) {
          // bypass
        } else {
          ret = zone_replica_attr_set.sub_logonly_replica_num(ReplicaAttr(1, 100));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::check_shrink_granted_pool_allowed_by_single_partition_locality(
    const share::schema::ObPartitionSchema& partition_schema, share::schema::ObSchemaGetterGuard& schema_guard,
    const common::ObIArray<share::ObResourcePool*>& pools, const common::ObIArray<int64_t>& new_unit_nums,
    bool& is_allowed)
{
  int ret = OB_SUCCESS;
  common::ObArray<common::ObZone> zone_list;
  common::ObArray<share::ObZoneReplicaNumSet> zone_locality;
  if (OB_FAIL(partition_schema.get_zone_list(schema_guard, zone_list))) {
    LOG_WARN("fail to get zone list", K(ret));
  } else if (OB_FAIL(partition_schema.get_zone_replica_attr_array_inherit(schema_guard, zone_locality))) {
    LOG_WARN("fail to get zone locality", K(ret));
  } else if (OB_FAIL(do_check_shrink_granted_pool_allowed_by_locality(
                 pools, zone_list, zone_locality, new_unit_nums, is_allowed))) {
    LOG_WARN("fail to do check shrink by locality", K(ret));
  } else {
  }  // no more to do
  return ret;
}

int ObUnitManager::check_shrink_granted_pool_allowed_by_partition_locality(
    share::schema::ObSchemaGetterGuard& schema_guard, const uint64_t tenant_id,
    const common::ObIArray<share::ObResourcePool*>& pools, const common::ObIArray<int64_t>& new_unit_nums,
    bool& is_allowed)
{
  int ret = OB_SUCCESS;
  is_allowed = true;
  common::ObArray<const share::schema::ObPartitionSchema*> partition_schemas;
  if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool do not grant to any tenant", K(ret), K(tenant_id));
  } else if (OB_FAIL(
                 ObPartMgrUtils::get_partition_entity_schemas_in_tenant(schema_guard, tenant_id, partition_schemas))) {
    LOG_WARN("fail to get table schemas of tenant", K(ret), K(tenant_id));
  } else {
    for (int64_t i = 0; is_allowed && OB_SUCC(ret) && i < partition_schemas.count(); ++i) {
      const share::schema::ObPartitionSchema* simple_schema = partition_schemas.at(i);
      if (OB_UNLIKELY(NULL == simple_schema)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("table schema is null", K(ret), KP(simple_schema));
      } else if (!simple_schema->has_self_partition()) {
        // table has not partitions, ignore it
      } else if (simple_schema->get_locality_str().empty()) {
        // table locality is empty, derived from tenant, ignore it
      } else if (OB_FAIL(check_shrink_granted_pool_allowed_by_single_partition_locality(
                     *simple_schema, schema_guard, pools, new_unit_nums, is_allowed))) {
        LOG_WARN("fail to check shrink by single table", K(ret));
      } else {
      }  // no more to do
    }
  }
  return ret;
}

int ObUnitManager::get_newest_schema_guard_in_inner_table(
    const uint64_t tenant_id, share::schema::ObSchemaGetterGuard& schema_guard)
{
  int ret = OB_SUCCESS;
  int64_t version_in_inner_table = OB_INVALID_VERSION;
  ObRefreshSchemaStatus schema_status;
  schema_status.tenant_id_ = tenant_id;
  ObSchemaStatusProxy* schema_status_proxy = GCTX.schema_status_proxy_;
  if (OB_UNLIKELY(NULL == proxy_ || NULL == schema_service_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("proxy_ or schema_service_ ptr null", K(ret), KP(proxy_), KP(schema_service_));
  } else if (OB_ISNULL(schema_status_proxy)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("schema_status_proxy is null", K(ret));
  } else if (GCTX.is_standby_cluster() &&
             OB_FAIL(schema_status_proxy->get_refresh_schema_status(tenant_id, schema_status))) {
    LOG_WARN("fail to get refresh schema status", K(ret), K(tenant_id));
  } else if (OB_FAIL(
                 schema_service_->get_schema_version_in_inner_table(*proxy_, schema_status, version_in_inner_table))) {
    LOG_WARN("fail to get latest schema version in inner table", K(ret), K(schema_status));
  } else if (OB_FAIL(schema_service_->get_tenant_schema_guard(tenant_id, schema_guard, version_in_inner_table))) {
    if (OB_SCHEMA_EAGAIN == ret) {
      int t_ret = OB_SUCCESS;
      ObArray<uint64_t> tenant_ids;
      if (OB_SUCCESS != (t_ret = tenant_ids.push_back(tenant_id))) {
        LOG_WARN("fail to push back tenant_id", K(t_ret), K(tenant_id));
      } else if (OB_SUCCESS != (t_ret = schema_service_->refresh_and_add_schema(tenant_ids))) {
        LOG_WARN("fail to refresh and add schema", K(t_ret), K(tenant_id));
      }
      LOG_INFO("need retry as local schema is not latest", K(ret), K(tenant_id), K(version_in_inner_table));
    } else {
      ret = OB_ERR_UNEXPECTED;
      LOG_ERROR("get schema manager failed!", K(ret));
    }
  }
  return ret;
}

//  Currently supports tenant-level and table-level locality,
//  and check shrinkage needs to be checked at the same time two levels of locality, tenant and table.
//  1 The tenant level is more intuitive.
//    directly compare the zone/region locality involved with the reduced unit num.
//  2 Three situations need to be considered at the table level:
//    2.1 Virtual tables, index tables, etc. without entity partitions, ignore them
//    2.2 The table with entity partition whose table locality is empty,
//        inherited from tenant, has been checked, and skipped;
//    2.3 Tables with entity partitions whose table locality is not empty are checked according to table locality
int ObUnitManager::check_shrink_granted_pool_allowed_by_locality(
    share::ObResourcePool* pool, const int64_t alter_unit_num, bool& is_allowed)
{
  int ret = OB_SUCCESS;
  share::schema::ObSchemaGetterGuard schema_guard;
  const share::schema::ObTenantSchema* tenant_schema = NULL;
  common::ObArray<share::ObResourcePool*>* pool_list = nullptr;
  common::ObArray<share::ObResourcePool*> new_pool_list;
  common::ObArray<int64_t> new_unit_nums;
  if (OB_UNLIKELY(NULL == pool || alter_unit_num <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(alter_unit_num));
  } else if (OB_FAIL(get_newest_schema_guard_in_inner_table(pool->tenant_id_, schema_guard))) {
    LOG_WARN("fail to get schema guard", K(ret));
  } else if (OB_FAIL(schema_guard.get_tenant_info(pool->tenant_id_, tenant_schema))) {
    LOG_WARN("fail to get tenant info", K(ret), "tenant_id", pool->tenant_id_);
  } else if (OB_UNLIKELY(NULL == tenant_schema)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("tenant schema is null", K(ret), KP(tenant_schema));
  } else if (OB_FAIL(get_pools_by_tenant(tenant_schema->get_tenant_id(), pool_list))) {
    LOG_WARN("fail to get pools by tenant", K(ret));
  } else if (OB_UNLIKELY(nullptr == pool_list)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool list ptr is null", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < pool_list->count(); ++i) {
      share::ObResourcePool* this_pool = pool_list->at(i);
      if (OB_UNLIKELY(nullptr == this_pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("this pool ptr is null", K(ret));
      } else if (OB_FAIL(new_pool_list.push_back(this_pool))) {
        LOG_WARN("fail to to push back", K(ret));
      } else if (OB_FAIL(new_unit_nums.push_back(this_pool->resource_pool_id_ == pool->resource_pool_id_
                                                     ? alter_unit_num
                                                     : this_pool->unit_count_))) {
        LOG_WARN("fail to push back", K(ret));
      }
    }
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(check_shrink_granted_pool_allowed_by_tenant_locality(
                   schema_guard, pool->tenant_id_, new_pool_list, new_unit_nums, is_allowed))) {
      LOG_WARN("fail to check shrink by tenant locality", K(ret));
    } else if (!is_allowed) {
      // no need to check any more
    } else if (OB_FAIL(check_shrink_granted_pool_allowed_by_partition_locality(
                   schema_guard, pool->tenant_id_, new_pool_list, new_unit_nums, is_allowed))) {
      LOG_WARN("fail to check shrink by table locality", K(ret));
    } else {
    }  // no more to do
  }
  return ret;
}

int ObUnitManager::check_shrink_granted_pool_allowed_by_alter_locality(share::ObResourcePool* pool, bool& is_allowed)
{
  int ret = OB_SUCCESS;
  rootserver::ObRootService* root_service = NULL;
  bool in_alter_locality = true;
  if (OB_UNLIKELY(NULL == pool)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool));
  } else if (OB_UNLIKELY(OB_INVALID_ID == pool->tenant_id_)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid tenant id", K(ret), "tenant_id", pool->tenant_id_);
  } else if (OB_UNLIKELY(NULL == (root_service = GCTX.root_service_))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("rootservice is null", K(ret));
  } else if (OB_FAIL(root_service->check_tenant_in_alter_locality(pool->tenant_id_, in_alter_locality))) {
    LOG_WARN("fail to check tenant in alter locality", K(ret), "tenant_id", pool->tenant_id_);
  } else if (in_alter_locality) {
    is_allowed = false;
    LOG_USER_ERROR(OB_OP_NOT_ALLOW, "shrink pool unit num while altering locality");
  } else {
  }  // no more to do
  return ret;
}

//  The shrinking operation of the granted resource pool requires the following pre-checks
//  1 The design avoids simultaneous migration and shrinkage of units.
//    Therefore, it is necessary to check whether all the units contained in the current resource pool are in the
//    migration state before shrinking. If so, shrinking operations are temporarily not allowed, and the migration needs
//    to be completed.
//  2 The scaling operation also needs to consider locality.
//    The number of copies of locality cannot exceed the number of units after scaling.
//    For example, when the locality is F, R@zone1, the unit num in zone1 cannot be reduced to 1.
//  3 Locality changes and scaling under the same tenant are not allowed to be performed at the same time
int ObUnitManager::check_shrink_granted_pool_allowed(
    share::ObResourcePool* pool, const int64_t alter_unit_num, bool& is_allowed)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(NULL == pool || alter_unit_num <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(alter_unit_num));
  } else if (OB_GTS_TENANT_ID == pool->tenant_id_) {
    is_allowed = true;
  } else if (OB_FAIL(check_shrink_granted_pool_allowed_by_migrate_unit(pool, alter_unit_num, is_allowed))) {
    LOG_WARN("fail to check by migrate unit", K(ret));
  } else if (!is_allowed) {
    LOG_USER_ERROR(OB_OP_NOT_ALLOW, "shrink pool unit num while unit migrating");
  } else if (OB_FAIL(check_shrink_granted_pool_allowed_by_locality(pool, alter_unit_num, is_allowed))) {
    LOG_WARN("fail to check by locality", K(ret));
  } else if (!is_allowed) {
    LOG_USER_ERROR(OB_OP_NOT_ALLOW, "shrink pool unit num causing not enough locality");
  } else if (OB_FAIL(check_shrink_granted_pool_allowed_by_alter_locality(pool, is_allowed))) {
    LOG_WARN("fail to check shrink granted pool allowed by alter locality", K(ret));
  } else if (!is_allowed) {
    LOG_USER_ERROR(OB_OP_NOT_ALLOW, "shrink pool unit num while altering locality");
  }
  return ret;
}

int ObUnitManager::register_shrink_pool_unit_num_rs_job(const uint64_t resource_pool_id, const uint64_t tenant_id,
    const int64_t new_unit_num, common::ObMySQLTransaction& trans)
{
  int ret = OB_SUCCESS;
  int64_t pos = 0;
  const int64_t extra_info_len = common::MAX_ROOTSERVICE_EVENT_EXTRA_INFO_LENGTH;
  char extra_info[common::MAX_ROOTSERVICE_EVENT_EXTRA_INFO_LENGTH] = {0};
  if (OB_SUCCESS != (ret = databuff_printf(extra_info, extra_info_len, pos, "new_unit_num: %ld", new_unit_num))) {
    if (OB_SIZE_OVERFLOW == ret) {
      LOG_WARN("format to buff size overflow", K(ret));
    } else {
      LOG_WARN("format new unit num failed", K(ret));
    }
  }
  if (OB_SUCC(ret)) {
    int64_t job_id = RS_JOB_CREATE(SHRINK_RESOURCE_POOL_UNIT_NUM,
        trans,
        "resource_pool_id",
        resource_pool_id,
        "tenant_id",
        tenant_id,
        "extra_info",
        extra_info);
    if (job_id < 1) {
      ret = OB_SQL_OPT_ERROR;
      LOG_WARN("insert into all_rootservice_job failed", K(ret));
    }
  }
  return ret;
}

int ObUnitManager::rollback_shrink_pool_unit_num_rs_job(
    const uint64_t resource_pool_id, const uint64_t tenant_id, common::ObMySQLTransaction& trans)
{
  ObRsJobInfo job_info;
  int ret = RS_JOB_FIND(job_info,
      trans,
      "job_type",
      "SHRINK_RESOURCE_POOL_UNIT_NUM",
      "job_status",
      "INPROGRESS",
      "resource_pool_id",
      resource_pool_id,
      "tenant_id",
      tenant_id);
  if (OB_SUCC(ret) && job_info.job_id_ > 0) {
    if (OB_FAIL(RS_JOB_COMPLETE(job_info.job_id_, -1, trans))) {  // Roll back, this shrink failed
      LOG_WARN("update all_rootservice_job failed", K(ret), K(job_info));
    }
  } else {
    LOG_WARN("failed to find rs job", K(ret), "tenant_id", tenant_id);
  }
  return ret;
}

int ObUnitManager::complete_shrink_pool_unit_num_rs_job(
    const uint64_t resource_pool_id, const uint64_t tenant_id, common::ObMySQLTransaction& trans)

{
  ObRsJobInfo job_info;
  int ret = RS_JOB_FIND(job_info,
      trans,
      "job_type",
      "SHRINK_RESOURCE_POOL_UNIT_NUM",
      "job_status",
      "INPROGRESS",
      "resource_pool_id",
      resource_pool_id,
      "tenant_id",
      tenant_id);
  if (OB_SUCC(ret) && job_info.job_id_ > 0) {
    if (OB_FAIL(RS_JOB_COMPLETE(job_info.job_id_, 0, trans))) {  // job success
      LOG_WARN("update all_rootservice_job failed", K(ret), K(job_info));
    }
  } else {
    LOG_WARN("failed to find rs job", K(ret), "tenant_id" K(tenant_id));
  }
  return ret;
}
int ObUnitManager::complete_migrate_unit_rs_job_in_pool(
    const int64_t resource_pool_id, const int result_ret, common::ObMySQLTransaction& trans)
{
  int ret = OB_SUCCESS;
  ObArray<ObUnit*>* units = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == resource_pool_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(resource_pool_id), K(ret));
  } else if (OB_FAIL(get_units_by_pool(resource_pool_id, units))) {
    LOG_WARN("fail to get unit by pool", K(resource_pool_id), K(ret));
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units is null", KP(units), K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
      const ObUnit* unit = units->at(i);
      if (OB_UNLIKELY(NULL == unit)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit should not be null", K(ret));
      } else if (unit->is_manual_migrate()) {
        char ip_buf[common::MAX_IP_ADDR_LENGTH];
        (void)unit->server_.ip_to_string(ip_buf, common::MAX_IP_ADDR_LENGTH);
        ObRsJobInfo job_info;
        int tmp_ret = RS_JOB_FIND(job_info,
            *proxy_,
            "job_type",
            "MIGRATE_UNIT",
            "job_status",
            "INPROGRESS",
            "unit_id",
            unit->unit_id_,
            "svr_ip",
            ip_buf,
            "svr_port",
            unit->server_.get_port());
        if (OB_SUCCESS == tmp_ret && job_info.job_id_ > 0) {
          if (OB_FAIL(RS_JOB_COMPLETE(job_info.job_id_, result_ret, trans))) {
            LOG_WARN("all_rootservice_job update failed", K(ret), K(result_ret), K(job_info));
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::shrink_granted_pool(
    share::ObResourcePool* pool, const int64_t alter_unit_num, const common::ObIArray<uint64_t>& delete_unit_id_array)
{
  int ret = OB_SUCCESS;
  common::ObMySQLTransaction trans;
  bool is_allowed = true;
  if (OB_UNLIKELY(NULL == pool || alter_unit_num <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(alter_unit_num));
  } else if (OB_INVALID_ID == pool->tenant_id_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool not grant to any tenant", K(ret), "tenant_id", pool->tenant_id_);
  } else if (pool->unit_count_ <= alter_unit_num) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN(
        "should be a shrink pool operation", K(ret), "cur_unit_num", pool->unit_count_, "new_unit_num", alter_unit_num);
  } else if (OB_FAIL(check_shrink_granted_pool_allowed(pool, alter_unit_num, is_allowed))) {
    LOG_WARN("fail to check shrink granted pool allowed", K(ret), "pool", *pool, K(alter_unit_num));
  } else if (!is_allowed) {
    ret = OB_OP_NOT_ALLOW;
    LOG_WARN("shrink granted pool is not allowed", K(ret), "pool", *pool);
  } else if (OB_FAIL(trans.start(proxy_))) {
    LOG_WARN("start transaction failed", K(ret));
  } else if (OB_FAIL(register_shrink_pool_unit_num_rs_job(
                 pool->resource_pool_id_, pool->tenant_id_, alter_unit_num, trans))) {
    LOG_WARN("do rs_job failed ", K(ret));
  } else {
    common::ObArray<ObUnit*> output_delete_unit_ptr_array;
    share::ObResourcePool new_pool;
    if (OB_FAIL(new_pool.assign(*pool))) {
      LOG_WARN("fail to assign new pool", K(ret));
    } else {
      new_pool.unit_count_ = alter_unit_num;
    }
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(ut_operator_.update_resource_pool(trans, new_pool))) {
      LOG_WARN("fail to update resource pool", K(ret));
    } else if (OB_FAIL(check_shrink_unit_num_zone_condition(pool, alter_unit_num, delete_unit_id_array))) {
      LOG_WARN("fail to check shrink unit num zone condition", K(ret));
    } else if (OB_FAIL(fill_delete_unit_ptr_array(
                   pool, delete_unit_id_array, alter_unit_num, output_delete_unit_ptr_array))) {
      LOG_WARN("fail to fill delete unit id array", K(ret));
    } else if (output_delete_unit_ptr_array.count() <= 0) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("zone unit ptrs has no element", K(ret), "zone_unit_cnt", output_delete_unit_ptr_array.count());
    } else if (OB_FAIL(check_unit_can_migrate(pool->tenant_id_, is_allowed))) {
      LOG_WARN("fail to check shrink_unit can migrate", K(ret));
    } else if (!is_allowed) {
      ret = OB_OP_NOT_ALLOW;
      LOG_USER_ERROR(OB_OP_NOT_ALLOW, "shrink pool unit num but unit can't migrate");
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < output_delete_unit_ptr_array.count(); ++i) {
        const ObUnit* unit = output_delete_unit_ptr_array.at(i);
        if (OB_UNLIKELY(NULL == unit)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unit ptr is null", K(ret), KP(unit), K(i));
        } else {
          ObUnit new_unit = *unit;
          new_unit.status_ = ObUnit::UNIT_STATUS_DELETING;
          if (OB_FAIL(ut_operator_.update_unit(trans, new_unit))) {
            LOG_WARN("fail to update unit", K(ret), K(new_unit));
          } else {
          }  // no more to do
        }
      }
    }
    // however, we need to end this transaction
    const bool commit = (OB_SUCCESS == ret);
    int tmp_ret = OB_SUCCESS;
    if (OB_SUCCESS != (tmp_ret = trans.end(commit))) {
      LOG_WARN("trans end failed", K(tmp_ret), K(commit));
      ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
    }
    if (OB_FAIL(ret)) {
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < output_delete_unit_ptr_array.count(); ++i) {
        ObUnit* unit = output_delete_unit_ptr_array.at(i);
        if (OB_UNLIKELY(NULL == unit)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unit ptr is null", K(ret));
        } else {
          unit->status_ = ObUnit::UNIT_STATUS_DELETING;
        }
      }
      if (OB_SUCC(ret)) {
        pool->unit_count_ = alter_unit_num;
      }
    }
  }
  return ret;
}

// Roll back the pool shrinkage and directly adjust the unit num and unit status of the resource pool to active.
int ObUnitManager::rollback_shrink_pool_unit_num(share::ObResourcePool* pool, const int64_t alter_unit_num)
{
  int ret = OB_SUCCESS;
  common::ObArray<share::ObUnit*>* units = NULL;
  common::ObMySQLTransaction trans;
  if (OB_UNLIKELY(NULL == pool || alter_unit_num <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(alter_unit_num));
  } else if (OB_FAIL(trans.start(proxy_))) {
    LOG_WARN("start transaction failed", K(ret));
  } else if (OB_FAIL(rollback_shrink_pool_unit_num_rs_job(pool->resource_pool_id_, pool->tenant_id_, trans))) {
    LOG_WARN("rollback rs_job failed ", K(ret));
  } else {
    if (OB_FAIL(get_units_by_pool(pool->resource_pool_id_, units))) {
      LOG_WARN("failt to get units by pool", K(ret), "pool_id", pool->resource_pool_id_);
    } else if (OB_UNLIKELY(NULL == units)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("units is null", K(ret), KP(units), "pool_id", pool->resource_pool_id_);
    } else if (units->count() <= 0) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("total unit num unexpected", K(ret));
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
        const ObUnit* this_unit = units->at(i);
        if (OB_UNLIKELY(NULL == this_unit)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unit ptr is null", K(ret));
        } else if (ObUnit::UNIT_STATUS_ACTIVE == this_unit->status_) {
          // go and process the unit in deleting
        } else if (ObUnit::UNIT_STATUS_DELETING == this_unit->status_) {
          ObUnit new_unit = *this_unit;
          new_unit.status_ = ObUnit::UNIT_STATUS_ACTIVE;
          if (OB_FAIL(ut_operator_.update_unit(trans, new_unit))) {
            LOG_WARN("fail to update unit", K(ret), K(new_unit), "cur_unit", *this_unit);
          }
        } else {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unexpected unit status", K(ret), "unit", *this_unit);
        }
      }
      if (OB_SUCC(ret)) {
        share::ObResourcePool new_pool;
        if (OB_FAIL(new_pool.assign(*pool))) {
          LOG_WARN("fail to assign new pool", K(ret));
        } else {
          new_pool.unit_count_ = alter_unit_num;
          if (OB_FAIL(ut_operator_.update_resource_pool(trans, new_pool))) {
            LOG_WARN("update resource pool failed", K(new_pool), K(ret));
          }
        }
      }
      const bool commit = (OB_SUCCESS == ret);
      int tmp_ret = OB_SUCCESS;
      if (OB_SUCCESS != (tmp_ret = trans.end(commit))) {
        LOG_WARN("trans end failed", K(commit), K(tmp_ret));
        ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
      }

      if (OB_SUCC(ret)) {
        for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
          ObUnit* this_unit = units->at(i);
          if (OB_UNLIKELY(NULL == this_unit)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unit ptr is null", K(ret), KP(this_unit));
          } else if (ObUnit::UNIT_STATUS_ACTIVE == this_unit->status_) {
            // go and process the unit in deleting
          } else if (ObUnit::UNIT_STATUS_DELETING == this_unit->status_) {
            this_unit->status_ = ObUnit::UNIT_STATUS_ACTIVE;
          } else {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unexpected unit status", K(ret), "unit", *this_unit);
          }
        }
        if (OB_SUCC(ret)) {
          pool->unit_count_ = alter_unit_num;
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::expend_pool_unit_num(share::ObResourcePool* pool, const int64_t alter_unit_num)
{
  int ret = OB_SUCCESS;
  const bool new_allocate_pool = false;
  common::ObMySQLTransaction trans;
  ObArray<ObAddr> new_servers;
  ObArray<share::ObUnit*>* units = NULL;
  ObArray<uint64_t> bak_unit_ids;
  if (OB_UNLIKELY(NULL == pool || alter_unit_num <= pool->unit_count_)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool ptr is null", K(ret), "pre_unit_cnt", pool->unit_count_, "cur_unit_cnt", alter_unit_num);
  } else if (OB_FAIL(trans.start(proxy_))) {
    LOG_WARN("start transaction failed", K(ret));
  } else if (OB_FAIL(get_units_by_pool(pool->resource_pool_id_, units))) {
    LOG_WARN("fail to get units by pool", K(ret));
  } else if (OB_FAIL(extract_unit_ids(*units, bak_unit_ids))) {
    LOG_WARN("fail to extract unit ids", K(ret));
  } else if (OB_FAIL(allocate_unit_groups(
                 trans, *pool, new_allocate_pool, alter_unit_num - pool->unit_count_, new_servers))) {
    LOG_WARN("arrange units failed", "pool", *pool, K(new_allocate_pool), K(ret));
  } else {
    share::ObResourcePool new_pool;
    if (OB_FAIL(new_pool.assign(*pool))) {
      LOG_WARN("failed to assign new_poll", K(ret));
    } else {
      new_pool.unit_count_ = alter_unit_num;
      if (OB_FAIL(ut_operator_.update_resource_pool(trans, new_pool))) {
        LOG_WARN("update_resource_pool failed", K(new_pool), K(ret));
      }
    }
  }

  if (trans.is_started()) {
    const bool commit = (OB_SUCC(ret));
    int temp_ret = OB_SUCCESS;
    if (OB_SUCCESS != (temp_ret = trans.end(commit))) {
      LOG_WARN("trans end failed", K(commit), K(temp_ret));
      ret = (OB_SUCCESS == ret) ? temp_ret : ret;
    }
  }

  if (OB_FAIL(ret)) {
    // avoid overwrite ret
    int64_t temp_ret = OB_SUCCESS;
    if (OB_SUCCESS != (temp_ret = delete_invalid_inmemory_units(pool->resource_pool_id_, bak_unit_ids))) {
      LOG_WARN("delete unit groups failed", "resource pool id", pool->resource_pool_id_, K(temp_ret));
    }
  } else {
    pool->unit_count_ = alter_unit_num;
  }
  return ret;
}

int ObUnitManager::get_pool_complete_unit_num_and_status(
    share::ObResourcePool* pool, int64_t& unit_num_per_zone, bool& has_unit_num_modification)
{
  int ret = OB_SUCCESS;
  common::ObArray<share::ObUnit*>* units = NULL;
  if (OB_UNLIKELY(NULL == pool)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool is null", K(ret));
  } else if (OB_FAIL(get_units_by_pool(pool->resource_pool_id_, units))) {
    LOG_WARN("fail to get units by pool", K(ret), "pool_id", pool->resource_pool_id_);
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units is null", K(ret), KP(units), "pool_id", pool->resource_pool_id_);
  } else if (units->count() <= 0) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("total unit num unexpected", K(ret), "total_unit_num", units->count());
  } else if (pool->zone_list_.count() <= 0) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool zone list count unexpected", K(ret), "pool_zone_list_count", pool->zone_list_.count());
  } else {
    int64_t total_unit_cnt = units->count();
    int64_t zone_cnt = pool->zone_list_.count();
    int64_t consult = total_unit_cnt / zone_cnt;
    if (total_unit_cnt != consult * zone_cnt) {
      // total_unit_cnt cannot be divisible by zone_cnt,
      // the number of units in each zone of the resource pool is inconsistent
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unexpected total unit cnt", K(ret), K(zone_cnt), K(total_unit_cnt));
    } else {
      unit_num_per_zone = consult;
      has_unit_num_modification = false;
      for (int64_t i = 0; OB_SUCC(ret) && i < units->count() && !has_unit_num_modification; ++i) {
        const ObUnit* this_unit = units->at(i);
        if (OB_UNLIKELY(NULL == this_unit)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unit ptr is null", K(ret), KP(this_unit));
        } else if (ObUnit::UNIT_STATUS_ACTIVE == this_unit->status_) {
          // an active unit, go and check next
        } else if (ObUnit::UNIT_STATUS_DELETING == this_unit->status_) {
          has_unit_num_modification = true;
        } else {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unexpected unit status", K(ret), "unit_status", this_unit->status_);
        }
      }
    }
  }
  return ret;
}

// According to the unit num of the current resource pool
// and the unit_num(alter_unit_num) of the resource pool after the change,
// the change type of the current operation is determined.
// Let the current num be cur_unit_num, and the num after the change should be alter_unit_num.
// The principle is as follows:
// 1 cur_unit_num == alter_unit_num, no change, means no operation, no modification
// 2 cur_unit_num <alter_unit_num, and there is currently no modification operation of the resource pool and no other
// unit num,
//   which is considered to be an expansion operation.
// 3 cur_unit_num <alter_unit_num, and the resource pool is shrinking,
//   the unit_num before shrinking is prev_unit_num,
//   and alter_unit_num is equal to prev_unit_num,
//   which is considered to be a shrinking rollback operation.
// 4 cur_unit_num> alter_unit_num, and the resource pool has not performed other unit num modification operations,
//   which is considered to be a shrinking operation
int ObUnitManager::determine_alter_unit_num_type(
    share::ObResourcePool* pool, const int64_t alter_unit_num, AlterUnitNumType& alter_unit_num_type)
{
  int ret = OB_SUCCESS;
  int64_t complete_unit_num_per_zone = 0;  // Contains the unit in the delete state
  bool has_unit_num_modification = true;
  if (OB_UNLIKELY(NULL == pool)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool is null", K(ret));
  } else if (alter_unit_num == pool->unit_count_) {
    alter_unit_num_type = AUN_NOP;  // do nothing
  } else if (OB_FAIL(
                 get_pool_complete_unit_num_and_status(pool, complete_unit_num_per_zone, has_unit_num_modification))) {
    LOG_WARN("fail to get pool complete unit num and status", K(ret));
  } else if (OB_UNLIKELY(complete_unit_num_per_zone <= 0)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected complete_unit_num", K(ret), K(complete_unit_num_per_zone));
  } else {
    if (has_unit_num_modification) {  // A unit num change is taking place
      if (alter_unit_num == complete_unit_num_per_zone) {
        alter_unit_num_type = AUN_ROLLBACK_SHRINK;
      } else {
        alter_unit_num_type = AUN_MAX;
      }
    } else {
      if (alter_unit_num > pool->unit_count_) {
        alter_unit_num_type = AUN_EXPEND;
      } else if (alter_unit_num < pool->unit_count_) {
        alter_unit_num_type = AUN_SHRINK;
      } else {
        alter_unit_num_type = AUN_NOP;
      }
    }
  }
  if (OB_SUCC(ret) && GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_1460) {
    if (AUN_SHRINK == alter_unit_num_type || AUN_ROLLBACK_SHRINK == alter_unit_num_type) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN("shrink pool unit num is not supported during upgrading to 1.4.6");
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "shrink pool unit num during upgrading to 1.4.6");
    }
  }
  return ret;
}

int ObUnitManager::alter_pool_unit_num(
    share::ObResourcePool* pool, int64_t alter_unit_num, const common::ObIArray<uint64_t>& delete_unit_id_array)
{
  int ret = OB_SUCCESS;
  AlterUnitNumType alter_unit_num_type = AUN_MAX;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (NULL == pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool is null", K(ret));
  } else if (alter_unit_num <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid alter_unit_num", K(alter_unit_num), K(ret));
  } else if (OB_FAIL(determine_alter_unit_num_type(pool, alter_unit_num, alter_unit_num_type))) {
    LOG_WARN("fail to determine alter unit num type", K(ret));
  } else if (AUN_NOP == alter_unit_num_type) {
    // do nothing
    if (delete_unit_id_array.count() > 0) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN("do not support deleting unit without unit num changed", K(ret));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "delete unit without unit num change");
    } else {
    }  // good
  } else if (AUN_EXPEND == alter_unit_num_type) {
    if (delete_unit_id_array.count() > 0) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN("do not support expand pool unit num combined with deleting unit", K(ret));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "expand pool unit num combined with deleting unit");
    } else if (OB_FAIL(expend_pool_unit_num(pool, alter_unit_num))) {
      LOG_WARN("fail to expend pool unit num", K(ret), K(alter_unit_num));
    }
  } else if (AUN_SHRINK == alter_unit_num_type) {
    if (OB_FAIL(shrink_pool_unit_num(pool, alter_unit_num, delete_unit_id_array))) {
      LOG_WARN("fail to shrink pool unit num", K(ret), K(alter_unit_num));
    }
  } else if (AUN_ROLLBACK_SHRINK == alter_unit_num_type) {
    if (delete_unit_id_array.count() > 0) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN("do not support rollback shrink pool unit num combined with deleting unit", K(ret));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "rollback shrink pool unit num combined with deleting unit");
    } else if (OB_FAIL(rollback_shrink_pool_unit_num(pool, alter_unit_num))) {
      LOG_WARN("fail to rollbakc shrink pool unit num", K(ret), K(alter_unit_num));
    }
  } else if (AUN_MAX == alter_unit_num_type) {
    ret = OB_OP_NOT_ALLOW;
    LOG_USER_ERROR(OB_OP_NOT_ALLOW, "alter unit num while the previous operation is in progress");
    LOG_WARN("alter unit num not allowed", K(ret));
  } else {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected alter unit num type", K(ret), K(alter_unit_num_type));
  }
  if (OB_FAIL(ret)) {
  } else if ((AUN_SHRINK == alter_unit_num_type || AUN_ROLLBACK_SHRINK == alter_unit_num_type) &&
             OB_INVALID_ID != pool->tenant_id_) {
    obrpc::ObAdminClearBalanceTaskArg::TaskType type = obrpc::ObAdminClearBalanceTaskArg::ALL;
    if (NULL == GCTX.root_service_) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("root service null", K(ret));
    } else if (OB_FAIL(GCTX.root_service_->get_rebalance_task_mgr().clear_task(pool->tenant_id_, type))) {
      LOG_WARN("fail to flush task", K(ret));
    } else {
    }  // no more to do
  } else {
  }  // no need to flush task
  return ret;
}

int ObUnitManager::get_zone_pools_unit_num(const common::ObZone& zone,
    const common::ObIArray<share::ObResourcePoolName>& new_pool_name_list, int64_t& total_unit_num,
    int64_t& full_unit_num, int64_t& logonly_unit_num)
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(ret));
  } else if (zone.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(zone));
  } else {
    common::ObArray<share::ObResourcePool*> pool_list;
    for (int64_t i = 0; OB_SUCC(ret) && i < new_pool_name_list.count(); ++i) {
      const share::ObResourcePoolName& pool_name = new_pool_name_list.at(i);
      share::ObResourcePool* pool = NULL;
      if (OB_FAIL(inner_get_resource_pool_by_name(pool_name, pool))) {
        LOG_WARN("fail to get resource pool by name", K(ret));
      } else if (OB_UNLIKELY(NULL == pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret), K(pool_name));
      } else if (OB_FAIL(pool_list.push_back(pool))) {
        LOG_WARN("fail to push back", K(ret));
      } else {
      }  // no more to do
    }
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(
                   inner_get_zone_pools_unit_num(zone, pool_list, total_unit_num, full_unit_num, logonly_unit_num))) {
      LOG_WARN("fail to inner get pools unit num", K(ret));
    }
  }
  return ret;
}

int ObUnitManager::check_can_remove_pool_zone_list(
    const share::ObResourcePool* pool, const common::ObIArray<common::ObZone>& to_be_removed_zones, bool& can_remove)
{
  int ret = OB_SUCCESS;
  can_remove = true;
  common::ObArray<share::ObResourcePool*>* pool_list = NULL;
  share::schema::ObSchemaGetterGuard schema_guard;
  const share::schema::ObTenantSchema* tenant_schema = NULL;
  common::ObArray<const share::schema::ObPartitionSchema*> partition_schemas;
  if (OB_UNLIKELY(NULL == pool) || OB_UNLIKELY(to_be_removed_zones.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(to_be_removed_zones));
  } else if (OB_INVALID_ID == pool->tenant_id_) {
    can_remove = true;  // this pool do not grant to any tenant, can remove zone unit
  } else if (OB_FAIL(get_pools_by_tenant(pool->tenant_id_, pool_list))) {
    LOG_WARN("fail to get pools by tenant", K(ret));
  } else if (OB_UNLIKELY(NULL == pool_list)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool list ptr is null", K(ret));
  } else if (OB_FAIL(get_newest_schema_guard_in_inner_table(pool->tenant_id_, schema_guard))) {
    LOG_WARN("fail to get schema guard", K(ret));
  } else if (OB_FAIL(schema_guard.get_tenant_info(pool->tenant_id_, tenant_schema))) {
    LOG_WARN("fail to get tenant schema", K(ret), "tenant_id", pool->tenant_id_);
  } else if (NULL == tenant_schema) {
    ret = OB_TENANT_NOT_EXIST;
    LOG_WARN("tenant schema is null", K(ret));
  } else if (!tenant_schema->get_previous_locality_str().empty()) {
    can_remove = false;
    LOG_WARN(
        "alter pool zone list is not allowed while locality modification", "tenant_id", tenant_schema->get_tenant_id());
  } else if (OB_FAIL(ObPartMgrUtils::get_partition_entity_schemas_in_tenant(
                 schema_guard, pool->tenant_id_, partition_schemas))) {
    LOG_WARN("fail to get partition schemas of tenant", K(ret), "tenant_id", pool->tenant_id_);
  } else {
    for (int64_t i = 0; can_remove && OB_SUCC(ret) && i < to_be_removed_zones.count(); ++i) {
      int64_t total_unit_num = 0;
      int64_t full_unit_num = 0;
      int64_t logonly_unit_num = 0;
      const common::ObZone& zone = to_be_removed_zones.at(i);
      bool enough = false;
      if (OB_FAIL(inner_get_zone_pools_unit_num(zone, *pool_list, total_unit_num, full_unit_num, logonly_unit_num))) {
        LOG_WARN("fail to get zone pools unit num", K(ret));
      } else if (total_unit_num != full_unit_num + logonly_unit_num) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit num value not match", K(ret), K(total_unit_num), K(full_unit_num), K(logonly_unit_num));
      } else {
        // Reduce the unit of this pool on to be remove zone
        total_unit_num -= pool->unit_count_;
        if (common::REPLICA_TYPE_FULL == pool->replica_type_) {
          full_unit_num -= pool->unit_count_;
        } else if (common::REPLICA_TYPE_LOGONLY == pool->replica_type_) {
          logonly_unit_num -= pool->unit_count_;
        } else {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("do not support this pool type", K(ret), K(*pool));
        }
      }
      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(inner_check_schema_zone_unit_enough(
                     zone, total_unit_num, full_unit_num, logonly_unit_num, *tenant_schema, schema_guard, enough))) {
        LOG_WARN("fail to inner check schema zone unit enough", K(ret));
      } else if (!enough) {
        can_remove = false;
      } else {
        for (int64_t j = 0; j < partition_schemas.count() && OB_SUCC(ret) && can_remove; ++j) {
          const ObPartitionSchema* simple_schema = partition_schemas.at(j);
          if (OB_UNLIKELY(NULL == simple_schema)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unexpected error, table schema null", K(ret), KP(simple_schema));
          } else if (!simple_schema->has_self_partition()) {
            // table without partition, ignore
          } else if (simple_schema->get_locality_str().empty()) {
            // empty, derived from tenant, go on next
          } else if (!simple_schema->get_previous_locality_str().empty()) {
            can_remove = false;
          } else if (OB_FAIL(inner_check_schema_zone_unit_enough(zone,
                         total_unit_num,
                         full_unit_num,
                         logonly_unit_num,
                         *simple_schema,
                         schema_guard,
                         enough))) {
            LOG_WARN("fail to check schema zone unit enough", K(ret));
          } else if (!enough) {
            can_remove = false;
          } else {
          }  //  go on to check next
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::inner_get_zone_pools_unit_num(const common::ObZone& zone,
    const common::ObIArray<share::ObResourcePool*>& pool_list, int64_t& total_unit_num, int64_t& full_unit_num,
    int64_t& logonly_unit_num)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K(ret));
  } else if (zone.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(zone));
  } else {
    total_unit_num = 0;
    full_unit_num = 0;
    logonly_unit_num = 0;
    for (int64_t i = 0; OB_SUCC(ret) && i < pool_list.count(); ++i) {
      share::ObResourcePool* pool = pool_list.at(i);
      if (OB_UNLIKELY(NULL == pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret));
      } else if (!has_exist_in_array(pool->zone_list_, zone)) {
        // ignore
      } else {
        total_unit_num += pool->unit_count_;
        if (common::REPLICA_TYPE_FULL == pool->replica_type_) {
          full_unit_num += pool->unit_count_;
        } else if (common::REPLICA_TYPE_LOGONLY == pool->replica_type_) {
          logonly_unit_num += pool->unit_count_;
        } else {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("do not support this pool type", K(ret), K(*pool));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::alter_pool_zone_list(share::ObResourcePool* pool, const ObIArray<ObZone>& zone_list)
{
  // The requirement of alter pool_zone_list is currently only for cluster relocation.
  // Before deleting the zone,
  // the pool_zone_list that contains the zone in all resource pools needs to be removed from the zone_list..
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_UNLIKELY(NULL == pool || zone_list.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), "new zone list", zone_list);
  } else {
    ObArray<ObZone> new_zone_list;
    // check repeat
    for (int64_t i = 0; i < zone_list.count() && OB_SUCC(ret); ++i) {
      if (has_exist_in_array(new_zone_list, zone_list.at(i))) {
        ret = OB_OP_NOT_ALLOW;
        LOG_USER_ERROR(OB_OP_NOT_ALLOW, "alter resource pool zone repeat");
        LOG_WARN("alter resource pool zone repeat not allow", K(ret));
      } else if (OB_FAIL(new_zone_list.push_back(zone_list.at(i)))) {
        LOG_WARN("fail to push back", K(ret));
      } else {
      }  // no more to do
    }
    if (OB_SUCC(ret)) {
      std::sort(new_zone_list.begin(), new_zone_list.end());
      bool is_add_pool_zone = false;
      bool is_remove_pool_zone = false;
      for (int64_t i = 0; i < new_zone_list.count() && OB_SUCC(ret); ++i) {
        if (!has_exist_in_array(pool->zone_list_, new_zone_list.at(i))) {
          is_add_pool_zone = true;
        } else {
        }  // nothing todo
      }
      for (int64_t i = 0; i < pool->zone_list_.count() && OB_SUCC(ret); ++i) {
        if (!has_exist_in_array(new_zone_list, pool->zone_list_.at(i))) {
          is_remove_pool_zone = true;
        } else {
        }  // nothing todo
      }
      if (is_add_pool_zone && is_remove_pool_zone) {
        ret = OB_OP_NOT_ALLOW;
        LOG_USER_ERROR(OB_OP_NOT_ALLOW, "Cannot add and delete zones at the same time");
        LOG_WARN("Cannot add and delete zones at the same time", K(ret));
      } else if (is_add_pool_zone) {
        if (OB_FAIL(add_pool_zone_list(pool, new_zone_list))) {
          LOG_WARN("fail to add pool zone list", K(ret));
        }
      } else {
        if (OB_FAIL(remove_pool_zone_list(pool, new_zone_list))) {
          LOG_WARN("fail to remoce pool zone list", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::remove_pool_zone_list(share::ObResourcePool* pool, const ObIArray<ObZone>& zone_list)
{
  int ret = OB_SUCCESS;
  bool can_remove = false;
  common::ObArray<common::ObZone> zones_to_be_removed;
  const common::ObIArray<common::ObZone>& prev_zone_list = pool->zone_list_;
  if (OB_FAIL(cal_to_be_removed_pool_zone_list(prev_zone_list, zone_list, zones_to_be_removed))) {
    LOG_WARN("fail to calculate to be removed pool zone list", K(ret));
  } else if (zones_to_be_removed.count() <= 0) {
    // no zones need to be removed, return SUCC directly
  } else if (OB_FAIL(check_can_remove_pool_zone_list(pool, zones_to_be_removed, can_remove))) {
    LOG_WARN("fail to check can remove pool zon list", K(ret));
  } else if (!can_remove) {
    ret = OB_OP_NOT_ALLOW;
    LOG_WARN("cannot alter resource pool zone list", K(ret), "pool", *pool, K(zones_to_be_removed));
    LOG_USER_ERROR(OB_OP_NOT_ALLOW, "alter resource pool zone list with not empty unit");
  } else if (OB_FAIL(do_remove_pool_zone_list(pool, zone_list, zones_to_be_removed))) {
    LOG_WARN("fail to do remove pool zone list", K(ret), "pool", *pool, K(zones_to_be_removed));
  } else {
  }  // no more to do
  return ret;
}

int ObUnitManager::add_pool_zone_list(share::ObResourcePool* pool, const ObIArray<ObZone>& zone_list)
{
  int ret = OB_SUCCESS;
  bool can_add = false;
  common::ObArray<common::ObZone> zones_to_be_add;
  const common::ObIArray<common::ObZone>& prev_zone_list = pool->zone_list_;
  if (OB_FAIL(cal_to_be_add_pool_zone_list(prev_zone_list, zone_list, zones_to_be_add))) {
    LOG_WARN("fail to calculate to be add pool zone list", K(ret));
  } else if (zones_to_be_add.count() <= 0) {
    // no zones need to be add, return SUCC directly
  } else if (OB_FAIL(check_can_add_pool_zone_list(pool, zones_to_be_add, can_add))) {
    LOG_WARN("fail to check can add pool zone list", K(ret));
  } else if (!can_add) {
    ret = OB_OP_NOT_ALLOW;
    LOG_WARN("cannot alter resource pool zone list", K(ret), "pool", *pool, K(zones_to_be_add));
    LOG_USER_ERROR(OB_OP_NOT_ALLOW, "alter resource pool zone list with not empty unit");
  } else if (OB_FAIL(do_add_pool_zone_list(pool, zone_list, zones_to_be_add))) {
    LOG_WARN("fail to do add pool zone list", K(ret), "pool", *pool, K(zones_to_be_add));
  } else {
  }  // no more to do
  return ret;
}

int ObUnitManager::cal_to_be_add_pool_zone_list(const common::ObIArray<common::ObZone>& prev_zone_list,
    const common::ObIArray<common::ObZone>& cur_zone_list, common::ObIArray<common::ObZone>& to_be_add_zones) const
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(prev_zone_list.count() <= 0 || cur_zone_list.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), "prev zone list", prev_zone_list, "cur zone list", cur_zone_list);
  } else {
    to_be_add_zones.reset();
    // Check if the added zone exists
    for (int64_t i = 0; OB_SUCC(ret) && i < cur_zone_list.count(); ++i) {
      const common::ObZone& this_zone = cur_zone_list.at(i);
      bool zone_exist = false;
      if (OB_FAIL(zone_mgr_.check_zone_exist(this_zone, zone_exist))) {
        LOG_WARN("failed to check zone exists", K(ret), K(this_zone));
      } else if (!zone_exist) {
        ret = OB_ZONE_INFO_NOT_EXIST;
        LOG_WARN("zone not exists", K(ret), K(this_zone));
      } else {
        if (has_exist_in_array(prev_zone_list, this_zone)) {
          // still exist, do nothing
        } else if (has_exist_in_array(to_be_add_zones, this_zone)) {
          // just add one time
          ret = OB_OP_NOT_ALLOW;
          LOG_USER_ERROR(OB_OP_NOT_ALLOW, "add repeat zone");
          LOG_WARN("not allow add repeat zone", K(ret));
        } else if (OB_FAIL(to_be_add_zones.push_back(this_zone))) {
          LOG_WARN("fail to push back", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::check_can_add_pool_zone_list(
    const share::ObResourcePool* pool, const common::ObIArray<common::ObZone>& to_be_add_zones, bool& can_add)
{
  int ret = OB_SUCCESS;
  can_add = true;
  common::ObArray<share::ObResourcePool*>* pool_list = NULL;
  share::schema::ObSchemaGetterGuard schema_guard;
  const share::schema::ObTenantSchema* tenant_schema = NULL;
  if (OB_UNLIKELY(NULL == pool) || OB_UNLIKELY(to_be_add_zones.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("ivnalid argument", K(ret), KP(pool), K(to_be_add_zones));
  } else if (OB_INVALID_ID == pool->tenant_id_) {
    can_add = true;  // not in tenant, can add zone unit
  } else if (OB_FAIL(get_pools_by_tenant(pool->tenant_id_, pool_list))) {
    LOG_WARN("fail to get pools by tenant", K(ret));
  } else if (OB_FAIL(get_newest_schema_guard_in_inner_table(pool->tenant_id_, schema_guard))) {
    LOG_WARN("fail to get schema guard", K(ret));
  } else if (OB_FAIL(schema_guard.get_tenant_info(pool->tenant_id_, tenant_schema))) {
    LOG_WARN("fail to get tenant schema", K(ret), "tenant_id", pool->tenant_id_);
  } else if (NULL == tenant_schema) {
    ret = OB_SCHEMA_ERROR;
    LOG_WARN("tenant schema is null", K(ret));
  } else if (!tenant_schema->get_previous_locality_str().empty()) {  // No locality changes are allowed at this time
    can_add = false;
    LOG_WARN(
        "alter pool zone list is not allowed while locality modification", "tenant_id", tenant_schema->get_tenant_id());
  } else {
  }  // nothing todo
  return ret;
}

int ObUnitManager::do_add_pool_zone_list(share::ObResourcePool* pool,
    const common::ObIArray<common::ObZone>& new_zone_list, const common::ObIArray<common::ObZone>& to_be_add_zones)
{
  int ret = OB_SUCCESS;
  common::ObMySQLTransaction trans;
  share::ObResourcePool new_pool;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_UNLIKELY(NULL == pool) || OB_UNLIKELY(to_be_add_zones.count() <= 0) ||
             OB_UNLIKELY(new_zone_list.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(to_be_add_zones), K(new_zone_list));
  } else {
    if (OB_FAIL(new_pool.assign(*pool))) {
      LOG_WARN("fail to assign new pool", K(ret));
    } else if (OB_FAIL(new_pool.zone_list_.assign(new_zone_list))) {
      LOG_WARN("fail to assign new pool zone list", K(ret));
    } else if (OB_FAIL(trans.start(proxy_))) {
      LOG_WARN("start transaction failed", K(ret));
    } else {
      if (OB_FAIL(increase_units_in_zones(trans, pool, to_be_add_zones))) {
        LOG_WARN("fail to add units in zones", K(ret), "pool id", pool->resource_pool_id_, K(to_be_add_zones));
      } else if (OB_FAIL(pool->zone_list_.assign(new_zone_list))) {
        LOG_WARN("fail to update pool zone list in memory", K(ret));
      } else if (OB_FAIL(ut_operator_.update_resource_pool(trans, new_pool))) {
        LOG_WARN("fail to update resource pool", K(ret));
      } else {
      }  // no more to do
      if (trans.is_started()) {
        const bool commit = (OB_SUCC(ret));
        int tmp_ret = OB_SUCCESS;
        if (OB_SUCCESS != (tmp_ret = trans.end(commit))) {
          LOG_WARN("fail to end trans", K(commit), K(tmp_ret));
          ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
        }
      } else {
      }  // nothing todo
    }
  }
  return ret;
}

int ObUnitManager::increase_units_in_zones(
    common::ObISQLClient& client, share::ObResourcePool* pool, const common::ObIArray<common::ObZone>& to_be_add_zones)
{
  int ret = OB_SUCCESS;
  share::ObWorker::CompatMode compat_mode = share::ObWorker::CompatMode::INVALID;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_ISNULL(pool) || OB_UNLIKELY(to_be_add_zones.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(to_be_add_zones));
  } else if (OB_UNLIKELY(nullptr == leader_coordinator_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("leader coordinator ptr is null", K(ret));
  } else if (OB_INVALID_ID == pool->tenant_id_) {
    // by pass
  } else if (OB_FAIL(ObCompatModeGetter::get_tenant_mode(pool->tenant_id_, compat_mode))) {
    LOG_WARN("fail to get tenant compat mode", K(ret));
  }
  ObNotifyTenantServerResourceProxy notify_proxy(
      leader_coordinator_->get_rpc_proxy(), &obrpc::ObSrvRpcProxy::notify_tenant_server_unit_resource);
  ObArray<ObAddr> excluded_servers;
  ObAddr server;
  ObUnit unit;
  if (OB_SUCC(ret)) {
    for (int64_t i = 0; OB_SUCC(ret) && i < to_be_add_zones.count(); ++i) {
      bool zone_exist = false;
      if (OB_FAIL(zone_mgr_.check_zone_exist(to_be_add_zones.at(i), zone_exist))) {
        LOG_WARN("failed to check zone exists", K(ret), K(to_be_add_zones.at(i)));
      } else if (!zone_exist) {
        ret = OB_ZONE_INFO_NOT_EXIST;
        LOG_WARN("zone not exists", K(ret), K(to_be_add_zones.at(i)));
      }
    }
  }
  if (OB_SUCC(ret)) {
    for (int64_t i = 0; i < to_be_add_zones.count() && OB_SUCC(ret); ++i) {  // for each add zone
      excluded_servers.reuse();
      if (OB_INVALID_ID == pool->tenant_id_) {
      } else {
        // The pool grant is given to a tenant,
        // and the server where the unit of the other pool of the tenant in the same zone
        // is located should also be regarded as excluded servers
        common::ObArray<uint64_t> processed_pool_id_array;
        common::ObArray<common::ObAddr> other_excluded_servers;
        if (OB_FAIL(processed_pool_id_array.push_back(pool->resource_pool_id_))) {
          LOG_WARN("fail to push back", K(ret));
        } else if (OB_FAIL(get_tenant_unit_servers(
                       pool->tenant_id_, to_be_add_zones.at(i), processed_pool_id_array, other_excluded_servers))) {
          LOG_WARN(
              "fail to get tenant unit servers", K(ret), "tenant_id", pool->tenant_id_, "zone", to_be_add_zones.at(i));
        } else if (OB_FAIL(append(excluded_servers, other_excluded_servers))) {
          LOG_WARN("fail to append other excluded servers", K(ret));
        }
      }
      if (OB_SUCC(ret) && GCONF.enable_sys_unit_standalone) {
        // When the system tenant is deployed independently,
        // the server where the unit of the system tenant is located is also required as the executed servers
        common::ObArray<uint64_t> processed_pool_id_array;
        common::ObArray<common::ObAddr> other_excluded_servers;
        if (OB_FAIL(get_tenant_unit_servers(
                OB_SYS_TENANT_ID, to_be_add_zones.at(i), processed_pool_id_array, other_excluded_servers))) {
          LOG_WARN("fail to get tenant unit servers", K(ret), "zone", pool->zone_list_.at(i));
        } else if (OB_FAIL(append(excluded_servers, other_excluded_servers))) {
          LOG_WARN("fail to append other excluded servers", K(ret));
        }
      }
      if (OB_SUCC(ret)) {
        ObUnitConfig* config = NULL;
        if (OB_FAIL(get_unit_config_by_id(pool->unit_config_id_, config))) {
          LOG_WARN("get_unit_config_by_id failed", "unit_config_id", pool->unit_config_id_, K(ret));
        } else if (NULL == config) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("config is null", KP(config), K(ret));
        } else {
          for (int64_t j = 0; OB_SUCC(ret) && j < pool->unit_count_; ++j) {
            uint64_t unit_id = OB_INVALID_ID;
            server.reset();
            if (OB_FAIL(choose_server_for_unit(*config, to_be_add_zones.at(i), excluded_servers, server))) {
              LOG_WARN("choose_unit_server failed",
                  "config",
                  *config,
                  "zone",
                  to_be_add_zones.at(i),
                  K(excluded_servers),
                  K(ret));
            } else if (OB_FAIL(excluded_servers.push_back(server))) {
              LOG_WARN("push_back failed", K(ret));
            } else if (OB_FAIL(fetch_new_unit_id(unit_id))) {
              LOG_WARN("fetch_new_unit_id failed", K(ret));
            } else {
              const bool is_delete = false;  // is_delete is false when allocate new unit
              unit.reset();
              unit.unit_id_ = unit_id;
              unit.resource_pool_id_ = pool->resource_pool_id_;
              unit.group_id_ = 0;  // group_id has no meaning, just fill it in as 0
              unit.zone_ = to_be_add_zones.at(i);
              unit.server_ = server;
              unit.status_ = ObUnit::UNIT_STATUS_ACTIVE;
              unit.replica_type_ = pool->replica_type_;
              if (OB_FAIL(try_notify_tenant_server_unit_resource(pool->tenant_id_,
                      is_delete,
                      notify_proxy,
                      *pool,
                      compat_mode,
                      unit,
                      false /*if not grant*/,
                      false /*skip offline server*/))) {
                LOG_WARN("fail to try notify server unit resource", K(ret));
              } else if (OB_FAIL(add_unit(client, unit))) {
                LOG_WARN("add_unit failed", K(unit), K(ret));
              }
            }
          }
        }
      }
      int tmp_ret = OB_SUCCESS;
      if (OB_SUCCESS != (tmp_ret = notify_proxy.wait())) {
        LOG_WARN("fail to wait notify resource", K(ret), K(tmp_ret));
        ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
      }
    }
  }
  return ret;
}

int ObUnitManager::do_remove_pool_zone_list(share::ObResourcePool* pool,
    const common::ObIArray<common::ObZone>& new_zone_list, const common::ObIArray<common::ObZone>& to_be_removed_zones)
{
  int ret = OB_SUCCESS;
  common::ObMySQLTransaction trans;
  share::ObResourcePool new_pool;
  common::ObArray<common::ObZone> new_zone_list1;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_UNLIKELY(NULL == pool) || OB_UNLIKELY(to_be_removed_zones.count() <= 0) ||
             OB_UNLIKELY(new_zone_list.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), K(to_be_removed_zones), K(new_zone_list));
  } else {
    if (OB_FAIL(new_pool.assign(*pool))) {
      LOG_WARN("fail to assign new pool", K(ret));
    } else if (OB_FAIL(new_pool.zone_list_.assign(new_zone_list))) {
      LOG_WARN("fail to assign new pool zone list", K(ret));
    } else if (OB_FAIL(trans.start(proxy_))) {
      LOG_WARN("start transaction failed", K(ret));
    } else {
      if (OB_FAIL(ut_operator_.remove_units_in_zones(trans, pool->resource_pool_id_, to_be_removed_zones))) {
        LOG_WARN("fail to remove units in zones", K(ret), "pool id", pool->resource_pool_id_, K(to_be_removed_zones));
      } else if (OB_FAIL(ut_operator_.update_resource_pool(trans, new_pool))) {
        LOG_WARN("fail to update resource pool", K(ret));
      } else {
      }  // no more to do
      if (trans.is_started()) {
        const bool commit = (OB_SUCC(ret));
        int tmp_ret = OB_SUCCESS;
        if (OB_SUCCESS != (tmp_ret = trans.end(commit))) {
          LOG_WARN("fail to end trans", K(commit), K(tmp_ret));
          ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
        }
      }
      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(delete_units_in_zones(pool->resource_pool_id_, to_be_removed_zones))) {
        LOG_WARN("fail to delete units in zones", K(ret), "pool id", pool->resource_pool_id_, K(to_be_removed_zones));
      } else if (OB_FAIL(pool->zone_list_.assign(new_zone_list))) {
        LOG_WARN("fail to update pool zone list in memory", K(ret));
      } else {
      }  // no more to do
    }
  }
  return ret;
}

int ObUnitManager::cal_to_be_removed_pool_zone_list(const common::ObIArray<common::ObZone>& prev_zone_list,
    const common::ObIArray<common::ObZone>& cur_zone_list, common::ObIArray<common::ObZone>& to_be_removed_zones) const
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(prev_zone_list.count() <= 0 || cur_zone_list.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), "prev zone list", prev_zone_list, "cur zone list", cur_zone_list);
  } else {
    to_be_removed_zones.reset();
    // Each zone in cur_zone_list must be included in prev_zone_list
    for (int64_t i = 0; OB_SUCC(ret) && i < cur_zone_list.count(); ++i) {
      const common::ObZone& this_zone = cur_zone_list.at(i);
      if (!has_exist_in_array(prev_zone_list, this_zone)) {
        ret = OB_NOT_SUPPORTED;
        LOG_USER_ERROR(OB_NOT_SUPPORTED, "alter resource pool zone list with a new zone");
        LOG_WARN("alter resource pool zone list with a new zone is not supported", K(ret));
      } else {
      }  // good
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < prev_zone_list.count(); ++i) {
      const common::ObZone& this_zone = prev_zone_list.at(i);
      if (has_exist_in_array(cur_zone_list, this_zone)) {
        // still exist, do nothing
      } else if (OB_FAIL(to_be_removed_zones.push_back(this_zone))) {
        LOG_WARN("fail to push back", K(ret));
      } else {
      }  // no more to do
    }
  }
  return ret;
}

int ObUnitManager::check_full_resource_pool_memory_condition(
    const common::ObIArray<share::ObResourcePool*>& pools, const share::ObUnitConfig& new_config) const
{
  int ret = OB_SUCCESS;
  for (int64_t i = 0; OB_SUCC(ret) && i < pools.count(); ++i) {
    const share::ObResourcePool* pool = pools.at(i);
    if (OB_UNLIKELY(nullptr == pool)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pool ptr is null", K(ret), KP(pool));
    } else if (REPLICA_TYPE_FULL != pool->replica_type_) {
      // bypass
    } else if (new_config.min_memory_ < GCONF.__min_full_resource_pool_memory) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN("full resource pool min memory illegal", K(ret));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "unit min memory less than __min_full_resource_pool_memory");
    }
  }
  return ret;
}

int ObUnitManager::check_expand_config(const common::ObIArray<share::ObResourcePool*>& pools,
    const share::ObUnitConfig& old_config, const share::ObUnitConfig& new_config) const
{
  int ret = OB_SUCCESS;
  common::hash::ObHashMap<ObAddr, int64_t> server_ref_count_map;
  common::ObZone zone;
  ObString err_str;
  AlterResourceErr err_index = ALT_ERR;
  int temp_ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (pools.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pools is empty", K(pools), K(ret));
  } else if (!old_config.is_valid() || !new_config.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid old_config or invalid new_config", K(old_config), K(new_config), K(ret));
  } else if (OB_FAIL(server_ref_count_map.create(
                 SERVER_REF_COUNT_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_SERVER_REF_COUNT_MAP))) {
    LOG_WARN(
        "pool_unit_map_ create failed", "bucket_num", static_cast<int64_t>(SERVER_REF_COUNT_MAP_BUCKET_NUM), K(ret));
  } else if (OB_FAIL(get_pools_servers(pools, server_ref_count_map))) {
    LOG_WARN("get pools server failed", K(pools), K(ret));
  } else {
    bool can_expand = true;
    const ObUnitConfig delta = new_config - old_config;
    ObUnitConfig expand_config;
    char temp_str[10][10] = {"MIN_CPU", "MAX_CPU", "MIN_MEM", "MAX_MEM", "ALT_ERR"};
    FOREACH_X(iter, server_ref_count_map, OB_SUCCESS == ret)
    {
      expand_config = delta * (iter->second);
      if (OB_FAIL(check_expand_config(iter->first, expand_config, can_expand, err_index))) {
        LOG_WARN("check expand config failed", K(ret));
      } else if (!can_expand) {
        if (OB_FAIL(server_mgr_.get_server_zone(iter->first, zone))) {
          LOG_WARN("get_server_zone failed", K(iter->first), K(ret));
        } else {
          ret = OB_MACHINE_RESOURCE_NOT_ENOUGH;
          if (MIN_CPU == err_index) {
            err_str.assign_ptr(temp_str[0], strlen(temp_str[0]));
          } else if (MAX_CPU == err_index) {
            err_str.assign_ptr(temp_str[1], strlen(temp_str[1]));
          } else if (MIN_MEM == err_index) {
            err_str.assign_ptr(temp_str[2], strlen(temp_str[2]));
          } else if (MAX_MEM == err_index) {
            err_str.assign_ptr(temp_str[3], strlen(temp_str[3]));
          } else {
            temp_ret = OB_ERR_UNEXPECTED;
            err_str.assign_ptr(temp_str[4], strlen(temp_str[4]));
            LOG_WARN("alter resource unexpected", K(temp_ret));
          }
          if (OB_SUCCESS == temp_ret) {
            const char* ip_ptr = to_cstring(iter->first);
            const char* resource_ptr = to_cstring(err_str);
            int64_t pos = 0;
            int temp_ret = OB_SUCCESS;
            char merge_ptr[128] = {'\0'};
            temp_ret = databuff_printf(
                merge_ptr, strlen(resource_ptr) + strlen(ip_ptr) + 1, pos, "%s%s", ip_ptr, resource_ptr);
            if (OB_SUCCESS != temp_ret) {
              LOG_WARN("fail to mearge resource err info", K(err_str), K(temp_ret));
            } else {
              LOG_USER_ERROR(OB_MACHINE_RESOURCE_NOT_ENOUGH, merge_ptr);
              LOG_WARN("server doesn't have enough resource to hold expanded config",
                  "server",
                  iter->first,
                  K(expand_config),
                  K(ret));
            }
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::check_expand_config(
    const share::ObResourcePool& pool, const ObUnitConfig& old_config, const ObUnitConfig& new_config) const
{
  int ret = OB_SUCCESS;
  bool can_expand = true;
  ObArray<ObAddr> servers;
  ObZone zone;
  bool duplicated_exist = false;
  ObString err_str;
  AlterResourceErr err_index = ALT_ERR;
  int temp_ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (!pool.is_valid() || !old_config.is_valid() || !new_config.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid pool or invalid old_config or invalid new_config", K(pool), K(old_config), K(new_config), K(ret));
  } else if (OB_FAIL(get_pool_servers(pool.resource_pool_id_, zone, servers))) {
    LOG_WARN("get_pool_servers failed", "pool_id", pool.resource_pool_id_, K(zone), K(ret));
  } else if (OB_FAIL(check_duplicated_server(servers, duplicated_exist))) {
    LOG_WARN("check_duplicated_server failed", K(servers), K(ret));
  } else if (duplicated_exist) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("find duplicated server in pool servers", K(servers), K(ret));
  } else {
    const ObUnitConfig expand_config = new_config - old_config;
    char temp_str[10][10] = {"MIN_CPU", "MAX_CPU", "MIN_MEM", "MAX_MEM", "ALT_ERR"};
    FOREACH_CNT_X(server, servers, OB_SUCCESS == ret)
    {
      if (OB_FAIL(check_expand_config(*server, expand_config, can_expand, err_index))) {
        LOG_WARN("check expand config on server", "server", *server, K(expand_config), K(ret));
      } else if (!can_expand) {
        ret = OB_MACHINE_RESOURCE_NOT_ENOUGH;
        if (MIN_CPU == err_index) {
          err_str.assign_ptr(temp_str[0], strlen(temp_str[0]));
        } else if (MAX_CPU == err_index) {
          err_str.assign_ptr(temp_str[1], strlen(temp_str[1]));
        } else if (MIN_MEM == err_index) {
          err_str.assign_ptr(temp_str[2], strlen(temp_str[2]));
        } else if (MAX_MEM == err_index) {
          err_str.assign_ptr(temp_str[3], strlen(temp_str[3]));
        } else {
          temp_ret = OB_ERR_UNEXPECTED;
          err_str.assign_ptr(temp_str[4], strlen(temp_str[4]));
          LOG_WARN("alter resource unexpected", K(temp_ret));
        }
        if (OB_SUCCESS == temp_ret) {
          const char* ip_ptr = to_cstring(*server);
          const char* resource_ptr = to_cstring(err_str);
          int64_t pos = 0;
          char merge_ptr[128] = {'\0'};
          int temp_ret = OB_SUCCESS;
          temp_ret =
              databuff_printf(merge_ptr, strlen(resource_ptr) + strlen(ip_ptr) + 1, pos, "%s%s", ip_ptr, resource_ptr);
          if (OB_SUCCESS != temp_ret) {
            LOG_WARN("fail to mearge resource err info", K(err_str), K(temp_ret));
          } else {
            LOG_USER_ERROR(OB_MACHINE_RESOURCE_NOT_ENOUGH, merge_ptr);
            LOG_WARN("server doesn't have enough resource to hold expanded config",
                "server",
                *server,
                K(expand_config),
                K(ret));
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::check_expand_config(
    const ObAddr& server, const ObUnitConfig& expand_config, bool& can_expand, AlterResourceErr& err_index) const
{
  int ret = OB_SUCCESS;
  ObServerStatus status;
  double hard_limit = 0;
  bool can_hold_unit = false;
  can_expand = true;
  // some item of expand_config may be negative, so we don't check expand_config here
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (!server.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid server", K(server), K(ret));
  } else if (OB_FAIL(get_hard_limit(hard_limit))) {
    LOG_WARN("get_hard_limit failed", K(ret));
  } else if (OB_FAIL(server_mgr_.get_server_status(server, status))) {
    LOG_WARN("get_server_status failed", K(server), K(ret));
  } else if (OB_FAIL(have_enough_resource(status, expand_config, hard_limit, can_hold_unit, err_index))) {
    LOG_WARN("fail to check have enough resource", K(status), K(hard_limit), K(ret));
  } else if (!can_hold_unit) {
    can_expand = false;
    // don't need to set ret
    LOG_WARN("find server can't hold expanded config", K(server), K(status), K(expand_config));
  } else {
    can_expand = true;
  }
  return ret;
}

int ObUnitManager::check_shrink_config(
    const ObIArray<share::ObResourcePool*>& pools, const ObUnitConfig& config, const ObUnitConfig& new_config) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (pools.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pools is empty", K(pools), K(ret));
  } else if (!config.is_valid() || !new_config.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid config or invalid new_config", K(config), K(new_config), K(ret));
  } else {
    if (new_config.max_cpu_ < config.max_cpu_) {
      // cpu don't need check
    }

    if (new_config.min_memory_ < config.min_memory_) {
      for (int64_t i = 0; OB_SUCC(ret) && i < pools.count(); ++i) {
        const share::ObResourcePool* pool = pools.at(i);
        if (OB_UNLIKELY(NULL == pool)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("pool ptr is null", K(ret));
        } else if (OB_FAIL(check_shrink_config(*pool, config, new_config))) {
          LOG_WARN("fail to check shrink config", K(ret));
        } else {
        }  // no more to do
      }
    }
  }
  return ret;
}

int ObUnitManager::check_shrink_config(
    const share::ObResourcePool& pool, const ObUnitConfig& config, const ObUnitConfig& new_config) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (!pool.is_valid() || !config.is_valid() || !new_config.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid pool or invalid config or invalid new_config", K(pool), K(config), K(new_config), K(ret));
  } else {
    if (new_config.max_cpu_ < config.max_cpu_) {
      // cpu don't need check
    }

    if (new_config.min_memory_ < config.min_memory_) {
      if (OB_INVALID_ID == pool.tenant_id_) {
        // do nothing
      } else if (OB_FAIL(check_shrink_memory(pool, config.min_memory_, new_config.min_memory_))) {
        LOG_WARN("check_shrink_memory failed",
            "tenant_id",
            pool.tenant_id_,
            "min_memory",
            config.min_memory_,
            "new min_memory",
            new_config.min_memory_,
            K(ret));
      }
    }
    // min_memory <= max_memory, if min_memory check pass, max_memory pass, so we don't
    // check max_memory here
  }
  return ret;
}

int ObUnitManager::check_shrink_memory(
    const share::ObResourcePool& pool, const int64_t min_memory, const int64_t new_min_memory) const
{
  int ret = OB_SUCCESS;
  ObArray<ObUnit*>* units = NULL;
  ObArray<common::ObAddr> unit_servers;

  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (OB_INVALID_ID == pool.tenant_id_) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid tenant_id", K(ret));
  } else if (min_memory < 0 || new_min_memory < 0 || new_min_memory >= min_memory) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid min_memory or invalid new_min_memory", K(min_memory), K(new_min_memory), K(ret));
  } else if (OB_FAIL(get_units_by_pool(pool.resource_pool_id_, units))) {
    LOG_WARN("fail to get units by pool", K(ret));
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units ptr is null", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
      ObUnit* unit = units->at(i);
      if (OB_UNLIKELY(NULL == unit)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit ptr is null", K(ret));
      } else if (OB_FAIL(unit_servers.push_back(unit->server_))) {
        LOG_WARN("fail to push back", K(ret));
      } else if (!unit->migrate_from_server_.is_valid()) {
        // this unit is not in migrating
      } else if (OB_FAIL(unit_servers.push_back(unit->migrate_from_server_))) {
        LOG_WARN("fail to push back", K(ret));
      }
    }
    const double max_used_ratio = 0.9;
    const double shrink_ratio = static_cast<double>(new_min_memory) / static_cast<double>(min_memory);
    int64_t max_used_memory = 0;
    ObArray<ObTenantMemstoreInfoOperator::TenantServerMemInfo> mem_infos;
    ObTenantMemstoreInfoOperator mem_info_operator(*proxy_);
    if (OB_FAIL(ret)) {
      // failed
    } else if (OB_FAIL(mem_info_operator.get(pool.tenant_id_, unit_servers, mem_infos))) {
      LOG_WARN("mem_info_operator get failed", K(ret));
    } else {
      FOREACH_CNT_X(mem_info, mem_infos, OB_SUCCESS == ret)
      {
        max_used_memory =
            static_cast<int64_t>(static_cast<double>(mem_info->memstore_limit_) * shrink_ratio * max_used_ratio);
        if (mem_info->total_memstore_used_ > max_used_memory) {
          ret = OB_NOT_SUPPORTED;
          LOG_USER_ERROR(OB_NOT_SUPPORTED, "requested min_memory over 90 percent of total available memory");
          LOG_WARN("new min_memory will cause memory use percentage over ninety percentage",
              "mem_info",
              *mem_info,
              K(min_memory),
              K(new_min_memory),
              K(max_used_ratio),
              K(max_used_memory),
              K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::copy_config_options(const ObUnitConfig& src, ObUnitConfig& dst)
{
  int ret = OB_SUCCESS;
  if (!src.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid src", K(src), K(ret));
  } else {
    if (std::fabs(dst.max_cpu_) < ObUnitConfig::CPU_EPSILON) {
      dst.max_cpu_ = src.max_cpu_;
    }
    if (0 == dst.min_cpu_) {
      dst.min_cpu_ = src.min_cpu_;
    }
    if (0 == dst.max_memory_) {
      dst.max_memory_ = src.max_memory_;
    }
    if (0 == dst.min_memory_) {
      dst.min_memory_ = src.min_memory_;
    }
    if (0 == dst.max_disk_size_) {
      dst.max_disk_size_ = src.max_disk_size_;
    }
    if (0 == dst.max_iops_) {
      dst.max_iops_ = src.max_iops_;
    }
    if (0 == dst.min_iops_) {
      dst.min_iops_ = src.min_iops_;
    }
    if (0 == dst.max_session_num_) {
      dst.max_session_num_ = src.max_session_num_;
    }
  }
  return ret;
}

// server count of pool won't be large, so two loop is ok
int ObUnitManager::check_duplicated_server(const ObIArray<ObAddr>& servers, bool& duplicated_exist)
{
  int ret = OB_SUCCESS;
  duplicated_exist = false;
  for (int64_t i = 0; i < servers.count(); ++i) {
    for (int64_t j = i + 1; j < servers.count(); ++j) {
      if (servers.at(i) == servers.at(j)) {
        duplicated_exist = true;
      }
    }
  }
  return ret;
}

int ObUnitManager::change_pool_config(share::ObResourcePool* pool, ObUnitConfig* config, ObUnitConfig* new_config)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (NULL == pool || NULL == config || NULL == new_config) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", KP(pool), KP(config), KP(new_config), K(ret));
  } else {
    share::ObResourcePool new_pool;
    if (OB_FAIL(new_pool.assign(*pool))) {
      LOG_WARN("failed to assign new_pool", K(ret));
    }
    if (OB_SUCC(ret)) {
      new_pool.unit_config_id_ = new_config->unit_config_id_;
      if (OB_FAIL(ut_operator_.update_resource_pool(*proxy_, new_pool))) {
        LOG_WARN("ut_operator_ update_resource_pool failed", K(new_pool), K(ret));
      } else if (OB_FAIL(dec_config_ref_count(config->unit_config_id_))) {
        LOG_WARN("dec_config_ref_count failed", "unit_config_id", config->unit_config_id_, K(ret));
      } else if (OB_FAIL(inc_config_ref_count(new_config->unit_config_id_))) {
        LOG_WARN("inc_config_ref_count failed", "unit_config_id", new_config->unit_config_id_, K(ret));
      } else if (OB_FAIL(delete_config_pool(config->unit_config_id_, pool))) {
        LOG_WARN("delete config pool failed", "config id", config->unit_config_id_, K(ret));
      } else if (OB_FAIL(insert_config_pool(new_config->unit_config_id_, pool))) {
        LOG_WARN("insert config pool failed", "config id", new_config->unit_config_id_, K(ret));
      } else if (OB_FAIL(update_pool_load(pool, new_config))) {
        LOG_WARN("update resource pool load failed", K(ret), "resource_pool", *pool, "unit_config", *new_config);
      } else {
        pool->unit_config_id_ = new_config->unit_config_id_;
      }
    }
  }
  return ret;
}

// The zones of multiple pools have no intersection
// 14x new semantics. If it is the source_pool used to store the copy of L, it can be compared
int ObUnitManager::check_pool_intersect(
    const uint64_t tenant_id, const ObIArray<ObResourcePoolName>& pool_names, bool& intersect)
{
  int ret = OB_SUCCESS;
  ObSEArray<ObString, OB_DEFAULT_REPLICA_NUM> zones;
  common::ObArray<share::ObResourcePool*>* pools = NULL;
  ;
  intersect = false;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (pool_names.count() <= 0 || OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool_names is empty", K(pool_names), K(tenant_id), K(ret));
  } else {
    FOREACH_CNT_X(pool_name, pool_names, OB_SUCCESS == ret && !intersect)
    {
      share::ObResourcePool* pool = NULL;
      if (OB_FAIL(inner_get_resource_pool_by_name(*pool_name, pool))) {
        LOG_WARN("get resource pool by name failed", "pool_name", *pool_name, K(ret));
      } else if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", KP(pool), K(ret));
      } else if (REPLICA_TYPE_LOGONLY == pool->replica_type_) {
        // nothing todo
      } else {
        FOREACH_CNT_X(zone, pool->zone_list_, OB_SUCCESS == ret && !intersect)
        {
          if (NULL == zone) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unit is null", K(ret));
          } else {
            ObString zone_str;
            zone_str.assign_ptr(zone->ptr(), static_cast<int32_t>(zone->size()));
            if (has_exist_in_array(zones, zone_str)) {
              intersect = true;
            } else if (OB_FAIL(zones.push_back(zone_str))) {
              LOG_WARN("push_back failed", K(ret));
            }
          }
        }  // end foreach zone
      }
    }  // end foreach pool
    if (OB_FAIL(ret)) {
    } else if (intersect) {
    } else if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
      if (OB_ENTRY_NOT_EXIST == ret) {
        // a new tenant, without resource pool already granted
        ret = OB_SUCCESS;
      } else {
        LOG_WARN("fail to get pools by tenant", K(ret), K(tenant_id));
      }
    } else if (OB_UNLIKELY(NULL == pools)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pools is null", K(ret), KP(pools));
    } else {
      for (int64_t i = 0; !intersect && OB_SUCC(ret) && i < pools->count(); ++i) {
        const share::ObResourcePool* pool = pools->at(i);
        if (OB_UNLIKELY(NULL == pool)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("pool ptr is null", K(ret), KP(pool));
        } else {
          for (int64_t j = 0; !intersect && OB_SUCC(ret) && j < zones.count(); ++j) {
            common::ObZone zone;
            if (OB_FAIL(zone.assign(zones.at(j).ptr()))) {
              LOG_WARN("fail to assign zone", K(ret));
            } else if (has_exist_in_array(pool->zone_list_, zone)) {
              intersect = true;
            } else {
            }  // good
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::change_pool_owner(ObISQLClient& client, const share::ObWorker::CompatMode compat_mode,
    const bool grant, const ObIArray<ObResourcePoolName>& pool_names, const uint64_t tenant_id, const bool is_bootstrap,
    const bool if_not_grant, const bool skip_offline_server)
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (OB_INVALID_ID == tenant_id || pool_names.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(tenant_id), K(pool_names), K(ret));
  } else if (OB_UNLIKELY(nullptr == leader_coordinator_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("leader coordinator ptr is null", K(ret));
  } else {
    ObNotifyTenantServerResourceProxy notify_proxy(
        leader_coordinator_->get_rpc_proxy(), &obrpc::ObSrvRpcProxy::notify_tenant_server_unit_resource);
    share::ObResourcePool new_pool;
    for (int64_t i = 0; OB_SUCC(ret) && i < pool_names.count(); ++i) {
      share::ObResourcePool* pool = NULL;
      if (OB_FAIL(inner_get_resource_pool_by_name(pool_names.at(i), pool))) {
        LOG_WARN("get resource pool by name failed", "pool_name", pool_names.at(i), K(ret));
      } else if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", KP(pool), K(ret));
      } else if (grant && OB_INVALID_ID != pool->tenant_id_) {
        ret = OB_RESOURCE_POOL_ALREADY_GRANTED;
        LOG_USER_ERROR(OB_RESOURCE_POOL_ALREADY_GRANTED, to_cstring(pool_names.at(i)));
        LOG_WARN("pool has already granted to other tenant, can't grant again", K(ret), K(tenant_id), "pool", *pool);
      } else if (!grant && OB_INVALID_ID != pool->tenant_id_ && pool->tenant_id_ != tenant_id) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("find pool already granted to other tenant, can not revoke", "pool", *pool, K(tenant_id), K(ret));
      } else if (!grant && OB_INVALID_ID == pool->tenant_id_) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("find pool not granted to any tenant, can not revoke", "pool", *pool, K(tenant_id), K(ret));
      } else {
        const bool is_delete = !grant;
        const uint64_t new_tenant_id = (grant ? tenant_id : OB_INVALID_ID);
        if (OB_FAIL(new_pool.assign(*pool))) {
          LOG_WARN("failed to assign new_pool", K(ret));
        } else {
          ObArray<ObUnit*>* units = nullptr;
          new_pool.tenant_id_ = new_tenant_id;
          if (OB_FAIL(ut_operator_.update_resource_pool(client, new_pool))) {
            LOG_WARN("update_resource_pool failed", K(new_pool), K(ret));
          } else if (OB_FAIL(get_units_by_pool(new_pool.resource_pool_id_, units))) {
            LOG_WARN("fail to get units by pool", K(ret));
          } else if (OB_UNLIKELY(nullptr == units)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("units ptr is null", K(ret));
          } else if (is_bootstrap) {
            // no need to notify unit
          } else {
            for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
              const ObUnit* unit = units->at(i);
              if (OB_UNLIKELY(nullptr == unit)) {
                ret = OB_ERR_UNEXPECTED;
                LOG_WARN("unit ptr is null", K(ret));
              } else if (OB_FAIL(try_notify_tenant_server_unit_resource(tenant_id,
                             is_delete,
                             notify_proxy,
                             new_pool,
                             compat_mode,
                             *unit,
                             if_not_grant,
                             skip_offline_server))) {
                LOG_WARN("fail to try notify server unit resource", K(ret));
              }
            }
          }
        }
      }
    }
    int tmp_ret = OB_SUCCESS;
    if (OB_SUCCESS != (tmp_ret = notify_proxy.wait())) {
      LOG_WARN("fail to wait notify resource", K(ret), K(tmp_ret));
      ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
    }
  }
  return ret;
}

int ObUnitManager::get_zone_units(const ObArray<share::ObResourcePool*>& pools, ObArray<ZoneUnit>& zone_units) const
{
  int ret = OB_SUCCESS;
  ObArray<ObZone> zones;
  zone_units.reuse();
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K_(inited), K_(loaded), K(ret));
  } else if (pools.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pools is empty", K(pools), K(ret));
  } else {
    FOREACH_CNT_X(pool, pools, OB_SUCCESS == ret)
    {
      if (NULL == *pool) {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("pool is null", "pool", OB_P(*pool), K(ret));
      } else {
        FOREACH_CNT_X(pool_zone, (*pool)->zone_list_, OB_SUCCESS == ret)
        {
          bool find = false;
          FOREACH_CNT_X(zone, zones, !find)
          {
            if (*zone == *pool_zone) {
              find = true;
            }
          }
          if (!find) {
            if (OB_FAIL(zones.push_back(*pool_zone))) {
              LOG_WARN("push_back failed", K(ret));
            }
          }
        }
      }
    }

    ZoneUnit zone_unit;
    ObArray<ObUnitInfo> unit_infos;
    FOREACH_CNT_X(zone, zones, OB_SUCCESS == ret)
    {
      zone_unit.reset();
      zone_unit.zone_ = *zone;
      FOREACH_CNT_X(pool, pools, OB_SUCCESS == ret)
      {
        unit_infos.reuse();
        if (NULL == *pool) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("pool is null", "pool", OB_P(*pool), K(ret));
        } else if (OB_FAIL(inner_get_unit_infos_of_pool((*pool)->resource_pool_id_, unit_infos))) {
          LOG_WARN("inner_get_unit_infos_of_pool failed", "pool id", (*pool)->resource_pool_id_, K(ret));
        } else {
          FOREACH_CNT_X(unit_info, unit_infos, OB_SUCCESS == ret)
          {
            if (unit_info->unit_.zone_ == *zone) {
              if (OB_FAIL(zone_unit.unit_infos_.push_back(*unit_info))) {
                LOG_WARN("push_back failed", K(ret));
              }
            }
          }
        }
      }
      if (OB_SUCC(ret)) {
        if (OB_FAIL(zone_units.push_back(zone_unit))) {
          LOG_WARN("push_back failed", K(zone_unit), K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::get_tenants_of_server(
    const common::ObAddr& server, common::hash::ObHashSet<uint64_t>& tenant_id_set) const
{
  int ret = OB_SUCCESS;
  ObArray<ObUnitLoad>* unit_loads = NULL;
  {
    SpinRLockGuard guard(lock_);
    if (!check_inner_stat()) {
      ret = OB_INNER_STAT_ERROR;
      LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
    } else if (!server.is_valid()) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("server is invalid", K(server), K(ret));
    } else if (OB_FAIL(get_loads_by_server(server, unit_loads))) {
      if (OB_ENTRY_NOT_EXIST != ret) {
        LOG_WARN("get_loads_by_server failed", K(server), K(ret));
      } else {
        ret = OB_SUCCESS;
        // just return empty set
      }
    } else if (NULL == unit_loads) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unit_loads is null", KP(unit_loads), K(ret));
    }
    if (OB_SUCC(ret) && !OB_ISNULL(unit_loads)) {
      FOREACH_CNT_X(unit_load, *unit_loads, OB_SUCCESS == ret)
      {
        if (!unit_load->is_valid()) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("invalid unit_load", "unit_load", *unit_load, K(ret));
        } else {
          const uint64_t tenant_id = unit_load->pool_->tenant_id_;
          if (OB_INVALID_ID == tenant_id) {
            // do nothing
          } else if (OB_FAIL(tenant_id_set.set_refactored(tenant_id))) {
            if (OB_HASH_EXIST == ret) {
              ret = OB_SUCCESS;
            } else {
              LOG_WARN("set tenant id failed", K(tenant_id), K(ret));
            }
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::check_tenant_on_server(const uint64_t tenant_id, const ObAddr& server, bool& on_server) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
  } else if (OB_INVALID_ID == tenant_id || !server.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid tenant_id or invalid server", K(tenant_id), K(server), K(ret));
  } else {
    ObArray<uint64_t> pool_ids;
    ObZone zone;
    ObArray<ObAddr> servers;
    if (OB_FAIL(get_pool_ids_of_tenant(tenant_id, pool_ids))) {
      LOG_WARN("get_pool_ids_of_tenant failed", K(tenant_id), K(ret));
    } else if (OB_FAIL(server_mgr_.get_server_zone(server, zone))) {
      LOG_WARN("get_server_zone failed", K(server), K(ret));
    } else {
      SpinRLockGuard guard(lock_);
      FOREACH_CNT_X(pool_id, pool_ids, OB_SUCCESS == ret && !on_server)
      {
        if (OB_FAIL(get_pool_servers(*pool_id, zone, servers))) {
          LOG_WARN("get_pool_servers failed", "pool_id", *pool_id, K(zone), K(ret));
        } else if (has_exist_in_array(servers, server)) {
          on_server = true;
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::admin_migrate_unit(
    const uint64_t unit_id, const ObAddr& dst, ObRebalanceTaskMgr* task_mgr, bool is_cancel)
{
  int ret = OB_SUCCESS;
  ObUnitInfo unit_info;
  ObArray<ObAddr> excluded_servers;
  ObServerStatus status;
  ObUnitConfig left_resource;
  ObZone src_zone;
  ObZone dst_zone;
  double hard_limit = 0;
  bool can_hold_unit = false;
  bool is_manual = true;
  SpinWLockGuard guard(lock_);
  common::ObMySQLTransaction trans;
  AlterResourceErr err_index = ALT_ERR;
  bool can_migrate = false;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
  } else if (OB_INVALID_ID == unit_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("unit id is invalid", K(unit_id), K(ret));
  } else if (!dst.is_valid() && !is_cancel) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("dst is invalid", K(dst), K(ret));
  } else if (OB_FAIL(get_hard_limit(hard_limit))) {
    LOG_WARN("get_hard_limit failed", K(ret));
  } else if (OB_FAIL(inner_get_unit_info_by_id(unit_id, unit_info))) {
    LOG_WARN("get unit info failed", K(unit_id), K(ret));
  } else if (ObUnit::UNIT_STATUS_ACTIVE != unit_info.unit_.status_) {
    ret = OB_OP_NOT_ALLOW;
    LOG_WARN("migrate a unit which is in deleting status", K(ret), K(unit_id));
    LOG_USER_ERROR(OB_OP_NOT_ALLOW, "migrate a unit which is in deleting status");
  } else if (OB_FAIL(server_mgr_.get_server_zone(unit_info.unit_.server_, src_zone))) {
    LOG_WARN("get server zone failed", "server", unit_info.unit_.server_, K(ret));
  } else if (dst == unit_info.unit_.migrate_from_server_ || is_cancel) {
    // cancel migrate unit
    if (is_cancel && !unit_info.unit_.migrate_from_server_.is_valid()) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("failed to cancel migrate unit, may be no migrate task", K(unit_info));
      LOG_USER_ERROR(OB_ERR_UNEXPECTED, "no migrate task to cancel");
    } else if (OB_FAIL(cancel_migrate_unit(unit_info.unit_, unit_info.pool_.tenant_id_ == OB_GTS_TENANT_ID))) {
      LOG_WARN("failed to cancel migrate unit", K(ret), K(unit_info));
    } else if (NULL != task_mgr) {
      task_mgr->clear_task(unit_info.pool_.tenant_id_, obrpc::ObAdminClearBalanceTaskArg::ALL);
    }
  } else if (OB_FAIL(server_mgr_.get_server_zone(dst, dst_zone))) {
    LOG_WARN("get server zone failed", "server", dst, K(ret));
  } else if (src_zone != dst_zone) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("migrate unit between zones is not supported", K(ret));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "migrate unit between zones");
  } else if (OB_FAIL(get_excluded_servers(unit_info.unit_, excluded_servers))) {
    LOG_WARN("get_excluded_servers failed", "unit", unit_info.unit_, K(ret));
  } else if (has_exist_in_array(excluded_servers, dst)) {
    ret = OB_NOT_SUPPORTED;
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "hold two units of a tenant in the same server");
    LOG_WARN("hold two units of a tenant in the same server is not supported", K(ret));
  } else if (OB_FAIL(server_mgr_.get_server_status(dst, status))) {
    LOG_WARN("get server status failed", "server", dst, K(ret));
  } else if (!status.can_migrate_in()) {
    ret = OB_SERVER_MIGRATE_IN_DENIED;
    LOG_WARN("server can not migrate in", K(dst), K(status), K(ret));
  } else if (OB_FAIL(have_enough_resource(status, unit_info.config_, hard_limit, can_hold_unit, err_index))) {
    LOG_WARN("calculate_left_resource failed", "status", status, K(hard_limit), K(ret));
  } else if (!can_hold_unit) {
    ret = OB_MACHINE_RESOURCE_NOT_ENOUGH;
    LOG_WARN("left resource can't hold unit",
        "server",
        dst,
        K(hard_limit),
        K(left_resource),
        "config",
        unit_info.config_,
        K(ret));
  } else if (OB_FAIL(check_unit_can_migrate(unit_info.pool_.tenant_id_, can_migrate))) {
    LOG_WARN("fail to check unit can migrate", K(ret));
  } else if (!can_migrate) {
    ret = OB_OP_NOT_ALLOW;
    LOG_USER_ERROR(OB_OP_NOT_ALLOW, "unit migrate may no has leader");
  } else if (OB_FAIL(migrate_unit(unit_id, dst, is_manual))) {
    LOG_WARN("migrate unit failed", K(unit_id), "destination", dst, K(ret));
  }

  return ret;
}

int ObUnitManager::check_unit_can_migrate(const uint64_t tenant_id, bool& can_migrate)
{
  int ret = OB_SUCCESS;
  share::schema::ObSchemaGetterGuard schema_guard;
  const share::schema::ObTenantSchema* tenant_schema = NULL;
  int64_t num = 0;
  can_migrate = false;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K_(inited), K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    can_migrate = true;
  } else if (OB_FAIL(schema_service_->get_tenant_schema_guard(OB_SYS_TENANT_ID, schema_guard))) {
    LOG_WARN("fail to get tenant schema guard", K(ret));
  } else if (OB_FAIL(schema_guard.get_tenant_info(tenant_id, tenant_schema))) {
    LOG_WARN("fail to get tenant info", K(ret));
  } else if (OB_ISNULL(tenant_schema)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("tenant schema is NULL", K(ret));
  } else if (OB_FAIL(tenant_schema->get_paxos_replica_num(schema_guard, num))) {
    LOG_WARN("fail to get paxos replica num", K(ret));
  } else if (num > 2) {
    // The tenant's quorum value needs to be at least greater than 2 in order to migrate successfully
    can_migrate = true;
  }
  return ret;
}

int ObUnitManager::cancel_migrate_unit(const share::ObUnit& unit, const bool is_gts_unit)
{
  int ret = OB_SUCCESS;
  ObServerStatus status;
  if (OB_FAIL(server_mgr_.get_server_status(unit.migrate_from_server_, status))) {
    LOG_WARN("get_server_status failed", "server", unit.migrate_from_server_, K(ret));
  } else if (!status.can_migrate_in() && !is_gts_unit) {
    ret = OB_SERVER_MIGRATE_IN_DENIED;
    LOG_WARN("server can not migrate in", "server", unit.migrate_from_server_, K(status), K(ret));
  } else {
    const EndMigrateOp op = REVERSE;
    if (OB_FAIL(end_migrate_unit(unit.unit_id_, op))) {
      LOG_WARN("end_migrate_unit failed", "unit_id", unit.unit_id_, K(op), K(ret));
    } else {
      LOG_INFO("cancel migrate unit", K(unit));
    }
  }
  return ret;
}

int ObUnitManager::try_cancel_migrate_unit(const share::ObUnit& unit, bool& is_canceled)
{
  int ret = OB_SUCCESS;
  ObServerStatus status;
  bool can_migrate_in = false;
  is_canceled = false;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
  } else if (!unit.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid unit", K(unit), K(ret));
  } else if (OB_FAIL(check_can_migrate_in(unit.server_, can_migrate_in))) {
    LOG_WARN("check_can_migrate_in failed", "server", unit.server_, K(ret));
  } else if (can_migrate_in) {
    // ignore, do nothing
  } else if (!unit.migrate_from_server_.is_valid()) {
    // ignore, do nothing
  } else if (OB_FAIL(server_mgr_.get_server_status(unit.migrate_from_server_, status))) {
    LOG_WARN("get_server_status failed", "server", unit.migrate_from_server_, K(ret));
  } else if (status.can_migrate_in()) {
    LOG_INFO("unit migrate_from_server can migrate in, "
             "migrate unit back to migrate_from_server",
        K(unit),
        K(status));
    const EndMigrateOp op = REVERSE;
    if (OB_FAIL(end_migrate_unit(unit.unit_id_, op))) {
      LOG_WARN("end_migrate_unit failed", "unit_id", unit.unit_id_, K(op), K(ret));
    } else {
      is_canceled = true;
      LOG_INFO("reverse unit migrate success", K(ret), "unit_id", unit.unit_id_, K(op));
    }
  }
  return ret;
}

// When deleting the server,
// you need to move all the units on the serer, and do the following processing for all the units on the server
// 1 The unit is on the server, and the unit is in a stable state (the state is active, migrate from is NULL),
//   this kind of unit is moved directly
// 2 The unit is on the server and is in the state of the server.
//   This unit has already been moved out and will not be processed
// 3 The unit is on the server, but the unit is in the delete state,
//   this kind of unit will be deleted later and will not be processed
// 4 The unit is migrating to this server.
//   This kind of unit attempts to migrate back to the source end of the unit migration,
//   and it fails to directly report an error.
// int ObUnitManager::make_server_empty(const ObAddr &server,
//                                     const ObIArray<ObAddr> &excluded_servers,
//                                     const ObArray<ObUnitLoad> *loads)
//{
//  int ret = OB_SUCCESS;
//  LOG_INFO("start make server empty", K(server), K(excluded_servers));
//  ObZone zone;
//  if (!check_inner_stat()) {
//    ret = OB_INNER_STAT_ERROR;
//    LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
//  } else if (!server.is_valid() || NULL == loads) {
//    ret = OB_INVALID_ARGUMENT;
//    LOG_WARN("invalid argument", K(server), KP(loads), K(ret));
//  } else if (loads->count() <= 0) {
//    ret = OB_INVALID_ARGUMENT;
//    LOG_WARN("loads is empty", K(ret));
//  } else if (OB_FAIL(server_mgr_.get_server_zone(server, zone))) {
//    LOG_WARN("get_server_zone failed", K(server), K(ret));
//  } else {
//    ObArray<ObUnitLoad> unit_loads;
//    FOREACH_CNT_X(ul, *loads, OB_SUCC(ret)) {
//      if (OB_FAIL(unit_loads.push_back(*ul))) {
//        LOG_WARN("push_back failed", K(ret));
//      }
//    }
//    ObAddr new_server;
//    ObArray<ObAddr> excluded_set;
//    FOREACH_CNT_X(ul, unit_loads, OB_SUCC(ret)) {
//      new_server.reset();
//      if (!ul->is_valid()) {
//        ret = OB_INVALID_ARGUMENT;
//        LOG_WARN("unit_load is invalid", "unit_load", *ul, K(ret));
//      } else if (server != ul->unit_->server_ && server != ul->unit_->migrate_from_server_) {
//        ret = OB_ERR_UNEXPECTED;
//        LOG_WARN("unit load on server, but server not in servers of unit",
//            K(server), "unit", *ul->unit_, K(ret));
//      }
//      if (OB_FAIL(ret)) {
//      } else if (ObUnit::UNIT_STATUS_DELETING == ul->unit_->status_) {
//        // unit in deleting status, no need to migrate out
//      } else if (server == ul->unit_->migrate_from_server_) {
//        // unit already migrate from server, do nothing
//      } else if (server == ul->unit_->server_ && ul->unit_->migrate_from_server_.is_valid()) {
//        // unit migrate to server, try cancel migrate
//        const ObAddr &source = ul->unit_->migrate_from_server_;
//        ObServerStatus status;
//        if (has_exist_in_array(excluded_servers, source)) {
//          // source in excluded server set, can not cancel migrate in
//          ret = OB_UNIT_IS_MIGRATING;
//          LOG_WARN("unit is migrating, and source can not migrate in, "
//              "can not migrate to other servers", K(ret), "unit", *ul->unit_);
//        } else if (OB_FAIL(server_mgr_.get_server_status(source, status))) {
//          LOG_WARN("get server status failed", K(ret), "server", source);
//        } else {
//          if (!status.can_migrate_in()) {
//            ret = OB_UNIT_IS_MIGRATING;
//            LOG_WARN("unit is migrating, and source can not migrate in, "
//                "can not migrate to other servers",
//                K(ret), "unit", *ul->unit_, "server_status", status);
//          } else {
//            const EndMigrateOp op = REVERSE;
//            if (OB_FAIL(end_migrate_unit(ul->unit_->unit_id_, op))) {
//              LOG_WARN("end_migrate_unit failed",
//                  "unit_id", ul->unit_->unit_id_, K(op), K(ret));
//            }
//          }
//        }
//      } else {
//        if (OB_FAIL(excluded_set.assign(excluded_servers))) {
//          LOG_WARN("assign array failed", K(ret));
//        } else if (OB_FAIL(get_excluded_servers(*(ul->unit_), excluded_set))) {
//          LOG_WARN("get_excluded_servers failed", "unit", *(ul->unit_), K(ret));
//        } else if (OB_FAIL(choose_server_for_unit(*(ul->unit_config_),
//            zone, excluded_set, new_server))) {
//          LOG_WARN("choose_unit_server failed", "unit config", *(ul->unit_config_),
//              K(zone), K(excluded_servers), K(ret));
//        } else if (OB_FAIL(migrate_unit(ul->unit_->unit_id_, new_server))) {
//          LOG_WARN("migrate_unit failed", "unit id", ul->unit_->unit_id_,
//              K(new_server), K(ret));
//        }
//      }
//    }
//  }
//  LOG_INFO("finish make server empty", K(server), K(ret));
//  return ret;
//}
//
int ObUnitManager::get_server_loads_internal(const ObZone& zone, const bool only_active,
    ObArray<ObServerLoad>& server_loads, double& sum_load, int64_t& alive_server_count, double* weights,
    int64_t weights_count)
{
  int ret = OB_SUCCESS;
  ObServerManager::ObServerStatusArray server_statuses;
  // zone can be empty, don't check it
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
  } else if (OB_FAIL(server_mgr_.get_server_statuses(zone, server_statuses))) {
    LOG_WARN("get_servers_of_zone failed", K(zone), K(ret));
  } else {
    alive_server_count = 0;
    sum_load = 0;
  }

  ObServerLoad server_load;
  for (int64_t i = 0; OB_SUCC(ret) && i < server_statuses.count(); ++i) {
    ObArray<ObUnitLoad>* unit_loads = NULL;
    ObServerStatus& status = server_statuses.at(i);
    server_load.reset();
    if (only_active && !status.is_active()) {
      // filter not active server
    } else {
      if (status.is_active()) {
        ++alive_server_count;
      }
      if (OB_FAIL(get_loads_by_server(status.server_, unit_loads))) {
        if (OB_ENTRY_NOT_EXIST != ret) {
          LOG_WARN("get_loads_by_server failed", "server", status.server_, K(ret));
        } else {
          ret = OB_SUCCESS;
          LOG_DEBUG("server is empty, no unit on it", "server", status.server_);
        }
      } else if (NULL == unit_loads) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit_loads is null", KP(unit_loads), K(ret));
      }

      // unit_loads is null if no unit on it
      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(server_load.build(unit_loads, status))) {
        LOG_WARN("server_load build failed", K(status), K(ret));
      } else if (OB_FAIL(server_loads.push_back(server_load))) {
        LOG_WARN("push_back failed", K(ret));
      } else {
      }
    }
  }  // end for
  if (OB_SUCC(ret) && server_loads.count() > 0) {
    if (OB_FAIL(ObResourceUtils::calc_server_resource_weight(server_loads, weights, weights_count))) {
      LOG_WARN("failed to calc resource weight", K(ret));
    } else {
      double load = 0;
      ARRAY_FOREACH(server_loads, i)
      {
        ObServerLoad& server_load = server_loads.at(i);
        if (OB_FAIL(server_load.get_load(weights, weights_count, load))) {
          LOG_WARN("get_load_percentage failed", K(ret));
        } else {
          sum_load += load;
        }
      }  // end for
    }
  }
  return ret;
}

int ObUnitManager::get_server_loads(
    const ObZone& zone, ObArray<ObServerLoad>& server_loads, double* weights, int64_t weights_count)
{
  int ret = OB_SUCCESS;
  double sum_load = 0;
  int64_t alive_server_count = 0;
  const bool only_active = false;
  SpinRLockGuard guard(lock_);
  // zone can be empty, don't check it
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
  } else if (OB_FAIL(get_server_loads_internal(
                 zone, only_active, server_loads, sum_load, alive_server_count, weights, weights_count))) {
    LOG_WARN("fail to get server loads internal", K(zone), K(only_active), K(ret));
  }

  return ret;
}

int ObUnitManager::get_hard_limit(double& hard_limit) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
  } else {
    hard_limit = static_cast<double>(server_config_->resource_hard_limit) / 100;
  }
  return ret;
}

int ObUnitManager::get_soft_limit(double& soft_limit) const
{
  int ret = OB_SUCCESS;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
  } else {
    soft_limit = static_cast<double>(server_config_->resource_soft_limit) / 100;
  }
  return ret;
}

// Check if the unit in the unit group has a migration task in progress
int ObUnitManager::check_unit_group_normal(const ObUnit& unit, bool& normal)
{
  int ret = OB_SUCCESS;
  normal = false;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
  } else if (!unit.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid unit", K(unit), K(ret));
  } else {
    normal =
        unit.server_.is_valid() && !unit.migrate_from_server_.is_valid() && ObUnit::UNIT_STATUS_ACTIVE == unit.status_;
    if (normal) {
      ObArray<ObUnit*>* units = NULL;
      if (OB_FAIL(get_units_by_pool(unit.resource_pool_id_, units))) {
        LOG_WARN("get units by pool failed", K(ret), "resource_pool_id", unit.resource_pool_id_);
      } else if (NULL == units) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("NULL units returned", K(ret));
      } else {
        FOREACH_X(u, *units, OB_SUCC(ret) && normal)
        {
          if (NULL == *u) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("NULL unit", K(ret));
          } else {
            // Check whether the partition in u has an intersection with the partition in unit
            // If there is an intersection and u is being migrated, normal = false, don't migrate unit for now
            //
            // Current strategy: As long as one unit in the zone is migrating, the remaining units cannot be migrated
            bool intersect = false;
            if (OB_SUCC(check_has_intersect_pg(unit, **u, intersect))) {
              if (intersect && ((*u)->migrate_from_server_.is_valid() || ObUnit::UNIT_STATUS_ACTIVE != (*u)->status_)) {
                normal = false;
              }
            }
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::check_has_intersect_pg(const share::ObUnit& a, const share::ObUnit& b, bool& intersect)
{
  UNUSED(a);
  UNUSED(b);
  intersect = true;
  return OB_SUCCESS;
}

int ObUnitManager::check_can_migrate_in(const ObAddr& server, bool& can_migrate_in) const
{
  int ret = OB_SUCCESS;
  ObServerStatus status;
  can_migrate_in = false;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check inner stat failed", K_(inited), K_(loaded), K(ret));
  } else if (!server.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid server", K(server), K(ret));
  } else if (OB_FAIL(server_mgr_.get_server_status(server, status))) {
    LOG_WARN("get_server_status failed", K(server), K(ret));
  } else {
    can_migrate_in = status.can_migrate_in();
  }
  return ret;
}

int ObUnitManager::try_migrate_unit(const uint64_t unit_id, const uint64_t tenant_id, const ObUnitStat &unit_stat,
    const ObIArray<ObUnitStat> &migrating_unit_stat, const ObAddr &dst, const bool is_manual)
{
  int ret = OB_SUCCESS;
  ObServerStatus server_status;
  if (unit_id != unit_stat.unit_id_) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid unit stat", K(unit_id), K(unit_stat), K(ret));
  } else if (OB_FAIL(server_mgr_.get_server_status(dst, server_status))) {
    LOG_WARN("fail get server status", K(dst), K(ret));
  } else {
    int64_t mig_partition_cnt = 0;
    int64_t mig_required_size = 0;
    for (int64_t i = 0; i < migrating_unit_stat.count(); ++i) {
      mig_partition_cnt += migrating_unit_stat.at(i).partition_cnt_;
      mig_required_size += migrating_unit_stat.at(i).required_size_;
    }
    // partition number list
    int64_t required_cnt = mig_partition_cnt + unit_stat.partition_cnt_ + server_status.resource_info_.partition_cnt_;
    // sstable Space constraints
    int64_t required_size = mig_required_size + unit_stat.required_size_ + server_status.resource_info_.disk_in_use_;
    int64_t total_size = server_status.resource_info_.disk_total_;
    int64_t required_percent = (100 * required_size) / total_size;
    int64_t limit_percent = GCONF.data_disk_usage_limit_percentage;
    if (server_status.resource_info_.partition_cnt_ < 0) {
      // The old version of the server cannot get the count and size information, it is always allowed to move in
    } else if (required_cnt > OB_MAX_PARTITION_NUM_PER_SERVER) {
      ret = OB_OP_NOT_ALLOW;
      LOG_ERROR("migrate unit fail. dest server has too many partitions",
          K(unit_id),
          K(unit_stat),
          K(dst),
          K(required_cnt),
          "limit_cnt",
          OB_MAX_PARTITION_NUM_PER_SERVER,
          K(ret));
    } else if (required_percent >= limit_percent) {
      ret = OB_OP_NOT_ALLOW;
      LOG_ERROR("migrate unit fail. dest server out of space",
          K(unit_id),
          K(unit_stat),
          K(dst),
          K(required_size),
          K(total_size),
          K(limit_percent),
          K(ret));
    }

    if (OB_SUCC(ret)) {
      bool can_migrate = false;
      if (OB_FAIL(check_unit_can_migrate(tenant_id, can_migrate))) {
        LOG_WARN("fail to check unit can migrate", KR(ret), K(tenant_id), K(can_migrate));
      } else if (!can_migrate) {
        LOG_INFO("can't migrate unit, don't need auto migrate unit", K(tenant_id));
      } else if (OB_FAIL(migrate_unit(unit_id, dst, is_manual))) {
        LOG_WARN("fail migrate unit", K(unit_id), K(dst), K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::migrate_unit(const uint64_t unit_id, const ObAddr& dst, const bool is_manual)
{
  int ret = OB_SUCCESS;
  share::ObWorker::CompatMode compat_mode = share::ObWorker::CompatMode::INVALID;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == unit_id || !dst.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(unit_id), K(dst), K(ret));
  } else if (OB_UNLIKELY(nullptr == leader_coordinator_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("leader coordinator ptr is null", K(ret));
  } else {
    ObUnit* unit = NULL;
    share::ObResourcePool* pool = NULL;
    if (OB_FAIL(get_unit_by_id(unit_id, unit))) {
      LOG_WARN("get_unit_by_id failed", K(unit_id), K(ret));
    } else if (NULL == unit) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unit is null", KP(unit), K(ret));
    } else if (ObUnit::UNIT_STATUS_ACTIVE != unit->status_) {
      ret = OB_OP_NOT_ALLOW;
      LOG_WARN("cannot migrate unit which is in deleting", K(ret), K(unit_id));
    } else if (OB_FAIL(get_resource_pool_by_id(unit->resource_pool_id_, pool))) {
      LOG_WARN("get_resource_pool_by_id failed", "resource pool id", unit->resource_pool_id_, K(ret));
    } else if (NULL == pool) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pool is null", KP(pool), K(ret));
    } else if (nullptr == schema_service_) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("schema service ptr is null", K(ret));
    } else if (OB_INVALID_ID == pool->tenant_id_) {
      // by pass
    } else if (OB_FAIL(ObCompatModeGetter::get_tenant_mode(pool->tenant_id_, compat_mode))) {
      LOG_WARN("fail to get tenant compat mode", K(ret));
    }
    if (OB_SUCC(ret)) {
      ObAddr src;
      ObZone zone;
      // granted: If the unit has not been assigned to the tenant, the migration can be performed immediately
      const bool granted = (OB_INVALID_ID != pool->tenant_id_);
      if (!granted && common::STANDBY_CLUSTER == ObClusterInfoGetter::get_cluster_type_v2()) {
        // Units without grant on the standby database are not allowed to be migrated
        ret = OB_OP_NOT_ALLOW;
        LOG_WARN("migrate not grant unit not valid", K(ret));
        LOG_USER_ERROR(OB_OP_NOT_ALLOW, "migrate unit which has not been granted");
      } else if (OB_FAIL(server_mgr_.get_server_zone(dst, zone))) {
        LOG_WARN("server_mgr_ get_server_zone failed", K(dst), K(ret));
      } else if (unit->server_ == dst) {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("unit->server same as migrate destination server", "unit", *unit, K(dst), K(ret));
      } else {
        src = unit->server_;
        if (unit->migrate_from_server_.is_valid()) {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("unit is already migrating, cannot migrate any more", "unit", *unit, K(ret));
          LOG_USER_ERROR(OB_NOT_SUPPORTED, "migrate unit already in migrating status");
        }

        if (OB_SUCC(ret)) {
          common::ObMySQLTransaction trans;
          ObUnit new_unit = *unit;
          new_unit.zone_ = zone;
          if (granted) {
            new_unit.migrate_from_server_ = unit->server_;
          }
          new_unit.server_ = dst;
          new_unit.is_manual_migrate_ = is_manual;
          const bool is_delete = false;  // is_delete is false when migrate unit
          int tmp_ret = OB_SUCCESS;
          ObNotifyTenantServerResourceProxy notify_proxy(
              leader_coordinator_->get_rpc_proxy(), &obrpc::ObSrvRpcProxy::notify_tenant_server_unit_resource);
          if (OB_FAIL(try_notify_tenant_server_unit_resource(pool->tenant_id_,
                  is_delete,
                  notify_proxy,
                  *pool,
                  compat_mode,
                  new_unit,
                  false /*if not grant*/,
                  false /*skip offline server*/))) {
            LOG_WARN("fail to try notify server unit resource", K(ret));
          }

          if (OB_SUCCESS != (tmp_ret = notify_proxy.wait())) {
            LOG_WARN("fail to wait notify resource", K(ret), K(tmp_ret));
            ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
          }

          if (OB_FAIL(ret)) {
          } else if (OB_FAIL(trans.start(proxy_))) {
            LOG_WARN("failed to start trans", K(ret));
          } else if (is_manual) {
            char ip_buf[common::MAX_IP_ADDR_LENGTH];
            (void)dst.ip_to_string(ip_buf, common::MAX_IP_ADDR_LENGTH);
            const int64_t job_id =
                RS_JOB_CREATE(MIGRATE_UNIT, trans, "unit_id", unit_id, "svr_ip", ip_buf, "svr_port", dst.get_port());
            if (job_id < 1) {
              ret = OB_SQL_OPT_ERROR;
              LOG_WARN("insert into all_rootservice_job failed ", K(ret));
            } else if (!granted) {
              if (OB_FAIL(RS_JOB_COMPLETE(job_id, OB_SUCCESS, trans))) {
                LOG_WARN("all_rootservice_job update failed", K(ret), K(job_id));
              }
            }
          }
          if (OB_FAIL(ret)) {
          } else if (OB_FAIL(ut_operator_.update_unit(trans, new_unit))) {
            LOG_WARN("update_unit failed", K(new_unit), K(ret));
          } else {
            *unit = new_unit;
          }
          if (trans.is_started()) {
            if (OB_SUCCESS != (tmp_ret = trans.end(OB_SUCC(ret)))) {
              ret = OB_SUCC(ret) ? tmp_ret : ret;
              LOG_WARN("trans commit failed", K(tmp_ret), K(ret));
            }
          }
        }

        // delete unit load if needed, insert unit load on dst
        ObUnitLoad load;
        if (OB_SUCC(ret)) {
          root_balance_->wakeup();
          if (!granted) {
            if (OB_FAIL(delete_unit_load(src, unit_id))) {
              LOG_WARN("delete_unit_load failed", K(src), K(unit_id), K(ret));
            }
          }

          if (OB_FAIL(ret)) {
          } else if (OB_FAIL(gen_unit_load(unit, load))) {
            LOG_WARN("gen_unit_load failed", "unit", *unit, K(ret));
          } else if (OB_FAIL(insert_unit_load(dst, load))) {
            LOG_WARN("insert_unit_load failed", K(dst), K(ret));
          }
        }

        if (OB_SUCC(ret)) {
          if (granted) {
            // ObArray<ObAddr> servers;
            if (OB_FAIL(insert_migrate_unit(unit->migrate_from_server_, unit->unit_id_))) {
              LOG_WARN("insert_migrate_unit failed", "unit", *unit, K(ret));
            }
          }

          if (OB_SUCC(ret)) {
            ROOTSERVICE_EVENT_ADD("unit",
                "migrate_unit",
                "unit_id",
                unit->unit_id_,
                "migrate_from_server",
                unit->migrate_from_server_,
                "server",
                unit->server_,
                "tenant_id",
                pool->tenant_id_);
          }
        }
      }
      LOG_INFO("migrate unit succeed", K(unit_id), K(src), K(dst), K(granted));
    }
  }
  LOG_INFO("migrate unit", K(unit_id), K(dst), K(ret));
  return ret;
}

int ObUnitManager::inner_try_delete_migrate_unit_resource(
    const uint64_t unit_id, const common::ObAddr& migrate_from_server)
{
  int ret = OB_SUCCESS;
  ObUnit* unit = NULL;
  share::ObResourcePool* pool = NULL;
  share::ObUnitConfig* unit_config = nullptr;
  share::ObWorker::CompatMode compat_mode = share::ObWorker::CompatMode::INVALID;
  bool is_alive = false;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("inner stat unexpected", K(ret), K(inited_), K(loaded_));
  } else if (OB_UNLIKELY(OB_INVALID_ID == unit_id)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(unit_id));
  } else if (OB_FAIL(get_unit_by_id(unit_id, unit))) {
    LOG_WARN("fail to get unit by id", K(ret), K(unit_id));
  } else if (OB_ISNULL(unit)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unit ptr is null", K(ret), KP(unit));
  } else if (!migrate_from_server.is_valid()) {
    LOG_INFO("unit not in migrating, no need to delete src resource", K(unit_id));
  } else if (OB_FAIL(server_mgr_.check_server_alive(migrate_from_server, is_alive))) {
    LOG_WARN("fail to check server alive", K(ret), "server", migrate_from_server);
  } else if (!is_alive) {
    LOG_INFO("src server not alive, ignore notify", K(unit_id), "server", migrate_from_server);
  } else if (OB_FAIL(get_resource_pool_by_id(unit->resource_pool_id_, pool))) {
    LOG_WARN("failed to get pool", K(ret), K(unit));
  } else if (OB_ISNULL(pool)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool ptr is null", K(ret), KP(pool));
  } else if (OB_FAIL(get_unit_config_by_id(pool->unit_config_id_, unit_config))) {
    LOG_WARN("fail to get unit config by id", K(ret));
  } else if (OB_UNLIKELY(nullptr == unit_config)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unit config is null", K(ret), "unit_config_id", pool->unit_config_id_);
  } else if (OB_INVALID_ID == pool->tenant_id_) {
    LOG_INFO("unit is not granted to any tenant", K(ret), "tenant_id", pool->tenant_id_);
  } else if (OB_FAIL(ObCompatModeGetter::get_tenant_mode(pool->tenant_id_, compat_mode))) {
    LOG_WARN("fail to get tenant compat mode", K(ret), "tenant_id", pool->tenant_id_, K(unit_id), "pool", *pool);
  } else {
    const int64_t rpc_timeout = NOTIFY_RESOURCE_RPC_TIMEOUT;
    obrpc::TenantServerUnitConfig tenant_unit_server_config;
    ObNotifyTenantServerResourceProxy notify_proxy(
        leader_coordinator_->get_rpc_proxy(), &obrpc::ObSrvRpcProxy::notify_tenant_server_unit_resource);
    if (OB_FAIL(tenant_unit_server_config.init(pool->tenant_id_,
            compat_mode,
            *unit_config,
            unit->replica_type_,
            false /*if not grant*/,
            true /*delete*/))) {
      LOG_WARN("fail to init tenant server unit config", K(ret), "tenant_id", pool->tenant_id_);
    } else if (OB_FAIL(notify_proxy.call(migrate_from_server, rpc_timeout, tenant_unit_server_config))) {
      LOG_WARN(
          "fail to call notify resource to server", K(ret), K(rpc_timeout), "unit", *unit, "dest", migrate_from_server);
    }
    int tmp_ret = OB_SUCCESS;
    if (OB_SUCCESS != (tmp_ret = notify_proxy.wait())) {
      LOG_WARN("fail to wait notify resource", K(ret), K(tmp_ret));
      ret = (OB_SUCCESS == ret) ? tmp_ret : ret;
    }
    if (OB_SUCC(ret)) {
      LOG_INFO("notify resource to server succeed", "unit", *unit, "dest", migrate_from_server);
    }
  }
  return ret;
}

int ObUnitManager::end_migrate_unit(const uint64_t unit_id, const EndMigrateOp end_migrate_op)
{
  int ret = OB_SUCCESS;
  uint64_t tenant_id = OB_INVALID_TENANT_ID;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == unit_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(unit_id), K(ret));
  } else if (end_migrate_op < COMMIT || end_migrate_op > REVERSE) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid end_migrate_op", K(end_migrate_op), K(ret));
  } else {
    ObUnit* unit = NULL;
    common::ObMySQLTransaction trans;
    if (OB_FAIL(get_unit_by_id(unit_id, unit))) {
      LOG_WARN("get_unit_by_id failed", K(unit_id), K(ret));
    } else if (NULL == unit) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unit is null", KP(unit), K(ret));
    } else if (!unit->migrate_from_server_.is_valid()) {
      // FIXME(): when can this happened, figure it out
      ret = OB_SUCCESS;
      LOG_WARN("unit is not in migrating status, maybe end_migrate_unit has ever called", "unit", *unit, K(ret));
    } else {
      const ObAddr migrate_from_server = unit->migrate_from_server_;
      const ObAddr unit_server = unit->server_;
      ObUnit new_unit = *unit;
      new_unit.is_manual_migrate_ = false;  // clear manual_migrate
      // generate new unit
      if (COMMIT == end_migrate_op) {
        new_unit.migrate_from_server_.reset();
      } else if (ABORT == end_migrate_op) {
        new_unit.server_ = unit->migrate_from_server_;
        new_unit.migrate_from_server_.reset();
      } else {
        new_unit.server_ = unit->migrate_from_server_;
        new_unit.migrate_from_server_ = unit->server_;
      }

      // update unit in sys_table and in memory
      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(trans.start(proxy_))) {
        LOG_WARN("failed to start transaction ", K(ret));
      } else if (OB_FAIL(ut_operator_.update_unit(trans, new_unit))) {
        LOG_WARN("ut_operator update unit failed", K(new_unit), K(ret));
      } else {
        if (ABORT == end_migrate_op) {
          if (OB_FAIL(delete_unit_load(unit->server_, unit->unit_id_))) {
            LOG_WARN("delete_unit_load failed", "unit", *unit, K(ret));
          }
        } else if (COMMIT == end_migrate_op) {
          if (OB_FAIL(delete_unit_load(unit->migrate_from_server_, unit->unit_id_))) {
            LOG_WARN("delete_unit_load failed", "unit", *unit, K(ret));
          }
        }
        if (OB_SUCC(ret)) {
          *unit = new_unit;
        }
      }

      // delete migrating unit from migrate_units of migrate_from_server,
      // if REVERSE == op, add migrating unit to migrate_units of unit_server
      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(delete_migrate_unit(migrate_from_server, unit->unit_id_))) {
        LOG_WARN("delete_migrate_unit failed", K(migrate_from_server), "unit_id", unit->unit_id_, K(ret));
      } else if (REVERSE == end_migrate_op) {
        if (OB_FAIL(insert_migrate_unit(unit_server, unit->unit_id_))) {
          LOG_WARN("insert_migrate_unit failed", K(unit_server), "unit_id", unit->unit_id_, K(ret));
        }
      }

      if (OB_SUCC(ret)) {
        int tmp_ret = OB_SUCCESS;
        share::ObResourcePool* pool = NULL;
        if (OB_SUCCESS != (tmp_ret = get_resource_pool_by_id(unit->resource_pool_id_, pool))) {
          LOG_WARN("failed to get pool", K(tmp_ret), K(unit));
        } else {
          tenant_id = pool->tenant_id_;
        }
        ROOTSERVICE_EVENT_ADD("unit",
            "finish_migrate_unit",
            "unit_id",
            unit_id,
            "end_op",
            end_migrate_op,
            "migrate_from_server",
            migrate_from_server,
            "server",
            unit_server,
            "tenant_id",
            tenant_id);

        // complete the job if exists
        char ip_buf[common::MAX_IP_ADDR_LENGTH];
        (void)unit_server.ip_to_string(ip_buf, common::MAX_IP_ADDR_LENGTH);
        ObRsJobInfo job_info;
        tmp_ret = RS_JOB_FIND(job_info,
            trans,
            "job_type",
            "MIGRATE_UNIT",
            "job_status",
            "INPROGRESS",
            "unit_id",
            unit_id,
            "svr_ip",
            ip_buf,
            "svr_port",
            unit_server.get_port());
        if (OB_SUCCESS == tmp_ret && job_info.job_id_ > 0) {
          tmp_ret = (end_migrate_op == COMMIT) ? OB_SUCCESS : (end_migrate_op == REVERSE ? OB_CANCELED : OB_TIMEOUT);
          if (OB_FAIL(RS_JOB_COMPLETE(job_info.job_id_, tmp_ret, trans))) {
            LOG_WARN("all_rootservice_job update failed", K(ret), K(job_info));
          }
        } else {
          // Can not find the situation, only the user manually opened will write rs_job
          LOG_WARN("no rs job", K(ret), K(tmp_ret), K(unit_id));
        }
      }
      const bool commit = OB_SUCC(ret) ? true : false;
      int tmp_ret = OB_SUCCESS;
      if (OB_SUCCESS != (tmp_ret = trans.end(commit))) {
        LOG_WARN("tran commit failed", K(tmp_ret));
      }
      ret = OB_SUCC(ret) ? tmp_ret : ret;

      if (OB_SUCC(ret) && COMMIT == end_migrate_op && OB_INVALID_TENANT_ID != tenant_id) {
        (void)inner_try_delete_migrate_unit_resource(unit_id, migrate_from_server);
      }
    }
  }

  if (OB_SUCC(ret) && REVERSE == end_migrate_op && OB_INVALID_TENANT_ID != tenant_id) {
    int tmp_ret = OB_SUCCESS;
    obrpc::ObAdminClearBalanceTaskArg::TaskType type = obrpc::ObAdminClearBalanceTaskArg::ALL;
    if (OB_SUCCESS != (tmp_ret = GCTX.root_service_->get_rebalance_task_mgr().clear_task(tenant_id, type))) {
      LOG_WARN("fail to clear task", K(ret), K(tenant_id), K(type));
    }
  }
  LOG_INFO("end migrate unit", K(unit_id), K(end_migrate_op), K(ret));
  return ret;
}

#define INSERT_ITEM_TO_MAP(map, key, pvalue)               \
  do {                                                     \
    if (OB_FAIL(ret)) {                                    \
    } else if (OB_FAIL(map.set_refactored(key, pvalue))) { \
      if (OB_HASH_EXIST == ret) {                          \
        LOG_WARN("key already exist", K(key), K(ret));     \
      } else {                                             \
        LOG_WARN("map set failed", K(ret));                \
      }                                                    \
    } else {                                               \
    }                                                      \
  } while (false)

#define SET_ITEM_TO_MAP(map, key, value)                             \
  do {                                                               \
    const int overwrite = 1;                                         \
    if (OB_FAIL(ret)) {                                              \
    } else if (OB_FAIL(map.set_refactored(key, value, overwrite))) { \
      LOG_WARN("map set failed", K(ret));                            \
    } else {                                                         \
    }                                                                \
  } while (false)

#define INSERT_ARRAY_TO_MAP(map, key, array)              \
  do {                                                    \
    if (OB_FAIL(ret)) {                                   \
    } else if (OB_FAIL(map.set_refactored(key, array))) { \
      if (OB_HASH_EXIST == ret) {                         \
        LOG_WARN("key already exist", K(key), K(ret));    \
      } else {                                            \
        LOG_WARN("map set failed", K(ret));               \
      }                                                   \
    } else {                                              \
    }                                                     \
  } while (false)

int ObUnitManager::build_unit_map(const ObIArray<ObUnit>& units)
{
  int ret = OB_SUCCESS;
  // units is empty if invoked during bootstrap
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_FAIL(id_unit_map_.clear())) {
    LOG_WARN("id_unit_map_ clear failed", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < units.count(); ++i) {
      ObUnit* unit = NULL;
      if (NULL == (unit = allocator_.alloc())) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_ERROR("alloc unit failed", K(ret));
      } else {
        *unit = units.at(i);
        if (OB_FAIL(insert_unit(unit))) {
          LOG_WARN("insert_unit failed", "unit", *unit, K(ret));
        }

        if (OB_FAIL(ret)) {
          // avoid memory leak
          allocator_.free(unit);
          unit = NULL;
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::build_config_map(const ObIArray<ObUnitConfig>& configs)
{
  int ret = OB_SUCCESS;
  // configs is empty if invoked during bootstrap
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_FAIL(id_config_map_.clear())) {
    LOG_WARN("id_config_map_ clear failed", K(ret));
  } else if (OB_FAIL(name_config_map_.clear())) {
    LOG_WARN("name_config_map_ clear failed", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < configs.count(); ++i) {
      ObUnitConfig* config = NULL;
      if (NULL == (config = config_allocator_.alloc())) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_ERROR("alloc unit config failed", K(ret));
      } else {
        *config = configs.at(i);
        if (OB_FAIL(insert_unit_config(config))) {
          LOG_WARN("insert_unit_config failed", KP(config), K(ret));
        }

        if (OB_FAIL(ret)) {
          config_allocator_.free(config);
          config = NULL;
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::build_pool_map(const ObIArray<share::ObResourcePool>& pools)
{
  int ret = OB_SUCCESS;
  // pools is empty if invoked during bootstrap
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_FAIL(id_pool_map_.clear())) {
    LOG_WARN("id_pool_map_ clear failed", K(ret));
  } else if (OB_FAIL(name_pool_map_.clear())) {
    LOG_WARN("name_pool_map_ clear failed", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < pools.count(); ++i) {
      share::ObResourcePool* pool = NULL;
      if (NULL == (pool = pool_allocator_.alloc())) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_ERROR("alloc resource pool failed", K(ret));
      } else {
        if (OB_FAIL(pool->assign(pools.at(i)))) {
          LOG_WARN("failed to assign pool", K(ret));
        } else {
          INSERT_ITEM_TO_MAP(id_pool_map_, pool->resource_pool_id_, pool);
          INSERT_ITEM_TO_MAP(name_pool_map_, pool->name_, pool);
          if (OB_FAIL(ret)) {
          } else if (OB_FAIL(inc_config_ref_count(pool->unit_config_id_))) {
            LOG_WARN("inc_config_ref_count failed", "config id", pool->unit_config_id_, K(ret));
          } else if (OB_FAIL(insert_config_pool(pool->unit_config_id_, pool))) {
            LOG_WARN("insert config pool failed", "config id", pool->unit_config_id_, K(ret));
          }
        }

        if (OB_FAIL(ret)) {
          pool_allocator_.free(pool);
          pool = NULL;
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::insert_unit_config(ObUnitConfig* config)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (NULL == config) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("config is null", KP(config), K(ret));
  } else if (!config->is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid config", "config", *config, K(ret));
  } else {
    INSERT_ITEM_TO_MAP(id_config_map_, config->unit_config_id_, config);
    INSERT_ITEM_TO_MAP(name_config_map_, config->name_, config);
    int64_t ref_count = 0;
    SET_ITEM_TO_MAP(config_ref_count_map_, config->unit_config_id_, ref_count);
  }
  return ret;
}

int ObUnitManager::inc_config_ref_count(const uint64_t config_id)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == config_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid config_id", K(config_id), K(ret));
  } else {
    int64_t ref_count = 0;
    if (OB_FAIL(get_config_ref_count(config_id, ref_count))) {
      LOG_WARN("get_config_ref_count failed", K(config_id), K(ret));
    } else {
      ++ref_count;
      SET_ITEM_TO_MAP(config_ref_count_map_, config_id, ref_count);
    }
  }
  return ret;
}

int ObUnitManager::dec_config_ref_count(const uint64_t config_id)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == config_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid config_id", K(config_id), K(ret));
  } else {
    int64_t ref_count = 0;
    if (OB_FAIL(get_config_ref_count(config_id, ref_count))) {
      LOG_WARN("get_config_ref_count failed", K(config_id), K(ret));
    } else {
      --ref_count;
      SET_ITEM_TO_MAP(config_ref_count_map_, config_id, ref_count);
    }
  }
  return ret;
}

int ObUnitManager::update_pool_map(share::ObResourcePool* resource_pool)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (NULL == resource_pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("resource_pool is null", KP(resource_pool), K(ret));
  } else if (!resource_pool->is_valid() || OB_INVALID_ID == resource_pool->resource_pool_id_) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid resource_pool", "resource_pool", *resource_pool, K(ret));
  } else {
    INSERT_ITEM_TO_MAP(id_pool_map_, resource_pool->resource_pool_id_, resource_pool);
    INSERT_ITEM_TO_MAP(name_pool_map_, resource_pool->name_, resource_pool);
  }
  return ret;
}

int ObUnitManager::insert_unit(ObUnit* unit)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_INFO("not init", K(ret));
  } else if (NULL == unit) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("unit is null", KP(unit), K(ret));
  } else if (!unit->is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid unit", "unit", *unit, K(ret));
  } else {
    ObArray<ObUnit*>* units = NULL;
    if (OB_FAIL(get_units_by_pool(unit->resource_pool_id_, units))) {
      if (OB_ENTRY_NOT_EXIST != ret) {
        LOG_WARN("get_units_by_pool failed", K(ret));
      } else {
        ret = OB_SUCCESS;
        if (NULL == (units = pool_unit_allocator_.alloc())) {
          ret = OB_ALLOCATE_MEMORY_FAILED;
          LOG_ERROR("alloc ObArray<ObUnit *> failed", K(ret));
        } else {
          if (OB_FAIL(units->push_back(unit))) {
            LOG_WARN("push_back failed", K(ret));
          } else {
            INSERT_ARRAY_TO_MAP(pool_unit_map_, unit->resource_pool_id_, units);
          }
          if (OB_FAIL(ret)) {
            pool_unit_allocator_.free(units);
            units = NULL;
          }
        }
      }
    } else if (NULL == units) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("units is null", KP(units), K(ret));
    } else if (OB_FAIL(units->push_back(unit))) {
      LOG_WARN("push_back failed", K(ret));
    }

    if (OB_SUCC(ret)) {
      INSERT_ITEM_TO_MAP(id_unit_map_, unit->unit_id_, unit);

      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(insert_unit_loads(unit))) {
        LOG_WARN("insert_unit_loads failed", "unit", *unit, K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::insert_unit_loads(ObUnit* unit)
{
  int ret = OB_SUCCESS;
  ObUnitLoad load;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (NULL == unit) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("unit is null", KP(unit), K(ret));
  } else if (!unit->is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid unit", "unit", *unit, K(ret));
  } else if (OB_FAIL(gen_unit_load(unit, load))) {
    LOG_WARN("gen_unit_load failed", "unit", *unit, K(ret));
  } else if (OB_FAIL(insert_unit_load(unit->server_, load))) {
    LOG_WARN("insert_unit_load failed", "server", unit->server_, K(ret));
  } else {
    if (OB_SUCCESS == ret && unit->migrate_from_server_.is_valid()) {
      if (OB_FAIL(insert_unit_load(unit->migrate_from_server_, load))) {
        LOG_WARN("insert_unit_load failed", "server", unit->migrate_from_server_, K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::insert_unit_load(const ObAddr& server, const ObUnitLoad& load)
{
  int ret = OB_SUCCESS;
  ObArray<ObUnitLoad>* loads = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!server.is_valid() || !load.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(server), K(load), K(ret));
  } else if (OB_FAIL(get_loads_by_server(server, loads))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_loads_by_server failed", K(server), K(ret));
    } else {
      ret = OB_SUCCESS;
      // not exist, alloc new array, add to hash map
      if (NULL == (loads = load_allocator_.alloc())) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_ERROR("alloc ObArray<ObUnitLoad> failed", K(ret));
      } else {
        if (OB_FAIL(loads->push_back(load))) {
          LOG_WARN("push_back failed", K(ret));
        } else if (OB_FAIL(insert_load_array(server, loads))) {
          LOG_WARN("insert_unit_load failed", K(server), K(ret));
        }
        if (OB_FAIL(ret)) {
          // avoid memory leak
          load_allocator_.free(loads);
          loads = NULL;
        }
      }
    }
  } else if (NULL == loads) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("loads is null", KP(loads), K(ret));
  } else {
    if (OB_FAIL(loads->push_back(load))) {
      LOG_WARN("push_back failed", K(ret));
    }
  }
  return ret;
}

int ObUnitManager::insert_load_array(const ObAddr& addr, ObArray<ObUnitLoad>* loads)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!addr.is_valid() || NULL == loads) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(addr), KP(loads), K(ret));
  } else if (loads->count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("loads is empty", "loads count", loads->count(), K(ret));
  } else {
    if (OB_FAIL(server_loads_.set_refactored(addr, loads))) {
      if (OB_HASH_EXIST == ret) {
        LOG_WARN("load array is not expect to exist", K(addr), K(ret));
      } else {
        LOG_WARN("set failed", K(addr), K(ret));
      }
    } else {
      // do nothing
    }
  }
  return ret;
}

int ObUnitManager::update_pool_load(share::ObResourcePool* pool, share::ObUnitConfig* new_config)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (NULL == pool || NULL == new_config) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(pool), KP(new_config));
  } else {
    FOREACH_X(sl, server_loads_, OB_SUCC(ret))
    {
      if (NULL == sl->second) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("NULL value", K(ret));
      }
      FOREACH_X(l, *sl->second, OB_SUCC(ret))
      {
        if (l->pool_ == pool) {
          l->unit_config_ = new_config;
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::gen_unit_load(ObUnit* unit, ObUnitLoad& load) const
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (NULL == unit) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("unit is null", KP(unit), K(ret));
  } else if (!unit->is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("unit is invalid", "unit", *unit, K(ret));
  } else {
    ObUnitConfig* config = NULL;
    share::ObResourcePool* pool = NULL;
    if (OB_FAIL(get_resource_pool_by_id(unit->resource_pool_id_, pool))) {
      LOG_WARN("get_resource_pool_by_id failed", "pool id", unit->resource_pool_id_, K(ret));
    } else if (NULL == pool) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pools is null", KP(pool), K(ret));
    } else if (OB_FAIL(get_unit_config_by_id(pool->unit_config_id_, config))) {
      LOG_WARN("get_unit_config_by_id failed", "unit config id", pool->unit_config_id_, K(ret));
    } else if (NULL == config) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("config is null", KP(config), K(ret));
    } else {
      load.unit_ = unit;
      load.pool_ = pool;
      load.unit_config_ = config;
    }
  }
  return ret;
}

int ObUnitManager::gen_unit_load(const uint64_t unit_id, ObUnitLoad& load) const
{
  int ret = OB_SUCCESS;
  ObUnit* unit = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == unit_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid unit_id", K(unit_id), K(ret));
  } else if (OB_FAIL(get_unit_by_id(unit_id, unit))) {
    LOG_WARN("get_unit_by_id failed", K(unit_id), K(ret));
  } else if (NULL == unit) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unit is null", KP(unit), K(ret));
  } else if (OB_FAIL(gen_unit_load(unit, load))) {
    LOG_WARN("gen_unit_load failed", "unit", *unit, K(ret));
  }
  return ret;
}

int ObUnitManager::insert_tenant_pool(const uint64_t tenant_id, share::ObResourcePool* pool)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == tenant_id || NULL == pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(tenant_id), KP(pool), K(ret));
  } else if (OB_FAIL(insert_id_pool(tenant_pools_map_, tenant_pools_allocator_, tenant_id, pool))) {
    LOG_WARN("insert tenant pool failed", K(tenant_id), KP(pool), K(ret));
  }

  return ret;
}

int ObUnitManager::insert_config_pool(const uint64_t config_id, share::ObResourcePool* pool)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == config_id || NULL == pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(config_id), KP(pool), K(ret));
  } else if (OB_FAIL(insert_id_pool(config_pools_map_, config_pools_allocator_, config_id, pool))) {
    LOG_WARN("insert config pool failed", K(config_id), KP(pool), K(ret));
  }

  return ret;
}

int ObUnitManager::insert_id_pool(common::hash::ObHashMap<uint64_t, common::ObArray<share::ObResourcePool*>*>& map,
    common::ObPooledAllocator<common::ObArray<share::ObResourcePool*> >& allocator, const uint64_t id,
    share::ObResourcePool* pool)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!map.created() || OB_INVALID_ID == id || NULL == pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", "map created", map.created(), K(id), KP(pool), K(ret));
  } else {
    ObArray<share::ObResourcePool*>* pools = NULL;
    if (OB_FAIL(get_pools_by_id(map, id, pools))) {
      if (OB_ENTRY_NOT_EXIST != ret) {
        LOG_WARN("get_pools_by_id failed", K(id), K(ret));
      } else {
        ret = OB_SUCCESS;
        if (NULL == (pools = allocator.alloc())) {
          ret = OB_ALLOCATE_MEMORY_FAILED;
          LOG_ERROR("alloc pools failed", K(ret));
        } else if (OB_FAIL(pools->push_back(pool))) {
          LOG_WARN("push_back failed", K(ret));
        } else if (OB_FAIL(insert_id_pool_array(map, id, pools))) {
          LOG_WARN("insert_id_pool_array failed", K(id), K(ret));
        }

        // avoid memory leak
        if (OB_SUCCESS != ret && NULL != pools) {
          allocator.free(pools);
          pools = NULL;
        }
      }
    } else if (NULL == pools) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pools is null", KP(pools), K(ret));
    } else if (!has_exist_in_array(*pools, pool)) {
      if (OB_FAIL(pools->push_back(pool))) {
        LOG_WARN("push_back failed", K(ret));
      }
    } else {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("resource pool already exists", K(ret), K(id), K(pools), K(pool));
    }
  }
  return ret;
}

int ObUnitManager::insert_id_pool_array(
    common::hash::ObHashMap<uint64_t, common::ObArray<share::ObResourcePool*>*>& map, const uint64_t id,
    ObArray<share::ObResourcePool*>* pools)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!map.created() || OB_INVALID_ID == id || NULL == pools) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", "map created", map.created(), K(id), KP(pools), K(ret));
  } else {
    if (OB_FAIL(map.set_refactored(id, pools))) {
      if (OB_HASH_EXIST == ret) {
        LOG_WARN("pools is not expect to exist", K(id), K(ret));
      } else {
        LOG_WARN("set failed", K(id), K(ret));
      }
    } else {
      // do nothing
    }
  }
  return ret;
}

int ObUnitManager::insert_migrate_unit(const ObAddr& src_server, const uint64_t unit_id)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!src_server.is_valid() || OB_INVALID_ID == unit_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(src_server), K(unit_id), K(ret));
  } else {
    ObArray<uint64_t>* migrate_units = NULL;
    if (OB_FAIL(get_migrate_units_by_server(src_server, migrate_units))) {
      if (OB_ENTRY_NOT_EXIST != ret) {
        LOG_WARN("get_migrate_units_by_server failed", K(src_server), K(ret));
      } else {
        ret = OB_SUCCESS;
        if (NULL == (migrate_units = migrate_units_allocator_.alloc())) {
          ret = OB_ALLOCATE_MEMORY_FAILED;
          LOG_ERROR("alloc  failed", K(ret));
        } else if (OB_FAIL(migrate_units->push_back(unit_id))) {
          LOG_WARN("push_back failed", K(ret));
        } else {
          INSERT_ARRAY_TO_MAP(server_migrate_units_map_, src_server, migrate_units);
        }

        // avoid memory leak
        if (OB_SUCCESS != ret && NULL != migrate_units) {
          migrate_units_allocator_.free(migrate_units);
          migrate_units = NULL;
        }
      }
    } else if (NULL == migrate_units) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("migrate_units is null", KP(migrate_units), K(ret));
    } else {
      if (OB_FAIL(migrate_units->push_back(unit_id))) {
        LOG_WARN("push_back failed", K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::set_server_ref_count(
    common::hash::ObHashMap<ObAddr, int64_t>& map, const ObAddr& server, const int64_t ref_count) const
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!map.created() || !server.is_valid() || ref_count <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", "map_created", map.created(), K(server), K(ref_count), K(ret));
  } else {
    SET_ITEM_TO_MAP(map, server, ref_count);
  }
  return ret;
}

#undef INSERT_ITEM_TO_MAP
#undef SET_ITEM_TO_MAP
#undef INSERT_ARRAY_TO_MAP

#define DELETE_ITEM_FROM_MAP(map, key)               \
  do {                                               \
    if (OB_FAIL(ret)) {                              \
    } else if (OB_FAIL(map.erase_refactored(key))) { \
      LOG_WARN("map erase failed", K(key), K(ret));  \
    } else {                                         \
    }                                                \
  } while (false)

int ObUnitManager::delete_unit_config(const uint64_t config_id, const ObUnitConfigName& name)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == config_id || name.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(config_id), K(name), K(ret));
  } else {
    DELETE_ITEM_FROM_MAP(id_config_map_, config_id);
    DELETE_ITEM_FROM_MAP(name_config_map_, name);
    DELETE_ITEM_FROM_MAP(config_ref_count_map_, config_id);
  }
  return ret;
}

int ObUnitManager::delete_resource_pool(const uint64_t pool_id, const ObResourcePoolName& name)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == pool_id || name.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(pool_id), K(name), K(ret));
  } else {
    DELETE_ITEM_FROM_MAP(id_pool_map_, pool_id);
    DELETE_ITEM_FROM_MAP(name_pool_map_, name);
  }
  return ret;
}

int ObUnitManager::delete_units_in_zones(
    const uint64_t resource_pool_id, const common::ObIArray<common::ObZone>& to_be_removed_zones)
{
  int ret = OB_SUCCESS;
  ObArray<ObUnit*>* units = NULL;
  ObArray<ObUnit*> left_units;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_UNLIKELY(OB_INVALID_ID == resource_pool_id) || OB_UNLIKELY(to_be_removed_zones.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(resource_pool_id), K(to_be_removed_zones));
  } else if (get_units_by_pool(resource_pool_id, units)) {
    LOG_WARN("fail to get units by pool", K(ret), K(resource_pool_id));
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units is null", K(ret), KP(units));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
      const ObUnit* unit = units->at(i);
      if (OB_UNLIKELY(NULL == unit)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit should not be null", "unit", OB_P(units->at(i)), K(ret));
      } else if (!has_exist_in_array(to_be_removed_zones, unit->zone_)) {
        if (OB_FAIL(left_units.push_back(units->at(i)))) {
          LOG_WARN("fail to push back", K(ret));
        } else {
        }  // no more to do
      } else if (OB_FAIL(delete_unit_loads(*unit))) {
        LOG_WARN("fail to delete unit load", K(ret), "unit", *units->at(i));
      } else {
        DELETE_ITEM_FROM_MAP(id_unit_map_, unit->unit_id_);
        if (OB_SUCC(ret)) {
          if (unit->migrate_from_server_.is_valid()) {
            // If the unit is being migrated, delete it from the state in memory
            if (OB_FAIL(delete_migrate_unit(unit->migrate_from_server_, unit->unit_id_))) {
              LOG_WARN("failed to delete migrate unit", K(ret), "unit", *unit);
            }
          }
        }
        if (OB_SUCC(ret)) {
          ROOTSERVICE_EVENT_ADD("unit", "drop_unit", "unit_id", units->at(i)->unit_id_);
          allocator_.free(units->at(i));
          units->at(i) = NULL;
          ;
        }
      }
    }
    if (OB_SUCC(ret)) {
      if (left_units.count() <= 0) {
        DELETE_ITEM_FROM_MAP(pool_unit_map_, resource_pool_id);
        if (OB_SUCC(ret)) {
          pool_unit_allocator_.free(units);
          units = NULL;
        }
      } else {
        if (OB_FAIL(units->assign(left_units))) {
          LOG_WARN("assign failed", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::delete_units_of_pool(const uint64_t resource_pool_id)
{
  int ret = OB_SUCCESS;
  ObArray<ObUnit*>* units = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == resource_pool_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(resource_pool_id), K(ret));
  } else if (OB_FAIL(get_units_by_pool(resource_pool_id, units))) {
    LOG_WARN("fail to get unit by pool", K(resource_pool_id), K(ret));
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units is null", KP(units), K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
      const ObUnit* unit = units->at(i);
      if (OB_UNLIKELY(NULL == unit)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit should not be null", K(ret));
      } else if (OB_FAIL(delete_unit_loads(*unit))) {
        LOG_WARN("fail to delete unit load", K(ret));
      } else {
        DELETE_ITEM_FROM_MAP(id_unit_map_, unit->unit_id_);
        if (OB_SUCC(ret)) {
          if (unit->migrate_from_server_.is_valid()) {
            if (OB_FAIL(delete_migrate_unit(unit->migrate_from_server_, unit->unit_id_))) {
              LOG_WARN("failed to delete migrate unit", K(ret), "unit", *unit);
            }
          }
        }

        if (OB_SUCC(ret)) {
          ROOTSERVICE_EVENT_ADD("unit", "drop_unit", "unit_id", units->at(i)->unit_id_);
          allocator_.free(units->at(i));
          units->at(i) = NULL;
        }
      }
    }
    if (OB_SUCC(ret)) {
      DELETE_ITEM_FROM_MAP(pool_unit_map_, resource_pool_id);
      if (OB_SUCC(ret)) {
        pool_unit_allocator_.free(units);
        units = NULL;
      }
    }
  }
  return ret;
}

int ObUnitManager::delete_invalid_inmemory_units(
    const uint64_t resource_pool_id, const common::ObIArray<uint64_t>& valid_unit_ids)
{
  int ret = OB_SUCCESS;
  ObArray<share::ObUnit*>* units = NULL;
  ObArray<share::ObUnit*> left_units;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == resource_pool_id || valid_unit_ids.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(resource_pool_id), "valid_unit_cnt", valid_unit_ids.count());
  } else if (OB_FAIL(get_units_by_pool(resource_pool_id, units))) {
    LOG_WARN("fail to get units by pool", K(ret), K(resource_pool_id));
  } else if (OB_UNLIKELY(NULL == units)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("units is null", KP(units), K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
      if (NULL == units->at(i)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unit ptr is null", K(ret));
      } else if (has_exist_in_array(valid_unit_ids, units->at(i)->unit_id_)) {
        if (OB_FAIL(left_units.push_back(units->at(i)))) {
          LOG_WARN("push_back failed", K(ret));
        }
      } else if (OB_FAIL(delete_unit_loads(*units->at(i)))) {
        LOG_WARN("fail to delete unit loads", K(ret), "unit", *units->at(i));
      } else {
        DELETE_ITEM_FROM_MAP(id_unit_map_, units->at(i)->unit_id_);
        if (OB_SUCC(ret)) {
          ROOTSERVICE_EVENT_ADD("unit", "drop_unit", "unit_id", units->at(i)->unit_id_);
          allocator_.free(units->at(i));
          units->at(i) = NULL;
        }
      }
    }
    if (OB_SUCC(ret)) {
      if (left_units.count() <= 0) {
        DELETE_ITEM_FROM_MAP(pool_unit_map_, resource_pool_id);
        if (OB_SUCC(ret)) {
          pool_unit_allocator_.free(units);
          units = NULL;
        }
      } else {
        if (OB_FAIL(units->assign(left_units))) {
          LOG_WARN("assign failed", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::delete_inmemory_units(const uint64_t resource_pool_id, const common::ObIArray<uint64_t>& unit_ids)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == resource_pool_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(resource_pool_id), K(ret));
  } else {
    ObArray<ObUnit*>* units = NULL;
    ObArray<ObUnit*> left_units;
    if (OB_FAIL(get_units_by_pool(resource_pool_id, units))) {
      LOG_WARN("get_units_by_pool failed", K(resource_pool_id), K(ret));
    } else if (NULL == units) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("units is null", KP(units), K(ret));
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
        if (NULL == units->at(i)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unit should not be null", "unit", OB_P(units->at(i)), K(ret));
        } else if (!has_exist_in_array(unit_ids, units->at(i)->unit_id_)) {
          if (OB_FAIL(left_units.push_back(units->at(i)))) {
            LOG_WARN("push_back failed", K(ret));
          }
        } else {
          if (OB_FAIL(delete_unit_loads(*units->at(i)))) {
            LOG_WARN("delete_unit_load failed", "unit", *units->at(i), K(ret));
          } else {
            DELETE_ITEM_FROM_MAP(id_unit_map_, units->at(i)->unit_id_);
            if (OB_SUCC(ret)) {
              ROOTSERVICE_EVENT_ADD("unit", "drop_unit", "unit_id", units->at(i)->unit_id_);
              allocator_.free(units->at(i));
              units->at(i) = NULL;
            }
          }
        }
      }
      if (OB_SUCC(ret)) {
        // if all units of pool are deleted, delete item from hashmap
        if (left_units.count() <= 0) {
          DELETE_ITEM_FROM_MAP(pool_unit_map_, resource_pool_id);
          if (OB_SUCC(ret)) {
            pool_unit_allocator_.free(units);
            units = NULL;
          }
        } else {
          if (OB_FAIL(units->assign(left_units))) {
            LOG_WARN("assign failed", K(ret));
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::delete_unit_loads(const ObUnit& unit)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!unit.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid unit", K(unit), K(ret));
  } else {
    const uint64_t unit_id = unit.unit_id_;
    if (OB_FAIL(delete_unit_load(unit.server_, unit_id))) {
      LOG_WARN("delete_unit_load failed", "server", unit.server_, K(unit_id), K(ret));
    } else {
      if (unit.migrate_from_server_.is_valid()) {
        if (OB_FAIL(delete_unit_load(unit.migrate_from_server_, unit_id))) {
          LOG_WARN("delete_unit_load failed", "server", unit.migrate_from_server_, K(unit_id), K(ret));
        } else {
          // do nothing
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::delete_unit_load(const ObAddr& server, const uint64_t unit_id)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!server.is_valid() || OB_INVALID_ID == unit_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(server), K(unit_id), K(ret));
  } else {
    ObArray<ObUnitLoad>* loads = NULL;
    if (OB_FAIL(get_loads_by_server(server, loads))) {
      LOG_WARN("get_loads_by_server failed", K(server), K(ret));
    } else if (NULL == loads) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("loads is null", KP(loads), K(ret));
    } else {
      int64_t index = -1;
      for (int64_t i = 0; OB_SUCC(ret) && i < loads->count(); ++i) {
        if (loads->at(i).unit_->unit_id_ == unit_id) {
          index = i;
          break;
        }
      }
      if (-1 == index) {
        ret = OB_ENTRY_NOT_EXIST;
        LOG_WARN("unit load not exist", K(server), K(unit_id), K(ret));
      } else {
        for (int64_t i = index; i < loads->count() - 1; ++i) {
          loads->at(i) = loads->at(i + 1);
        }
        loads->pop_back();
        if (0 == loads->count()) {
          load_allocator_.free(loads);
          loads = NULL;
          DELETE_ITEM_FROM_MAP(server_loads_, server);
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::delete_tenant_pool(const uint64_t tenant_id, share::ObResourcePool* pool)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == tenant_id || NULL == pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(tenant_id), KP(pool), K(ret));
  } else if (OB_FAIL(delete_id_pool(tenant_pools_map_, tenant_pools_allocator_, tenant_id, pool))) {
    LOG_WARN("delete tenant pool failed", K(ret), K(tenant_id), "pool", *pool);
  }
  return ret;
}

int ObUnitManager::delete_config_pool(const uint64_t config_id, share::ObResourcePool* pool)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == config_id || NULL == pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(config_id), KP(pool), K(ret));
  } else if (OB_FAIL(delete_id_pool(config_pools_map_, config_pools_allocator_, config_id, pool))) {
    LOG_WARN("delete config pool failed", K(ret), K(config_id), "pool", *pool);
  }
  return ret;
}

int ObUnitManager::delete_id_pool(common::hash::ObHashMap<uint64_t, common::ObArray<share::ObResourcePool*>*>& map,
    common::ObPooledAllocator<common::ObArray<share::ObResourcePool*> >& allocator, const uint64_t id,
    share::ObResourcePool* pool)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!map.created() || OB_INVALID_ID == id || NULL == pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", "map created", map.created(), K(id), KP(pool), K(ret));
  } else {
    ObArray<share::ObResourcePool*>* pools = NULL;
    if (OB_FAIL(get_pools_by_id(map, id, pools))) {
      LOG_WARN("get_pools_by_id failed", K(id), K(ret));
    } else if (NULL == pools) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("pools is null", KP(pools), K(ret));
    } else {
      int64_t index = -1;
      for (int64_t i = 0; i < pools->count(); ++i) {
        if (pools->at(i) == pool) {
          index = i;
          break;
        }
      }
      if (-1 == index) {
        ret = OB_ENTRY_NOT_EXIST;
        LOG_WARN("pool not exist", K(id), K(ret));
      } else if (OB_FAIL(pools->remove(index))) {
        LOG_WARN("remove failed", K(index), K(ret));
      } else if (0 == pools->count()) {
        allocator.free(pools);
        pools = NULL;
        DELETE_ITEM_FROM_MAP(map, id);
      }
    }
  }
  return ret;
}

int ObUnitManager::delete_migrate_unit(const ObAddr& src_server, const uint64_t unit_id)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!src_server.is_valid() || OB_INVALID_ID == unit_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(src_server), K(unit_id), K(ret));
  } else {
    ObArray<uint64_t>* migrate_units = NULL;
    if (OB_FAIL(get_migrate_units_by_server(src_server, migrate_units))) {
      LOG_WARN("get_migrate_units_by_server failed", K(src_server), K(ret));
    } else if (NULL == migrate_units) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("migrate_units is null", KP(migrate_units), K(ret));
    } else {
      int64_t index = -1;
      for (int64_t i = 0; i < migrate_units->count(); ++i) {
        if (migrate_units->at(i) == unit_id) {
          index = i;
          break;
        }
      }
      if (-1 == index) {
        ret = OB_ENTRY_NOT_EXIST;
        LOG_WARN("migrate_unit not exist", K(unit_id), K(ret));
      } else if (OB_FAIL(migrate_units->remove(index))) {
        LOG_WARN("remove failed", K(index), K(ret));
      } else if (0 == migrate_units->count()) {
        migrate_units_allocator_.free(migrate_units);
        migrate_units = NULL;
        DELETE_ITEM_FROM_MAP(server_migrate_units_map_, src_server);
      }
    }
  }
  return ret;
}

#undef DELETE_ITEM_FROM_MAP

#define GET_ITEM_FROM_MAP(map, key, value)          \
  do {                                              \
    if (OB_FAIL(map.get_refactored(key, value))) {  \
      if (OB_HASH_NOT_EXIST == ret) {               \
        ret = OB_ENTRY_NOT_EXIST;                   \
      } else {                                      \
        LOG_WARN("map get failed", K(key), K(ret)); \
      }                                             \
    } else {                                        \
    }                                               \
  } while (false)

int ObUnitManager::update_unit_load(share::ObUnit* unit, share::ObResourcePool* new_pool)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(!inited_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (NULL == unit || NULL == new_pool) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(unit), KP(new_pool));
  } else {
    ObArray<ObUnitManager::ObUnitLoad>* server_load = NULL;
    GET_ITEM_FROM_MAP(server_loads_, unit->server_, server_load);
    if (OB_FAIL(ret)) {
      LOG_WARN("fail to get server load", K(ret), "server", unit->server_);
    } else if (NULL == server_load) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("loads ptr is null", K(ret));
    } else {
      FOREACH_X(l, *server_load, OB_SUCC(ret))
      {
        if (l->unit_ == unit) {
          l->pool_ = new_pool;
        }
      }
    }
    if (OB_FAIL(ret)) {
    } else if (unit->migrate_from_server_.is_valid()) {
      ObArray<ObUnitManager::ObUnitLoad>* migrate_from_load = NULL;
      GET_ITEM_FROM_MAP(server_loads_, unit->migrate_from_server_, migrate_from_load);
      if (OB_FAIL(ret)) {
        LOG_WARN("fail to get server load", K(ret), "migrate_from_server", unit->migrate_from_server_);
      } else if (NULL == migrate_from_load) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("loads ptr is null", K(ret));
      } else {
        FOREACH_X(l, *migrate_from_load, OB_SUCC(ret))
        {
          if (l->unit_ == unit) {
            l->pool_ = new_pool;
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::get_unit_config_by_name(const ObUnitConfigName& name, ObUnitConfig*& config) const
{
  int ret = OB_SUCCESS;
  config = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (name.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid name", K(name), K(ret));
  } else {
    GET_ITEM_FROM_MAP(name_config_map_, name, config);
  }
  return ret;
}

int ObUnitManager::get_unit_config_by_id(const uint64_t config_id, ObUnitConfig*& config) const
{
  int ret = OB_SUCCESS;
  config = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == config_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(config_id), K(ret));
  } else {
    GET_ITEM_FROM_MAP(id_config_map_, config_id, config);
  }
  return ret;
}

int ObUnitManager::get_config_ref_count(const uint64_t config_id, int64_t& ref_count) const
{
  int ret = OB_SUCCESS;
  ref_count = 0;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == config_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(config_id), K(ret));
  } else {
    GET_ITEM_FROM_MAP(config_ref_count_map_, config_id, ref_count);
    if (OB_FAIL(ret)) {
      if (OB_ENTRY_NOT_EXIST == ret) {
      } else {
        LOG_WARN("GET_ITEM_FROM_MAP failed", K(config_id), K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::get_server_ref_count(
    common::hash::ObHashMap<ObAddr, int64_t>& map, const ObAddr& server, int64_t& ref_count) const
{
  int ret = OB_SUCCESS;
  ref_count = 0;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!map.created() || !server.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", "map created", map.created(), K(server), K(ret));
  } else {
    GET_ITEM_FROM_MAP(map, server, ref_count);
    if (OB_FAIL(ret)) {
      if (OB_ENTRY_NOT_EXIST == ret) {
      } else {
        LOG_WARN("GET_ITEM_FROM_MAP failed", K(server), K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::get_resource_pool_by_name(const ObResourcePoolName& name, share::ObResourcePool& pool) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  share::ObResourcePool* inner_pool = nullptr;
  if (OB_FAIL(inner_get_resource_pool_by_name(name, inner_pool))) {
    LOG_WARN("fail to inner get resource pool by name", K(ret), K(name));
  } else if (OB_UNLIKELY(nullptr == inner_pool)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("inner pool ptr is null", K(ret));
  } else if (OB_FAIL(pool.assign(*inner_pool))) {
    LOG_WARN("fail to assign pool", K(ret));
  }
  return ret;
}

int ObUnitManager::inner_get_resource_pool_by_name(const ObResourcePoolName& name, share::ObResourcePool*& pool) const
{
  int ret = OB_SUCCESS;
  pool = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (name.is_empty()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid name", K(name), K(ret));
  } else {
    GET_ITEM_FROM_MAP(name_pool_map_, name, pool);
  }
  return ret;
}

int ObUnitManager::get_resource_pool_by_id(const uint64_t pool_id, share::ObResourcePool*& pool) const
{
  int ret = OB_SUCCESS;
  pool = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == pool_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(pool_id), K(ret));
  } else {
    GET_ITEM_FROM_MAP(id_pool_map_, pool_id, pool);
  }
  return ret;
}

int ObUnitManager::get_units_by_pool(const uint64_t pool_id, ObArray<ObUnit*>*& units) const
{
  int ret = OB_SUCCESS;
  units = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == pool_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(pool_id), K(ret));
  } else {
    GET_ITEM_FROM_MAP(pool_unit_map_, pool_id, units);
  }
  return ret;
}

int ObUnitManager::get_unit_by_id(const uint64_t unit_id, ObUnit*& unit) const
{
  int ret = OB_SUCCESS;
  unit = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == unit_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(unit_id), K(ret));
  } else {
    GET_ITEM_FROM_MAP(id_unit_map_, unit_id, unit);
  }
  return ret;
}

int ObUnitManager::get_loads_by_server(const ObAddr& addr, ObArray<ObUnitManager::ObUnitLoad>*& loads) const
{
  int ret = OB_SUCCESS;
  loads = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!addr.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(addr), K(ret));
  } else {
    GET_ITEM_FROM_MAP(server_loads_, addr, loads);
  }
  return ret;
}

int ObUnitManager::get_pools_by_tenant(const uint64_t tenant_id, ObArray<share::ObResourcePool*>*& pools) const
{
  int ret = OB_SUCCESS;
  pools = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(tenant_id), K(ret));
  } else if (OB_FAIL(get_pools_by_id(tenant_pools_map_, tenant_id, pools))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_pools_by_id failed", K(tenant_id), K(ret));
    }
  }
  return ret;
}

int ObUnitManager::get_pools_by_config(const uint64_t config_id, ObArray<share::ObResourcePool*>*& pools) const
{
  int ret = OB_SUCCESS;
  pools = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_INVALID_ID == config_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(config_id), K(ret));
  } else if (OB_FAIL(get_pools_by_id(config_pools_map_, config_id, pools))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_pools_by_id failed", K(config_id), K(ret));
    }
  }
  return ret;
}

int ObUnitManager::get_pools_by_id(
    const common::hash::ObHashMap<uint64_t, common::ObArray<share::ObResourcePool*>*>& map, const uint64_t id,
    ObArray<share::ObResourcePool*>*& pools) const
{
  int ret = OB_SUCCESS;
  pools = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!map.created() || OB_INVALID_ID == id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", "map created", map.created(), K(id), K(ret));
  } else {
    GET_ITEM_FROM_MAP(map, id, pools);
  }
  return ret;
}

int ObUnitManager::inner_check_single_logonly_pool_for_locality(const share::ObResourcePool& pool,
    const common::ObIArray<share::ObZoneReplicaAttrSet>& zone_locality, bool& is_legal)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("ObUnitManager not init", K(ret), K(inited_));
  } else if (REPLICA_TYPE_LOGONLY != pool.replica_type_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool replica type unexpected", K(ret), K(pool));
  } else {
    is_legal = true;
    for (int64_t i = 0; is_legal && i < pool.zone_list_.count(); ++i) {
      const common::ObZone& zone = pool.zone_list_.at(i);
      for (int64_t j = 0; is_legal && j < zone_locality.count(); ++j) {
        const common::ObIArray<common::ObZone>& zone_set = zone_locality.at(j).zone_set_;
        if (zone_set.count() <= 1) {
          // bypass Non-mixed locality
        } else {  // mixed locality
          is_legal = !has_exist_in_array(zone_set, zone);
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::inner_check_logonly_pools_for_locality(const common::ObIArray<share::ObResourcePool*>& pools,
    const common::ObIArray<share::ObZoneReplicaAttrSet>& zone_locality, bool& is_legal)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("ObUnitManager not init", K(ret), K(inited_));
  } else if (OB_UNLIKELY(pools.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid arguemnt", K(ret), "pool_count", pools.count());
  } else {
    is_legal = true;
    for (int64_t i = 0; is_legal && OB_SUCC(ret) && i < pools.count(); ++i) {
      share::ObResourcePool* pool = pools.at(i);
      if (OB_UNLIKELY(nullptr == pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret), KP(pool));
      } else if (REPLICA_TYPE_LOGONLY != pool->replica_type_) {
        // bypass, since this is not logonly pool
      } else if (OB_FAIL(inner_check_single_logonly_pool_for_locality(*pool, zone_locality, is_legal))) {
        LOG_WARN("fail to inner check single logonly pool for locality", K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::inner_check_pools_unit_num_enough_for_locality(const common::ObIArray<share::ObResourcePool*>& pools,
    const common::ObIArray<common::ObZone>& schema_zone_list, const ZoneLocalityIArray& zone_locality, bool& is_enough)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("ObUnitManager not init", K(ret), K(inited_));
  } else if (pools.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(pools.count()));
  } else {
    common::ObArray<int64_t> unit_nums;
    for (int64_t i = 0; OB_SUCC(ret) && i < pools.count(); ++i) {
      share::ObResourcePool* pool = pools.at(i);
      if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret), KP(pool));
      } else if (OB_FAIL(unit_nums.push_back(pool->unit_count_))) {
        LOG_WARN("fail to push back", K(ret));
      } else {
      }  // no more to do
    }
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(do_check_shrink_granted_pool_allowed_by_locality(
                   pools, schema_zone_list, zone_locality, unit_nums, is_enough))) {
      LOG_WARN("fail to check pools unit num enough for locality", K(ret));
    } else {
    }  // no more to do
  }
  return ret;
}

// The legality check consists of two parts
// 1 In the locality of the mixed scene, there can be no logonly resource pool
// 2 Can the unit num of the resource pool fit all locality copies
int ObUnitManager::check_pools_unit_legality_for_locality(const common::ObIArray<share::ObResourcePoolName>& pools,
    const common::ObIArray<common::ObZone>& schema_zone_list, const ZoneLocalityIArray& zone_locality, bool& is_legal)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("ObUnitManager not init", K(ret), K(inited_));
  } else if (pools.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(pools.count()));
  } else {
    SpinRLockGuard guard(lock_);
    common::ObArray<share::ObResourcePool*> pool_ptrs;
    for (int64_t i = 0; OB_SUCC(ret) && i < pools.count(); ++i) {
      share::ObResourcePool* pool_ptr = NULL;
      if (OB_FAIL(inner_get_resource_pool_by_name(pools.at(i), pool_ptr))) {
        LOG_WARN("fail to get resource pool by name", K(ret), "pool_name", pools.at(i));
      } else if (OB_FAIL(pool_ptrs.push_back(pool_ptr))) {
        LOG_WARN("fail to push back", K(ret));
      } else {
      }  // no more to do
    }
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(inner_check_logonly_pools_for_locality(pool_ptrs, zone_locality, is_legal))) {
      LOG_WARN("fail to check logonly pools for locality", K(ret));
    } else if (!is_legal) {
      // no need to check any more
    } else if (OB_FAIL(inner_check_pools_unit_num_enough_for_locality(
                   pool_ptrs, schema_zone_list, zone_locality, is_legal))) {
      LOG_WARN("fail to check pools unit num enough for locality", K(ret));
    } else {
    }  // no more to do
  }
  return ret;
}

int ObUnitManager::get_migrate_units_by_server(const ObAddr& server, common::ObIArray<uint64_t>& migrate_units) const
{
  int ret = OB_SUCCESS;
  ObArray<uint64_t>* units = NULL;
  if (OB_FAIL(get_migrate_units_by_server(server, units))) {
    if (OB_ENTRY_NOT_EXIST == ret) {
      ret = OB_SUCCESS;  // no migrating units
    } else {
      LOG_WARN("fail get migrate units by server", K(server), K(ret));
    }
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
      const uint64_t unit_id = units->at(i);
      if (OB_FAIL(migrate_units.push_back(unit_id))) {
        LOG_WARN("fail push back unit id to array", K(unit_id), K(i), K(ret));
      }
    }
  }
  return ret;
}

int ObUnitManager::get_migrate_units_by_server(const ObAddr& server, common::ObArray<uint64_t>*& migrate_units) const
{
  int ret = OB_SUCCESS;
  migrate_units = NULL;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (!server.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid server", K(server), K(ret));
  } else {
    GET_ITEM_FROM_MAP(server_migrate_units_map_, server, migrate_units);
  }
  return ret;
}

#undef DELETE_ITEM_FROM_MAP

int ObUnitManager::fetch_new_unit_config_id(uint64_t& config_id)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else {
    ObMaxIdFetcher id_fetcher(*proxy_);
    uint64_t combine_id = OB_INVALID_ID;
    if (OB_FAIL(id_fetcher.fetch_new_max_id(OB_SYS_TENANT_ID, OB_MAX_USED_UNIT_CONFIG_ID_TYPE, combine_id))) {
      LOG_WARN("fetch_max_id failed", "id_type", OB_MAX_USED_UNIT_CONFIG_ID_TYPE, K(ret));
    } else {
      config_id = extract_pure_id(combine_id);
    }
  }
  return ret;
}

int ObUnitManager::fetch_new_resource_pool_id(uint64_t& resource_pool_id)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else {
    uint64_t combine_id = OB_INVALID_ID;
    ObMaxIdFetcher id_fetcher(*proxy_);
    if (OB_FAIL(id_fetcher.fetch_new_max_id(OB_SYS_TENANT_ID, OB_MAX_USED_RESOURCE_POOL_ID_TYPE, combine_id))) {
      LOG_WARN("fetch_new_max_id failed", "id_type", OB_MAX_USED_RESOURCE_POOL_ID_TYPE, K(ret));
    } else {
      resource_pool_id = extract_pure_id(combine_id);
    }
  }
  return ret;
}

int ObUnitManager::fetch_new_unit_id(uint64_t& unit_id)
{
  int ret = OB_SUCCESS;
  if (!inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else {
    uint64_t combine_id = OB_INVALID_ID;
    ObMaxIdFetcher id_fetcher(*proxy_);
    if (OB_FAIL(id_fetcher.fetch_new_max_id(OB_SYS_TENANT_ID, OB_MAX_USED_UNIT_ID_TYPE, combine_id))) {
      LOG_WARN("fetch_new_max_id failed", "id_type", OB_MAX_USED_UNIT_ID_TYPE, K(ret));
    } else {
      unit_id = extract_pure_id(combine_id);
    }
  }
  return ret;
}

int ObUnitManager::check_bootstrap_pool(const share::ObResourcePool& pool)
{
  int ret = OB_SUCCESS;
  if (!pool.is_valid()) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid pool", K(pool), K(ret));
  } else if (OB_SYS_UNIT_CONFIG_ID == pool.unit_config_id_ || OB_GTS_UNIT_CONFIG_ID == pool.unit_config_id_) {
    // good
  } else {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("pool not sys pool", K(pool), K(ret));
  }
  return ret;
}

int ObUnitManager::inner_get_tenant_zone_full_unit_num(
    const int64_t tenant_id, const common::ObZone& zone, int64_t& unit_num)
{
  int ret = OB_SUCCESS;
  ObArray<share::ObResourcePool*>* pools = NULL;
  if (OB_UNLIKELY(!inited_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_UNLIKELY(OB_INVALID_ID == tenant_id)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id));
  } else if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
    LOG_WARN("fail to get pools by tenant", K(ret), K(tenant_id));
  } else if (OB_UNLIKELY(NULL == pools)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pools ptr is null", K(ret), KP(pools));
  } else {
    bool find = false;
    for (int64_t i = 0; !find && OB_SUCC(ret) && i < pools->count(); ++i) {
      share::ObResourcePool* pool = pools->at(i);
      if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret), KP(pool));
      } else if (!has_exist_in_array(pool->zone_list_, zone)) {
        // not in this pool
      } else if (REPLICA_TYPE_FULL == pool->replica_type_) {
        unit_num = pool->unit_count_;
        find = true;
      } else {
      }  // not a full replica type resource pool, go on to check next
    }
    if (OB_FAIL(ret)) {
    } else if (!find) {
      unit_num = 0;
    }
  }
  return ret;
}

int ObUnitManager::get_tenant_zone_unit_loads(const int64_t tenant_id, const common::ObZone& zone,
    const common::ObReplicaType replica_type, common::ObIArray<ObUnitManager::ObUnitLoad>& unit_loads)
{
  int ret = OB_SUCCESS;
  ObArray<share::ObResourcePool*>* pools = NULL;
  unit_loads.reset();
  if (OB_UNLIKELY(!inited_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_UNLIKELY(OB_INVALID_ID == tenant_id || zone.is_empty() ||
                         !ObReplicaTypeCheck::is_replica_type_valid(replica_type))) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id), K(zone), K(replica_type));
  } else if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
    if (OB_ENTRY_NOT_EXIST == ret) {
      ret = OB_SUCCESS;
    } else {
      LOG_WARN("fail to get pools by tenant", K(ret), K(tenant_id));
    }
  } else if (OB_UNLIKELY(NULL == pools)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool ptr is null", K(ret), KP(pools));
  } else {
    unit_loads.reset();
    share::ObResourcePool* target_pool = NULL;
    for (int64_t i = 0; NULL == target_pool && OB_SUCC(ret) && i < pools->count(); ++i) {
      share::ObResourcePool* pool = pools->at(i);
      if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret), KP(pool));
      } else if (!has_exist_in_array(pool->zone_list_, zone)) {
        // not in this pool
      } else if (replica_type == pool->replica_type_) {
        target_pool = pool;
      } else {
      }  // not a full replica type resource pool, go on to check next
    }
    if (OB_FAIL(ret)) {
    } else if (NULL == target_pool) {
      ret = OB_ENTRY_NOT_EXIST;
    } else {
      ObArray<share::ObUnit*>* units = NULL;
      if (OB_FAIL(get_units_by_pool(target_pool->resource_pool_id_, units))) {
        LOG_WARN("fail to get units by pool", K(ret), "pool_id", target_pool->resource_pool_id_);
      } else if (OB_UNLIKELY(NULL == units)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("units ptr is null", K(ret), KP(units));
      } else {
        for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
          ObUnitLoad unit_load;
          ObUnit* unit = units->at(i);
          if (NULL == unit) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unit ptr is null", K(ret));
          } else if (unit->zone_ != zone) {
            // not this zone, ignore
          } else if (OB_FAIL(gen_unit_load(unit, unit_load))) {
            LOG_WARN("fail to gen unit load", K(ret));
          } else if (OB_FAIL(unit_loads.push_back(unit_load))) {
            LOG_WARN("fail to push back", K(ret));
          } else {
          }  // no more to do
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::get_tenant_zone_all_unit_loads(
    const int64_t tenant_id, const common::ObZone& zone, common::ObIArray<ObUnitManager::ObUnitLoad>& unit_loads)
{
  int ret = OB_SUCCESS;
  ObArray<share::ObResourcePool*>* pools = NULL;
  unit_loads.reset();
  if (OB_UNLIKELY(!inited_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else if (OB_UNLIKELY(OB_INVALID_ID == tenant_id || zone.is_empty())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id), K(zone));
  } else if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
    if (OB_ENTRY_NOT_EXIST == ret) {
      ret = OB_SUCCESS;
    } else {
      LOG_WARN("fail to get pools by tenant", K(ret), K(tenant_id));
    }
  } else if (OB_UNLIKELY(NULL == pools)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pool ptr is null", K(ret), KP(pools));
  } else {
    unit_loads.reset();
    common::ObArray<share::ObResourcePool*> target_pools;
    for (int64_t i = 0; OB_SUCC(ret) && i < pools->count(); ++i) {
      share::ObResourcePool* pool = pools->at(i);
      if (NULL == pool) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool ptr is null", K(ret), KP(pool));
      } else if (!has_exist_in_array(pool->zone_list_, zone)) {
        // not in this pool
      } else if (OB_FAIL(target_pools.push_back(pool))) {
        LOG_WARN("fail to push back", K(ret));
      } else {
      }  // no more to do
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < target_pools.count(); ++i) {
      ObArray<share::ObUnit*>* units = NULL;
      share::ObResourcePool* target_pool = target_pools.at(i);
      if (OB_UNLIKELY(NULL == target_pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("target pool ptr is null", K(ret), KP(target_pool));
      } else if (OB_FAIL(get_units_by_pool(target_pool->resource_pool_id_, units))) {
        LOG_WARN("fail to get units by pool", K(ret), "pool_id", target_pool->resource_pool_id_);
      } else if (OB_UNLIKELY(NULL == units)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("units ptr is null", K(ret), KP(units));
      } else {
        for (int64_t i = 0; OB_SUCC(ret) && i < units->count(); ++i) {
          ObUnitLoad unit_load;
          ObUnit* unit = units->at(i);
          if (NULL == unit) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("unit ptr is null", K(ret));
          } else if (unit->zone_ != zone) {
            // not this zone, ignore
          } else if (OB_FAIL(gen_unit_load(unit, unit_load))) {
            LOG_WARN("fail to gen unit load", K(ret));
          } else if (OB_FAIL(unit_loads.push_back(unit_load))) {
            LOG_WARN("fail to push back", K(ret));
          } else {
          }  // no more to do
        }
      }
    }
    if (OB_FAIL(ret)) {
    } else if (unit_loads.count() <= 0) {
      ret = OB_ENTRY_NOT_EXIST;
    }
  }
  return ret;
}

// After 14x, when create/modity tenants may appear,
// the unit overlaps on the OBS, which needs to be broken up.
// Guarantee a UNIT on an OBS
int ObUnitManager::distrubte_for_unit_intersect(const uint64_t tenant_id, const ObIArray<ObResourcePoolName>& pools)
{
  int ret = OB_SUCCESS;
  SpinWLockGuard guard(lock_);
  const bool enable_sys_unit_standalone = GCONF.enable_sys_unit_standalone;
  ObArray<ObAddr> sys_unit_servers;
  const common::ObZone empty_zone;  // means all zones
  const common::ObArray<uint64_t> empty_processed_id_array;
  if (pools.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(pools));
  } else if (OB_UNLIKELY(OB_INVALID_ID == tenant_id)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id));
  } else if (OB_FAIL(
                 get_tenant_unit_servers(OB_SYS_TENANT_ID, empty_zone, empty_processed_id_array, sys_unit_servers))) {
    LOG_WARN("fail to get tenant unit servers", K(ret));
  } else {
    ObArray<ObZone> zones;
    ObArray<ObAddr> servers;
    ObArray<ObUnitInfo> need_migrate_unit;
    ObArray<ObUnitInfo> unit_infos;
    share::ObResourcePool* pool = NULL;
    for (int64_t i = 0; i < pools.count() && OB_SUCC(ret); i++) {
      unit_infos.reset();
      if (OB_FAIL(inner_get_resource_pool_by_name(pools.at(i), pool))) {
        LOG_WARN("fail to get resource_pool by name", K(ret), K(pools), K(i));
      } else if (OB_ISNULL(pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get invalid pool", K(ret), K(pool));
      } else if (OB_FAIL(inner_get_unit_infos_of_pool(pool->resource_pool_id_, unit_infos))) {
        LOG_WARN("fail to get unit infos", K(ret), K(*pool));
      } else {
        for (int64_t j = 0; j < unit_infos.count() && OB_SUCC(ret); j++) {
          if (!has_exist_in_array(servers, unit_infos.at(j).unit_.server_)) {
            if (OB_FAIL(servers.push_back(unit_infos.at(j).unit_.server_))) {
              LOG_WARN("fail to push back", K(ret), K(unit_infos), K(j));
            }
          } else if (OB_FAIL(need_migrate_unit.push_back(unit_infos.at(j)))) {
            LOG_WARN("fail to push back", K(ret), K(unit_infos), K(j));
          }
        }
      }
    }  // end for pools
    ObArray<ObAddr> excluded_servers;
    if (OB_FAIL(ret)) {
      // nothing todo
    } else if (OB_FAIL(excluded_servers.assign(servers))) {
      LOG_WARN("fail to assign array", K(ret), K(servers));
    } else if (OB_SYS_TENANT_ID != tenant_id && enable_sys_unit_standalone &&
               OB_FAIL(append(excluded_servers, sys_unit_servers))) {
      LOG_WARN("fail to append sys unit servers", K(ret));
    } else {
      ObArray<ObAddr> servers_in_zone;
      ObAddr dest_server;
      for (int64_t i = 0; i < need_migrate_unit.count() && OB_SUCC(ret); i++) {
        const ObZone& zone = need_migrate_unit.at(i).unit_.zone_;
        if (OB_FAIL(choose_server_for_unit(need_migrate_unit.at(i).config_, zone, excluded_servers, dest_server))) {
          LOG_WARN("fail to choose server for unit", K(ret), K(zone), K(excluded_servers));

        } else if (OB_FAIL(migrate_unit(need_migrate_unit.at(i).unit_.unit_id_, dest_server, false))) {
          LOG_WARN("fail to migrate unit", K(ret), K(need_migrate_unit), K(i), K(dest_server));
        } else if (OB_FAIL(excluded_servers.push_back(dest_server))) {
          LOG_WARN("fail to push back", K(ret), K(excluded_servers));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::get_logonly_unit_ids(ObIArray<uint64_t>& unit_ids) const
{
  int ret = OB_SUCCESS;
  unit_ids.reset();
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  }
  for (ObHashMap<uint64_t, ObArray<ObUnit*>*>::const_iterator it = pool_unit_map_.begin();
       OB_SUCCESS == ret && it != pool_unit_map_.end();
       ++it) {
    if (NULL == it->second) {
      ret = OB_ERR_UNEXPECTED;
      LOG_ERROR("pointer of ObArray<ObUnit *> is null", "pool_id", it->first, K(ret));
    } else if (it->second->count() <= 0) {
      ret = OB_ERR_UNEXPECTED;
      LOG_ERROR("array of unit is empty", "pool_id", it->first, K(ret));
    } else {
      const ObArray<ObUnit*> units = *it->second;
      for (int64_t i = 0; OB_SUCC(ret) && i < units.count(); ++i) {
        uint64_t unit_id = units.at(i)->unit_id_;
        if (REPLICA_TYPE_LOGONLY != units.at(i)->replica_type_) {
          // nothing todo
        } else if (OB_FAIL(unit_ids.push_back(unit_id))) {
          LOG_WARN("fail push back it", K(unit_id), K(ret));
        } else {
          LOG_WARN("get logonly unit ids", K(unit_id));
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::get_unit_info_by_id(const uint64_t unit_id, share::ObUnitInfo& unit_info) const
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("fail to check inner stat", K(ret), K(inited_), K(loaded_));
  } else if (OB_FAIL(inner_get_unit_info_by_id(unit_id, unit_info))) {
    LOG_WARN("fail to get unit info by id", K(ret), K(unit_id));
  }
  return ret;
}

int ObUnitManager::get_logonly_unit_by_tenant(const int64_t tenant_id, ObIArray<ObUnitInfo>& logonly_unit_infos)
{
  int ret = OB_SUCCESS;
  share::schema::ObSchemaGetterGuard schema_guard;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id));
  } else if (OB_FAIL(get_newest_schema_guard_in_inner_table(tenant_id, schema_guard))) {
    LOG_WARN("fail to get schema guard", K(ret));
  } else if (OB_FAIL(get_logonly_unit_by_tenant(schema_guard, tenant_id, logonly_unit_infos))) {
    LOG_WARN("fail to get logonly unit", K(ret), K(tenant_id));
  }
  return ret;
}

int ObUnitManager::get_logonly_unit_by_tenant(
    share::schema::ObSchemaGetterGuard& schema_guard, const int64_t tenant_id, ObIArray<ObUnitInfo>& logonly_unit_infos)
{
  int ret = OB_SUCCESS;
  const ObTenantSchema* tenant_schema = NULL;
  logonly_unit_infos.reset();
  ObArray<ObUnitInfo> unit_infos;
  SpinRLockGuard guard(lock_);
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id));
  } else if (OB_FAIL(schema_guard.get_tenant_info(tenant_id, tenant_schema))) {
    LOG_WARN("fail to get tenant info", K(ret), K(tenant_id));
  } else if (OB_ISNULL(tenant_schema)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get invalid tenant_schema", K(ret), K(tenant_id));
  } else if (OB_FAIL(inner_get_active_unit_infos_of_tenant(*tenant_schema, unit_infos))) {
    LOG_WARN("fail to get active unit", K(ret), K(tenant_id));
  } else {
    for (int64_t i = 0; i < unit_infos.count() && OB_SUCC(ret); i++) {
      if (REPLICA_TYPE_LOGONLY != unit_infos.at(i).unit_.replica_type_) {
        // nothing todo
      } else if (OB_FAIL(logonly_unit_infos.push_back(unit_infos.at(i)))) {
        LOG_WARN("fail to push back", K(ret), K(unit_infos));
      }
    }
  }
  return ret;
}

int ObUnitManager::get_unit_infos(
    const common::ObIArray<share::ObResourcePoolName>& pools, ObIArray<ObUnitInfo>& unit_infos)
{
  int ret = OB_SUCCESS;
  SpinRLockGuard guard(lock_);
  unit_infos.reset();
  if (pools.count() <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(pools));
  } else {
    ObArray<ObUnitInfo> pool_units;
    share::ObResourcePool* pool = NULL;
    for (int64_t i = 0; i < pools.count() && OB_SUCC(ret); i++) {
      pool_units.reset();
      if (OB_FAIL(inner_get_resource_pool_by_name(pools.at(i), pool))) {
        LOG_WARN("fail to get resource pool", K(ret), K(i), K(pools));
      } else if (OB_ISNULL(pool)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get invalid pool", K(ret), K(pools));
      } else if (OB_FAIL(inner_get_unit_infos_of_pool(pool->resource_pool_id_, pool_units))) {
        LOG_WARN("fail to get unit infos", K(ret), K(*pool));
      } else {
        for (int64_t j = 0; j < pool_units.count() && OB_SUCC(ret); j++) {
          if (OB_FAIL(unit_infos.push_back(pool_units.at(j)))) {
            LOG_WARN("fail to push back", K(ret), K(pool_units));
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::inner_get_active_unit_infos_of_tenant(
    const ObTenantSchema& tenant_schema, ObIArray<ObUnitInfo>& unit_info)
{
  int ret = OB_SUCCESS;
  ObArray<uint64_t> pool_ids;
  uint64_t tenant_id = tenant_schema.get_tenant_id();
  common::ObArray<common::ObZone> tenant_zone_list;
  ObArray<share::ObResourcePool*>* pools = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_FAIL(tenant_schema.get_zone_list(tenant_zone_list))) {
    LOG_WARN("fail to get zone list", K(ret));
  } else if (OB_FAIL(get_pools_by_tenant(tenant_id, pools))) {
    if (OB_ENTRY_NOT_EXIST != ret) {
      LOG_WARN("get_pools_by_tenant failed", K(tenant_id), K(ret));
    } else {
      // just return empty pool_ids
      ret = OB_SUCCESS;
      LOG_WARN("tenant doesn't own any pool", K(tenant_id), K(ret));
    }
  } else if (NULL == pools) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("pools is null", KP(pools), K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < pools->count(); ++i) {
      if (NULL == pools->at(i)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("pool is null", "pool", OB_P(pools->at(i)), K(ret));
      } else if (OB_FAIL(pool_ids.push_back(pools->at(i)->resource_pool_id_))) {
        LOG_WARN("push_back failed", K(ret));
      }
    }
  }
  if (OB_SUCC(ret)) {
    ObArray<ObUnitInfo> unit_in_pool;
    for (int64_t i = 0; i < pool_ids.count() && OB_SUCC(ret); i++) {
      uint64_t pool_id = pool_ids.at(i);
      unit_in_pool.reset();
      if (OB_FAIL(inner_get_unit_infos_of_pool(pool_id, unit_in_pool))) {
        LOG_WARN("fail to inner get unit infos", K(ret), K(pool_id));
      } else {
        for (int64_t j = 0; j < unit_in_pool.count() && OB_SUCC(ret); j++) {
          if (ObUnit::UNIT_STATUS_ACTIVE != unit_in_pool.at(j).unit_.status_) {
            // nothing todo
          } else if (!has_exist_in_array(tenant_zone_list, unit_in_pool.at(j).unit_.zone_)) {
            // nothing todo
          } else if (OB_FAIL(unit_info.push_back(unit_in_pool.at(j)))) {
            LOG_WARN("fail to push back", K(ret), K(unit_in_pool), K(j));
          }
        }
      }
    }
  }
  return ret;
}

int ObUnitManager::inner_get_active_unit_infos_of_tenant(const uint64_t tenant_id, ObIArray<ObUnitInfo>& unit_info)
{
  int ret = OB_SUCCESS;
  unit_info.reset();
  share::schema::ObSchemaGetterGuard schema_guard;
  const share::schema::ObTenantSchema* tenant_schema = NULL;
  if (!check_inner_stat()) {
    ret = OB_INNER_STAT_ERROR;
    LOG_WARN("check_inner_stat failed", K(inited_), K(loaded_), K(ret));
  } else if (OB_INVALID_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(tenant_id));
  } else if (OB_FAIL(get_newest_schema_guard_in_inner_table(tenant_id, schema_guard))) {
    LOG_WARN("fail to get schema guard", K(ret));
  } else if (OB_FAIL(schema_guard.get_tenant_info(tenant_id, tenant_schema))) {
    LOG_WARN("fail to get tenant info", K(ret), K(tenant_id));
  } else if (OB_UNLIKELY(NULL == tenant_schema)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("tenant schema is null", K(ret), KP(tenant_schema));
  } else if (OB_FAIL(inner_get_active_unit_infos_of_tenant(*tenant_schema, unit_info))) {
    LOG_WARN("fail to get active unit infos", K(ret), K(tenant_id));
  }
  return ret;
}

int64_t ObUnitManager::get_unit_min_memory()
{
  return OB_UNIT_MIN_MEMORY;
}

}  // namespace rootserver
}  // end namespace oceanbase
