1223 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1223 lines
		
	
	
		
			45 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.
 | 
						|
 */
 | 
						|
 | 
						|
#define USING_LOG_PREFIX SHARE
 | 
						|
 | 
						|
#include "share/ob_web_service_root_addr.h"
 | 
						|
#include <curl/curl.h>
 | 
						|
#include "lib/json/ob_json.h"
 | 
						|
#include "lib/string/ob_sql_string.h"
 | 
						|
#include "share/config/ob_server_config.h"
 | 
						|
#include "observer/ob_server_struct.h"
 | 
						|
#include "share/ob_cluster_version.h"
 | 
						|
#include "share/ob_rpc_struct.h"
 | 
						|
#include "share/ob_inner_config_root_addr.h"
 | 
						|
 | 
						|
namespace oceanbase
 | 
						|
{
 | 
						|
using namespace common;
 | 
						|
 | 
						|
namespace share
 | 
						|
{
 | 
						|
void ObClusterRsAddr::reset()
 | 
						|
{
 | 
						|
  cluster_id_ = OB_INVALID_ID;
 | 
						|
  addr_.reset();
 | 
						|
}
 | 
						|
 | 
						|
bool ObClusterRsAddr::is_valid() const
 | 
						|
{
 | 
						|
  return cluster_id_ > 0 && addr_.is_valid();
 | 
						|
}
 | 
						|
 | 
						|
int ObClusterRsAddr::assign(const ObClusterRsAddr &other)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (this != &other) {
 | 
						|
    cluster_id_ = other.cluster_id_;
 | 
						|
    addr_ = other.addr_;
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
void ObClusterAddr::reset()
 | 
						|
{
 | 
						|
  cluster_id_ = common::OB_INVALID_ID;
 | 
						|
  cluster_role_ = INVALID_CLUSTER_ROLE;
 | 
						|
  cluster_status_ = INVALID_CLUSTER_STATUS;
 | 
						|
  timestamp_ = 0;
 | 
						|
  cluster_name_.reset();
 | 
						|
  addr_list_.reuse();
 | 
						|
  readonly_addr_list_.reuse();
 | 
						|
  cluster_idx_ = common::OB_INVALID_INDEX;
 | 
						|
  current_scn_ = OB_INVALID_VERSION;
 | 
						|
  redo_transport_options_.reset();
 | 
						|
  protection_level_ = common::MAXIMUM_PERFORMANCE_LEVEL;
 | 
						|
  sync_status_ = NOT_AVAILABLE;
 | 
						|
  last_hb_ts_ = common::OB_INVALID_TIMESTAMP;
 | 
						|
}
 | 
						|
 | 
						|
bool ObClusterAddr::is_valid() const
 | 
						|
{
 | 
						|
  bool bret = true;
 | 
						|
  if (OB_INVALID_ID == cluster_id_
 | 
						|
      || INVALID_CLUSTER_ROLE == cluster_role_
 | 
						|
      || 0 == cluster_name_.size()) {
 | 
						|
    bret = false;
 | 
						|
  }
 | 
						|
  return bret;
 | 
						|
}
 | 
						|
int ObClusterAddr::assign(const ObClusterAddr &other)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (OB_FAIL(addr_list_.assign(other.addr_list_))) {
 | 
						|
    LOG_WARN("failed to assign addr list", K(ret), K(other));
 | 
						|
  } else if (OB_FAIL(readonly_addr_list_.assign(other.readonly_addr_list_))) {
 | 
						|
    LOG_WARN("failed to assign addr list", K(ret), K(other));
 | 
						|
  } else if (OB_FAIL(cluster_name_.assign(other.cluster_name_))) {
 | 
						|
    LOG_WARN("fail to assign", KR(ret), K(other));
 | 
						|
  } else {
 | 
						|
    cluster_id_ = other.cluster_id_;
 | 
						|
    cluster_idx_ = other.cluster_idx_;
 | 
						|
    cluster_role_ = other.cluster_role_;
 | 
						|
    cluster_status_ = other.cluster_status_;
 | 
						|
    current_scn_ = other.current_scn_;
 | 
						|
    redo_transport_options_ = other.redo_transport_options_;
 | 
						|
    protection_level_ = other.protection_level_;
 | 
						|
    sync_status_ = other.sync_status_;
 | 
						|
    last_hb_ts_ = other.last_hb_ts_;
 | 
						|
    timestamp_ = other.timestamp_;
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
bool ObClusterAddr::operator==(const ObClusterAddr &other) const
 | 
						|
{
 | 
						|
  bool b_ret = false;
 | 
						|
  if (this == &other) {
 | 
						|
    b_ret = true;
 | 
						|
  } else if (addr_list_.count() != other.addr_list_.count()
 | 
						|
             || readonly_addr_list_.count() != other.readonly_addr_list_.count()
 | 
						|
             || cluster_id_ != other.cluster_id_
 | 
						|
             || cluster_idx_ != other.cluster_idx_
 | 
						|
             || cluster_role_ != other.cluster_role_
 | 
						|
             || cluster_status_ != other.cluster_status_
 | 
						|
             || cluster_name_ != other.cluster_name_
 | 
						|
             || current_scn_ != other.current_scn_
 | 
						|
             || timestamp_ != other.timestamp_
 | 
						|
             || redo_transport_options_ != other.redo_transport_options_
 | 
						|
             || protection_level_ != other.protection_level_) {
 | 
						|
    b_ret = false;
 | 
						|
  } else {
 | 
						|
    b_ret = true;
 | 
						|
    for (int64_t i = 0; b_ret && i < other.addr_list_.count(); ++i) {
 | 
						|
      if (addr_list_.at(i) == other.addr_list_.at(i)) {
 | 
						|
        continue;
 | 
						|
      } else {
 | 
						|
        b_ret = false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    for (int64_t i = 0; b_ret && i < other.readonly_addr_list_.count(); ++i) {
 | 
						|
      if (readonly_addr_list_.at(i) == other.readonly_addr_list_.at(i)) {
 | 
						|
        continue;
 | 
						|
      } else {
 | 
						|
        b_ret = false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (!b_ret) {
 | 
						|
    LOG_INFO("not equal", K(b_ret), "this", *this, K(other));
 | 
						|
  }
 | 
						|
  return b_ret;
 | 
						|
}
 | 
						|
int ObClusterAddr::append_redo_transport_options_change(
 | 
						|
    common::ObString &redo_transport_options,
 | 
						|
    common::ObIAllocator &alloc) const
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  ObSqlString str;
 | 
						|
 | 
						|
  if (OB_FAIL(redo_transport_options_.get_redo_transport_options_str(str))) {
 | 
						|
    LOG_WARN("fail to redo_transport_options", KR(ret), K(redo_transport_options_));
 | 
						|
  } else if (OB_FAIL(ob_write_string(alloc, str.string(), redo_transport_options))) {
 | 
						|
    LOG_WARN("failed to write stirng", KR(ret), K(str));
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObClusterAddr::construct_rootservice_list(
 | 
						|
    common::ObString &rootservice_list,
 | 
						|
    common::ObIAllocator &alloc) const
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  ObSqlString str;
 | 
						|
 | 
						|
  if (OB_FAIL(ObInnerConfigRootAddr::format_rootservice_list(addr_list_, str))) {
 | 
						|
    LOG_WARN("fail to format rootservice list", KR(ret), K(addr_list_));
 | 
						|
  } else if (str.length() <= 0) {
 | 
						|
    rootservice_list.reset();
 | 
						|
    LOG_INFO("cluster rootservice list is empty", K(addr_list_), K(str));
 | 
						|
  } else if (OB_FAIL(ob_write_string(alloc, str.string(), rootservice_list))) {
 | 
						|
    LOG_WARN("failed to write stirng", KR(ret), K(str));
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
OB_SERIALIZE_MEMBER(ObClusterAddr, cluster_id_, cluster_role_, addr_list_,
 | 
						|
                    readonly_addr_list_, timestamp_, cluster_name_, cluster_idx_,
 | 
						|
                    cluster_status_, current_scn_, redo_transport_options_, protection_level_,
 | 
						|
                    sync_status_, last_hb_ts_);
 | 
						|
 | 
						|
int ObWebServiceRootAddr::build_new_config_url(char* buf, const int64_t buf_len,
 | 
						|
                                               const char* config_url, const int64_t cluster_id)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (OB_ISNULL(buf) || OB_ISNULL(config_url) || INVALID_CLUSTER_ID == cluster_id) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(ret), K(buf), K(config_url), K(cluster_id));
 | 
						|
  } else {
 | 
						|
    int64_t pos = 0;
 | 
						|
    //compatible with obtest and configserver
 | 
						|
    //it can remove after upgrade obtest
 | 
						|
    ObString tmp_url(strlen(config_url), config_url);
 | 
						|
    if (OB_ISNULL(tmp_url.find('?'))) {
 | 
						|
      BUF_PRINTF("%s?%s=2&%s=%ld", config_url, JSON_VERSION, JSON_OB_CLUSTER_ID, cluster_id);
 | 
						|
    } else {
 | 
						|
      BUF_PRINTF("%s&%s=2&%s=%ld", config_url, JSON_VERSION, JSON_OB_CLUSTER_ID, cluster_id);
 | 
						|
    }
 | 
						|
    if (OB_FAIL(ret)) {
 | 
						|
      LOG_WARN("fail to print buf", K(ret), K(config_url));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObWebServiceRootAddr::store(const ObIAddrList &addr_list, const ObIAddrList &readonly_addr_list,
 | 
						|
                                const bool force, const common::ObClusterRole cluster_role,
 | 
						|
                                const int64_t timestamp)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  UNUSED(force); //always update web config
 | 
						|
  if (OB_FAIL(check_inner_stat())) {
 | 
						|
    LOG_WARN("fail to check inner stat", KR(ret));
 | 
						|
  } else if (addr_list.empty()) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(ret), "addr count", addr_list.count());
 | 
						|
  } else {
 | 
						|
    const char *url = config_->obconfig_url.str();
 | 
						|
    const char *appname = config_->cluster.str();
 | 
						|
    const int64_t cluster_id = config_->cluster_id;
 | 
						|
    //default 4s
 | 
						|
    const int64_t timeout_ms = config_->rpc_timeout / 1000 + 2 * 1000;
 | 
						|
    const int64_t max_config_length = OB_MAX_CONFIG_URL_LENGTH;
 | 
						|
    char new_config_url[max_config_length] = {'\0'};
 | 
						|
    if (NULL == url || NULL == appname || cluster_id <= 0 || timeout_ms <= 0) {
 | 
						|
      ret = OB_ERR_UNEXPECTED;
 | 
						|
      LOG_ERROR("NULL url or NULL appname or invalid timeout",
 | 
						|
          K(ret), KP(url), KP(appname), K(cluster_id), K(timeout_ms));
 | 
						|
    } else if (OB_FAIL(build_new_config_url(new_config_url, max_config_length, url, cluster_id))) {
 | 
						|
      LOG_WARN("fail to build new config url", K(ret), K(cluster_id), K(url));
 | 
						|
    } else if (OB_FAIL(store_rs_list_on_url(addr_list, readonly_addr_list, appname, cluster_id,
 | 
						|
                                            cluster_role, new_config_url, timeout_ms,
 | 
						|
                                            timestamp))) {
 | 
						|
      LOG_WARN("store_rs_list_on_url fail",
 | 
						|
          K(ret), K(addr_list), K(readonly_addr_list), K(appname),
 | 
						|
          K(new_config_url), K(timeout_ms),
 | 
						|
          K(timestamp));
 | 
						|
    } else {
 | 
						|
      LOG_INFO("store_rs_list_on_url success", K(ret), K(addr_list), K(cluster_role),
 | 
						|
               K(readonly_addr_list), K(appname), K(new_config_url), K(timeout_ms));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int ObWebServiceRootAddr::fetch(
 | 
						|
    ObIAddrList &addr_list,
 | 
						|
    ObIAddrList &readonly_addr_list)
 | 
						|
{
 | 
						|
  int ret = OB_NOT_SUPPORTED;
 | 
						|
  UNUSEDx(addr_list, readonly_addr_list);
 | 
						|
  LOG_WARN("observer can not fetch rs list from configserver", KR(ret));
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObWebServiceRootAddr::store_rs_list_on_url(
 | 
						|
    const ObIAddrList &rs_list,
 | 
						|
    const ObIAddrList &readonly_rs_list,
 | 
						|
    const char *appname,
 | 
						|
    const int64_t cluster_id,
 | 
						|
    const common::ObClusterRole cluster_role,
 | 
						|
    const char *url,
 | 
						|
    const int64_t timeout_ms,
 | 
						|
    const int64_t timestamp)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  ObSqlString json;
 | 
						|
  ObSqlString content;
 | 
						|
  if (rs_list.count() <= 0 || NULL == url || NULL == appname
 | 
						|
      || cluster_id <= 0 || timeout_ms <= 0) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid arguments", K(ret),
 | 
						|
        "addr_count", rs_list.count(), KP(url), KP(appname), K(cluster_id), K(timeout_ms));
 | 
						|
  } else if (OB_FAIL(to_json(rs_list, readonly_rs_list, appname,
 | 
						|
                             cluster_id, cluster_role, timestamp, json))) {
 | 
						|
    LOG_WARN("convert addr list to json format failed", K(ret), K(rs_list), K(readonly_rs_list), K(appname));
 | 
						|
  } else if (OB_FAIL(call_service(json.ptr(), content, url, timeout_ms))) {
 | 
						|
    LOG_WARN("call web service failed", K(ret), K(json), K(url), K(timeout_ms));
 | 
						|
  } else if (OB_FAIL(check_store_result(content))) {
 | 
						|
    LOG_WARN("fail to check result", K(ret), K(content), K(url));
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObWebServiceRootAddr::check_store_result(const ObSqlString &content)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  ObArenaAllocator allocator(ObModIds::OB_JSON_PARSER);
 | 
						|
  json::Parser parser;
 | 
						|
  json::Value *root = NULL;
 | 
						|
  if (OB_FAIL(parser.init(&allocator))) {
 | 
						|
    LOG_WARN("json parser init failed", K(ret));
 | 
						|
  } else if (OB_ISNULL(content.ptr()) || content.empty()) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    LOG_WARN("get invalid content", K(ret), K(content));
 | 
						|
  } else if (OB_FAIL(parser.parse(content.ptr(), strlen(content.ptr()), root))) {
 | 
						|
    LOG_WARN("parse json failed", K(ret), K(content));
 | 
						|
  } else if (OB_ISNULL(root)) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    LOG_WARN("no root value", K(ret));
 | 
						|
  } else if (json::JT_OBJECT != root->get_type()) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    LOG_WARN("error json format", K(ret), K(content), "root", *root);
 | 
						|
  } else {
 | 
						|
    bool find_code = false;
 | 
						|
    DLIST_FOREACH(it, root->get_object()) {
 | 
						|
      if (it->name_.case_compare(JSON_RES_CODE) == 0) {
 | 
						|
        find_code = true;
 | 
						|
        if (NULL == it->value_) {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("NULL value pointer", K(ret));
 | 
						|
        } else if (json::JT_NUMBER != it->value_->get_type()) {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("unexpected code type", K(ret), "type", it->value_->get_type());
 | 
						|
        } else {
 | 
						|
          const int64_t code = it->value_->get_number();
 | 
						|
          if (2018 == code) {
 | 
						|
            ret = OB_OBCONFIG_CLUSTER_NOT_EXIST;
 | 
						|
            LOG_WARN("cluster not exist", K(ret), K(code));
 | 
						|
          } else if (200 != code) {
 | 
						|
            ret = OB_OBCONFIG_RETURN_ERROR;
 | 
						|
            LOG_WARN("return code not success", K(ret), K(code));
 | 
						|
          }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (OB_SUCC(ret) && !find_code) {
 | 
						|
      ret = OB_OBCONFIG_RETURN_ERROR;
 | 
						|
      LOG_WARN("fail to find response code", K(ret));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObWebServiceRootAddr::fetch_rs_list_from_url(
 | 
						|
    const char *appname,
 | 
						|
    const char *url,
 | 
						|
    const int64_t timeout_ms,
 | 
						|
    ObIAddrList &rs_list,
 | 
						|
    ObIAddrList &readonly_rs_list,
 | 
						|
    ObClusterRole &cluster_role)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  ObSqlString json;
 | 
						|
  ObClusterAddr cluster;
 | 
						|
 | 
						|
  // appname can be NULL to ignore appname check
 | 
						|
  if (NULL == url || timeout_ms <= 0) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid arguments", K(ret), KP(url), K(timeout_ms));
 | 
						|
  } else if (OB_FAIL(call_service(NULL, json, url, timeout_ms))) {
 | 
						|
    LOG_WARN("call web service failed", K(ret), K(url), K(timeout_ms));
 | 
						|
  } else if (json.empty()) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    LOG_WARN("web service returned empty result", K(ret));
 | 
						|
  } else if (OB_FAIL(from_json(json.ptr(), appname, cluster))) {
 | 
						|
    LOG_WARN("convert json to rootserver address list failed",
 | 
						|
        K(ret), K(json), K(appname));
 | 
						|
  } else if (OB_FAIL(rs_list.assign(cluster.addr_list_))) {
 | 
						|
    LOG_WARN("fail to assign", KR(ret));
 | 
						|
  } else if (OB_FAIL(readonly_rs_list.assign(cluster.readonly_addr_list_))) {
 | 
						|
    LOG_WARN("fail to assign", KR(ret));
 | 
						|
  } else {
 | 
						|
    cluster_role = cluster.cluster_role_;
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
// json format:
 | 
						|
//
 | 
						|
//    { "rs_list" :
 | 
						|
//        [ {
 | 
						|
//            "address" : "ip:port",
 | 
						|
//            "role" : "leader",
 | 
						|
//            "sql_port" : 3306
 | 
						|
//          },
 | 
						|
//          {
 | 
						|
//            "address" : "ip:port",
 | 
						|
//            "role" : "follower",
 | 
						|
//            "sql_port" : 3306
 | 
						|
//          },
 | 
						|
//          {
 | 
						|
//            "address" : "ip:port",
 | 
						|
//            "role" : "follower",
 | 
						|
//            "sql_port" : 3306
 | 
						|
//          }
 | 
						|
//        ],
 | 
						|
//      "readonly_rs_list" :
 | 
						|
//        [ {
 | 
						|
//            "address" : "ip:port",
 | 
						|
//            "role" : "follower",
 | 
						|
//            "sql_port" : 3306
 | 
						|
//          },
 | 
						|
//          {
 | 
						|
//            "address" : "ip:port",
 | 
						|
//            "role" : "follower",
 | 
						|
//            "sql_port" : 3306
 | 
						|
//          },
 | 
						|
//          {
 | 
						|
//            "address" : "ip:port",
 | 
						|
//            "role" : "follower",
 | 
						|
//            "sql_port" : 3306
 | 
						|
//          }
 | 
						|
//        ]
 | 
						|
//    }
 | 
						|
//
 | 
						|
int ObWebServiceRootAddr::parse_data(const json::Value *data,
 | 
						|
                                     ObClusterAddr &cluster)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  json::Value *rs_list = NULL;
 | 
						|
  json::Value *readonly_rs_list = NULL;
 | 
						|
  cluster.reset();
 | 
						|
  if (NULL == data) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    LOG_WARN("no data filed found", K(ret));
 | 
						|
  } else if (json::JT_OBJECT != data->get_type()) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    LOG_WARN("data filed not object", K(ret), "data", *data);
 | 
						|
  } else {
 | 
						|
    DLIST_FOREACH(it, data->get_object()) {
 | 
						|
      if (0 == it->name_.case_compare(JSON_RS_LIST)) {
 | 
						|
        rs_list = it->value_;
 | 
						|
      } else if (0 == it->name_.case_compare(JSON_READONLY_RS_LIST)) {
 | 
						|
        readonly_rs_list = it->value_;
 | 
						|
      } else if (0 == it->name_.case_compare(JSON_TYPE)) {
 | 
						|
        if (OB_ISNULL(it->value_)) {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("NULL value pointer", K(ret));
 | 
						|
        } else if (json::JT_STRING != it->value_->get_type()) {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("unexpected cluster type", K(ret), "type", it->value_->get_type());
 | 
						|
        } else if (it->value_->get_string().case_compare(JSON_PRIMARY) == 0) {
 | 
						|
          cluster.cluster_role_ = PRIMARY_CLUSTER;
 | 
						|
        } else if (it->value_->get_string().case_compare(JSON_STANDBY) == 0) {
 | 
						|
          cluster.cluster_role_ = STANDBY_CLUSTER;
 | 
						|
        } else {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("invalid cluster type", K(ret), "type", it->value_->get_string());
 | 
						|
        }
 | 
						|
      } else if (it->name_.case_compare(JSON_OB_REGION_ID) == 0
 | 
						|
                 || it->name_.case_compare(JSON_OB_CLUSTER_ID) == 0) {
 | 
						|
        if (NULL == it->value_) {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("NULL value pointer", K(ret));
 | 
						|
        } else if (json::JT_NUMBER != it->value_->get_type()) {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("unexpected cluster_id type", K(ret), "type", it->value_->get_type());
 | 
						|
        } else {
 | 
						|
          cluster.cluster_id_ = it->value_->get_number();
 | 
						|
        }
 | 
						|
      } else if (it->name_.case_compare(JSON_TIMESTAMP) == 0) {
 | 
						|
        if (NULL == it->value_) {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("NULL value pointer", K(ret));
 | 
						|
        } else if (json::JT_NUMBER != it->value_->get_type()) {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("unexpected cluster_id type", K(ret), "type", it->value_->get_type());
 | 
						|
        } else {
 | 
						|
          cluster.timestamp_ = it->value_->get_number();
 | 
						|
        }
 | 
						|
      } else if (0 == it->name_.case_compare(JSON_OB_REGION)
 | 
						|
                 || 0 == it->name_.case_compare(JSON_OB_CLUSTER)) {
 | 
						|
        if (NULL == it->value_) {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("NULL value pointer", K(ret));
 | 
						|
        } else if (json::JT_STRING != it->value_->get_type()) {
 | 
						|
          ret = OB_ERR_UNEXPECTED;
 | 
						|
          LOG_WARN("unexpected obregion type", K(ret), "type", it->value_->get_type());
 | 
						|
        } else if (OB_FAIL(cluster.cluster_name_.assign(it->value_->get_string()))) {
 | 
						|
          LOG_WARN("fail to assign string", KR(ret));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (OB_SUCC(ret)) {
 | 
						|
    if (NULL == rs_list) {
 | 
						|
      ret = OB_ERR_UNEXPECTED;
 | 
						|
      LOG_WARN("no rs list found in json", K(ret));
 | 
						|
    } else if (OB_FAIL(get_addr_list(rs_list, cluster.addr_list_))) {
 | 
						|
      LOG_WARN("fail to parse rs_list", K(ret), "rs_list", *rs_list);
 | 
						|
    } else if (NULL == readonly_rs_list) {
 | 
						|
      // readonly_rs_list is allowed to be null
 | 
						|
      LOG_WARN("no readonly rs list found in json", K(ret));
 | 
						|
    } else if (OB_FAIL(get_addr_list(readonly_rs_list, cluster.readonly_addr_list_))) {
 | 
						|
      LOG_WARN("fail to parse readonly_rs_list", K(ret), "readonly_rs_list", *readonly_rs_list);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObWebServiceRootAddr::from_json(
 | 
						|
    const char *json_str,
 | 
						|
    const char *appname,
 | 
						|
    ObClusterAddr &cluster)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  cluster.reset();
 | 
						|
  ObArenaAllocator allocator(ObModIds::OB_JSON_PARSER);
 | 
						|
  json::Parser parser;
 | 
						|
  json::Value *root = NULL;
 | 
						|
  // appname can be NULL to ignore appname check
 | 
						|
  if (NULL == json_str) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(ret), KP(json_str));
 | 
						|
  } else if (OB_FAIL(parser.init(&allocator))) {
 | 
						|
    LOG_WARN("json parser init failed", K(ret));
 | 
						|
  } else if (OB_FAIL(parser.parse(json_str, strlen(json_str), root))) {
 | 
						|
    LOG_WARN("parse json failed", K(ret), K(json_str));
 | 
						|
  } else if (NULL == root) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    LOG_WARN("no root value", K(ret));
 | 
						|
  } else {
 | 
						|
    json::Value *data = NULL;
 | 
						|
    //  check return code and get data filed
 | 
						|
    if (json::JT_OBJECT != root->get_type()) {
 | 
						|
      ret = OB_ERR_UNEXPECTED;
 | 
						|
      LOG_WARN("error json format", K(ret), K(json_str), "root", *root);
 | 
						|
    } else {
 | 
						|
      DLIST_FOREACH(it, root->get_object()) {
 | 
						|
        if (it->name_.case_compare(JSON_RES_DATA) == 0) {
 | 
						|
          data = it->value_;
 | 
						|
        }
 | 
						|
        if (it->name_.case_compare(JSON_RES_CODE) == 0) {
 | 
						|
          if (NULL == it->value_) {
 | 
						|
            ret = OB_ERR_UNEXPECTED;
 | 
						|
            LOG_WARN("NULL value pointer", K(ret));
 | 
						|
          } else if (json::JT_NUMBER != it->value_->get_type()) {
 | 
						|
            ret = OB_ERR_UNEXPECTED;
 | 
						|
            LOG_WARN("unexpected code type", K(ret), "type", it->value_->get_type());
 | 
						|
          } else {
 | 
						|
            const int64_t code = it->value_->get_number();
 | 
						|
            if (200 != code) {
 | 
						|
              ret = OB_OBCONFIG_RETURN_ERROR;
 | 
						|
              LOG_WARN("return code not success", K(ret), K(code));
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (OB_FAIL(ret)) {
 | 
						|
    } else if (OB_ISNULL(data)) {
 | 
						|
      ret = OB_ERR_UNEXPECTED;
 | 
						|
      LOG_WARN("no data filed found", K(ret));
 | 
						|
    } else if (OB_FAIL(parse_data(data, cluster))) {
 | 
						|
      LOG_WARN("fail to parse data", KR(ret));
 | 
						|
    } else if (NULL != appname && cluster.cluster_name_.str().case_compare(appname) != 0) {
 | 
						|
      ret = OB_OBCONFIG_APPNAME_MISMATCH;
 | 
						|
      LOG_ERROR("obconfig appname mismatch",
 | 
						|
                K(ret), K(appname), "obregion", cluster.cluster_name_);
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObWebServiceRootAddr::get_addr_list(json::Value *&rs_list, ObIAddrList &addr_list)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  addr_list.reuse();
 | 
						|
  if (OB_ISNULL(rs_list)) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("rs_list is null", K(ret));
 | 
						|
  } else if (json::JT_ARRAY != rs_list->get_type()) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    LOG_WARN("rs list is not array", K(ret), "type", rs_list->get_type());
 | 
						|
  } else {
 | 
						|
    ObString addr_str;
 | 
						|
    ObString role_str;
 | 
						|
    // traverse rs_list array
 | 
						|
    DLIST_FOREACH(it, rs_list->get_array()) {
 | 
						|
      if (json::JT_OBJECT != it->get_type()) {
 | 
						|
        ret = OB_ERR_UNEXPECTED;
 | 
						|
        LOG_WARN("not object in array", K(ret), "type", it->get_type());
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      addr_str.reset();
 | 
						|
      role_str.reset();
 | 
						|
      int64_t sql_port = OB_INVALID_INDEX;
 | 
						|
      DLIST_FOREACH(p, it->get_object()) {
 | 
						|
        if (p->name_.case_compare(JSON_ADDRESS) == 0) {
 | 
						|
          if (NULL == p->value_) {
 | 
						|
            ret = OB_ERR_UNEXPECTED;
 | 
						|
            LOG_WARN("NULL value pointer", K(ret));
 | 
						|
          } else if (json::JT_STRING != p->value_->get_type()) {
 | 
						|
            ret = OB_ERR_UNEXPECTED;
 | 
						|
            LOG_WARN("unexpected address type", K(ret), "type", p->value_->get_type());
 | 
						|
          } else {
 | 
						|
            addr_str = p->value_->get_string();
 | 
						|
          }
 | 
						|
        } else if (p->name_.case_compare(JSON_ROLE) == 0) {
 | 
						|
          if (NULL == p->value_) {
 | 
						|
            ret = OB_ERR_UNEXPECTED;
 | 
						|
            LOG_WARN("NULL value pointer", K(ret));
 | 
						|
          } else if (json::JT_STRING != p->value_->get_type()) {
 | 
						|
            ret = OB_ERR_UNEXPECTED;
 | 
						|
            LOG_WARN("unexpected role type", K(ret), "type", p->value_->get_type());
 | 
						|
          } else {
 | 
						|
            role_str = p->value_->get_string();
 | 
						|
          }
 | 
						|
        } else if (p->name_.case_compare(JSON_SQL_PORT) == 0) {
 | 
						|
          if (NULL == p->value_) {
 | 
						|
            ret = OB_ERR_UNEXPECTED;
 | 
						|
            LOG_WARN("NULL value pointer", K(ret));
 | 
						|
          } else if (json::JT_NUMBER != p->value_->get_type()) {
 | 
						|
            ret = OB_ERR_UNEXPECTED;
 | 
						|
            LOG_WARN("unexpected sql_port type", K(ret), "type", p->value_->get_type());
 | 
						|
          } else {
 | 
						|
            sql_port = p->value_->get_number();
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (OB_FAIL(ret)) {
 | 
						|
      } else if (addr_str.empty()) {
 | 
						|
        ret = OB_ERR_UNEXPECTED;
 | 
						|
        LOG_WARN("no address found in rs object", K(ret));
 | 
						|
      } else if (OB_FAIL(add_to_list(addr_str, sql_port, role_str, addr_list))) {
 | 
						|
        LOG_WARN("add address to list failed", K(ret),
 | 
						|
            K(addr_str), K(sql_port), K(role_str));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObWebServiceRootAddr::add_to_list(common::ObString &addr_str, const int64_t sql_port,
 | 
						|
                                      common::ObString &role_str, ObIAddrList &addr_list)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (addr_str.empty() || sql_port <= 0 || role_str.empty()) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(ret), K(addr_str), K(sql_port), K(role_str));
 | 
						|
  } else {
 | 
						|
    ObRootAddr rs;
 | 
						|
    ObAddr addr;
 | 
						|
    ObRole role;
 | 
						|
    if (OB_FAIL(addr.parse_from_string(addr_str))) {
 | 
						|
      LOG_WARN("convert string to address failed", K(ret), K(addr_str));
 | 
						|
    } else {
 | 
						|
      if (role_str.case_compare("LEADER") == 0) {
 | 
						|
        role = LEADER;
 | 
						|
      } else if (role_str.case_compare("FOLLOWER") != 0) {
 | 
						|
        ret = OB_ERR_UNEXPECTED;
 | 
						|
        LOG_WARN("invalid role string", K(ret), K(role));
 | 
						|
      } else {
 | 
						|
        role = FOLLOWER;
 | 
						|
      }
 | 
						|
 | 
						|
      if (OB_SUCC(ret)) {
 | 
						|
        if (OB_FAIL(rs.init(addr, role, sql_port))) {
 | 
						|
          LOG_WARN("failed to simple init", KR(ret), K(addr), K(role), K(sql_port));
 | 
						|
        } else if (OB_FAIL(addr_list.push_back(rs))) {
 | 
						|
          LOG_WARN("add to array failed", K(ret), K(rs));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObWebServiceRootAddr::to_json(
 | 
						|
    const ObIAddrList &addr_list,
 | 
						|
    const ObIAddrList &readonly_addr_list,
 | 
						|
    const char *appname,
 | 
						|
    const int64_t cluster_id,
 | 
						|
    const common::ObClusterRole cluster_role,
 | 
						|
    const int64_t timestamp,
 | 
						|
    common::ObSqlString &json)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  const char* type_str = (PRIMARY_CLUSTER == cluster_role) ? JSON_PRIMARY : JSON_STANDBY;
 | 
						|
  // TODO support get RS list
 | 
						|
  if (OB_ISNULL(appname)) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(ret), "addr count", addr_list.count(), KP(appname));
 | 
						|
  } else if (OB_FAIL(json.append_fmt("{\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":%ld,\"%s\":%ld,\"%s\":\"%s\",\"%s\":%ld,\"%s\":[",
 | 
						|
                                        JSON_OB_REGION, appname,
 | 
						|
                                        JSON_OB_CLUSTER, appname,
 | 
						|
                                        JSON_OB_REGION_ID, cluster_id,
 | 
						|
                                        JSON_OB_CLUSTER_ID, cluster_id,
 | 
						|
                                        JSON_TYPE, type_str, JSON_TIMESTAMP, timestamp, JSON_RS_LIST))) {
 | 
						|
    LOG_WARN("assign string failed", K(ret));
 | 
						|
  } else {
 | 
						|
    for (int64_t i = 0; OB_SUCC(ret) && i < addr_list.count(); ++i) {
 | 
						|
      if (i > 0) {
 | 
						|
        if (OB_FAIL(json.append(","))) {
 | 
						|
          LOG_WARN("append string failed", K(ret));
 | 
						|
        }
 | 
						|
      }
 | 
						|
      char ip_buf[OB_IP_STR_BUFF] = "";
 | 
						|
      ObRole role = addr_list.at(i).get_role();
 | 
						|
      if (OB_FAIL(ret)) {
 | 
						|
      } else if (!addr_list.at(i).get_server().ip_to_string(ip_buf, sizeof(ip_buf))) {
 | 
						|
        ret = OB_ERR_UNEXPECTED;
 | 
						|
        LOG_WARN("convert ip to string failed", K(ret), "server", addr_list.at(i).get_server());
 | 
						|
      } else if (!is_strong_leader(role) && !is_follower(role)) {
 | 
						|
        ret = OB_ERR_UNEXPECTED;
 | 
						|
        LOG_WARN("invalid role type", K(ret), K(role));
 | 
						|
      } else if (OB_FAIL(json.append_fmt("{\"%s\":\"%s:%d\",\"%s\":\"%s\",\"%s\":%ld}",
 | 
						|
 | 
						|
          JSON_ADDRESS, ip_buf, addr_list.at(i).get_server().get_port(),
 | 
						|
          JSON_ROLE, is_strong_leader(role) ? "LEADER" : "FOLLOWER",
 | 
						|
          JSON_SQL_PORT, addr_list.at(i).get_sql_port()))) {
 | 
						|
        LOG_WARN("append string failed", K(ret));
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // generate readonly_rs_list
 | 
						|
    if (OB_SUCC(ret)) {
 | 
						|
      if (OB_FAIL(json.append_fmt("],\"%s\":[", JSON_READONLY_RS_LIST))) {
 | 
						|
        LOG_WARN("append string failed", K(ret));
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    for (int64_t i = 0; OB_SUCC(ret) && i < readonly_addr_list.count(); ++i) {
 | 
						|
      if (i > 0) {
 | 
						|
        if (OB_FAIL(json.append(","))) {
 | 
						|
          LOG_WARN("append string failed", K(ret));
 | 
						|
        }
 | 
						|
      }
 | 
						|
      char ip_buf[OB_IP_STR_BUFF] = "";
 | 
						|
      if (OB_FAIL(ret)) {
 | 
						|
      } else if (!readonly_addr_list.at(i).get_server().ip_to_string(ip_buf, sizeof(ip_buf))) {
 | 
						|
        ret = OB_ERR_UNEXPECTED;
 | 
						|
        LOG_WARN("convert ip to string failed", K(ret), "server", readonly_addr_list.at(i).get_server());
 | 
						|
      } else if (OB_FAIL(json.append_fmt("{\"%s\":\"%s:%d\",\"%s\":\"%s\",\"%s\":%ld}",
 | 
						|
          JSON_ADDRESS, ip_buf, readonly_addr_list.at(i).get_server().get_port(),
 | 
						|
          JSON_ROLE, "FOLLOWER",
 | 
						|
          JSON_SQL_PORT, readonly_addr_list.at(i).get_sql_port()))) {
 | 
						|
        LOG_WARN("append string failed", K(ret));
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (OB_SUCC(ret)) {
 | 
						|
      if (OB_FAIL(json.append_fmt("]}"))) {
 | 
						|
        LOG_WARN("append string failed", K(ret));
 | 
						|
      } else {
 | 
						|
        LOG_INFO("to json success", K(json));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObWebServiceRootAddr::call_service(const char *post_data,
 | 
						|
    common::ObSqlString &content,
 | 
						|
    const char *config_url,
 | 
						|
    const int64_t timeout_ms,
 | 
						|
    const bool is_delete)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  const int64_t begin = ObTimeUtility::current_time();
 | 
						|
  CURL *curl = curl_easy_init();
 | 
						|
  // post_data can be NULL for http get.
 | 
						|
  if (NULL == config_url || timeout_ms <= 0) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(ret), KP(config_url), K(timeout_ms));
 | 
						|
  } else if (NULL == curl) {
 | 
						|
    ret = OB_CURL_ERROR;
 | 
						|
    LOG_WARN("init curl failed", K(ret));
 | 
						|
  } else {
 | 
						|
    // set options
 | 
						|
    CURLcode cc = CURLE_OK;
 | 
						|
    struct curl_slist *list = NULL;
 | 
						|
    if (CURLE_OK != (cc = curl_easy_setopt(curl, CURLOPT_URL, config_url))) {
 | 
						|
      LOG_WARN("set url failed", K(cc), "url", config_url);
 | 
						|
    } else {
 | 
						|
      if (NULL != post_data) {
 | 
						|
        if (NULL == (list = curl_slist_append(list, "Content-Type: application/json"))) {
 | 
						|
          cc = CURLE_OUT_OF_MEMORY;
 | 
						|
          LOG_WARN("append list failed", K(cc));
 | 
						|
        } else if (CURLE_OK != (cc =  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list))) {
 | 
						|
          LOG_WARN("set http header failed", K(cc));
 | 
						|
        } else if (CURLE_OK != (cc = curl_easy_setopt(
 | 
						|
            curl, CURLOPT_POSTFIELDSIZE, strlen(post_data)))) {
 | 
						|
          LOG_WARN("set post data size failed", K(cc), "size", strlen(post_data));
 | 
						|
        } else if (CURLE_OK != (cc = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data))) {
 | 
						|
          LOG_WARN("set post data failed", K(cc), K(post_data));
 | 
						|
        } else if (is_delete
 | 
						|
                   && CURLE_OK != (cc = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"))) {
 | 
						|
          LOG_WARN("fail to set option", KR(ret));
 | 
						|
        } else {
 | 
						|
          LOG_INFO("post data success", K(post_data));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    const int64_t no_signal = 1;
 | 
						|
    const int64_t no_delay = 1;
 | 
						|
    const int64_t max_redirect = 3; // set max redirect
 | 
						|
    const int64_t follow_location = 1; // for http redirect 301 302
 | 
						|
    if (CURLE_OK != cc) {
 | 
						|
    } else if (CURLE_OK != (cc = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, no_signal))) {
 | 
						|
      LOG_WARN("set no signal failed", K(cc), K(no_signal));
 | 
						|
    } else if (CURLE_OK != (cc = curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout_ms))) {
 | 
						|
      LOG_WARN("set timeout failed", K(cc), K(timeout_ms));
 | 
						|
    } else if (CURLE_OK != (cc = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, timeout_ms))) {
 | 
						|
      LOG_WARN("set connect timeout failed", K(cc), K(timeout_ms));
 | 
						|
    } else if (CURLE_OK != (cc = curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, no_delay))) {
 | 
						|
      LOG_WARN("set no delay failed", K(cc), K(no_delay));
 | 
						|
    } else if (CURLE_OK != (cc = curl_easy_setopt(curl, CURLOPT_MAXREDIRS, max_redirect))) {
 | 
						|
      LOG_WARN("set max redirect failed", K(cc), K(max_redirect));
 | 
						|
    } else if (CURLE_OK != (cc = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, follow_location))) {
 | 
						|
      LOG_WARN("set follow location failed", K(cc), K(follow_location));
 | 
						|
    } else if (CURLE_OK != (cc = curl_easy_setopt(
 | 
						|
        curl, CURLOPT_WRITEFUNCTION, &curl_write_data))) {
 | 
						|
      LOG_WARN("set write function failed", K(cc));
 | 
						|
    } else if (CURLE_OK != (cc = curl_easy_setopt(
 | 
						|
        curl, CURLOPT_WRITEDATA, &content))) {
 | 
						|
      LOG_WARN("set write data failed", K(cc));
 | 
						|
    }
 | 
						|
 | 
						|
    // send && recv
 | 
						|
    int64_t http_code = 0;
 | 
						|
    if (CURLE_OK != cc) {
 | 
						|
    } else if (CURLE_OK != (cc = curl_easy_perform(curl))) {
 | 
						|
      LOG_WARN("curl easy perform failed", K(cc));
 | 
						|
    } else if (CURLE_OK != (cc = curl_easy_getinfo(
 | 
						|
        curl, CURLINFO_RESPONSE_CODE, &http_code))) {
 | 
						|
      LOG_WARN("curl getinfo failed", K(cc));
 | 
						|
    } else {
 | 
						|
      // http status code 2xx means success
 | 
						|
      if (http_code / 100 != 2) {
 | 
						|
        ret = OB_CURL_ERROR;
 | 
						|
        LOG_WARN("unexpected http status code", K(ret), K(http_code), K(content));
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (OB_SUCC(ret)) {
 | 
						|
      if (CURLE_OK != cc) {
 | 
						|
        ret = OB_CURL_ERROR;
 | 
						|
        LOG_WARN("curl error", K(ret), "curl_error_code", cc,
 | 
						|
            "curl_error_message", curl_easy_strerror(cc));
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (NULL != list) {
 | 
						|
      curl_slist_free_all(list);
 | 
						|
      list = NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (NULL != curl) {
 | 
						|
    curl_easy_cleanup(curl);
 | 
						|
    curl = NULL;
 | 
						|
  }
 | 
						|
  const int64_t consume_time = ObTimeUtility::current_time() - begin;
 | 
						|
  LOG_TRACE("call service", K(ret), K(consume_time),
 | 
						|
      "method", NULL == post_data ? "GET" : "POST");
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int64_t ObWebServiceRootAddr::curl_write_data(
 | 
						|
    void *ptr, int64_t size, int64_t nmemb, void *stream)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  // This function may be called with zero bytes data if the transferred file is empty.
 | 
						|
  if (NULL == stream || size < 0 || nmemb < 0) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(ret), K(stream), K(size), K(nmemb));
 | 
						|
  } else {
 | 
						|
    ObSqlString *content = static_cast<ObSqlString *>(stream);
 | 
						|
    if (size * nmemb > 0) {
 | 
						|
      if (NULL == ptr) {
 | 
						|
        ret = OB_INVALID_ARGUMENT;
 | 
						|
        LOG_WARN("receive data but pointer is NULL", K(ret), KP(ptr), K(size), K(nmemb));
 | 
						|
      } else if (size * nmemb + content->length() > MAX_RECV_CONTENT_LEN) {
 | 
						|
        ret = OB_SIZE_OVERFLOW;
 | 
						|
        LOG_WARN("unexpected long content", K(ret),
 | 
						|
            "new_byte", size * nmemb,
 | 
						|
            "received_byte", content->length(),
 | 
						|
            LITERAL_K(MAX_RECV_CONTENT_LEN));
 | 
						|
      } else if (OB_FAIL(content->append(static_cast<const char *>(ptr), size * nmemb))) {
 | 
						|
        LOG_WARN("append data failed", K(ret));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return OB_SUCCESS == ret ? size * nmemb : 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//{
 | 
						|
//    "Message": "successful",
 | 
						|
//    "Success": true,
 | 
						|
//    "Code": 200,
 | 
						|
//    "Data": [{
 | 
						|
//        "ObRegion": "ob2.rongxuan.lc",
 | 
						|
//        "ObRegionId": 2,
 | 
						|
//        "RsList": [{
 | 
						|
//            "address": "10.101.67.165:16825",
 | 
						|
//            "role": "LEADER",
 | 
						|
//            "sql_port": 16860
 | 
						|
//        }, {
 | 
						|
//            "address": "10.218.78.76:16827",
 | 
						|
//            "role": "FOLLOWER",
 | 
						|
//            "sql_port": 16862
 | 
						|
//        }],
 | 
						|
//        "ReadonlyRsList": []
 | 
						|
//    }]
 | 
						|
//}
 | 
						|
 | 
						|
int ObWebServiceRootAddr::get_all_cluster_info(common::ObServerConfig *config,
 | 
						|
                                               ObClusterIAddrList &cluster_list)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  UNUSED(config);
 | 
						|
  cluster_list.reset();
 | 
						|
  //if (OB_ISNULL(config)) {
 | 
						|
  //  ret = OB_INVALID_ARGUMENT;
 | 
						|
  //  LOG_WARN("invalid argument", K(ret), K(config));
 | 
						|
  //} else {
 | 
						|
  //  const char *url = config->obconfig_url.str();
 | 
						|
  //  const char *appname = config->cluster.str();
 | 
						|
  //  int64_t timeout_ms = config->rpc_timeout / 1000;
 | 
						|
  //  const int64_t buf_len = OB_MAX_CONFIG_URL_LENGTH;
 | 
						|
  //  char buf[buf_len] = {'\0'};
 | 
						|
  //  if (NULL == url || NULL == appname || timeout_ms <= 0) {
 | 
						|
  //    ret = OB_ERR_UNEXPECTED;
 | 
						|
  //    LOG_ERROR("NULL url or NULL appname or invalid timeout",
 | 
						|
  //              K(ret), KP(url), KP(appname), K(timeout_ms));
 | 
						|
  //  } else {
 | 
						|
  //    int64_t pos = 0;
 | 
						|
  //    ObString tmp_url(strlen(url), url);
 | 
						|
  //    if (OB_ISNULL(tmp_url.find('?'))) {
 | 
						|
  //      BUF_PRINTF("%s?%s=2", url, JSON_VERSION);
 | 
						|
  //    } else {
 | 
						|
  //      BUF_PRINTF("%s&%s=2", url, JSON_VERSION);
 | 
						|
  //    }
 | 
						|
  //  }
 | 
						|
  //  ObSqlString json;
 | 
						|
  //  if (OB_FAIL(ret)) {
 | 
						|
  //  } else if (OB_FAIL(call_service(NULL, json, buf, timeout_ms))) {
 | 
						|
  //    LOG_WARN("fail to call service", K(ret), K(buf));
 | 
						|
  //  } else if (json.empty()) {
 | 
						|
  //    ret = OB_ERR_UNEXPECTED;
 | 
						|
  //    LOG_WARN("web service returned empty result", K(ret));
 | 
						|
  //  } else if (OB_FAIL(get_all_cluster_info(json.ptr(), cluster_list))) {
 | 
						|
  //    LOG_WARN("fail to get all cluster addr", K(ret), K(json), K(buf));
 | 
						|
  //  } else {
 | 
						|
  //    LOG_INFO("get all cluster addr success", K(cluster_list));
 | 
						|
  //  }
 | 
						|
  //}
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
//int ObWebServiceRootAddr::get_all_cluster_info(const char *json_str,
 | 
						|
//                                               ObClusterIAddrList &cluster_list)
 | 
						|
//{
 | 
						|
//  int ret = OB_SUCCESS;
 | 
						|
//  ObArenaAllocator allocator(ObModIds::OB_JSON_PARSER);
 | 
						|
//  json::Parser parser;
 | 
						|
//  json::Value *root = NULL;
 | 
						|
//  if (NULL == json_str) {
 | 
						|
//    ret = OB_INVALID_ARGUMENT;
 | 
						|
//    LOG_WARN("invalid argument", K(ret), KP(json_str));
 | 
						|
//  } else if (OB_FAIL(parser.init(&allocator))) {
 | 
						|
//    LOG_WARN("json parser init failed", K(ret));
 | 
						|
//  } else if (OB_FAIL(parser.parse(json_str, strlen(json_str), root))) {
 | 
						|
//    LOG_WARN("parse json failed", K(ret), K(json_str));
 | 
						|
//  } else if (NULL == root) {
 | 
						|
//    ret = OB_ERR_UNEXPECTED;
 | 
						|
//    LOG_WARN("no root value", K(ret));
 | 
						|
//  } else {
 | 
						|
//    cluster_list.reuse();
 | 
						|
//    json::Value *data = NULL;
 | 
						|
//    //  check return code and get data filed
 | 
						|
//    if (json::JT_OBJECT != root->get_type()) {
 | 
						|
//      ret = OB_ERR_UNEXPECTED;
 | 
						|
//      LOG_WARN("error json format", K(ret), K(json_str), "root", *root);
 | 
						|
//    } else {
 | 
						|
//      DLIST_FOREACH(it, root->get_object()) {
 | 
						|
//        if (it->name_.case_compare(JSON_RES_DATA) == 0) {
 | 
						|
//          data = it->value_;
 | 
						|
//        }
 | 
						|
//        if (it->name_.case_compare(JSON_RES_CODE) == 0) {
 | 
						|
//          if (NULL == it->value_) {
 | 
						|
//            ret = OB_ERR_UNEXPECTED;
 | 
						|
//            LOG_WARN("NULL value pointer", K(ret));
 | 
						|
//          } else if (json::JT_NUMBER != it->value_->get_type()) {
 | 
						|
//            ret = OB_ERR_UNEXPECTED;
 | 
						|
//            LOG_WARN("unexpected code type", K(ret), "type", it->value_->get_type());
 | 
						|
//          } else {
 | 
						|
//            const int64_t code = it->value_->get_number();
 | 
						|
//            if (200 != code) {
 | 
						|
//              ret = OB_OBCONFIG_RETURN_ERROR;
 | 
						|
//              LOG_WARN("return code not success", K(ret), K(code));
 | 
						|
//            }
 | 
						|
//          }
 | 
						|
//        }
 | 
						|
//      }
 | 
						|
//    }
 | 
						|
//
 | 
						|
//    // check appname and get data
 | 
						|
//    if (OB_SUCC(ret)) {
 | 
						|
//      if (OB_ISNULL(data)) {
 | 
						|
//        ret = OB_ERR_UNEXPECTED;
 | 
						|
//        LOG_WARN("no data filed found", K(ret));
 | 
						|
//      } else if (json::JT_ARRAY != data->get_type()) {
 | 
						|
//        ret = OB_INVALD_WEB_SERVICE_CONTENT;
 | 
						|
//        LOG_WARN("data filed not array", K(ret), "data", *data);
 | 
						|
//      } else {
 | 
						|
//        ObClusterAddr cluster_addr;
 | 
						|
//        DLIST_FOREACH(it, data->get_array()) {
 | 
						|
//          if (json::JT_OBJECT != it->get_type()) {
 | 
						|
//            ret = OB_ERR_UNEXPECTED;
 | 
						|
//            LOG_WARN("not object in array", K(ret), "type", it->get_type());
 | 
						|
//            break;
 | 
						|
//          }
 | 
						|
//          cluster_addr.reset();
 | 
						|
//          DLIST_FOREACH(p, it->get_object()) {
 | 
						|
//            if (p->name_.case_compare(JSON_OB_CLUSTER) == 0) {
 | 
						|
//              if (OB_ISNULL(p->value_)) {
 | 
						|
//                ret = OB_ERR_UNEXPECTED;
 | 
						|
//                LOG_WARN("NULL value pointer", K(ret));
 | 
						|
//              } else if (json::JT_STRING != p->value_->get_type()) {
 | 
						|
//                ret = OB_ERR_UNEXPECTED;
 | 
						|
//                LOG_WARN("unexpected address type", K(ret), "type", p->value_->get_type());
 | 
						|
//              } else {
 | 
						|
//                cluster_addr.cluster_name_ = p->value_->get_string();
 | 
						|
//              }
 | 
						|
//            } else if (p->name_.case_compare(JSON_TIMESTAMP) == 0) {
 | 
						|
//              if (NULL == p->value_) {
 | 
						|
//                ret = OB_ERR_UNEXPECTED;
 | 
						|
//                LOG_WARN("NULL value pointer", K(ret));
 | 
						|
//              } else if (json::JT_NUMBER != p->value_->get_type()) {
 | 
						|
//                ret = OB_ERR_UNEXPECTED;
 | 
						|
//                LOG_WARN("unexpected cluster_id type", K(ret), "type", p->value_->get_type());
 | 
						|
//              } else {
 | 
						|
//                cluster_addr.timestamp_ = p->value_->get_number();
 | 
						|
//              }
 | 
						|
//            } else if (p->name_.case_compare(JSON_OB_CLUSTER_ID) == 0) {
 | 
						|
//              if (NULL == p->value_) {
 | 
						|
//                ret = OB_ERR_UNEXPECTED;
 | 
						|
//                LOG_WARN("NULL value pointer", K(ret));
 | 
						|
//              } else if (json::JT_NUMBER != p->value_->get_type()) {
 | 
						|
//                ret = OB_ERR_UNEXPECTED;
 | 
						|
//                LOG_WARN("unexpected cluster_id type", K(ret), "type", p->value_->get_type());
 | 
						|
//              } else {
 | 
						|
//                cluster_addr.cluster_id_ = p->value_->get_number();
 | 
						|
//              }
 | 
						|
//            } else if (p->name_.case_compare(JSON_TYPE) == 0) {
 | 
						|
//              if (OB_ISNULL(p->value_)) {
 | 
						|
//                ret = OB_ERR_UNEXPECTED;
 | 
						|
//                LOG_WARN("NULL value pointer", K(ret));
 | 
						|
//              } else if (json::JT_STRING != p->value_->get_type()) {
 | 
						|
//                ret = OB_ERR_UNEXPECTED;
 | 
						|
//                LOG_WARN("unexpected cluster type", K(ret), "type", p->value_->get_type());
 | 
						|
//              } else if (p->value_->get_string().case_compare(JSON_PRIMARY) == 0) {
 | 
						|
//                cluster_addr.cluster_role_ = PRIMARY_CLUSTER;
 | 
						|
//              } else if (p->value_->get_string().case_compare(JSON_STANDBY) == 0) {
 | 
						|
//                cluster_addr.cluster_role_ = STANDBY_CLUSTER;
 | 
						|
//              } else {
 | 
						|
//                ret = OB_ERR_UNEXPECTED;
 | 
						|
//                LOG_WARN("invalid cluster type", K(ret), "type", p->value_->get_string());
 | 
						|
//              }
 | 
						|
//            } else if (p->name_.case_compare(JSON_RS_LIST) == 0) {
 | 
						|
//              if (OB_FAIL(get_addr_list(p->value_, cluster_addr.addr_list_))) {
 | 
						|
//                LOG_WARN("fail to get addr list", K(ret), K(p));
 | 
						|
//              }
 | 
						|
//            } else if (p->name_.case_compare(JSON_READONLY_RS_LIST) == 0) {
 | 
						|
//              if (OB_FAIL(get_addr_list(p->value_, cluster_addr.readonly_addr_list_))) {
 | 
						|
//                LOG_WARN("fail to get addr list", K(ret), K(p));
 | 
						|
//              }
 | 
						|
//            }
 | 
						|
//          }
 | 
						|
//          if (OB_FAIL(ret)) {
 | 
						|
//            //nothing todo
 | 
						|
//          } else if (OB_FAIL(cluster_list.push_back(cluster_addr))) {
 | 
						|
//            LOG_WARN("fail to push back cluster addr", K(ret), K(cluster_addr));
 | 
						|
//          } else {
 | 
						|
//            LOG_INFO("push back cluster addr success", K(cluster_addr));
 | 
						|
//          }
 | 
						|
//        } //end DLIST_FOREACH(it, data->get_array(
 | 
						|
//      }
 | 
						|
//    }
 | 
						|
//  }
 | 
						|
//  return ret;
 | 
						|
//}
 | 
						|
 | 
						|
 | 
						|
static const char *redo_transport_options_strs[] = {"SYNC", "ASYNC", "NET_TIMEOUT", "REOPEN", "MAX_FAILURE"};
 | 
						|
 | 
						|
 | 
						|
ObRedoTransportOption::RedoOptionProfile ObRedoTransportOption::str_to_redo_transport_options(const char *str)
 | 
						|
{
 | 
						|
  RedoOptionProfile redo_transport_options = RedoOptionProfile::INVALID_TYPE;
 | 
						|
  if (OB_ISNULL(str)) {
 | 
						|
    //nothing
 | 
						|
  } else {
 | 
						|
    ObString option(str);
 | 
						|
    for (int64_t i = 0; i < ARRAYSIZEOF(redo_transport_options_strs); i++) {
 | 
						|
      if (0 == option.case_compare(redo_transport_options_strs[i])) {
 | 
						|
        redo_transport_options = static_cast<RedoOptionProfile>(i);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return redo_transport_options;
 | 
						|
}
 | 
						|
OB_SERIALIZE_MEMBER(ObRedoTransportOption, net_timeout_, reopen_, max_failure_, is_sync_);
 | 
						|
 | 
						|
int ObRedoTransportOption::append_redo_transport_options_change(
 | 
						|
    const ObString &redo_transport_options_str) {
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  //incremental update
 | 
						|
  if (redo_transport_options_str.empty()) {
 | 
						|
  } else {
 | 
						|
    SMART_VAR(char[OB_MAX_CONFIG_VALUE_LEN], format_str) {
 | 
						|
      if (OB_FAIL(ObConfigLogArchiveOptionsItem::format_option_str(
 | 
						|
              to_cstring(redo_transport_options_str),
 | 
						|
              redo_transport_options_str.length(),
 | 
						|
              format_str,
 | 
						|
              OB_MAX_CONFIG_VALUE_LEN))) {
 | 
						|
        LOG_WARN("failed to format option str", KR(ret));
 | 
						|
      } else {
 | 
						|
        char *saveptr = NULL;
 | 
						|
        char *key_name = STRTOK_R(format_str, " ", &saveptr);
 | 
						|
        while(OB_NOT_NULL(key_name) && OB_SUCC(ret)) {
 | 
						|
          char *s = NULL;
 | 
						|
          char *value_str = NULL;
 | 
						|
          RedoOptionProfile redo_transport_options = str_to_redo_transport_options(key_name);
 | 
						|
          if (RedoOptionProfile::INVALID_TYPE == redo_transport_options) {
 | 
						|
            ret = OB_INVALID_ARGUMENT;
 | 
						|
            LOG_WARN("failed to construct redo option", KR(ret),
 | 
						|
                K(redo_transport_options_str), K(redo_transport_options));
 | 
						|
          } else if (RedoOptionProfile::SYNC == redo_transport_options) {
 | 
						|
            is_sync_ = true;
 | 
						|
          } else if (RedoOptionProfile::ASYNC == redo_transport_options) {
 | 
						|
            is_sync_ = false;
 | 
						|
          } else if (OB_ISNULL(s = STRTOK_R(NULL, " ", &saveptr))) {
 | 
						|
            ret = OB_ERR_PARAM_INVALID;
 | 
						|
            LOG_WARN("failed to get value", KR(ret), K(saveptr));
 | 
						|
          } else if (0 != ObString::make_string("=").case_compare(s)) {
 | 
						|
            ret = OB_ERR_PARAM_INVALID;
 | 
						|
            LOG_WARN("expect \"=\"", KR(ret), K(s), K(saveptr));
 | 
						|
          } else if (OB_ISNULL(value_str = STRTOK_R(NULL, " ", &saveptr))) {
 | 
						|
            ret = OB_ERR_PARAM_INVALID;
 | 
						|
            LOG_WARN("failed to get value", KR(ret), K(saveptr));
 | 
						|
          } else {
 | 
						|
            int64_t value = 0;
 | 
						|
            if (OB_FAIL(ob_atoll(value_str, value))) {
 | 
						|
              LOG_WARN("failed to get number", KR(ret), K(value_str));
 | 
						|
            } else if (OB_UNLIKELY(value < 0)) {
 | 
						|
              ret = OB_ERR_PARAM_INVALID;
 | 
						|
              LOG_WARN("value should not be negative number", KR(ret), K(value_str));
 | 
						|
            } else if (RedoOptionProfile::NET_TIMEOUT == redo_transport_options) {
 | 
						|
              net_timeout_ = value;
 | 
						|
            } else if (RedoOptionProfile::REOPEN == redo_transport_options) {
 | 
						|
              reopen_ = value;
 | 
						|
            } else if (RedoOptionProfile::MAX_FAILURE == redo_transport_options) {
 | 
						|
              max_failure_ = value;
 | 
						|
            } else {
 | 
						|
              ret = OB_ERR_PARAM_INVALID;
 | 
						|
              LOG_WARN("unknown redo option", KR(ret), K(redo_transport_options));
 | 
						|
            }
 | 
						|
          }
 | 
						|
          if (OB_FAIL(ret)) {
 | 
						|
          } else {
 | 
						|
            key_name = STRTOK_R(NULL, " ", &saveptr);
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObRedoTransportOption::assign(const ObRedoTransportOption &other)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (this != &other) {
 | 
						|
    net_timeout_ = other.net_timeout_;
 | 
						|
    reopen_ = other.reopen_;
 | 
						|
    max_failure_ = other.max_failure_;
 | 
						|
    is_sync_ = other.is_sync_;
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
ObRedoTransportOption& ObRedoTransportOption::operator=(const ObRedoTransportOption &other)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (this != &other) {
 | 
						|
    if (OB_FAIL(assign(other))) {
 | 
						|
      LOG_WARN("fail to assign", KR(ret), K(other));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
bool ObRedoTransportOption::operator!=(const ObRedoTransportOption &other) const
 | 
						|
{
 | 
						|
  return !(*this == other);
 | 
						|
}
 | 
						|
bool ObRedoTransportOption::operator==(const ObRedoTransportOption &other) const
 | 
						|
{
 | 
						|
  return net_timeout_ == other.net_timeout_
 | 
						|
         && reopen_ == other.reopen_
 | 
						|
         && max_failure_ == other.max_failure_
 | 
						|
         && is_sync_ == other.is_sync_;
 | 
						|
}
 | 
						|
 | 
						|
int ObRedoTransportOption::get_redo_transport_options_str(ObSqlString &str) const
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (is_sync_) {
 | 
						|
    if (OB_FAIL(str.assign("SYNC "))) {
 | 
						|
      LOG_WARN("failed to assign str", KR(ret));
 | 
						|
    }
 | 
						|
  } else if (OB_FAIL(str.assign("ASYNC "))) {
 | 
						|
    LOG_WARN("failed to assign str", KR(ret));
 | 
						|
  }
 | 
						|
  if (OB_FAIL(ret)) {
 | 
						|
  } else if (OB_FAIL(str.append_fmt("NET_TIMEOUT = %ld",
 | 
						|
                                    net_timeout_))) {
 | 
						|
    LOG_WARN("failed to assign str", KR(ret), "this", *this);
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
} // end namespace share
 | 
						|
} // end oceanbase
 |