oceanbase/unittest/rootserver/test_unit_placement.cpp
wangzelin.wzl 93a1074b0c patch 4.0
2022-10-24 17:57:12 +08:00

349 lines
10 KiB
C++

/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#include <gtest/gtest.h>
#include "lib/utility/ob_test_util.h"
#include "lib/json/ob_json.h"
#include "rootserver/ob_unit_placement_strategy.h"
#include "ob_rs_test_utils.h"
using namespace oceanbase::common;
using namespace oceanbase::rootserver;
using namespace oceanbase;
class TestUnitPlacement: public ::testing::Test
{
public:
TestUnitPlacement();
virtual ~TestUnitPlacement();
virtual void SetUp();
virtual void TearDown();
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(TestUnitPlacement);
static const char* const BASE_DIR;
protected:
// function members
void run_case(const char* casename);
void build_case(json::Value *root,
common::ObArray<ObUnitPlacementStrategy::ObServerResource> &servers,
common::ObArray<share::ObUnitConfig> &units);
void output_result(const char* filename,
const common::ObArray<ObUnitPlacementStrategy::ObServerResource> &servers,
const ObArray<int64_t> &units_placement);
protected:
// data members
};
const char* const TestUnitPlacement::BASE_DIR = "./unit_placement_testcase/";
TestUnitPlacement::TestUnitPlacement()
{
}
TestUnitPlacement::~TestUnitPlacement()
{
}
void TestUnitPlacement::SetUp()
{
}
void TestUnitPlacement::TearDown()
{
}
class CaseBuilder: public json::Walker
{
enum State
{
IS_NONE,
IS_SERVER,
IS_ZONE,
IS_SERVER_CPU,
IS_SERVER_MEM,
IS_UNIT_CPU,
IS_UNIT_MEM,
IS_UNIT_NUM
};
public:
CaseBuilder(const json::Value *root,
common::ObArray<ObUnitPlacementStrategy::ObServerResource> &servers,
common::ObArray<share::ObUnitConfig> &units)
:Walker(root),
servers_(servers),
units_(units),
in_servers_(false),
in_units_(false),
state_(IS_NONE),
cur_unit_config_id_(1)
{}
virtual ~CaseBuilder() {}
virtual int on_null(int level, json::Type parent)
{
UNUSED(level);
UNUSED(parent);
return OB_SUCCESS;
}
virtual int on_true(int level, json::Type parent)
{
UNUSED(level);
UNUSED(parent);
return OB_SUCCESS;
}
virtual int on_false(int level, json::Type parent)
{
UNUSED(level);
UNUSED(parent);
return OB_SUCCESS;
}
virtual int on_string(int level, json::Type parent, const json::String &str)
{
UNUSED(level);
UNUSED(parent);
if (state_ == IS_SERVER) {
cur_server_resource_.addr_.set_ip_addr(str, 8888);
OB_LOG(DEBUG, "addr value", K(str), "addr", cur_server_resource_.addr_);
}
return OB_SUCCESS;
}
virtual int on_number(int level, json::Type parent, const json::Number &num)
{
UNUSED(level);
UNUSED(parent);
switch(state_) {
case IS_SERVER_CPU:
cur_server_resource_.capacity_[RES_CPU] = static_cast<double>(num);
break;
case IS_SERVER_MEM:
cur_server_resource_.capacity_[RES_MEM] = static_cast<double>(num);
break;
case IS_UNIT_CPU:
cur_unit_.min_cpu_ = static_cast<double>(num);
break;
case IS_UNIT_MEM:
cur_unit_.min_memory_ = num;
break;
case IS_UNIT_NUM:
cur_unit_num_ = num;
default:
break;
}
return OB_SUCCESS;
}
virtual int on_array_start(int level, json::Type parent, const json::Array &arr)
{
UNUSED(level);
UNUSED(parent);
UNUSED(arr);
return OB_SUCCESS;
}
virtual int on_array_end(int level, json::Type parent, const json::Array &arr)
{
UNUSED(level);
UNUSED(parent);
UNUSED(arr);
return OB_SUCCESS;
}
virtual int on_array_item_start(int level, json::Type parent, const json::Value *val)
{
UNUSED(level);
UNUSED(parent);
UNUSED(val);
return OB_SUCCESS;
}
virtual int on_array_item_end(int level, json::Type parent, const json::Value *val, bool is_last)
{
UNUSED(level);
UNUSED(parent);
UNUSED(val);
UNUSED(is_last);
return OB_SUCCESS;
}
virtual int on_object_start(int level, json::Type parent, const json::Object &obj)
{
UNUSED(level);
UNUSED(parent);
UNUSED(obj);
return OB_SUCCESS;
}
virtual int on_object_end(int level, json::Type parent, const json::Object &obj)
{
int ret = OB_SUCCESS;
UNUSED(level);
UNUSED(obj);
if (parent == json::JT_ARRAY
&& in_servers_) {
ret = servers_.push_back(cur_server_resource_);
} else if (in_units_ && parent == json::JT_ARRAY) {
cur_unit_.unit_config_id_ = cur_unit_config_id_++;
for (int64_t i = 0; i < cur_unit_num_ && OB_SUCC(ret); ++i) {
ret = units_.push_back(cur_unit_);
}
}
return ret;
}
virtual int on_object_member_start(int level, json::Type parent, const json::Pair *kv)
{
UNUSED(level);
UNUSED(parent);
if (kv->name_ == ObString::make_string("servers")) {
servers_.reuse();
in_servers_ = true;
} else if (kv->name_ == ObString::make_string("units")) {
units_.reuse();
in_units_ = true;
}
state_ = IS_NONE;
if (in_servers_) {
if (kv->name_ == ObString::make_string("server")) {
state_ = IS_SERVER;
} else if (kv->name_ == ObString::make_string("zone")) {
} else if (kv->name_ == ObString::make_string("resources")) {
} else if (kv->name_ == ObString::make_string("cpu")) {
state_ = IS_SERVER_CPU;
} else if (kv->name_ == ObString::make_string("memory")) {
state_ = IS_SERVER_MEM;
}
} else if (in_units_) {
if (kv->name_ == ObString::make_string("cpu")) {
state_ = IS_UNIT_CPU;
} else if (kv->name_ == ObString::make_string("memory")) {
state_ = IS_UNIT_MEM;
} else if (kv->name_ == ObString::make_string("num")) {
state_ = IS_UNIT_NUM;
}
}
return OB_SUCCESS;
}
virtual int on_object_member_end(int level, json::Type parent, const json::Pair *kv, bool is_last)
{
UNUSED(level);
UNUSED(parent);
UNUSED(is_last);
if (kv->name_ == ObString::make_string("servers")) {
in_servers_ = false;
} else if (kv->name_ == ObString::make_string("units")) {
in_units_ = false;
}
return OB_SUCCESS;
}
virtual int on_walk_start()
{
return OB_SUCCESS;
}
virtual int on_walk_end()
{
return OB_SUCCESS;
}
private:
common::ObArray<ObUnitPlacementStrategy::ObServerResource> &servers_;
common::ObArray<share::ObUnitConfig> &units_;
ObUnitPlacementStrategy::ObServerResource cur_server_resource_;
share::ObUnitConfig cur_unit_;
int64_t cur_unit_num_;
bool in_servers_;
bool in_units_;
State state_;
uint64_t cur_unit_config_id_;
};
void TestUnitPlacement::build_case(json::Value *root,
common::ObArray<ObUnitPlacementStrategy::ObServerResource> &servers,
common::ObArray<share::ObUnitConfig> &units)
{
CaseBuilder case_builder(root, servers, units);
ASSERT_EQ(OB_SUCCESS, case_builder.go());
OB_LOG(INFO, "CASE", K(servers), K(units));
}
void TestUnitPlacement::output_result(const char* filename,
const common::ObArray<ObUnitPlacementStrategy::ObServerResource> &servers,
const ObArray<int64_t> &units_placement)
{
FILE *fp = fopen(filename, "w+");
ASSERT_TRUE(NULL != fp);
for (int64_t i = 0; i < servers.count(); ++i) {
const ObUnitPlacementStrategy::ObServerResource &s = servers.at(i);
fprintf(fp, "Server: %s\n", S(s.addr_));
fprintf(fp, "CPU: %f\n", s.assigned_[RES_CPU]/s.capacity_[RES_CPU]);
fprintf(fp, "MEM: %f\n", s.assigned_[RES_MEM]/s.capacity_[RES_MEM]);
fprintf(fp, "UNITS: ");
for (int64_t j = 0; j < units_placement.count(); ++j) {
if (units_placement.at(j) == i) {
fprintf(fp, "%ld ", j);
}
}
fprintf(fp, "\n\n");
}
if (NULL != fp) {
fclose(fp);
}
}
void TestUnitPlacement::run_case(const char* casename)
{
char filename[512];
snprintf(filename, 512, "%s%s.test", BASE_DIR, casename);
printf("run case: %s\n", filename);
ObArenaAllocator allocator(ObModIds::TEST);
json::Value *root = NULL;
common::ObArray<ObUnitPlacementStrategy::ObServerResource> servers;
common::ObArray<share::ObUnitConfig> units;
ASSERT_NO_FATAL_FAILURE(ob_parse_case_file(allocator, filename, root));
ASSERT_NO_FATAL_FAILURE(build_case(root, servers, units));
// go
ObUnitPlacementDPStrategy placement_s;
common::ObAddr chosen;
ObArray<int64_t> units_placement;
for (int64_t i = 0; i < units.count(); ++i) {
ASSERT_EQ(OB_SUCCESS, placement_s.choose_server(servers, units.at(i), chosen));
OB_LOG(INFO, "server is choosen", K(i), K(chosen));
for (int j = 0; j < servers.count(); ++j) {
ObUnitPlacementStrategy::ObServerResource &s = servers.at(j);
if (s.addr_ == chosen) {
s.assigned_[RES_CPU] += units.at(i).min_cpu_;
s.assigned_[RES_MEM] += static_cast<double>(units.at(i).min_memory_);
ASSERT_EQ(OB_SUCCESS, units_placement.push_back(j));
break;
}
}
}
// print result
OB_LOG(INFO, "OUTPUT", K(servers));
char output_file[512];
snprintf(output_file, 512, "%s%s.tmp", BASE_DIR, casename);
ASSERT_NO_FATAL_FAILURE(output_result(output_file, servers, units_placement));
ASSERT_NO_FATAL_FAILURE(ob_check_result(BASE_DIR, casename));
}
TEST_F(TestUnitPlacement, basic_test)
{
ASSERT_NO_FATAL_FAILURE(run_case("shenglian"));
ASSERT_NO_FATAL_FAILURE(run_case("ffd_avg_sum"));
ASSERT_NO_FATAL_FAILURE(run_case("split_demands"));
}
int main(int argc, char **argv)
{
oceanbase::common::ObLogger::get_logger().set_log_level("DEBUG");
::testing::InitGoogleTest(&argc,argv);
return RUN_ALL_TESTS();
}