Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 30 additions & 21 deletions src/core/cm/launcher/balancer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,63 +100,66 @@
continue;
}

Error scheduleErr = ErrorEnum::eNotFound;
RankedError scheduleErr;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still do not understand why we need ranked error. Instance scheduling should fail on first error.
In our case, if there are different manifests for different arch. First we should check if there are nodes matches item arches. If not, return error - no suitable node architecture found. Then we try to schedule according to resource, if there are not enough resources available, return resource error.


for (const auto& manifest : imageIndex->mManifests) {
LOG_DBG() << "Try to schedule instance" << Log::Field("instance", id)
<< Log::Field("manifest", manifest.mDigest);

scheduleErr = ScheduleInstance(instance, manifest);
if (scheduleErr.IsNone()) {
auto currentError = ScheduleInstance(instance, manifest);
if (currentError.IsNone()) {
LOG_DBG() << "Instance scheduled successfully" << Log::Field("nodeID", info.mNodeID);

break;
}

scheduleErr = RankedError::SelectHigherRankedError(scheduleErr, currentError);
}

if (!scheduleErr.IsNone()) {
LOG_ERR() << "Can't schedule instance" << Log::Field(scheduleErr);
LOG_ERR() << "Can't schedule instance" << Log::Field(scheduleErr.mError);

mInstanceManager->ScheduleInstance(instance, scheduleErr);
mInstanceManager->ScheduleInstance(instance, scheduleErr.mError);

Check warning on line 122 in src/core/cm/launcher/balancer.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the value returned from "ScheduleInstance".

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6niNdBLcrXcrnj1&open=AZ5Jm6niNdBLcrXcrnj1&pullRequest=571
}
}

return ErrorEnum::eNone;
}

Error Balancer::ScheduleInstance(SharedPtr<Instance>& instance, const oci::IndexContentDescriptor& imageDescriptor)
RankedError Balancer::ScheduleInstance(
SharedPtr<Instance>& instance, const oci::IndexContentDescriptor& imageDescriptor)
{
auto nodes = MakeUnique<StaticArray<Node*, cMaxNumNodes>>(&mAllocator);

auto releaseConfigs = DeferRelease(reinterpret_cast<int*>(1), [&](int*) { instance->ResetConfigs(); });

if (auto err = instance->LoadConfigs(imageDescriptor); !err.IsNone()) {
return AOS_ERROR_WRAP(Error(err, "can't load instance configs"));
return {AOS_ERROR_WRAP(Error(err, "can't load instance configs")), RankedError::cHighErrorRank};
}

// Select node runtimes
if (auto err = mNodeManager->GetConnectedNodes(*nodes); !err.IsNone()) {
return AOS_ERROR_WRAP(Error(err, "get connected nodes failed"));
return {AOS_ERROR_WRAP(Error(err, "get connected nodes failed")), RankedError::cHighErrorRank};
}

if (auto err = SelectNodes(*instance, *nodes); !err.IsNone()) {
return AOS_ERROR_WRAP(Error(err, "can't find node for instance"));
return {AOS_ERROR_WRAP(Error(err, "can't find node for instance")), RankedError::cHighErrorRank};
}

auto [nodeRuntime, selectErr] = SelectRuntime(*instance, *nodes);
if (!selectErr.IsNone()) {
return AOS_ERROR_WRAP(Error(selectErr, "can't find runtime for instance"));
return selectErr;
}

// Schedule instance
auto& node = nodeRuntime.mFirst;
const auto& runtime = nodeRuntime.mSecond;

if (auto err = mInstanceManager->ScheduleInstance(instance, *node, runtime->mRuntimeID); !err.IsNone()) {
return AOS_ERROR_WRAP(Error(err, "can't schedule instance"));
return {AOS_ERROR_WRAP(Error(err, "can't schedule instance")), RankedError::cHighErrorRank};
}

return ErrorEnum::eNone;
return {ErrorEnum::eNone, RankedError::cNoErrorRank};
}

Error Balancer::SelectNodes(Instance& instance, Array<Node*>& nodes)
Expand Down Expand Up @@ -194,42 +197,48 @@
nodes.RemoveIf([&instance](const Node* node) { return !instance.AreNodeResourcesOk(node->GetInfo().mResources); });
}

