From b28ece0cff355ee53640cdd85bf2d41a6dd53d32 Mon Sep 17 00:00:00 2001 From: Oleksandr Grytsov Date: Wed, 29 Jul 2026 19:09:36 +0300 Subject: [PATCH] sm: launcher: implement InitInstances At startup a runtime only knows what it is currently running, while the launcher knows the full set of instances that should exist. Each runtime must reconcile its own state against that list: stop anything not in it and properly initialize already-running instances, without starting anything new yet. Group the stored instances by runtime and call each registered runtime's InitInstances with only the instances that belong to it. Add the corresponding InitInstances mock to RuntimeMock and cover the grouping behavior with a unit test. Grow the launcher allocator to fit the extra per-runtime instances array. Signed-off-by: Oleksandr Grytsov Reviewed-by: Mykhailo Lohvynenko Reviewed-by: Mykola Kobets Reviewed-by: Mykola Solianko --- src/core/sm/launcher/itf/runtime.hpp | 12 ++++ src/core/sm/launcher/launcher.cpp | 29 +++++++++ src/core/sm/launcher/launcher.hpp | 5 +- src/core/sm/launcher/tests/launcher.cpp | 59 +++++++++++++++++++ .../sm/launcher/tests/mocks/runtimemock.hpp | 1 + 5 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/core/sm/launcher/itf/runtime.hpp b/src/core/sm/launcher/itf/runtime.hpp index 97b6423bf..8b91ab602 100644 --- a/src/core/sm/launcher/itf/runtime.hpp +++ b/src/core/sm/launcher/itf/runtime.hpp @@ -48,6 +48,18 @@ class RuntimeItf : public monitoring::InstanceMonitoringProviderItf { */ virtual Error GetRuntimeInfo(RuntimeInfo& runtimeInfo) const = 0; + /** + * Initializes instances. + * + * Launcher provides list of known instances to runtime at startup. Runtime should stop all instances that are not + * in the list and properly initialize already running instances. Runtime should not start any instance at this + * stage, it should only prepare them for future start. + * + * @param instancesInfo instances info. + * @return Error. + */ + virtual Error InitInstances(const Array& instancesInfo) = 0; + /** * Start instance. * diff --git a/src/core/sm/launcher/launcher.cpp b/src/core/sm/launcher/launcher.cpp index edcfdfa34..a9ed66b9c 100644 --- a/src/core/sm/launcher/launcher.cpp +++ b/src/core/sm/launcher/launcher.cpp @@ -79,6 +79,8 @@ Error Launcher::Start() return AOS_ERROR_WRAP(err); } + InitInstances(*storedInstances); + lock.Unlock(); LoadInstancesData(*storedInstances); @@ -361,6 +363,33 @@ void Launcher::OnDisconnect() StartTTLTimer(); } +void Launcher::InitInstances(const Array& instancesInfo) +{ + LOG_DBG() << "Init instances" << Log::Field("numInstances", instancesInfo.Size()); + + for (auto& it : mRuntimes) { + auto runtimeInstances = MakeUnique(&mAllocator); + + for (const auto& instanceInfo : instancesInfo) { + if (instanceInfo.mRuntimeID != it.mSecond) { + continue; + } + + if (auto err = runtimeInstances->PushBack(instanceInfo); !err.IsNone()) { + LOG_ERR() << "Failed to add instance to runtime init list" << Log::Field("instance", instanceInfo) + << Log::Field(AOS_ERROR_WRAP(err)); + + break; + } + } + + if (auto err = it.mFirst->InitInstances(*runtimeInstances); !err.IsNone()) { + LOG_ERR() << "Failed to init instances" << Log::Field("runtimeID", it.mSecond) + << Log::Field(AOS_ERROR_WRAP(err)); + } + } +} + void Launcher::RunRebootThread() { while (true) { diff --git a/src/core/sm/launcher/launcher.hpp b/src/core/sm/launcher/launcher.hpp index 954213834..801caafd3 100644 --- a/src/core/sm/launcher/launcher.hpp +++ b/src/core/sm/launcher/launcher.hpp @@ -173,7 +173,7 @@ class Launcher : public LauncherItf, static constexpr auto cMaxNumSubscribers = 4; static constexpr auto cAllocatorSize = 2 * sizeof(StaticArray) - + 2 * sizeof(InstanceInfoArray) + sizeof(InstanceStatusArray) + + 3 * sizeof(InstanceInfoArray) + sizeof(InstanceStatusArray) + cMaxNumConcurrentItems * (sizeof(oci::ImageConfig) + sizeof(oci::ItemConfig) + Max(sizeof(StaticString) + sizeof(oci::ImageManifest), @@ -181,7 +181,7 @@ class Launcher : public LauncherItf, + Max(sizeof(StaticArray), sizeof(StaticArray) + sizeof(StaticArray)); - static constexpr auto cMaxNumAllocations = 4 + cMaxNumConcurrentItems * 4; + static constexpr auto cMaxNumAllocations = 5 + cMaxNumConcurrentItems * 4; void OnConnect() override; void OnDisconnect() override; @@ -233,6 +233,7 @@ class Launcher : public LauncherItf, void StartTTLTimer(); void StopExpiredInstances(UniqueLock& lock); void SendNodeInstancesStatuses(); + void InitInstances(const Array& instancesInfo); StaticAllocator mAllocator; StaticArray mSubscribers; diff --git a/src/core/sm/launcher/tests/launcher.cpp b/src/core/sm/launcher/tests/launcher.cpp index 429ca0b6b..b9da0b2ae 100644 --- a/src/core/sm/launcher/tests/launcher.cpp +++ b/src/core/sm/launcher/tests/launcher.cpp @@ -162,11 +162,13 @@ class LauncherTest : public Test { EXPECT_CALL(mRuntime0, Stop).WillRepeatedly(Return(ErrorEnum::eNone)); EXPECT_CALL(mRuntime0, GetRuntimeInfo) .WillRepeatedly(DoAll(SetArgReferee<0>(CreateRuntimeInfo("runtime0")), Return(ErrorEnum::eNone))); + EXPECT_CALL(mRuntime0, InitInstances).WillRepeatedly(Return(ErrorEnum::eNone)); EXPECT_CALL(mRuntime1, Start).WillRepeatedly(Return(ErrorEnum::eNone)); EXPECT_CALL(mRuntime1, Stop).WillRepeatedly(Return(ErrorEnum::eNone)); EXPECT_CALL(mRuntime1, GetRuntimeInfo) .WillRepeatedly(DoAll(SetArgReferee<0>(CreateRuntimeInfo("runtime1")), Return(ErrorEnum::eNone))); + EXPECT_CALL(mRuntime1, InitInstances).WillRepeatedly(Return(ErrorEnum::eNone)); mImageManifest.mItemConfig.EmplaceValue(); @@ -246,6 +248,63 @@ TEST_F(LauncherTest, NoStoredInstancesOnModuleStart) ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); } +TEST_F(LauncherTest, InitInstances) +{ + const std::vector cStoredInfos = { + CreateInstanceInfo("item0", 0, "1.0.0", "runtime0"), + CreateInstanceInfo("item1", 1, "1.0.0", "runtime1"), + CreateInstanceInfo("item2", 2, "1.0.0", "runtime0"), + }; + + const std::vector cRuntime0Infos = {cStoredInfos[0], cStoredInfos[2]}; + const std::vector cRuntime1Infos = {cStoredInfos[1]}; + + mStorage.Init(cStoredInfos); + + auto err = mLauncher.Init(GetRuntimesArray(), mImageManager, mSender, mStorage, mOCISpec, mItemInfoProvider, + mCloudConnection, mNetworkManager, mInstanceIDProvider, mResourceInfoProvider); + ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); + + EXPECT_CALL(mRuntime0, InitInstances(Array(&cRuntime0Infos.front(), cRuntime0Infos.size()))) + .WillOnce(Return(ErrorEnum::eNone)); + EXPECT_CALL(mRuntime1, InitInstances(Array(&cRuntime1Infos.front(), cRuntime1Infos.size()))) + .WillOnce(Return(ErrorEnum::eNone)); + + EXPECT_CALL(mRuntime0, StartInstance) + .WillRepeatedly(Invoke([](const InstanceInfo& instance, InstanceStatus& status) { + SetInstanceStatus(instance, InstanceStateEnum::eActive, status); + + return ErrorEnum::eNone; + })); + + EXPECT_CALL(mRuntime1, StartInstance) + .WillRepeatedly(Invoke([](const InstanceInfo& instance, InstanceStatus& status) { + SetInstanceStatus(instance, InstanceStateEnum::eActive, status); + + return ErrorEnum::eNone; + })); + + err = mLauncher.Start(); + ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); + + EXPECT_CALL(mRuntime0, StopInstance) + .WillRepeatedly(Invoke([](const InstanceIdent& instance, InstanceStatus& status) { + SetInstanceStatus(instance, InstanceStateEnum::eInactive, status); + + return ErrorEnum::eNone; + })); + + EXPECT_CALL(mRuntime1, StopInstance) + .WillRepeatedly(Invoke([](const InstanceIdent& instance, InstanceStatus& status) { + SetInstanceStatus(instance, InstanceStateEnum::eInactive, status); + + return ErrorEnum::eNone; + })); + + err = mLauncher.Stop(); + ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); +} + TEST_F(LauncherTest, SendActiveComponentNodeInstancesStatusOnModuleStart) { const std::vector cRuntime0Components = { diff --git a/src/core/sm/launcher/tests/mocks/runtimemock.hpp b/src/core/sm/launcher/tests/mocks/runtimemock.hpp index 8654e1acb..c3a4bd4a7 100644 --- a/src/core/sm/launcher/tests/mocks/runtimemock.hpp +++ b/src/core/sm/launcher/tests/mocks/runtimemock.hpp @@ -21,6 +21,7 @@ class RuntimeMock : public RuntimeItf { MOCK_METHOD(Error, Start, (), (override)); MOCK_METHOD(Error, Stop, (), (override)); MOCK_METHOD(Error, GetRuntimeInfo, (RuntimeInfo&), (const, override)); + MOCK_METHOD(Error, InitInstances, (const Array&), (override)); MOCK_METHOD(Error, StartInstance, (const InstanceInfo&, InstanceStatus&), (override)); MOCK_METHOD(Error, StopInstance, (const InstanceIdent&, InstanceStatus&), (override)); MOCK_METHOD(Error, Reboot, (), (override));