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
6 changes: 4 additions & 2 deletions src/core/cm/imagemanager/imagemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1417,9 +1417,11 @@ bool ImageManager::StartAction()

mCondVar.Wait(lock, [this]() { return !mInProgress || mCancel; });

if (mCancel) {
mCancel = false;
const bool cancelledWhileRunning = mCancel && mInProgress;

mCancel = false;

if (cancelledWhileRunning) {
return false;
}

Expand Down
39 changes: 37 additions & 2 deletions src/core/common/spaceallocator/spaceallocator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,42 @@ class Partition {
return ErrorEnum::eNone;
}

/**
* Adjusts allocated size without changing allocation count.
* Used by resize operations so that mAllocationCount tracks live Space objects only.
*
* @param oldSize previously allocated size to return.
* @param newSize new size to reserve.
* @return Error.
*/
Error AdjustSize(size_t oldSize, size_t newSize)
{
LockGuard lock {mMutex};

mAvailableSize += oldSize;

if (newSize > mAvailableSize) {
if (mOutdatedItems.Size() == 0) {
return Error(ErrorEnum::eNoMemory, "not enough space");
}

auto [freedSize, err] = RemoveOutdatedItems(newSize - mAvailableSize);
if (!err.IsNone()) {
return err;
}

mAvailableSize += freedSize;

if (newSize > mAvailableSize) {
return Error(ErrorEnum::eNoMemory, "not enough space");
}
}

mAvailableSize -= newSize;

return ErrorEnum::eNone;
}

/**
* Add outdated item.
*
Expand Down Expand Up @@ -501,13 +537,12 @@ class SpaceAllocator : public SpaceAllocatorItf, public SpaceAllocatorStorage {
}

Free(oldSize);
mPartition->Free(oldSize);

if (auto err = Allocate(newSize); !err.IsNone()) {
return err;
}

if (auto err = mPartition->Allocate(newSize); !err.IsNone()) {
if (auto err = mPartition->AdjustSize(oldSize, newSize); !err.IsNone()) {
Free(newSize);

return err;
Expand Down
210 changes: 206 additions & 4 deletions src/core/sm/imagemanager/imagemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,17 +339,195 @@

LOG_DBG() << "Remove item" << Log::Field("id", id) << Log::Field("version", version);

UpdateItemData evictedData;

if (!FindUpdateItemData(id, version, evictedData)) {
if (auto err = mStorage->RemoveUpdateItem(id, version); !err.IsNone()) {
LOG_ERR() << "Failed to remove update item" << Log::Field("itemID", id) << Log::Field("version", version)
<< Log::Field(err);
}

auto [size, err] = RemoveOrphans();
if (!err.IsNone()) {
return {0, AOS_ERROR_WRAP(err)};
}

return size;
}

// Memory budget: remainingBlobs + remainingLayers + itemsData (freed in CalcRemainingBlobsAndLayers scope)
// + 1 manifest/config pair per CalcItemBlobsAndLayers call — fits existing cAllocatorSize.
auto remainingBlobs = MakeUnique<StaticArray<StaticString<cFilePathLen>, cMaxNumInstalledBlobs>>(&mAllocator);
auto remainingLayers = MakeUnique<StaticArray<StaticString<cFilePathLen>, cMaxNumInstalledLayers>>(&mAllocator);

if (!remainingBlobs || !remainingLayers) {
if (auto err = mStorage->RemoveUpdateItem(id, version); !err.IsNone()) {
LOG_ERR() << "Failed to remove update item" << Log::Field("itemID", id) << Log::Field("version", version)
<< Log::Field(err);
}

auto [size, err] = RemoveOrphans();
if (!err.IsNone()) {
return {0, AOS_ERROR_WRAP(err)};
}

return size;
}

if (auto err = CalcRemainingBlobsAndLayers(id, version, *remainingBlobs, *remainingLayers); !err.IsNone()) {
LOG_ERR() << "Failed to calculate remaining blobs and layers" << Log::Field(err);
}

if (auto err = mStorage->RemoveUpdateItem(id, version); !err.IsNone()) {
LOG_ERR() << "Failed to remove update item" << Log::Field("itemID", id) << Log::Field("version", version)
<< Log::Field(err);
}

auto [size, err] = RemoveOrphans();
if (!err.IsNone()) {
return RetWithError<size_t>(0, AOS_ERROR_WRAP(err));
return DeleteEvictedItemFiles(evictedData, *remainingBlobs, *remainingLayers);
}

bool ImageManager::FindUpdateItemData(const String& id, const String& version, UpdateItemData& data)
{
auto itemsData = MakeUnique<UpdateItemDataStaticArray>(&mAllocator);
if (!itemsData) {
return false;
}

if (auto err = mStorage->GetAllUpdateItems(*itemsData); !err.IsNone()) {
return false;
}

for (const auto& item : *itemsData) {
if (item.mID == id && item.mVersion == version) {
data = item;

return true;
}
}

return size;
return false;
}

Error ImageManager::CalcRemainingBlobsAndLayers(const String& skipID, const String& skipVersion,
Array<StaticString<cFilePathLen>>& blobs, Array<StaticString<cFilePathLen>>& layers)
{
auto itemsData = MakeUnique<UpdateItemDataStaticArray>(&mAllocator);
if (!itemsData) {
return AOS_ERROR_WRAP(ErrorEnum::eNoMemory);
}

if (auto err = mStorage->GetAllUpdateItems(*itemsData); !err.IsNone()) {
return AOS_ERROR_WRAP(err);
}

for (const auto& item : *itemsData) {
if (item.mID == skipID && item.mVersion == skipVersion) {
continue;
}

if (auto err = CalcItemBlobsAndLayers(item, blobs, layers); !err.IsNone()) {
LOG_ERR() << "Failed to calculate item blobs and layers" << Log::Field("itemID", item.mID)
<< Log::Field("version", item.mVersion) << Log::Field(err);
}
}

return ErrorEnum::eNone;
}

RetWithError<size_t> ImageManager::DeleteEvictedItemFiles(const UpdateItemData& evictedData,

Check failure on line 437 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 89 to the 25 allowed.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65q7&open=AZ7bGTv8pJWmB04s65q7&pullRequest=593
const Array<StaticString<cFilePathLen>>& remainingBlobs, const Array<StaticString<cFilePathLen>>& remainingLayers)
{
// Only delete files exclusively owned by the evicted item (not referenced by any remaining DB item).
// Files for concurrent in-progress installs are never listed in evictedData's manifest,
// so they are safe from deletion here.
size_t freedSize = 0;
StaticString<cFilePathLen> path;
StaticString<cFilePathLen> manifestPath;

auto manifest = MakeUnique<oci::ImageManifest>(&mAllocator);
if (!manifest) {
return {0, ErrorEnum::eNone};
}

if (auto err = CreateBlobPath(evictedData.mManifestDigest, manifestPath); !err.IsNone()) {
return {0, ErrorEnum::eNone};
}

if (auto err = mOCISpec->LoadImageManifest(manifestPath, *manifest); !err.IsNone()) {
LOG_ERR() << "Failed to load manifest for evicted item" << Log::Field(err);
} else {
if (manifest->mItemConfig.HasValue()) {
if (auto err = CreateBlobPath(manifest->mItemConfig->mDigest, path); err.IsNone()) {

Check warning on line 460 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Declaration shadows a local variable "err" in the outer scope.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65rA&open=AZ7bGTv8pJWmB04s65rA&pullRequest=593
if (remainingBlobs.Find(path) == remainingBlobs.end()) {

Check warning on line 461 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Merge this "if" statement with the enclosing one.

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

Check failure on line 461 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65q8&open=AZ7bGTv8pJWmB04s65q8&pullRequest=593
auto [sz, szErr] = fs::CalculateSize(path);
freedSize += sz;

if (auto removeErr = fs::RemoveAll(path); !removeErr.IsNone()) {
LOG_ERR() << "Failed to remove orphaned item config" << Log::Field(removeErr);
}
}
}
}

if (evictedData.mType == UpdateItemTypeEnum::eService) {
if (auto err = CreateBlobPath(manifest->mConfig.mDigest, path); err.IsNone()) {

Check warning on line 473 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Declaration shadows a local variable "err" in the outer scope.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65rB&open=AZ7bGTv8pJWmB04s65rB&pullRequest=593
auto imageConfigPath = path;

auto imageConfig = MakeUnique<oci::ImageConfig>(&mAllocator);
if (imageConfig) {

Check warning on line 477 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the init-statement to declare "imageConfig" inside the if statement.

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

Check failure on line 477 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65q9&open=AZ7bGTv8pJWmB04s65q9&pullRequest=593
if (auto err = mOCISpec->LoadImageConfig(imageConfigPath, *imageConfig); err.IsNone()) {

Check warning on line 478 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Declaration shadows a local variable "err" in the outer scope.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65rC&open=AZ7bGTv8pJWmB04s65rC&pullRequest=593
for (const auto& diffID : imageConfig->mRootfs.mDiffIDs) {
if (auto err = CreateLayerPath(diffID, path); err.IsNone()) {

Check warning on line 480 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Declaration shadows a local variable "err" in the outer scope.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65rD&open=AZ7bGTv8pJWmB04s65rD&pullRequest=593
if (remainingLayers.Find(path) == remainingLayers.end()) {

Check warning on line 481 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Merge this "if" statement with the enclosing one.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65rG&open=AZ7bGTv8pJWmB04s65rG&pullRequest=593
auto [sz, szErr] = fs::CalculateSize(path);
freedSize += sz;

if (auto removeErr = fs::RemoveAll(path); !removeErr.IsNone()) {
LOG_ERR() << "Failed to remove orphaned layer" << Log::Field(removeErr);
}
}
}
}
} else {
LOG_ERR() << "Failed to load image config for evicted item" << Log::Field(err);
}
}

if (remainingBlobs.Find(imageConfigPath) == remainingBlobs.end()) {

Check failure on line 496 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65q-&open=AZ7bGTv8pJWmB04s65q-&pullRequest=593
auto [sz, szErr] = fs::CalculateSize(imageConfigPath);
freedSize += sz;

if (auto removeErr = fs::RemoveAll(imageConfigPath); !removeErr.IsNone()) {
LOG_ERR() << "Failed to remove orphaned image config" << Log::Field(removeErr);
}
}
}
}

for (const auto& layer : manifest->mLayers) {
if (auto err = CreateBlobPath(layer.mDigest, path); err.IsNone()) {

Check warning on line 508 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Declaration shadows a local variable "err" in the outer scope.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65rE&open=AZ7bGTv8pJWmB04s65rE&pullRequest=593
if (remainingBlobs.Find(path) == remainingBlobs.end()) {

Check failure on line 509 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

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

Check warning on line 509 in src/core/sm/imagemanager/imagemanager.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Merge this "if" statement with the enclosing one.

See more on https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&issues=AZ7bGTv8pJWmB04s65rH&open=AZ7bGTv8pJWmB04s65rH&pullRequest=593
auto [sz, szErr] = fs::CalculateSize(path);
freedSize += sz;

if (auto removeErr = fs::RemoveAll(path); !removeErr.IsNone()) {
LOG_ERR() << "Failed to remove orphaned layer blob" << Log::Field(removeErr);
}
}
}
}
}

if (remainingBlobs.Find(manifestPath) == remainingBlobs.end()) {
auto [sz, szErr] = fs::CalculateSize(manifestPath);
freedSize += sz;

if (auto removeErr = fs::RemoveAll(manifestPath); !removeErr.IsNone()) {
LOG_ERR() << "Failed to remove orphaned manifest" << Log::Field(removeErr);
}
}

return {freedSize, ErrorEnum::eNone};
}

Error ImageManager::CreateBlobPath(const String& digest, String& path) const
Expand Down Expand Up @@ -1292,6 +1470,30 @@
}
}

for (const auto& digest : mInProgressBlobs) {
StaticString<cFilePathLen> blobPath;

if (auto err = CreateBlobPath(digest, blobPath); !err.IsNone()) {
LOG_ERR() << "Failed to create path for in-progress blob" << Log::Field("digest", digest)
<< Log::Field(err);
continue;
}

if (auto err = usedBlobs->PushBack(blobPath); !err.IsNone()) {
LOG_ERR() << "Failed to protect in-progress blob" << Log::Field(err);
}

StaticString<cFilePathLen> layerPath;

if (auto err = CreateLayerPath(digest, layerPath); !err.IsNone()) {
continue;
}

if (auto err = usedLayers->PushBack(layerPath); !err.IsNone()) {
LOG_ERR() << "Failed to protect in-progress layer" << Log::Field(err);
}
}

size_t removedSize = 0;
size_t size = 0;
Error err;
Expand Down
6 changes: 6 additions & 0 deletions src/core/sm/imagemanager/imagemanager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ class ImageManager : public ImageManagerItf, public ItemInfoProviderItf, public
Error HandleItemsIntegrity();
Error CalcItemBlobsAndLayers(const UpdateItemData& itemData, Array<StaticString<cFilePathLen>>& itemBlobs,
Array<StaticString<cFilePathLen>>& itemLayers);
Error CalcRemainingBlobsAndLayers(const String& skipID, const String& skipVersion,
Array<StaticString<cFilePathLen>>& blobs, Array<StaticString<cFilePathLen>>& layers);
bool FindUpdateItemData(const String& id, const String& version, UpdateItemData& data);
RetWithError<size_t> DeleteEvictedItemFiles(const UpdateItemData& evictedData,
const Array<StaticString<cFilePathLen>>& remainingBlobs,
const Array<StaticString<cFilePathLen>>& remainingLayers);
RetWithError<size_t> RemoveOrphanBlobs(const Array<StaticString<cFilePathLen>>& usedBlobs);
RetWithError<size_t> RemoveOrphanLayers(const Array<StaticString<cFilePathLen>>& usedLayers);
RetWithError<size_t> RemoveOrphans();
Expand Down
Loading