RetWithError<Pair<Node*, const RuntimeInfo*>> Balancer::SelectRuntime(Instance& instance, Array<Node*>& nodes)
RetWithRankedError<Pair<Node*, const RuntimeInfo*>> Balancer::SelectRuntime(Instance& instance, Array<Node*>& nodes)
{
auto nodeRuntimes = MakeUnique<NodeRuntimes>(&mAllocator);

if (auto err = CreateRuntimes(nodes, *nodeRuntimes); !err.IsNone()) {
return {nullptr, AOS_ERROR_WRAP(err)};
return {nullptr, AOS_ERROR_WRAP(err), RankedError::cHighErrorRank};
}

FilterByRuntimeType(instance, *nodeRuntimes);
if (nodeRuntimes->IsEmpty()) {
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "no runtimes with requested runtime type"))};
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "no runtimes with requested runtime type")),
RankedError::cLowErrorRank};
}

FilterByPlatform(instance, *nodeRuntimes);
if (nodeRuntimes->IsEmpty()) {
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "no runtimes with requested platform"))};
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "no runtimes with requested platform")),
RankedError::cLowErrorRank};
}

FilterByCPU(instance, *nodeRuntimes);
if (nodeRuntimes->IsEmpty()) {
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "no runtimes with requested CPU"))};
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "no runtimes with requested CPU")),
RankedError::cHighErrorRank};
}

FilterByRAM(instance, *nodeRuntimes);
if (nodeRuntimes->IsEmpty()) {
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "no runtimes with requested RAM"))};
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "no runtimes with requested RAM")),
RankedError::cHighErrorRank};
}

FilterByNumInstances(*nodeRuntimes);
if (nodeRuntimes->IsEmpty()) {
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "no runtimes with requested RAM"))};
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "no runtimes with enough num instances")),
RankedError::cHighErrorRank};
}

FilterTopPriorityNodes(*nodeRuntimes);
if (nodeRuntimes->IsEmpty()) {
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "failed top priority nodes filtering"))};
return {nullptr, AOS_ERROR_WRAP(Error(ErrorEnum::eNotFound, "failed top priority nodes filtering")),
RankedError::cLowErrorRank};
}

// Select best node.
Expand Down Expand Up @@ -262,7 +271,7 @@
// Return result.
Pair<Node*, const RuntimeInfo*> result {bestNode.mFirst, bestNodeRuntimes.Front()};

return {result, ErrorEnum::eNone};
return {result, ErrorEnum::eNone, RankedError::cNoErrorRank};
}

Error Balancer::CreateRuntimes(Array<Node*>& nodes, NodeRuntimes& runtimes)
Expand Down
5 changes: 3 additions & 2 deletions src/core/cm/launcher/balancer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "imageinfoprovider.hpp"
#include "instancemanager.hpp"
#include "nodemanager.hpp"
#include "rankederror.hpp"

