Files
apache--brpc/src/brpc/cluster_recover_policy.cpp
T
2026-07-13 13:29:29 +08:00

150 lines
5.0 KiB
C++

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include <vector>
#include <gflags/gflags.h>
#include "brpc/cluster_recover_policy.h"
#include "butil/scoped_lock.h"
#include "butil/synchronization/lock.h"
#include "brpc/server_id.h"
#include "brpc/socket.h"
#include "butil/fast_rand.h"
#include "butil/time.h"
#include "butil/string_splitter.h"
namespace brpc {
DEFINE_int64(detect_available_server_interval_ms, 10, "The interval "
"to detect available server count in DefaultClusterRecoverPolicy");
DefaultClusterRecoverPolicy::DefaultClusterRecoverPolicy(
int64_t min_working_instances, int64_t hold_seconds)
: _recovering(false)
, _min_working_instances(min_working_instances)
, _last_usable(0)
, _last_usable_change_time_ms(0)
, _hold_seconds(hold_seconds)
, _usable_cache(0)
, _usable_cache_time_ms(0) { }
void DefaultClusterRecoverPolicy::StartRecover() {
std::unique_lock<butil::Mutex> mu(_mutex);
_recovering = true;
}
bool DefaultClusterRecoverPolicy::StopRecoverIfNecessary() {
if (!_recovering) {
return false;
}
int64_t now_ms = butil::cpuwide_time_ms();
std::unique_lock<butil::Mutex> mu(_mutex);
if (_last_usable_change_time_ms != 0 && _last_usable != 0 &&
(now_ms - _last_usable_change_time_ms > _hold_seconds * 1000)) {
_recovering = false;
_last_usable = 0;
_last_usable_change_time_ms = 0;
mu.unlock();
return false;
}
mu.unlock();
return true;
}
uint64_t DefaultClusterRecoverPolicy::GetUsableServerCount(
int64_t now_ms, const std::vector<ServerId>& server_list) {
if (now_ms - _usable_cache_time_ms < FLAGS_detect_available_server_interval_ms) {
return _usable_cache;
}
uint64_t usable = 0;
size_t n = server_list.size();
SocketUniquePtr ptr;
for (size_t i = 0; i < n; ++i) {
if (Socket::Address(server_list[i].id, &ptr) == 0
&& ptr->IsAvailable()) {
usable++;
}
}
{
std::unique_lock<butil::Mutex> mu(_mutex);
_usable_cache = usable;
_usable_cache_time_ms = now_ms;
}
return _usable_cache;
}
bool DefaultClusterRecoverPolicy::DoReject(const std::vector<ServerId>& server_list) {
if (!_recovering) {
return false;
}
int64_t now_ms = butil::cpuwide_time_ms();
uint64_t usable = GetUsableServerCount(now_ms, server_list);
if (_last_usable != usable) {
std::unique_lock<butil::Mutex> mu(_mutex);
if (_last_usable != usable) {
_last_usable = usable;
_last_usable_change_time_ms = now_ms;
}
}
if (butil::fast_rand_less_than(_min_working_instances) >= usable) {
return true;
}
return false;
}
bool GetRecoverPolicyByParams(const butil::StringPiece& params,
std::shared_ptr<ClusterRecoverPolicy>* ptr_out) {
int64_t min_working_instances = -1;
int64_t hold_seconds = -1;
bool has_meet_params = false;
for (butil::KeyValuePairsSplitter sp(params.begin(), params.end(), ' ', '=');
sp; ++sp) {
if (sp.value().empty()) {
LOG(ERROR) << "Empty value for " << sp.key() << " in lb parameter";
return false;
}
if (sp.key() == "min_working_instances") {
if (!butil::StringToInt64(sp.value(), &min_working_instances)) {
return false;
}
has_meet_params = true;
continue;
} else if (sp.key() == "hold_seconds") {
if (!butil::StringToInt64(sp.value(), &hold_seconds)) {
return false;
}
has_meet_params = true;
continue;
}
LOG(ERROR) << "Failed to set this unknown parameters " << sp.key_and_value();
return false;
}
if (min_working_instances > 0 && hold_seconds > 0) {
ptr_out->reset(
new DefaultClusterRecoverPolicy(min_working_instances, hold_seconds));
} else if (has_meet_params) {
// In this case, user set some params but not in the right way, just return
// false to let user take care of this situation.
LOG(ERROR) << "Invalid params=`" << params << "'";
return false;
}
return true;
}
} // namespace brpc