* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* Licensed 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 "instance_family_caches.h"
#include <string>
#include <unordered_map>
#include "actor/actor.hpp"
#include "async/defer.hpp"
#include "common/constants/actor_name.h"
#include "common/constants/signal.h"
#include "common/resource_view/resource_type.h"
#include "common/types/instance_state.h"
#include "function_master/global_scheduler/global_sched.h"
namespace functionsystem::instance_manager {
InstanceFamilyCaches::InstanceFamilyCaches()
{
auto info = std::make_shared<InstanceInfo>();
info->set_instanceid("");
family_[""] = InstanceFamilyEntry{ .childrenInstanceID = {}, .info = info };
}
std::list<std::shared_ptr<InstanceInfo>> InstanceFamilyCaches::GetAllDescendantsOf(
const std::string &instanceID, const bool noDetachedInstance)
{
if (family_.find(instanceID) == family_.end()) {
return {};
}
std::list<std::shared_ptr<InstanceInfo>> descendants{ family_.at(instanceID).info };
for (auto iter = descendants.begin(); iter != descendants.end(); iter++) {
if (*iter == nullptr) {
continue;
}
for (const auto& child : family_[(*iter)->instanceid()].childrenInstanceID) {
if (auto itChild = family_.find(child);
itChild != family_.end() && (!itChild->second.info->detached() || !noDetachedInstance)) {
descendants.emplace_back(itChild->second.info);
}
}
}
descendants.pop_front();
return descendants;
}
void InstanceFamilyCaches::RemoveInstance(const std::string &instanceID)
{
auto itInst = family_.find(instanceID);
if (itInst == family_.end()) {
YRLOG_WARN("trying to remove non-exists instance({})", instanceID);
return;
}
auto itRoot = family_.find("");
if (itRoot == family_.end()) {
YRLOG_WARN("failed to add instance({}), root instance is not existed", instanceID);
family_.erase(itInst);
return;
}
auto parentID = itInst->second.info->detached() ? "" : itInst->second.info->parentid();
auto itParent = family_.find(parentID);
if (itParent == family_.end()) {
YRLOG_WARN("trying to remove instance({}), but its parent({}) not exists", instanceID, parentID);
family_.erase(itInst);
itRoot->second.childrenInstanceID.erase(instanceID);
return;
}
for (const auto &child : itInst->second.childrenInstanceID) {
if (family_.find(child) != family_.end()) {
itRoot->second.childrenInstanceID.insert(child);
}
}
family_.erase(itInst);
itParent->second.childrenInstanceID.erase(instanceID);
itRoot->second.childrenInstanceID.erase(instanceID);
}
bool InstanceFamilyCaches::IsInstanceExists(const std::string &instanceID)
{
return family_.find(instanceID) != family_.end();
}
void InstanceFamilyCaches::AddInstance(const std::shared_ptr<InstanceInfo> info)
{
auto parentID = info->detached() ? "" : info->parentid();
auto itParent = family_.find(parentID);
if (itParent == family_.end()) {
YRLOG_WARN("trying to add instance({}), but its parent({}) not exists", info->instanceid(), parentID);
itParent = family_.find("");
if (itParent == family_.end()) {
YRLOG_WARN("trying to add instance({}), but root not exists", info->instanceid());
return;
}
}
itParent->second.childrenInstanceID.insert(info->instanceid());
auto itInst = family_.find(info->instanceid());
if (itInst != family_.end()) {
YRLOG_DEBUG("trying to add existed instance({}) again, update info", info->instanceid());
itInst->second.info = info;
return;
}
family_.emplace(info->instanceid(), InstanceFamilyEntry{ .childrenInstanceID = {}, .info = info });
}
std::shared_ptr<InstanceInfo> InstanceFamilyCaches::GetInstance(const std::string &instanceID)
{
if (instanceID.empty()) {
return nullptr;
}
auto iter = family_.find(instanceID);
if (iter == family_.end()) {
return nullptr;
}
return iter->second.info;
}
void InstanceFamilyCaches::SyncInstances(const std::unordered_map<std::string, std::shared_ptr<InstanceInfo>> &infos)
{
YRLOG_DEBUG("begin sync {} instance", infos.size());
for (const auto &iter : infos) {
auto status = iter.second->instancestatus().code();
if (status == static_cast<int32_t>(InstanceState::EXITING) ||
status == static_cast<int32_t>(InstanceState::EXITED) ||
status == static_cast<int32_t>(InstanceState::FATAL)) {
YRLOG_WARN("instance({}) is not healthy, status({}), skip add parent", iter.second->instanceid(), status);
continue;
}
family_.emplace(iter.second->instanceid(),
InstanceFamilyEntry{ .childrenInstanceID = {}, .info = iter.second });
}
}
std::unordered_map<std::string, InstanceFamilyEntry> InstanceFamilyCaches::GetFamily() const
{
auto copiedFamily(family_);
copiedFamily.erase("");
return copiedFamily;
}
}