namespace aos::cm::launcher {

Expand Down Expand Up @@ -66,7 +67,7 @@ class Balancer {

Error PerformNodeBalancing(Array<SharedPtr<Instance>>& instances);

Error ScheduleInstance(SharedPtr<Instance>& instance, const oci::IndexContentDescriptor& imageDescriptor);
RankedError ScheduleInstance(SharedPtr<Instance>& instance, const oci::IndexContentDescriptor& imageDescriptor);

// Selects nodes
Error SelectNodes(Instance& instance, Array<Node*>& nodes);
Expand All @@ -75,7 +76,7 @@ class Balancer {
void FilterNodesByResources(Instance& instance, Array<Node*>& nodes);

// Selects runtime
RetWithError<Pair<Node*, const RuntimeInfo*>> SelectRuntime(Instance& instance, Array<Node*>& nodes);
RetWithRankedError<Pair<Node*, const RuntimeInfo*>> SelectRuntime(Instance& instance, Array<Node*>& nodes);

Error CreateRuntimes(Array<Node*>& nodes, NodeRuntimes& runtimes);

Expand Down
111 changes: 111 additions & 0 deletions src/core/cm/launcher/rankederror.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright (C) 2025 EPAM Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef AOS_CORE_CM_LAUNCHER_RANKEDERROR_HPP_
#define AOS_CORE_CM_LAUNCHER_RANKEDERROR_HPP_

#include <core/common/tools/error.hpp>

namespace aos::cm::launcher {

/**
* Error container with explicit error rank.
*/
struct RankedError {
static constexpr int cLowErrorRank = 1;

Check warning on line 18 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this builtin type with an alias that makes the type size explicit

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnj2&open=AZ5Jm6utNdBLcrXcrnj2&pullRequest=571
static constexpr int cHighErrorRank = 2;

Check warning on line 19 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this builtin type with an alias that makes the type size explicit

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnj3&open=AZ5Jm6utNdBLcrXcrnj3&pullRequest=571
static constexpr int cNoErrorRank = 3;

Check warning on line 20 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this builtin type with an alias that makes the type size explicit

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnj4&open=AZ5Jm6utNdBLcrXcrnj4&pullRequest=571

// cppcheck-suppress noExplicitConstructor
RankedError(const Error& error = ErrorEnum::eNone, int errorRank = cNoErrorRank)

Check warning on line 23 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this builtin type with an alias that makes the type size explicit

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnj6&open=AZ5Jm6utNdBLcrXcrnj6&pullRequest=571

Check failure on line 23 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add the "explicit" keyword to this constructor.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnj5&open=AZ5Jm6utNdBLcrXcrnj5&pullRequest=571
: mError(error)
, mErrorRank(errorRank)
{
}

bool IsNone() const { return mError.IsNone(); }

/**
* Selects error with higher rank.
*
* If one of errors is none, returns the other one.
*/
static RankedError SelectHigherRankedError(const RankedError& left, const RankedError& right)
{
if (left.IsNone()) {
return right;
}

if (right.IsNone()) {
return left;
}

return left.mErrorRank >= right.mErrorRank ? left : right;
}

Error mError;
int mErrorRank {};

Check warning on line 50 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this builtin type with an alias that makes the type size explicit

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnj7&open=AZ5Jm6utNdBLcrXcrnj7&pullRequest=571
};

/**
* Container that holds value and ranked error.
*
* @tparam T value type.
*/
template <typename T>
struct RetWithRankedError {
// cppcheck-suppress noExplicitConstructor
/**
* Constructs return value with error instance and rank.
*
* @param value return value.
* @param error return error.
* @param errorRank return error rank.
*/
RetWithRankedError(const T& value, const Error& error = ErrorEnum::eNone, int errorRank = RankedError::cNoErrorRank)

Check warning on line 68 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this builtin type with an alias that makes the type size explicit

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnj9&open=AZ5Jm6utNdBLcrXcrnj9&pullRequest=571

Check failure on line 68 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add the "explicit" keyword to this constructor.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnj8&open=AZ5Jm6utNdBLcrXcrnj8&pullRequest=571
: mValue(value)
, mRankedError(error, errorRank)
{
}

// cppcheck-suppress noExplicitConstructor
/**
* Constructs return value with error instance and rank.
*
* @param value return value.
* @param error return error.
* @param errorRank return error rank.
*/
RetWithRankedError(T&& value, const Error& error = ErrorEnum::eNone, int errorRank = RankedError::cNoErrorRank)

Check failure on line 82 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add the "explicit" keyword to this constructor.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnj-&open=AZ5Jm6utNdBLcrXcrnj-&pullRequest=571

Check warning on line 82 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this builtin type with an alias that makes the type size explicit

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnkA&open=AZ5Jm6utNdBLcrXcrnkA&pullRequest=571

Check warning on line 82 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

"std::move" is never called on this rvalue reference argument.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnj_&open=AZ5Jm6utNdBLcrXcrnj_&pullRequest=571
: mValue(Move(value))
, mRankedError(error, errorRank)
{
}

/**
* Comparison operators.
*/
bool operator==(const RetWithRankedError<T>& other) const

Check warning on line 91 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make this member overloaded operator a hidden friend.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnkB&open=AZ5Jm6utNdBLcrXcrnkB&pullRequest=571
{
return mValue == other.mValue && mRankedError.mError == other.mRankedError.mError
&& mRankedError.mErrorRank == other.mRankedError.mErrorRank;
}
bool operator!=(const RetWithRankedError<T>& other) const { return !(*this == other); }

Check warning on line 96 in src/core/cm/launcher/rankederror.hpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make this member overloaded operator a hidden friend.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ5Jm6utNdBLcrXcrnkC&open=AZ5Jm6utNdBLcrXcrnkC&pullRequest=571

/**
* Holds returned value.
*/
T mValue;

/**
* Holds returned ranked error.
*/
RankedError mRankedError;
};

} // namespace aos::cm::launcher

#endif
Loading