Repository: aosedge/aos_core_lib_cpp
Pull request #255: Implement Space allocator
Author: login: MykolaSuperman
Created: 2025-02-05T09:58:28Z | Merged: 2025-05-16T07:29:22Z



Diff:
diff --git a/include/aos/common/config.hpp b/include/aos/common/config.hpp
index c433e4aee..ff5adcea5 100644
--- a/include/aos/common/config.hpp
+++ b/include/aos/common/config.hpp
@@ -519,6 +519,13 @@
 #define AOS_CONFIG_TYPES_FUNC_SERVICE_MAX_COUNT 16
 #endif
 
+/**
+ * Max number of outdated items.
+ */
+#ifndef AOS_CONFIG_SPACEALLOCATOR_MAX_OUTDATED_ITEMS
+#define AOS_CONFIG_SPACEALLOCATOR_MAX_OUTDATED_ITEMS 64
+#endif
+
 /**
  * Monitoring poll period.
  */
diff --git a/include/aos/common/spaceallocator/spaceallocator.hpp b/include/aos/common/spaceallocator/spaceallocator.hpp
index 92448694d..d4794edf7 100644
--- a/include/aos/common/spaceallocator/spaceallocator.hpp
+++ b/include/aos/common/spaceallocator/spaceallocator.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 EPAM Systems, Inc.
+ * Copyright (C) 2025 EPAM Systems, Inc.
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -7,12 +7,14 @@
 #ifndef AOS_SPACEALLOCATOR_HPP_
 #define AOS_SPACEALLOCATOR_HPP_
 
+#include "aos/common/tools/fs.hpp"
+#include "aos/common/tools/function.hpp"
+#include "aos/common/tools/map.hpp"
 #include "aos/common/tools/memory.hpp"
 #include "aos/common/tools/time.hpp"
 #include "aos/common/types.hpp"
 
 namespace aos::spaceallocator {
-
 /**
  * Item remover interface.
  */
@@ -32,6 +34,9 @@ class ItemRemoverItf {
     virtual ~ItemRemoverItf() = default;
 };
 
+/**
+ * Space interface.
+ */
 class SpaceItf {
 public:
     /**
@@ -54,14 +59,14 @@ class SpaceItf {
      * @param size new size.
      * @return Error.
      */
-    virtual Error Resize(uint64_t size) = 0;
+    virtual Error Resize(size_t size) = 0;
 
     /**
      * Returns space size.
      *
-     * @return uint64_t.
+     * @return size_t.
      */
-    virtual uint64_t Size() const = 0;
+    virtual size_t Size() const = 0;
 
     /**
      * Destructor.
@@ -80,7 +85,7 @@ class SpaceAllocatorItf {
      * @param size size to allocate.
      * @return RetWithError<UniquePtr<SpaceItf>>.
      */
-    virtual RetWithError<UniquePtr<SpaceItf>> AllocateSpace(uint64_t size) = 0;
+    virtual RetWithError<UniquePtr<SpaceItf>> AllocateSpace(size_t size) = 0;
 
     /**
      * Frees space.
@@ -88,7 +93,7 @@ class SpaceAllocatorItf {
      * @param size size to free.
      * @return void.
      */
-    virtual void FreeSpace(uint64_t size) = 0;
+    virtual void FreeSpace(size_t size) = 0;
 
     /**
      * Adds outdated item.
@@ -98,7 +103,7 @@ class SpaceAllocatorItf {
      * @param timestamp item timestamp.
      * @return Error.
      */
-    virtual Error AddOutdatedItem(const String& id, uint64_t size, const Time& timestamp) = 0;
+    virtual Error AddOutdatedItem(const String& id, size_t size, const Time& timestamp) = 0;
 
     /**
      * Restores outdated item.
@@ -108,6 +113,13 @@ class SpaceAllocatorItf {
      */
     virtual Error RestoreOutdatedItem(const String& id) = 0;
 
+    /**
+     * Allocates done.
+     *
+     * @return Error.
+     */
+    virtual Error AllocateDone() = 0;
+
     /**
      * Destructor.
      */
@@ -122,8 +134,9 @@ class Space : public SpaceItf {
     /**
      * Crates space instance.
      */
-    explicit Space(size_t size)
+    Space(size_t size, SpaceAllocatorItf* allocator)
         : mSize(size)
+        , mAllocator(allocator)
     {
     }
 
@@ -132,14 +145,19 @@ class Space : public SpaceItf {
      *
      * @return Error.
      */
-    Error Accept() override { return ErrorEnum::eNone; }
+    Error Accept() override { return mAllocator->AllocateDone(); }
 
     /**
      * Releases space.
      *
      * @return Error.
      */
-    Error Release() override { return ErrorEnum::eNone; }
+    Error Release() override
+    {
+        mAllocator->FreeSpace(mSize);
+
+        return mAllocator->AllocateDone();
+    }
 
     /**
      * Resizes space.
@@ -147,7 +165,7 @@ class Space : public SpaceItf {
      * @param size new size.
      * @return Error.
      */
-    Error Resize(uint64_t size) override
+    Error Resize(size_t size) override
     {
         mSize = size;
 
@@ -157,29 +175,373 @@ class Space : public SpaceItf {
     /**
      * Returns space size.
      *
-     * @return uint64_t.
+     * @return size_t.
      */
-    uint64_t Size() const override { return mSize; }
+    size_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+struct Partition;
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    size_t                                                                                                     mSize;
+    SpaceAllocatorItf*                      mAllocator {};
+    StaticFunction<cDefaultFunctionMaxSize> mFreeCallback;
+    Partition*                              mPartition {};
+    ItemRemoverItf*                         mRemover {};
+    Time                                    mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+class Partition {
+public:
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return Error.
+     */
+    Error AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return ErrorEnum::eNone;
+            }
+        }
+
+        Error err = mOutdatedItems.PushBack(item);
+        if (!err.IsNone()) {
+            mOutdatedItems.Sort(
+                [](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+            auto& oldestItem = mOutdatedItems[0];
+
+            if (auto removeErr = oldestItem.mRemover->RemoveItem(oldestItem.mID); !removeErr.IsNone()) {
+                return removeErr;
+            }
+
+            oldestItem.mFreeCallback();
+            mAvailableSize += oldestItem.mSize;
+
+            oldestItem = item;
+
+            return ErrorEnum::eNone;
+        }
+
+        return err;
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr size_t cMaxNumOutdatedItems = AOS_CONFIG_SPACEALLOCATOR_MAX_OUTDATED_ITEMS;
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    size_t                                          mLimit {};
+    size_t                                          mTotalSize {};
+    size_t                                          mAllocatorCount {};
+    fs::FSPlatformItf*                              mPlatformFS {};
+    StaticArray<OutdatedItem, cMaxNumOutdatedItems> mOutdatedItems;
+
+private:
+    static constexpr size_t cMaxLimit = 100;
+
+    RetWithError<size_t> RemoveOutdatedItems(size_t size)
+    {
+        size_t totalSize = 0;
+
+        for (const auto& item : mOutdatedItems) {
+            totalSize += item.mSize;
+        }
+
+        if (size > totalSize) {
+            return {0, Error(ErrorEnum::eNoMemory, "partition limit exceeded")};
+        }
+
+        mOutdatedItems.Sort([](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+        size_t freedSize = 0;
+        size_t i         = 0;
+
+        for (; freedSize < size; i++) {
+            auto& item = mOutdatedItems[i];
+
+            if (auto err = item.mRemover->RemoveItem(item.mID); !err.IsNone()) {
+                return {freedSize, err};
+            }
+
+            item.mFreeCallback();
+            freedSize += item.mSize;
+        }
+
+        mOutdatedItems.Erase(mOutdatedItems.begin(), mOutdatedItems.begin() + i);
+
+        return {freedSize, ErrorEnum::eNone};
+    }
+
+    size_t mAllocationCount {};
+    size_t mAvailableSize {};
+    Mutex  mMutex {};
+};
+
+/**
+ * Space allocator storage.
+ */
+struct SpaceAllocatorStorage {
+    static inline StaticMap<String, Partition, cMaxNumPartitions> mPartitions;
+    static inline Mutex                                           mPartitionsMutex;
 };
 
 /**
  * Space allocator instance.
  */
 template <size_t cNumAllocations>
-class SpaceAllocator : public SpaceAllocatorItf {
+class SpaceAllocator : public SpaceAllocatorItf, public SpaceAllocatorStorage {
 public:
+    /**
+     * Constructor.
+     */
+    SpaceAllocator() = default;
+
+    /**
+     * Initializes space allocator.
+     *
+     * @param path path to allocate space.
+     * @param limit limit in percents.
+     * @param remover item remover.
+     * @param platformFS platform file system.
+     * @return Error.
+     */
+    Error Init(const String& path, size_t limit, ItemRemoverItf& remover, fs::FSPlatformItf& platformFS)
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        mRemover    = &remover;
+        mPlatformFS = &platformFS;
+        mPath       = path;
+
+        auto [mountPoint, errMountPoint] = mPlatformFS->GetMountPoint(path);
+        if (!errMountPoint.IsNone()) {
+            return errMountPoint;
+        }
+
+        Error err;
+
+        auto partitionIt = mPartitions.Find(mountPoint);
+        if (partitionIt == mPartitions.end()) {
+            if (err = mPartitions.TryEmplace(mountPoint, Partition()); !err.IsNone()) {
+                return err;
+            }
+
+            partitionIt = mPartitions.end() - 1;
+
+            if (err = NewPartition(mountPoint, partitionIt->mSecond); !err.IsNone()) {
+                return err;
+            }
+        }
+
+        mPartition = &partitionIt->mSecond;
+        mPartition->mAllocatorCount++;
+
+        if (limit != 0) {
+            if (err = mPartition->AddLimit(limit); !err.IsNone()) {
+                return err;
+            }
+
+            mSizeLimit = mPartition->mTotalSize * mPartition->mLimit / 100;
+        }
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Closes space allocator.
+     *
+     * @return Error.
+     */
+    Error Close()
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        Error err;
+
+        if (auto errRemovePartLimit = mPartition->RemoveLimit(mPartition->mLimit); !errRemovePartLimit.IsNone()) {
+            err = errRemovePartLimit;
+        }
+
+        mPartition->mAllocatorCount--;
+
+        if (mPartition->mAllocatorCount != 0) {
+            return err;
+        }
+
+        if (auto errRemovePart = mPartitions.Remove(mPartition->mMountPoint);
+            !err.IsNone() && !errRemovePart.IsNone()) {
+            err = errRemovePart;
+        }
+
+        return err;
+    }
+
     /**
      * Allocates space.
      *
      * @param size size to allocate.
      * @return RetWithError<UniquePtr<SpaceItf>>.
      */
-    RetWithError<UniquePtr<SpaceItf>> AllocateSpace(uint64_t size) override
+    RetWithError<UniquePtr<SpaceItf>> AllocateSpace(size_t size) override
     {
-        return UniquePtr<SpaceItf>(MakeUnique<Space>(&mAllocator, size));
+        auto err = Allocate(size);
+        if (!err.IsNone()) {
+            return {nullptr, err};
+        }
+
+        if (err = mPartition->Allocate(size); !err.IsNone()) {
+            return {nullptr, err};
+        }
+
+        return UniquePtr<SpaceItf>(MakeUnique<Space>(&mAllocator, size, this));
     };
 
     /**
@@ -188,7 +550,26 @@ class SpaceAllocator : public SpaceAllocatorItf {
      * @param size size to free.
      * @return void.
      */
-    void FreeSpace(uint64_t size) override { (void)size; }
+    void FreeSpace(size_t size) override
+    {
+        Free(size);
+
+        mPartition->Free(size);
+    }
+
+    /**
+     * Allocates done.
+     *
+     * @return Error.
+     */
+    Error AllocateDone() override
+    {
+        if (auto err = Done(); !err.IsNone()) {
+            return err;
+        }
+
+        return mPartition->Done();
+    }
 
     /**
      * Adds outdated item.
@@ -198,13 +579,23 @@ class SpaceAllocator : public SpaceAllocatorItf {
      * @param timestamp item timestamp.
      * @return Error.
      */
-    Error AddOutdatedItem(const String& id, uint64_t size, const Time& timestamp) override
+    Error AddOutdatedItem(const String& id, size_t size, const Time& timestamp) override
     {
-        (void)id;
-        (void)size;
-        (void)timestamp;
+        if (mRemover == nullptr) {
+            return Error(ErrorEnum::eNotFound, "no item remover");
+        }
 
-        return ErrorEnum::eNone;
+        OutdatedItem item;
+        item.mID        = id;
+        item.mSize      = size;
+        item.mPartition = mPartition;
+        item.mRemover   = mRemover;
+        item.mTimestamp = timestamp;
+        item.mAllocator = this;
+
+        item.mFreeCallback = aos::StaticFunction<> {[this, size](void*) { this->Free(size); }};
+
+        return mPartition->AddOutdatedItem(item);
     }
 
     /**
@@ -215,13 +606,149 @@ class SpaceAllocator : public SpaceAllocatorItf {
      */
     Error RestoreOutdatedItem(const String& id) override
     {
-        (void)id;
+        mPartition->RestoreOutdatedItem(id);
 
         return ErrorEnum::eNone;
     }
 
 private:
+    Error NewPartition(const String& path, Partition& partition)
+    {
+        auto [totalSize, err] = mPlatformFS->GetTotalSize(path);
+        if (!err.IsNone()) {
+            return err;
+        }
+
+        partition.mMountPoint = path;
+        partition.mTotalSize  = totalSize;
+        partition.mPlatformFS = mPlatformFS;
+
+        return ErrorEnum::eNone;
+    }
+
+    Error Allocate(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mSizeLimit == 0) {
+            return ErrorEnum::eNone;
+        }
+
+        if (mAllocationCount == 0) {
+            auto [allocatedSize, err] = mPlatformFS->GetDirSize(mPath);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAllocatedSize = allocatedSize;
+        }
+
+        if (mAllocatedSize + size > mSizeLimit) {
+            auto [freedSize, err] = RemoveOutdatedItems(mAllocatedSize + size - mSizeLimit);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            if (freedSize > mAllocatedSize) {
+                mAllocatedSize = 0;
+            } else {
+                mAllocatedSize -= freedSize;
+            }
+        }
+
+        mAllocatedSize += size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    RetWithError<size_t> RemoveOutdatedItems(size_t size)
+    {
+        size_t totalSize = 0;
+
+        for (const auto& item : mPartition->mOutdatedItems) {
+            if (item.mAllocator != this) {
+                continue;
+            }
+
+            totalSize += item.mSize;
+        }
+
+        if (size > totalSize) {
+            return {0, Error(ErrorEnum::eNoMemory, "partition limit exceeded")};
+        }
+
+        mPartition->mOutdatedItems.Sort(
+            [](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+        size_t freedSize = 0;
+        size_t i         = 0;
+
+        for (auto& item : mPartition->mOutdatedItems) {
+            if (item.mAllocator != this || freedSize >= size) {
+                mPartition->mOutdatedItems[i] = item;
+                i++;
+
+                continue;
+            }
+
+            if (auto err = item.mRemover->RemoveItem(item.mID); !err.IsNone()) {
+                return {freedSize, err};
+            }
+
+            item.mPartition->Free(item.mSize);
+
+            freedSize += item.mSize;
+        }
+
+        mPartition->mOutdatedItems.Erase(mPartition->mOutdatedItems.begin() + i, mPartition->mOutdatedItems.end());
+
+        return {freedSize, ErrorEnum::eNone};
+    }
+
+    void Free(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mSizeLimit == 0) {
+            return;
+        }
+
+        if (mAllocationCount > 0) {
+            if (size < mAllocatedSize) {
+                mAllocatedSize -= size;
+            } else {
+                mAllocatedSize = 0;
+            }
+        }
+    }
+
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mSizeLimit == 0) {
+            return ErrorEnum::eNone;
+        }
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
     StaticAllocator<sizeof(Space) * cNumAllocations> mAllocator;
+    size_t                                           mSizeLimit {};
+    size_t                                           mAllocationCount {};
+    size_t                                           mAllocatedSize {};
+    StaticString<cFilePathLen>                       mPath;
+    ItemRemoverItf*                                  mRemover {};
+    fs::FSPlatformItf*                               mPlatformFS {};
+    Partition*                                       mPartition {};
+    Mutex                                            mMutex;
 };
 
 } // namespace aos::spaceallocator
diff --git a/include/aos/common/tools/fs.hpp b/include/aos/common/tools/fs.hpp
index 4afcc553f..02d26e60a 100644
--- a/include/aos/common/tools/fs.hpp
+++ b/include/aos/common/tools/fs.hpp
@@ -27,6 +27,49 @@ constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 constexpr auto cDirIteratorMaxSize = AOS_CONFIG_FS_DIR_ITERATOR_MAX_COUNT;
 
 namespace fs {
+/**
+ * File system platform interface.
+ */
+class FSPlatformItf {
+public:
+    /**
+     * Destructor.
+     */
+    virtual ~FSPlatformItf() = default;
+
+    /**
+     * Gets mount point for the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<StaticString<cFilePathLen>>.
+     */
+    virtual RetWithError<StaticString<cFilePathLen>> GetMountPoint(const String& dir) const = 0;
+
+    /**
+     * Gets total size of the file system.
+     *
+     * @param dir directory path.
+     * @return RetWithError<size_t>.
+     */
+    virtual RetWithError<size_t> GetTotalSize(const String& dir) const = 0;
+
+    /**
+     * Gets directory size.
+     *
+     * @param dir directory path.
+     * @return RetWithError<size_t>.
+     */
+    virtual RetWithError<size_t> GetDirSize(const String& dir) const = 0;
+
+    /**
+     * Gets available size.
+     *
+     * @param dir directory path.
+     * @return RetWithError<size_t>.
+     */
+    virtual RetWithError<size_t> GetAvailableSize(const String& dir) const = 0;
+};
+
 /**
  * Directory iterator.
  * The iteration order is unspecified, except that each directory entry is visited only once.
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 8455673a3..21ca67720 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -15,3 +15,4 @@ add_subdirectory(include)
 add_subdirectory(mocks)
 add_subdirectory(sm)
 add_subdirectory(utils)
+add_subdirectory(spaceallocator)
diff --git a/tests/include/mocks/filesystemmock.hpp b/tests/include/mocks/filesystemmock.hpp
new file mode 100644
index 000000000..9858f5d3d
--- /dev/null
+++ b/tests/include/mocks/filesystemmock.hpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2025 EPAM Systems, Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef AOS_FILESYSTEM_MOCK_HPP_
+#define AOS_FILESYSTEM_MOCK_HPP_
+
+#include <gmock/gmock.h>
+
+#include "aos/common/tools/fs.hpp"
+
+namespace aos {
+class FSPlatformMock : public fs::FSPlatformItf {
+public:
+    MOCK_METHOD(RetWithError<StaticString<cFilePathLen>>, GetMountPoint, (const String& dir), (const, override));
+    MOCK_METHOD(RetWithError<size_t>, GetTotalSize, (const String& dir), (const, override));
+    MOCK_METHOD(RetWithError<size_t>, GetDirSize, (const String& dir), (const, override));
+    MOCK_METHOD(RetWithError<size_t>, GetAvailableSize, (const String& dir), (const, override));
+};
+} // namespace aos
+
+#endif
diff --git a/tests/include/mocks/spaceallocatormock.hpp b/tests/include/mocks/spaceallocatormock.hpp
new file mode 100644
index 000000000..2ef5169dc
--- /dev/null
+++ b/tests/include/mocks/spaceallocatormock.hpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2025 EPAM Systems, Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef AOS_SPACEALLOCATOR_MOCK_HPP_
+#define AOS_SPACEALLOCATOR_MOCK_HPP_
+
+#include <gmock/gmock.h>
+
+#include "aos/common/spaceallocator/spaceallocator.hpp"
+
+namespace aos::spaceallocator {
+
+class ItemRemoverMock : public ItemRemoverItf {
+public:
+    MOCK_METHOD(Error, RemoveItem, (const String& id), (override));
+};
+
+} // namespace aos::spaceallocator
+
+#endif
diff --git a/tests/sm/stubs/spaceallocatorstub.hpp b/tests/sm/stubs/spaceallocatorstub.hpp
index 01c76e896..9e4fd5040 100644
--- a/tests/sm/stubs/spaceallocatorstub.hpp
+++ b/tests/sm/stubs/spaceallocatorstub.hpp
@@ -22,7 +22,7 @@ class SpaceStub : public SpaceItf {
      *
      * @param size space size.
      */
-    explicit SpaceStub(uint64_t size)
+    explicit SpaceStub(size_t size)
         : mSize(size)
     {
     }
@@ -47,7 +47,7 @@ class SpaceStub : public SpaceItf {
      * @param size new size.
      * @return Error.
      */
-    Error Resize(uint64_t size) override
+    Error Resize(size_t size) override
     {
         mSize = size;
 
@@ -59,10 +59,10 @@ class SpaceStub : public SpaceItf {
      *
      * @return uint64_t.
      */
-    uint64_t Size() const override { return mSize; }
+    size_t Size() const override { return mSize; }
 
 private:
-    uint64_t mSize = 0;
+    size_t mSize = 0;
 };
 
 /**
@@ -76,7 +76,7 @@ class SpaceAllocatorStub : public SpaceAllocatorItf {
      * @param size size to allocate.
      * @return RetWithError<UniquePtr<SpaceItf>>.
      */
-    RetWithError<UniquePtr<SpaceItf>> AllocateSpace(uint64_t size) override
+    RetWithError<UniquePtr<SpaceItf>> AllocateSpace(size_t size) override
     {
         return {UniquePtr<SpaceItf>(MakeUnique<SpaceStub>(&mAllocator, size))};
     }
@@ -87,7 +87,7 @@ class SpaceAllocatorStub : public SpaceAllocatorItf {
      * @param size size to free.
      * @return void.
      */
-    void FreeSpace(uint64_t size) override
+    void FreeSpace(size_t size) override
     {
         (void)size;
 
@@ -102,7 +102,7 @@ class SpaceAllocatorStub : public SpaceAllocatorItf {
      * @param timestamp item timestamp.
      * @return Error.
      */
-    Error AddOutdatedItem(const String& id, uint64_t size, const Time& timestamp) override
+    Error AddOutdatedItem(const String& id, size_t size, const Time& timestamp) override
     {
         (void)id;
         (void)size;
@@ -124,6 +124,13 @@ class SpaceAllocatorStub : public SpaceAllocatorItf {
         return ErrorEnum::eNone;
     }
 
+    /**
+     * Allocates done.
+     *
+     * @return Error.
+     */
+    Error AllocateDone() override { return ErrorEnum::eNone; }
+
 private:
     StaticAllocator<1024> mAllocator;
 };
diff --git a/tests/spaceallocator/CMakeLists.txt b/tests/spaceallocator/CMakeLists.txt
new file mode 100644
index 000000000..95f4d6290
--- /dev/null
+++ b/tests/spaceallocator/CMakeLists.txt
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2025 EPAM Systems, Inc.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+set(TARGET aosspaceallocator_test)
+
+# ######################################################################################################################
+# Sources
+# ######################################################################################################################
+
+set(SOURCES spaceallocator_test.cpp)
+
+# ######################################################################################################################
+# Includes
+# ######################################################################################################################
+
+include_directories(${PROJECT_SOURCE_DIR}/tests/include)
+
+# ######################################################################################################################
+# Target
+# ######################################################################################################################
+
+add_executable(${TARGET} ${SOURCES})
+target_link_libraries(${TARGET} aoscommon aostestutils GTest::gmock_main)
+
+gtest_discover_tests(${TARGET})
diff --git a/tests/spaceallocator/spaceallocator_test.cpp b/tests/spaceallocator/spaceallocator_test.cpp
new file mode 100644
index 000000000..37a53b9a8
--- /dev/null
+++ b/tests/spaceallocator/spaceallocator_test.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2025 EPAM Systems, Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <gtest/gtest.h>
+
+#include "aos/common/spaceallocator/spaceallocator.hpp"
+#include "mocks/filesystemmock.hpp"
+#include "mocks/spaceallocatormock.hpp"
+
+using namespace testing;
+
+namespace aos::spaceallocator {
+
+/***********************************************************************************************************************
+ * Suite
+ **********************************************************************************************************************/
+
+class SpaceallocatorTest : public Test {
+protected:
+    StrictMock<FSPlatformMock>       mPlatformFS;
+    StrictMock<ItemRemoverMock>      mRemover;
+    const String                     mPath       = "/test/path";
+    const size_t                     mLimit      = 0;
+    static constexpr auto            cKilobyte   = 1024;
+    const size_t                     mTotalSize  = 1 * cKilobyte * cKilobyte;
+    const StaticString<cFilePathLen> mMountPoint = "/mnt/test";
+};
+
+/***********************************************************************************************************************
+ * Tests
+ **********************************************************************************************************************/
+
+TEST_F(SpaceallocatorTest, AllocateSuccess)
+{
+    SpaceAllocator<5> mSpaceAllocator;
+
+    EXPECT_CALL(mPlatformFS, GetMountPoint(mPath))
+        .WillOnce(Return(RetWithError<StaticString<cFilePathLen>>(mMountPoint, ErrorEnum::eNone)));
+
+    EXPECT_CALL(mPlatformFS, GetTotalSize(mMountPoint))
+        .WillOnce(Return(RetWithError<size_t>(mTotalSize, ErrorEnum::eNone)));
+
+    ASSERT_TRUE(mSpaceAllocator.Init(mPath, mLimit, mRemover, mPlatformFS).IsNone());
+
+    EXPECT_CALL(mPlatformFS, GetAvailableSize(mMountPoint))
+        .WillOnce(Return(RetWithError<size_t>(mTotalSize, ErrorEnum::eNone)));
+
+    const size_t size1 = 256 * cKilobyte;
+
+    auto [space1, err1] = mSpaceAllocator.AllocateSpace(size1);
+    ASSERT_TRUE(err1.IsNone());
+    ASSERT_NE(space1.Get(), nullptr);
+
+    const size_t size2  = 512 * cKilobyte;
+    auto [space2, err2] = mSpaceAllocator.AllocateSpace(size2);
+    ASSERT_TRUE(err2.IsNone());
+    ASSERT_NE(space2.Get(), nullptr);
+
+    auto [space3, err3] = mSpaceAllocator.AllocateSpace(512 * cKilobyte);
+    ASSERT_FALSE(err3.IsNone());
+
+    EXPECT_TRUE(space2->Release().IsNone());
+
+    auto [space4, err4] = mSpaceAllocator.AllocateSpace(512 * cKilobyte);
+    EXPECT_TRUE(err4.IsNone());
+    ASSERT_NE(space4.Get(), nullptr);
+
+    EXPECT_TRUE(space4->Accept().IsNone());
+    EXPECT_TRUE(space1->Accept().IsNone());
+
+    EXPECT_EQ(space1->Accept(), ErrorEnum::eNotFound);
+    EXPECT_EQ(space1->Release(), ErrorEnum::eNotFound);
+
+    ASSERT_TRUE(mSpaceAllocator.Close().IsNone());
+}
+
+TEST_F(SpaceallocatorTest, MultipleAllocators)
+{
+    SpaceAllocator<1> allocator1;
+    SpaceAllocator<1> allocator2;
+    SpaceAllocator<2> allocator3;
+
+    EXPECT_CALL(mPlatformFS, GetMountPoint(mPath))
+        .Times(3)
+        .WillRepeatedly(Return(RetWithError<StaticString<cFilePathLen>>(mMountPoint, ErrorEnum::eNone)));
+
+    EXPECT_CALL(mPlatformFS, GetTotalSize(mMountPoint))
+        .WillOnce(Return(RetWithError<size_t>(mTotalSize, ErrorEnum::eNone)));
+
+    ASSERT_TRUE(allocator1.Init(mPath, 0, mRemover, mPlatformFS).IsNone());
+    ASSERT_TRUE(allocator2.Init(mPath, 0, mRemover, mPlatformFS).IsNone());
+    ASSERT_TRUE(allocator3.Init(mPath, 0, mRemover, mPlatformFS).IsNone());
+
+    EXPECT_CALL(mPlatformFS, GetAvailableSize(mMountPoint))
+        .WillOnce(Return(RetWithError<size_t>(mTotalSize, ErrorEnum::eNone)));
+
+    const size_t size1  = 256 * cKilobyte;
+    auto [space1, err1] = allocator1.AllocateSpace(size1);
+    ASSERT_TRUE(err1.IsNone());
+    ASSERT_NE(space1.Get(), nullptr);
+
+    const size_t size2  = 512 * cKilobyte;
+    auto [space2, err2] = allocator2.AllocateSpace(size2);
+    ASSERT_TRUE(err2.IsNone());
+    ASSERT_NE(space2.Get(), nullptr);
+
+    auto [space3, err3] = allocator3.AllocateSpace(512 * cKilobyte);
+    ASSERT_FALSE(err3.IsNone());
+    ASSERT_EQ(space3.Get(), nullptr);
+
+    ASSERT_TRUE(space2->Release().IsNone());
+
+    auto [space3New, err3New] = allocator3.AllocateSpace(512 * cKilobyte);
+    ASSERT_TRUE(err3New.IsNone());
+    ASSERT_NE(space3New.Get(), nullptr);
+
+    ASSERT_TRUE(space3New->Accept().IsNone());
+    ASSERT_TRUE(space1->Accept().IsNone());
+
+    ASSERT_TRUE(allocator1.Close().IsNone());
+    ASSERT_TRUE(allocator2.Close().IsNone());
+    ASSERT_TRUE(allocator3.Close().IsNone());
+}
+
+TEST_F(SpaceallocatorTest, OutdatedItems)
+{
+    struct TestFile {
+        String name;
+        size_t size;
+        Time   timestamp;
+    };
+
+    const Time now = Time::Now();
+
+    // Total outdated files size 576 Kb
+    std::vector<TestFile> outdatedFiles = {{"file1.data", 128 * cKilobyte, now.Add(-1 * Time::cHours)},
+        {"file2.data", 32 * cKilobyte, now.Add(-6 * Time::cHours)},
+        {"file3.data", 64 * cKilobyte, now.Add(-5 * Time::cHours)},
+        {"file4.data", 256 * cKilobyte, now.Add(-4 * Time::cHours)},
+        {"file5.data", 32 * cKilobyte, now.Add(-2 * Time::cHours)},
+        {"file6.data", 256 * cKilobyte, now.Add(-3 * Time::cHours)}};
+
+    size_t totalOutdatedSize = 0;
+    for (const auto& file : outdatedFiles) {
+        totalOutdatedSize += file.size;
+    }
+
+    // Add ~5% overhead for filesystem metadata
+    totalOutdatedSize += totalOutdatedSize / 20;
+
+    SpaceAllocator<2> mSpaceAllocator;
+
+    EXPECT_CALL(mPlatformFS, GetMountPoint(mPath))
+        .WillOnce(Return(RetWithError<StaticString<cFilePathLen>>(mMountPoint, ErrorEnum::eNone)));
+
+    // Reduce total size to account for filesystem overhead
+    const size_t effectiveTotalSize = 1 * cKilobyte * cKilobyte - (50 * cKilobyte); // 1MB minus 50KB for fs overhead
+    EXPECT_CALL(mPlatformFS, GetTotalSize(mMountPoint))
+        .WillOnce(Return(RetWithError<size_t>(effectiveTotalSize, ErrorEnum::eNone)));
+
+    ASSERT_TRUE(mSpaceAllocator.Init(mPath, 100, mRemover, mPlatformFS).IsNone());
+
+    std::vector<std::string> removedFiles;
+    EXPECT_CALL(mRemover, RemoveItem(testing::_)).WillRepeatedly(testing::Invoke([&removedFiles](const String& id) {
+        removedFiles.push_back(id.CStr());
+        return ErrorEnum::eNone;
+    }));
+
+    for (const auto& file : outdatedFiles) {
+        ASSERT_TRUE(mSpaceAllocator.AddOutdatedItem(file.name, file.size, file.timestamp).IsNone());
+    }
+
+    EXPECT_CALL(mPlatformFS, GetDirSize(mPath))
+        .WillOnce(Return(RetWithError<size_t>(totalOutdatedSize, ErrorEnum::eNone)));
+
+    EXPECT_CALL(mPlatformFS, GetAvailableSize(mMountPoint))
+        .WillOnce(Return(RetWithError<size_t>(effectiveTotalSize - totalOutdatedSize, ErrorEnum::eNone)));
+
+    auto [space, err] = mSpaceAllocator.AllocateSpace(256 * cKilobyte);
+    ASSERT_TRUE(err.IsNone());
+    ASSERT_NE(space.Get(), nullptr);
+
+    std::vector<String> expectedRemovedFiles = {outdatedFiles[1].name, outdatedFiles[2].name, outdatedFiles[3].name};
+    EXPECT_EQ(removedFiles.size(), expectedRemovedFiles.size());
+    for (size_t i = 0; i < removedFiles.size(); i++) {
+        EXPECT_STREQ(removedFiles[i].c_str(), expectedRemovedFiles[i].CStr());
+    }
+
+    ASSERT_TRUE(space->Release().IsNone());
+
+    size_t remainingSize = totalOutdatedSize;
+    for (const auto& file : outdatedFiles) {
+        if (file.name == "file2.data" || file.name == "file3.data" || file.name == "file4.data") {
+            remainingSize -= file.size;
+        }
+    }
+
+    // Add ~5% overhead for filesystem metadata
+    remainingSize += remainingSize / 20;
+
+    removedFiles.clear();
+
+    EXPECT_CALL(mPlatformFS, GetDirSize(mPath)).WillOnce(Return(RetWithError<size_t>(remainingSize, ErrorEnum::eNone)));
+
+    auto [space2, err2] = mSpaceAllocator.AllocateSpace(1024 * cKilobyte);
+    ASSERT_FALSE(err2.IsNone());
+    ASSERT_EQ(space2.Get(), nullptr);
+    EXPECT_TRUE(removedFiles.empty());
+
+    ASSERT_TRUE(mSpaceAllocator.RestoreOutdatedItem(outdatedFiles[0].name).IsNone());
+    ASSERT_TRUE(mSpaceAllocator.RestoreOutdatedItem(outdatedFiles[4].name).IsNone());
+    ASSERT_TRUE(mSpaceAllocator.RestoreOutdatedItem(outdatedFiles[5].name).IsNone());
+
+    EXPECT_CALL(mPlatformFS, GetDirSize(mPath)).WillOnce(Return(RetWithError<size_t>(remainingSize, ErrorEnum::eNone)));
+
+    auto [space3, err3] = mSpaceAllocator.AllocateSpace(512 * cKilobyte);
+    ASSERT_FALSE(err3.IsNone());
+    ASSERT_EQ(space3.Get(), nullptr);
+
+    ASSERT_TRUE(mSpaceAllocator.Close().IsNone());
+}
+
+TEST_F(SpaceallocatorTest, PartLimit)
+{
+    struct TestFile {
+        String name;
+        size_t size;
+    };
+
+    // Total exists files 224 Kb
+    std::vector<TestFile> existFiles
+        = {{"file1.data", 96 * cKilobyte}, {"file2.data", 32 * cKilobyte}, {"file3.data", 64 * cKilobyte}};
+
+    size_t totalExistSize = 0;
+    for (const auto& file : existFiles) {
+        totalExistSize += file.size;
+    }
+
+    // Add ~5% overhead for filesystem metadata
+    totalExistSize += totalExistSize / 20;
+
+    EXPECT_CALL(mPlatformFS, GetMountPoint(mPath))
+        .WillOnce(Return(RetWithError<StaticString<cFilePathLen>>(mMountPoint, ErrorEnum::eNone)));
+
+    // Total size is 1MB minus filesystem overhead
+    const size_t effectiveTotalSize = 1 * cKilobyte * cKilobyte - (50 * cKilobyte);
+    EXPECT_CALL(mPlatformFS, GetTotalSize(mMountPoint))
+        .WillOnce(Return(RetWithError<size_t>(effectiveTotalSize, ErrorEnum::eNone)));
+
+    SpaceAllocator<2> mSpaceAllocator;
+
+    // Initialize allocator with 50% limit
+    ASSERT_TRUE(mSpaceAllocator.Init(mPath, 50, mRemover, mPlatformFS).IsNone());
+
+    EXPECT_CALL(mPlatformFS, GetDirSize(mPath))
+        .WillOnce(Return(RetWithError<size_t>(totalExistSize, ErrorEnum::eNone)));
+
+    EXPECT_CALL(mPlatformFS, GetAvailableSize(mMountPoint))
+        .WillOnce(Return(RetWithError<size_t>(effectiveTotalSize - totalExistSize, ErrorEnum::eNone)));
+
+    auto [space1, err1] = mSpaceAllocator.AllocateSpace(256 * cKilobyte);
+    ASSERT_TRUE(err1.IsNone());
+    ASSERT_NE(space1.Get(), nullptr);
+
+    auto [space2, err2] = mSpaceAllocator.AllocateSpace(128 * cKilobyte);
+    ASSERT_FALSE(err2.IsNone());
+    ASSERT_EQ(space2.Get(), nullptr);
+
+    mSpaceAllocator.FreeSpace(128 * cKilobyte);
+
+    auto [space3, err3] = mSpaceAllocator.AllocateSpace(128 * cKilobyte);
+    ASSERT_TRUE(err3.IsNone());
+    ASSERT_NE(space3.Get(), nullptr);
+
+    ASSERT_TRUE(space3->Release().IsNone());
+    ASSERT_TRUE(space1->Accept().IsNone());
+
+    ASSERT_TRUE(mSpaceAllocator.Close().IsNone());
+}
+
+} // namespace aos::spaceallocator


Reviews:
user: login: al1img
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-08T15:46:23Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-12T05:39:05Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-12T05:39:12Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-12T05:41:41Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-12T05:41:48Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-12T05:42:01Z
user: login: mlohvynenko
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-12T10:04:11Z
user: login: al1img
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-14T15:01:11Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T06:39:11Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T06:39:19Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:20:41Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:20:59Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:21:20Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:24:05Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:24:11Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:24:18Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:24:25Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:24:36Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:24:42Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:24:52Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:24:58Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:25:20Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:26:14Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T08:56:31Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T09:11:20Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T09:11:40Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T09:11:47Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T09:11:54Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T09:12:00Z
user: login: al1img
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-15T10:29:31Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T10:58:06Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T10:58:11Z
user: login: al1img
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-15T11:22:32Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T11:39:56Z
user: login: mykola-kobets-epam
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T11:47:20Z
user: login: al1img
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-15T14:17:33Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T14:29:12Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T14:29:21Z
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T15:03:30Z
user: login: mlohvynenko
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-15T15:04:22Z

Review comments:
diff_hunk: @@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2024 EPAM Systems, Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef LOG_HPP_
path: include/aos/common/spaceallocator/log.hpp
user: login: al1img
body: We can't use log in headers due to LOG_MODULE overrides. So, unfortunately, log from space allocator should be removed.

In general, it looks like implementation of space allocator should be done in cpp file.
created_at: 2025-02-10T15:39:23Z
author_association: COLLABORATOR
diff_hunk: @@ -24,6 +24,44 @@ namespace aos {
  */
 constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 
+/**
path: include/aos/common/tools/fs.hpp
user: login: al1img
body: We have fs namespace now instead of classes.  Move this interface to `spaceallocator.hpp`
created_at: 2025-05-08T15:39:53Z
author_association: COLLABORATOR
diff_hunk: @@ -24,6 +24,44 @@ namespace aos {
  */
 constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 
+/**
+ * File system interface.
+ */
+class HostFSItf {
+public:
+    /**
+     * Gets mount point for the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<StaticString<cFilePathLen>>.
+     */
+    virtual RetWithError<StaticString<cFilePathLen>> GetMountPoint(const String& dir) const = 0;
+
+    /**
+     * Gets total size of the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetTotalSize(const String& dir) const = 0;
path: include/aos/common/tools/fs.hpp
user: login: al1img
body: What is the difference between `GetTotalSize` and `GetDirSize`?
created_at: 2025-05-08T15:40:48Z
author_association: COLLABORATOR
diff_hunk: @@ -122,8 +147,9 @@ class Space : public SpaceItf {
     /**
      * Crates space instance.
      */
-    explicit Space(size_t size)
+    explicit Space(size_t size, SpaceAllocatorItf* allocator)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: explicit can be removed
created_at: 2025-05-08T15:42:05Z
author_association: COLLABORATOR
diff_hunk: @@ -171,6 +438,105 @@ class Space : public SpaceItf {
 template <size_t cNumAllocations>
 class SpaceAllocator : public SpaceAllocatorItf {
 public:
+    /**
+     * Constructor.
+     */
+    SpaceAllocator() = default;
+    /**
+     * Destructor.
+     */
+    ~SpaceAllocator()
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        mPartitions.Clear();
+    }
+
+    /**
+     * Initializes space allocator.
+     *
+     * @param path path to allocate space.
+     * @param limit limit in percents.
+     * @param remover item remover.
+     * @param hostFS host file system.
+     * @return Error.
+     */
+    Error Init(const String& path, u_int limit, ItemRemoverItf& remover, HostFSItf& hostFS)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: Let's add cpp file for space allocator.
created_at: 2025-05-08T15:46:12Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2024 EPAM Systems, Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef LOG_HPP_
path: include/aos/common/spaceallocator/log.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-12T05:39:05Z
author_association: NONE
diff_hunk: @@ -24,6 +24,44 @@ namespace aos {
  */
 constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 
+/**
path: include/aos/common/tools/fs.hpp
user: login: MykolaSuperman
body: moved
created_at: 2025-05-12T05:39:11Z
author_association: NONE
diff_hunk: @@ -24,6 +24,44 @@ namespace aos {
  */
 constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 
+/**
+ * File system interface.
+ */
+class HostFSItf {
+public:
+    /**
+     * Gets mount point for the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<StaticString<cFilePathLen>>.
+     */
+    virtual RetWithError<StaticString<cFilePathLen>> GetMountPoint(const String& dir) const = 0;
+
+    /**
+     * Gets total size of the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetTotalSize(const String& dir) const = 0;
path: include/aos/common/tools/fs.hpp
user: login: MykolaSuperman
body: `GetTotalSize` – Returns the total size of the file system (disk).
`GetDirSize``  – Returns the amount of space used by a directory.
created_at: 2025-05-12T05:41:40Z
author_association: NONE
diff_hunk: @@ -122,8 +147,9 @@ class Space : public SpaceItf {
     /**
      * Crates space instance.
      */
-    explicit Space(size_t size)
+    explicit Space(size_t size, SpaceAllocatorItf* allocator)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-12T05:41:48Z
author_association: NONE
diff_hunk: @@ -171,6 +438,105 @@ class Space : public SpaceItf {
 template <size_t cNumAllocations>
 class SpaceAllocator : public SpaceAllocatorItf {
 public:
+    /**
+     * Constructor.
+     */
+    SpaceAllocator() = default;
+    /**
+     * Destructor.
+     */
+    ~SpaceAllocator()
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        mPartitions.Clear();
+    }
+
+    /**
+     * Initializes space allocator.
+     *
+     * @param path path to allocate space.
+     * @param limit limit in percents.
+     * @param remover item remover.
+     * @param hostFS host file system.
+     * @return Error.
+     */
+    Error Init(const String& path, u_int limit, ItemRemoverItf& remover, HostFSItf& hostFS)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: decide to left in header file
created_at: 2025-05-12T05:42:00Z
author_association: NONE
diff_hunk: @@ -0,0 +1,29 @@
+#
+# Copyright (C) 2023 Renesas Electronics Corporation.
path: tests/spaceallocator/CMakeLists.txt
user: login: mlohvynenko
body: Fix copyright: date and remove renesas
created_at: 2025-05-12T10:03:42Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2023 EPAM Systems, Inc.
path: tests/spaceallocator/spaceallocator_test.cpp
user: login: mlohvynenko
body: Fix date
created_at: 2025-05-12T10:03:54Z
author_association: MEMBER
diff_hunk: @@ -519,6 +519,13 @@
 #define AOS_CONFIG_TYPES_FUNC_SERVICE_MAX_COUNT 16
 #endif
 
+/**
+ * Max number of outdated items.
+ */
+#ifndef AOS_CONFIG_TYPES_MAX_OUTDATED_ITEMS
+#define AOS_CONFIG_TYPES_MAX_OUTDATED_ITEMS 40
path: include/aos/common/config.hpp
user: login: al1img
body: Better to use power of 2: 64 is good digit.
created_at: 2025-05-14T07:27:02Z
author_association: COLLABORATOR
diff_hunk: @@ -108,10 +114,26 @@ class SpaceAllocatorItf {
      */
     virtual Error RestoreOutdatedItem(const String& id) = 0;
 
+    /**
+     * Allocates done.
+     *
+     * @return Error.
+     */
+    virtual Error AllocateDone() = 0;
+
     /**
      * Destructor.
      */
     virtual ~SpaceAllocatorItf() = default;
+
+protected:
+    static inline StaticMap<String, SharedPtr<Partition>, cMaxNumPartitions> mPartitions;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: All protected, private staff should in allocator implementation, not interface.

`sPartitions` for static memebers
`sParitionsMutex`


created_at: 2025-05-14T13:37:25Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: Error should  be returned
created_at: 2025-05-14T13:47:56Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: If we have no space to push new outdated item, we should remove oldest outdated item and free resource.
created_at: 2025-05-14T13:48:02Z
author_association: COLLABORATOR
diff_hunk: @@ -108,10 +114,26 @@ class SpaceAllocatorItf {
      */
     virtual Error RestoreOutdatedItem(const String& id) = 0;
 
+    /**
+     * Allocates done.
+     *
+     * @return Error.
+     */
+    virtual Error AllocateDone() = 0;
+
     /**
      * Destructor.
      */
     virtual ~SpaceAllocatorItf() = default;
+
+protected:
+    static inline StaticMap<String, SharedPtr<Partition>, cMaxNumPartitions> mPartitions;
+    static inline Mutex                                                      mPartitionsMutex;
+
+private:
+    friend class Partition;
+
+    virtual void Free(u_int64_t size) = 0;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t for size
created_at: 2025-05-14T14:11:03Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr u_int64_t cMaxLimit = 100;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t. and it should be private for `Partition`
created_at: 2025-05-14T14:12:48Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr u_int64_t cMaxLimit = 100;
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    u_int64_t                                       mLimit {};
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t for all of these items
created_at: 2025-05-14T14:13:03Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr u_int64_t cMaxLimit = 100;
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    u_int64_t                                       mLimit {};
+    u_int64_t                                       mTotalSize {};
+    u_int32_t                                       mAllocatorCount {};
+    fs::FSPlatformItf*                              mPlatformFS {};
+    StaticArray<OutdatedItem, cMaxNumOutdatedItems> mOutdatedItems;
+
+private:
+    RetWithError<u_int64_t> RemoveOutdatedItems(uint64_t size)
+    {
+        u_int64_t totalSize = 0;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t
created_at: 2025-05-14T14:14:31Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr u_int64_t cMaxLimit = 100;
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    u_int64_t                                       mLimit {};
+    u_int64_t                                       mTotalSize {};
+    u_int32_t                                       mAllocatorCount {};
+    fs::FSPlatformItf*                              mPlatformFS {};
+    StaticArray<OutdatedItem, cMaxNumOutdatedItems> mOutdatedItems;
+
+private:
+    RetWithError<u_int64_t> RemoveOutdatedItems(uint64_t size)
+    {
+        u_int64_t totalSize = 0;
+
+        for (const auto& item : mOutdatedItems) {
+            totalSize += item.mSize;
+        }
+
+        if (size > totalSize) {
+            return {0, Error(ErrorEnum::eNoMemory, "partition limit exceeded")};
+        }
+
+        mOutdatedItems.Sort([](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+        u_int64_t freedSize = 0;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t
created_at: 2025-05-14T14:14:36Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr u_int64_t cMaxLimit = 100;
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    u_int64_t                                       mLimit {};
+    u_int64_t                                       mTotalSize {};
+    u_int32_t                                       mAllocatorCount {};
+    fs::FSPlatformItf*                              mPlatformFS {};
+    StaticArray<OutdatedItem, cMaxNumOutdatedItems> mOutdatedItems;
+
+private:
+    RetWithError<u_int64_t> RemoveOutdatedItems(uint64_t size)
+    {
+        u_int64_t totalSize = 0;
+
+        for (const auto& item : mOutdatedItems) {
+            totalSize += item.mSize;
+        }
+
+        if (size > totalSize) {
+            return {0, Error(ErrorEnum::eNoMemory, "partition limit exceeded")};
+        }
+
+        mOutdatedItems.Sort([](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+        u_int64_t freedSize = 0;
+        size_t    i         = 0;
+
+        for (; freedSize < size; i++) {
+            const auto& item = mOutdatedItems[i];
+
+            if (auto err = item.mRemover->RemoveItem(item.mID); !err.IsNone()) {
+                return {freedSize, err};
+            }
+
+            item.mAllocator->Free(item.mSize);
+
+            freedSize += item.mSize;
+        }
+
+        mOutdatedItems.Erase(mOutdatedItems.begin(), mOutdatedItems.begin() + i);
+
+        return {freedSize, ErrorEnum::eNone};
+    }
+
+    u_int32_t mAllocationCount {};
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t for both vars
created_at: 2025-05-14T14:15:07Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: Looks like this field is not necessary
created_at: 2025-05-14T14:15:50Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t
created_at: 2025-05-14T14:16:00Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t
created_at: 2025-05-14T14:16:08Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t
created_at: 2025-05-14T14:16:17Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t
created_at: 2025-05-14T14:16:27Z
author_association: COLLABORATOR
diff_hunk: @@ -171,6 +417,99 @@ class Space : public SpaceItf {
 template <size_t cNumAllocations>
 class SpaceAllocator : public SpaceAllocatorItf {
 public:
+    /**
+     * Constructor.
+     */
+    SpaceAllocator() = default;
+    /**
+     * Destructor.
+     */
+    ~SpaceAllocator()
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        mPartitions.Clear();
+    }
+
+    /**
+     * Initializes space allocator.
+     *
+     * @param path path to allocate space.
+     * @param limit limit in percents.
+     * @param remover item remover.
+     * @param platformFS platform file system.
+     * @return Error.
+     */
+    Error Init(const String& path, u_int limit, ItemRemoverItf& remover, fs::FSPlatformItf& platformFS)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t
created_at: 2025-05-14T14:17:01Z
author_association: COLLABORATOR
diff_hunk: @@ -215,13 +584,154 @@ class SpaceAllocator : public SpaceAllocatorItf {
      */
     Error RestoreOutdatedItem(const String& id) override
     {
-        (void)id;
+        mPartition->RestoreOutdatedItem(id);
 
         return ErrorEnum::eNone;
     }
 
 private:
-    StaticAllocator<sizeof(Space) * cNumAllocations> mAllocator;
+    RetWithError<SharedPtr<Partition>> NewPartition(const String& path)
+    {
+        auto [totalSize, err] = mPlatformFS->GetTotalSize(path);
+        if (!err.IsNone()) {
+            return {nullptr, err};
+        }
+
+        SharedPtr<Partition> partition = MakeShared<Partition>(&mPartitionAllocator);
+
+        partition->mMountPoint = path;
+        partition->mTotalSize  = totalSize;
+        partition->mPlatformFS = mPlatformFS;
+
+        return {partition, ErrorEnum::eNone};
+    }
+
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mSizeLimit == 0) {
+            return ErrorEnum::eNone;
+        }
+
+        if (mAllocationCount == 0) {
+            auto [allocatedSize, err] = mPlatformFS->GetDirSize(mPath);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAllocatedSize = allocatedSize;
+        }
+
+        if (mSizeLimit > 0 && mAllocatedSize + size > mSizeLimit) {
+            auto [freedSize, err] = RemoveOutdatedItems(mAllocatedSize + size - mSizeLimit);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            if (freedSize > mAllocatedSize) {
+                mAllocatedSize = 0;
+            } else {
+                mAllocatedSize -= freedSize;
+            }
+        }
+
+        mAllocatedSize += size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    RetWithError<u_int64_t> RemoveOutdatedItems(uint64_t size)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t
created_at: 2025-05-14T14:20:06Z
author_association: COLLABORATOR
diff_hunk: @@ -215,13 +584,154 @@ class SpaceAllocator : public SpaceAllocatorItf {
      */
     Error RestoreOutdatedItem(const String& id) override
     {
-        (void)id;
+        mPartition->RestoreOutdatedItem(id);
 
         return ErrorEnum::eNone;
     }
 
 private:
-    StaticAllocator<sizeof(Space) * cNumAllocations> mAllocator;
+    RetWithError<SharedPtr<Partition>> NewPartition(const String& path)
+    {
+        auto [totalSize, err] = mPlatformFS->GetTotalSize(path);
+        if (!err.IsNone()) {
+            return {nullptr, err};
+        }
+
+        SharedPtr<Partition> partition = MakeShared<Partition>(&mPartitionAllocator);
+
+        partition->mMountPoint = path;
+        partition->mTotalSize  = totalSize;
+        partition->mPlatformFS = mPlatformFS;
+
+        return {partition, ErrorEnum::eNone};
+    }
+
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mSizeLimit == 0) {
+            return ErrorEnum::eNone;
+        }
+
+        if (mAllocationCount == 0) {
+            auto [allocatedSize, err] = mPlatformFS->GetDirSize(mPath);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAllocatedSize = allocatedSize;
+        }
+
+        if (mSizeLimit > 0 && mAllocatedSize + size > mSizeLimit) {
+            auto [freedSize, err] = RemoveOutdatedItems(mAllocatedSize + size - mSizeLimit);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            if (freedSize > mAllocatedSize) {
+                mAllocatedSize = 0;
+            } else {
+                mAllocatedSize -= freedSize;
+            }
+        }
+
+        mAllocatedSize += size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    RetWithError<u_int64_t> RemoveOutdatedItems(uint64_t size)
+    {
+        u_int64_t totalSize = 0;
+
+        for (const auto& item : mPartition->mOutdatedItems) {
+            if (item.mAllocator != this) {
+                continue;
+            }
+
+            totalSize += item.mSize;
+        }
+
+        if (size > totalSize) {
+            return {0, Error(ErrorEnum::eNoMemory, "partition limit exceeded")};
+        }
+
+        mPartition->mOutdatedItems.Sort(
+            [](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+        u_int64_t freedSize = 0;
+        size_t    i         = 0;
+
+        for (auto& item : mPartition->mOutdatedItems) {
+            if (item.mAllocator != this || freedSize >= size) {
+                mPartition->mOutdatedItems[i] = item;
+                i++;
+
+                continue;
+            }
+
+            if (auto err = item.mRemover->RemoveItem(item.mID); !err.IsNone()) {
+                return {freedSize, err};
+            }
+
+            item.mPartition->Free(item.mSize);
+
+            freedSize += item.mSize;
+        }
+
+        mPartition->mOutdatedItems.Erase(mPartition->mOutdatedItems.begin() + i, mPartition->mOutdatedItems.end());
+
+        return {freedSize, ErrorEnum::eNone};
+    }
+
+    void Free(u_int64_t size) override
+    {
+        LockGuard lock {mMutex};
+
+        if (mSizeLimit == 0) {
+            return;
+        }
+
+        if (mAllocationCount > 0) {
+            if (size < mAllocatedSize) {
+                mAllocatedSize -= size;
+            } else {
+                mAllocatedSize = 0;
+            }
+        }
+    }
+
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mSizeLimit == 0) {
+            return ErrorEnum::eNone;
+        }
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    friend class Partition;
+
+    StaticAllocator<sizeof(Space) * cNumAllocations>       mAllocator;
+    StaticAllocator<sizeof(Partition) * cMaxNumPartitions> mPartitionAllocator;
+    u_int64_t                                              mSizeLimit {};
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: size_t
created_at: 2025-05-14T14:21:01Z
author_association: COLLABORATOR
diff_hunk: @@ -24,6 +24,44 @@ namespace aos {
  */
 constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 
+/**
+ * File system interface.
+ */
+class HostFSItf {
+public:
+    /**
+     * Gets mount point for the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<StaticString<cFilePathLen>>.
+     */
+    virtual RetWithError<StaticString<cFilePathLen>> GetMountPoint(const String& dir) const = 0;
+
+    /**
+     * Gets total size of the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetTotalSize(const String& dir) const = 0;
path: include/aos/common/tools/fs.hpp
user: login: al1img
body: size_t for all sizes
created_at: 2025-05-14T14:21:18Z
author_association: COLLABORATOR
diff_hunk: @@ -27,6 +27,49 @@ constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 constexpr auto cDirIteratorMaxSize = AOS_CONFIG_FS_DIR_ITERATOR_MAX_COUNT;
 
 namespace fs {
+/**
+ * File system platform interface.
+ */
+class FSPlatformItf {
+public:
+    /**
+     * Destructor.
+     */
+    virtual ~FSPlatformItf() = default;
+
+    /**
+     * Gets mount point for the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<StaticString<cFilePathLen>>.
+     */
+    virtual RetWithError<StaticString<cFilePathLen>> GetMountPoint(const String& dir) const = 0;
+
+    /**
+     * Gets total size of the file system.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetTotalSize(const String& dir) const = 0;
+
+    /**
+     * Gets directory size.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetDirSize(const String& dir) const = 0;
path: include/aos/common/tools/fs.hpp
user: login: al1img
body: ditto
created_at: 2025-05-14T14:21:27Z
author_association: COLLABORATOR
diff_hunk: @@ -27,6 +27,49 @@ constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 constexpr auto cDirIteratorMaxSize = AOS_CONFIG_FS_DIR_ITERATOR_MAX_COUNT;
 
 namespace fs {
+/**
+ * File system platform interface.
+ */
+class FSPlatformItf {
+public:
+    /**
+     * Destructor.
+     */
+    virtual ~FSPlatformItf() = default;
+
+    /**
+     * Gets mount point for the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<StaticString<cFilePathLen>>.
+     */
+    virtual RetWithError<StaticString<cFilePathLen>> GetMountPoint(const String& dir) const = 0;
+
+    /**
+     * Gets total size of the file system.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetTotalSize(const String& dir) const = 0;
+
+    /**
+     * Gets directory size.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetDirSize(const String& dir) const = 0;
+
+    /**
+     * Gets available size.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetAvailableSize(const String& dir) const = 0;
path: include/aos/common/tools/fs.hpp
user: login: al1img
body: ditto
created_at: 2025-05-14T14:21:31Z
author_association: COLLABORATOR
diff_hunk: @@ -171,6 +417,99 @@ class Space : public SpaceItf {
 template <size_t cNumAllocations>
 class SpaceAllocator : public SpaceAllocatorItf {
 public:
+    /**
+     * Constructor.
+     */
+    SpaceAllocator() = default;
+    /**
+     * Destructor.
+     */
+    ~SpaceAllocator()
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        mPartitions.Clear();
+    }
+
+    /**
+     * Initializes space allocator.
+     *
+     * @param path path to allocate space.
+     * @param limit limit in percents.
+     * @param remover item remover.
+     * @param platformFS platform file system.
+     * @return Error.
+     */
+    Error Init(const String& path, u_int limit, ItemRemoverItf& remover, fs::FSPlatformItf& platformFS)
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        mRemover    = &remover;
+        mPlatformFS = &platformFS;
+        mPath       = path;
+
+        auto [mountPoint, errMountPoint] = mPlatformFS->GetMountPoint(path);
+        if (!errMountPoint.IsNone()) {
+            return errMountPoint;
+        }
+
+        Error err;
+
+        auto partitionIt = mPartitions.Find(mountPoint);
+        if (partitionIt == mPartitions.end()) {
+            if (Tie(mPartition, err) = NewPartition(mountPoint); !err.IsNone()) {
+                return err;
+            }
+
+            if (err = mPartitions.TryEmplace(mountPoint, mPartition); !err.IsNone()) {
+                return err;
+            }
+        } else {
+            mPartition = partitionIt->mSecond;
+        }
+
+        mPartition->mAllocatorCount++;
+
+        if (limit != 0) {
+            if (err = mPartition->AddLimit(limit); !err.IsNone()) {
+                return err;
+            }
+
+            mSizeLimit = mPartition->mTotalSize * mPartition->mLimit / 100;
+        }
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Closes space allocator.
+     *
+     * @return Error.
+     */
+    Error Close()
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        Error err;
+
+        if (auto errRemovePartLimit = mPartition->RemoveLimit(mPartition->mLimit); !errRemovePartLimit.IsNone()) {
+            err = errRemovePartLimit;
+        }
+
+        mPartition->mAllocatorCount--;
+
+        if (mPartition->mAllocatorCount != 0) {
+            return err;
+        }
+
+        if (auto errRemovePart = mPartitions.Remove(mPartition->mMountPoint);
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: We should have something like this:

```c++
static inline StaticMap<String, Partition, cMaxNumPartitions> mPartitions;
```

And no need to remove partition from map
created_at: 2025-05-14T15:01:07Z
author_association: COLLABORATOR
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: needed, because it called from spaceallocator class when remove outdated item
created_at: 2025-05-15T06:39:11Z
author_association: NONE
diff_hunk: @@ -108,10 +114,26 @@ class SpaceAllocatorItf {
      */
     virtual Error RestoreOutdatedItem(const String& id) = 0;
 
+    /**
+     * Allocates done.
+     *
+     * @return Error.
+     */
+    virtual Error AllocateDone() = 0;
+
     /**
      * Destructor.
      */
     virtual ~SpaceAllocatorItf() = default;
+
+protected:
+    static inline StaticMap<String, SharedPtr<Partition>, cMaxNumPartitions> mPartitions;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T06:39:19Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T07:20:41Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T07:20:59Z
author_association: NONE
diff_hunk: @@ -108,10 +114,26 @@ class SpaceAllocatorItf {
      */
     virtual Error RestoreOutdatedItem(const String& id) = 0;
 
+    /**
+     * Allocates done.
+     *
+     * @return Error.
+     */
+    virtual Error AllocateDone() = 0;
+
     /**
      * Destructor.
      */
     virtual ~SpaceAllocatorItf() = default;
+
+protected:
+    static inline StaticMap<String, SharedPtr<Partition>, cMaxNumPartitions> mPartitions;
+    static inline Mutex                                                      mPartitionsMutex;
+
+private:
+    friend class Partition;
+
+    virtual void Free(u_int64_t size) = 0;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: not relevant
created_at: 2025-05-15T07:21:20Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T07:24:04Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T07:24:11Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T07:24:18Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: done
created_at: 2025-05-15T07:24:24Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr u_int64_t cMaxLimit = 100;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: done
created_at: 2025-05-15T07:24:36Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr u_int64_t cMaxLimit = 100;
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    u_int64_t                                       mLimit {};
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T07:24:42Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr u_int64_t cMaxLimit = 100;
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    u_int64_t                                       mLimit {};
+    u_int64_t                                       mTotalSize {};
+    u_int32_t                                       mAllocatorCount {};
+    fs::FSPlatformItf*                              mPlatformFS {};
+    StaticArray<OutdatedItem, cMaxNumOutdatedItems> mOutdatedItems;
+
+private:
+    RetWithError<u_int64_t> RemoveOutdatedItems(uint64_t size)
+    {
+        u_int64_t totalSize = 0;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T07:24:52Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr u_int64_t cMaxLimit = 100;
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    u_int64_t                                       mLimit {};
+    u_int64_t                                       mTotalSize {};
+    u_int32_t                                       mAllocatorCount {};
+    fs::FSPlatformItf*                              mPlatformFS {};
+    StaticArray<OutdatedItem, cMaxNumOutdatedItems> mOutdatedItems;
+
+private:
+    RetWithError<u_int64_t> RemoveOutdatedItems(uint64_t size)
+    {
+        u_int64_t totalSize = 0;
+
+        for (const auto& item : mOutdatedItems) {
+            totalSize += item.mSize;
+        }
+
+        if (size > totalSize) {
+            return {0, Error(ErrorEnum::eNoMemory, "partition limit exceeded")};
+        }
+
+        mOutdatedItems.Sort([](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+        u_int64_t freedSize = 0;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T07:24:58Z
author_association: NONE
diff_hunk: @@ -162,7 +190,225 @@ class Space : public SpaceItf {
     uint64_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    uint64_t                                                                                                   mSize;
+    SpaceAllocatorItf*   mAllocator {};
+    SharedPtr<Partition> mPartition {};
+    ItemRemoverItf*      mRemover {};
+    Time                 mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(u_int64_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return void.
+     */
+    void AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return;
+            }
+        }
+
+        mOutdatedItems.PushBack(item);
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    static constexpr u_int64_t cMaxLimit = 100;
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    u_int64_t                                       mLimit {};
+    u_int64_t                                       mTotalSize {};
+    u_int32_t                                       mAllocatorCount {};
+    fs::FSPlatformItf*                              mPlatformFS {};
+    StaticArray<OutdatedItem, cMaxNumOutdatedItems> mOutdatedItems;
+
+private:
+    RetWithError<u_int64_t> RemoveOutdatedItems(uint64_t size)
+    {
+        u_int64_t totalSize = 0;
+
+        for (const auto& item : mOutdatedItems) {
+            totalSize += item.mSize;
+        }
+
+        if (size > totalSize) {
+            return {0, Error(ErrorEnum::eNoMemory, "partition limit exceeded")};
+        }
+
+        mOutdatedItems.Sort([](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+        u_int64_t freedSize = 0;
+        size_t    i         = 0;
+
+        for (; freedSize < size; i++) {
+            const auto& item = mOutdatedItems[i];
+
+            if (auto err = item.mRemover->RemoveItem(item.mID); !err.IsNone()) {
+                return {freedSize, err};
+            }
+
+            item.mAllocator->Free(item.mSize);
+
+            freedSize += item.mSize;
+        }
+
+        mOutdatedItems.Erase(mOutdatedItems.begin(), mOutdatedItems.begin() + i);
+
+        return {freedSize, ErrorEnum::eNone};
+    }
+
+    u_int32_t mAllocationCount {};
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T07:25:20Z
author_association: NONE
diff_hunk: @@ -171,6 +417,99 @@ class Space : public SpaceItf {
 template <size_t cNumAllocations>
 class SpaceAllocator : public SpaceAllocatorItf {
 public:
+    /**
+     * Constructor.
+     */
+    SpaceAllocator() = default;
+    /**
+     * Destructor.
+     */
+    ~SpaceAllocator()
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        mPartitions.Clear();
+    }
+
+    /**
+     * Initializes space allocator.
+     *
+     * @param path path to allocate space.
+     * @param limit limit in percents.
+     * @param remover item remover.
+     * @param platformFS platform file system.
+     * @return Error.
+     */
+    Error Init(const String& path, u_int limit, ItemRemoverItf& remover, fs::FSPlatformItf& platformFS)
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T07:26:14Z
author_association: NONE
diff_hunk: @@ -171,6 +417,99 @@ class Space : public SpaceItf {
 template <size_t cNumAllocations>
 class SpaceAllocator : public SpaceAllocatorItf {
 public:
+    /**
+     * Constructor.
+     */
+    SpaceAllocator() = default;
+    /**
+     * Destructor.
+     */
+    ~SpaceAllocator()
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        mPartitions.Clear();
+    }
+
+    /**
+     * Initializes space allocator.
+     *
+     * @param path path to allocate space.
+     * @param limit limit in percents.
+     * @param remover item remover.
+     * @param platformFS platform file system.
+     * @return Error.
+     */
+    Error Init(const String& path, u_int limit, ItemRemoverItf& remover, fs::FSPlatformItf& platformFS)
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        mRemover    = &remover;
+        mPlatformFS = &platformFS;
+        mPath       = path;
+
+        auto [mountPoint, errMountPoint] = mPlatformFS->GetMountPoint(path);
+        if (!errMountPoint.IsNone()) {
+            return errMountPoint;
+        }
+
+        Error err;
+
+        auto partitionIt = mPartitions.Find(mountPoint);
+        if (partitionIt == mPartitions.end()) {
+            if (Tie(mPartition, err) = NewPartition(mountPoint); !err.IsNone()) {
+                return err;
+            }
+
+            if (err = mPartitions.TryEmplace(mountPoint, mPartition); !err.IsNone()) {
+                return err;
+            }
+        } else {
+            mPartition = partitionIt->mSecond;
+        }
+
+        mPartition->mAllocatorCount++;
+
+        if (limit != 0) {
+            if (err = mPartition->AddLimit(limit); !err.IsNone()) {
+                return err;
+            }
+
+            mSizeLimit = mPartition->mTotalSize * mPartition->mLimit / 100;
+        }
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Closes space allocator.
+     *
+     * @return Error.
+     */
+    Error Close()
+    {
+        LockGuard lock {mPartitionsMutex};
+
+        Error err;
+
+        if (auto errRemovePartLimit = mPartition->RemoveLimit(mPartition->mLimit); !errRemovePartLimit.IsNone()) {
+            err = errRemovePartLimit;
+        }
+
+        mPartition->mAllocatorCount--;
+
+        if (mPartition->mAllocatorCount != 0) {
+            return err;
+        }
+
+        if (auto errRemovePart = mPartitions.Remove(mPartition->mMountPoint);
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: We have this map, i removed shared_ptr for `Partition.`
Also we need to remove item from map when counter of allocation if equal 0  

created_at: 2025-05-15T08:56:31Z
author_association: NONE
diff_hunk: @@ -215,13 +584,154 @@ class SpaceAllocator : public SpaceAllocatorItf {
      */
     Error RestoreOutdatedItem(const String& id) override
     {
-        (void)id;
+        mPartition->RestoreOutdatedItem(id);
 
         return ErrorEnum::eNone;
     }
 
 private:
-    StaticAllocator<sizeof(Space) * cNumAllocations> mAllocator;
+    RetWithError<SharedPtr<Partition>> NewPartition(const String& path)
+    {
+        auto [totalSize, err] = mPlatformFS->GetTotalSize(path);
+        if (!err.IsNone()) {
+            return {nullptr, err};
+        }
+
+        SharedPtr<Partition> partition = MakeShared<Partition>(&mPartitionAllocator);
+
+        partition->mMountPoint = path;
+        partition->mTotalSize  = totalSize;
+        partition->mPlatformFS = mPlatformFS;
+
+        return {partition, ErrorEnum::eNone};
+    }
+
+    Error Allocate(u_int64_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mSizeLimit == 0) {
+            return ErrorEnum::eNone;
+        }
+
+        if (mAllocationCount == 0) {
+            auto [allocatedSize, err] = mPlatformFS->GetDirSize(mPath);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAllocatedSize = allocatedSize;
+        }
+
+        if (mSizeLimit > 0 && mAllocatedSize + size > mSizeLimit) {
+            auto [freedSize, err] = RemoveOutdatedItems(mAllocatedSize + size - mSizeLimit);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            if (freedSize > mAllocatedSize) {
+                mAllocatedSize = 0;
+            } else {
+                mAllocatedSize -= freedSize;
+            }
+        }
+
+        mAllocatedSize += size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    RetWithError<u_int64_t> RemoveOutdatedItems(uint64_t size)
+    {
+        u_int64_t totalSize = 0;
+
+        for (const auto& item : mPartition->mOutdatedItems) {
+            if (item.mAllocator != this) {
+                continue;
+            }
+
+            totalSize += item.mSize;
+        }
+
+        if (size > totalSize) {
+            return {0, Error(ErrorEnum::eNoMemory, "partition limit exceeded")};
+        }
+
+        mPartition->mOutdatedItems.Sort(
+            [](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+        u_int64_t freedSize = 0;
+        size_t    i         = 0;
+
+        for (auto& item : mPartition->mOutdatedItems) {
+            if (item.mAllocator != this || freedSize >= size) {
+                mPartition->mOutdatedItems[i] = item;
+                i++;
+
+                continue;
+            }
+
+            if (auto err = item.mRemover->RemoveItem(item.mID); !err.IsNone()) {
+                return {freedSize, err};
+            }
+
+            item.mPartition->Free(item.mSize);
+
+            freedSize += item.mSize;
+        }
+
+        mPartition->mOutdatedItems.Erase(mPartition->mOutdatedItems.begin() + i, mPartition->mOutdatedItems.end());
+
+        return {freedSize, ErrorEnum::eNone};
+    }
+
+    void Free(u_int64_t size) override
+    {
+        LockGuard lock {mMutex};
+
+        if (mSizeLimit == 0) {
+            return;
+        }
+
+        if (mAllocationCount > 0) {
+            if (size < mAllocatedSize) {
+                mAllocatedSize -= size;
+            } else {
+                mAllocatedSize = 0;
+            }
+        }
+    }
+
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mSizeLimit == 0) {
+            return ErrorEnum::eNone;
+        }
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    friend class Partition;
+
+    StaticAllocator<sizeof(Space) * cNumAllocations>       mAllocator;
+    StaticAllocator<sizeof(Partition) * cMaxNumPartitions> mPartitionAllocator;
+    u_int64_t                                              mSizeLimit {};
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T09:11:20Z
author_association: NONE
diff_hunk: @@ -24,6 +24,44 @@ namespace aos {
  */
 constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 
+/**
+ * File system interface.
+ */
+class HostFSItf {
+public:
+    /**
+     * Gets mount point for the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<StaticString<cFilePathLen>>.
+     */
+    virtual RetWithError<StaticString<cFilePathLen>> GetMountPoint(const String& dir) const = 0;
+
+    /**
+     * Gets total size of the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetTotalSize(const String& dir) const = 0;
path: include/aos/common/tools/fs.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T09:11:39Z
author_association: NONE
diff_hunk: @@ -24,6 +24,44 @@ namespace aos {
  */
 constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 
+/**
+ * File system interface.
+ */
+class HostFSItf {
+public:
+    /**
+     * Gets mount point for the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<StaticString<cFilePathLen>>.
+     */
+    virtual RetWithError<StaticString<cFilePathLen>> GetMountPoint(const String& dir) const = 0;
+
+    /**
+     * Gets total size of the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetTotalSize(const String& dir) const = 0;
path: include/aos/common/tools/fs.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T09:11:47Z
author_association: NONE
diff_hunk: @@ -27,6 +27,49 @@ constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 constexpr auto cDirIteratorMaxSize = AOS_CONFIG_FS_DIR_ITERATOR_MAX_COUNT;
 
 namespace fs {
+/**
+ * File system platform interface.
+ */
+class FSPlatformItf {
+public:
+    /**
+     * Destructor.
+     */
+    virtual ~FSPlatformItf() = default;
+
+    /**
+     * Gets mount point for the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<StaticString<cFilePathLen>>.
+     */
+    virtual RetWithError<StaticString<cFilePathLen>> GetMountPoint(const String& dir) const = 0;
+
+    /**
+     * Gets total size of the file system.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetTotalSize(const String& dir) const = 0;
+
+    /**
+     * Gets directory size.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetDirSize(const String& dir) const = 0;
path: include/aos/common/tools/fs.hpp
user: login: MykolaSuperman
body: done
created_at: 2025-05-15T09:11:54Z
author_association: NONE
diff_hunk: @@ -27,6 +27,49 @@ constexpr auto cFilePathLen = AOS_CONFIG_FS_FILE_PATH_LEN;
 constexpr auto cDirIteratorMaxSize = AOS_CONFIG_FS_DIR_ITERATOR_MAX_COUNT;
 
 namespace fs {
+/**
+ * File system platform interface.
+ */
+class FSPlatformItf {
+public:
+    /**
+     * Destructor.
+     */
+    virtual ~FSPlatformItf() = default;
+
+    /**
+     * Gets mount point for the given directory.
+     *
+     * @param dir directory path.
+     * @return RetWithError<StaticString<cFilePathLen>>.
+     */
+    virtual RetWithError<StaticString<cFilePathLen>> GetMountPoint(const String& dir) const = 0;
+
+    /**
+     * Gets total size of the file system.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetTotalSize(const String& dir) const = 0;
+
+    /**
+     * Gets directory size.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetDirSize(const String& dir) const = 0;
+
+    /**
+     * Gets available size.
+     *
+     * @param dir directory path.
+     * @return RetWithError<int64_t>.
+     */
+    virtual RetWithError<int64_t> GetAvailableSize(const String& dir) const = 0;
path: include/aos/common/tools/fs.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T09:12:00Z
author_association: NONE
diff_hunk: @@ -157,29 +175,362 @@ class Space : public SpaceItf {
     /**
      * Returns space size.
      *
-     * @return uint64_t.
+     * @return size_t.
      */
-    uint64_t Size() const override { return mSize; }
+    size_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+struct Partition;
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    size_t                                                                                                     mSize;
+    SpaceAllocatorItf*                      mAllocator {};
+    StaticFunction<cDefaultFunctionMaxSize> mFreeCallback;
+    Partition*                              mPartition {};
+    ItemRemoverItf*                         mRemover {};
+    Time                                    mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return Error.
+     */
+    Error AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return ErrorEnum::eNone;
+            }
+        }
+
+        Error err = mOutdatedItems.PushBack(item);
+        if (!err.IsNone()) {
+            mOutdatedItems.Sort(
+                [](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+            mOutdatedItems[0] = item;
+
+            return ErrorEnum::eNone;
+        }
+
+        return err;
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    size_t                                          mLimit {};
+    size_t                                          mTotalSize {};
+    size_t                                          mAllocatorCount {};
+    fs::FSPlatformItf*                              mPlatformFS {};
+    StaticArray<OutdatedItem, cMaxNumOutdatedItems> mOutdatedItems;
+
+private:
+    static constexpr size_t cMaxLimit = 100;
+
+    RetWithError<size_t> RemoveOutdatedItems(size_t size)
+    {
+        size_t totalSize = 0;
+
+        for (const auto& item : mOutdatedItems) {
+            totalSize += item.mSize;
+        }
+
+        if (size > totalSize) {
+            return {0, Error(ErrorEnum::eNoMemory, "partition limit exceeded")};
+        }
+
+        mOutdatedItems.Sort([](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+        size_t freedSize = 0;
+        size_t i         = 0;
+
+        for (; freedSize < size; i++) {
+            auto& item = mOutdatedItems[i];
+
+            if (auto err = item.mRemover->RemoveItem(item.mID); !err.IsNone()) {
+                return {freedSize, err};
+            }
+
+            // item.mAllocator->Free(item.mSize);
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: Is this comment relevant?
created_at: 2025-05-15T10:26:14Z
author_association: COLLABORATOR
diff_hunk: @@ -157,29 +175,362 @@ class Space : public SpaceItf {
     /**
      * Returns space size.
      *
-     * @return uint64_t.
+     * @return size_t.
      */
-    uint64_t Size() const override { return mSize; }
+    size_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+struct Partition;
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    size_t                                                                                                     mSize;
+    SpaceAllocatorItf*                      mAllocator {};
+    StaticFunction<cDefaultFunctionMaxSize> mFreeCallback;
+    Partition*                              mPartition {};
+    ItemRemoverItf*                         mRemover {};
+    Time                                    mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return Error.
+     */
+    Error AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return ErrorEnum::eNone;
+            }
+        }
+
+        Error err = mOutdatedItems.PushBack(item);
+        if (!err.IsNone()) {
+            mOutdatedItems.Sort(
+                [](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+            mOutdatedItems[0] = item;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: You can't just overwrite first item here. Item remover itf should be called for this item, available size should be updated etc.
created_at: 2025-05-15T10:29:25Z
author_association: COLLABORATOR
diff_hunk: @@ -157,29 +175,362 @@ class Space : public SpaceItf {
     /**
      * Returns space size.
      *
-     * @return uint64_t.
+     * @return size_t.
      */
-    uint64_t Size() const override { return mSize; }
+    size_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+struct Partition;
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    size_t                                                                                                     mSize;
+    SpaceAllocatorItf*                      mAllocator {};
+    StaticFunction<cDefaultFunctionMaxSize> mFreeCallback;
+    Partition*                              mPartition {};
+    ItemRemoverItf*                         mRemover {};
+    Time                                    mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return Error.
+     */
+    Error AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return ErrorEnum::eNone;
+            }
+        }
+
+        Error err = mOutdatedItems.PushBack(item);
+        if (!err.IsNone()) {
+            mOutdatedItems.Sort(
+                [](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+            mOutdatedItems[0] = item;
+
+            return ErrorEnum::eNone;
+        }
+
+        return err;
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
+     */
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+    StaticString<cFilePathLen>                      mMountPoint;
+    size_t                                          mLimit {};
+    size_t                                          mTotalSize {};
+    size_t                                          mAllocatorCount {};
+    fs::FSPlatformItf*                              mPlatformFS {};
+    StaticArray<OutdatedItem, cMaxNumOutdatedItems> mOutdatedItems;
+
+private:
+    static constexpr size_t cMaxLimit = 100;
+
+    RetWithError<size_t> RemoveOutdatedItems(size_t size)
+    {
+        size_t totalSize = 0;
+
+        for (const auto& item : mOutdatedItems) {
+            totalSize += item.mSize;
+        }
+
+        if (size > totalSize) {
+            return {0, Error(ErrorEnum::eNoMemory, "partition limit exceeded")};
+        }
+
+        mOutdatedItems.Sort([](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+        size_t freedSize = 0;
+        size_t i         = 0;
+
+        for (; freedSize < size; i++) {
+            auto& item = mOutdatedItems[i];
+
+            if (auto err = item.mRemover->RemoveItem(item.mID); !err.IsNone()) {
+                return {freedSize, err};
+            }
+
+            // item.mAllocator->Free(item.mSize);
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T10:58:06Z
author_association: NONE
diff_hunk: @@ -157,29 +175,362 @@ class Space : public SpaceItf {
     /**
      * Returns space size.
      *
-     * @return uint64_t.
+     * @return size_t.
      */
-    uint64_t Size() const override { return mSize; }
+    size_t Size() const override { return mSize; }
 
 private:
-    size_t mSize;
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+struct Partition;
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    size_t                                                                                                     mSize;
+    SpaceAllocatorItf*                      mAllocator {};
+    StaticFunction<cDefaultFunctionMaxSize> mFreeCallback;
+    Partition*                              mPartition {};
+    ItemRemoverItf*                         mRemover {};
+    Time                                    mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return Error.
+     */
+    Error AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return ErrorEnum::eNone;
+            }
+        }
+
+        Error err = mOutdatedItems.PushBack(item);
+        if (!err.IsNone()) {
+            mOutdatedItems.Sort(
+                [](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+            mOutdatedItems[0] = item;
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T10:58:11Z
author_association: NONE
diff_hunk: @@ -373,6 +373,11 @@ static constexpr auto cFuncServiceLen = AOS_CONFIG_TYPES_FUNC_SERVICE_LEN;
  */
 static constexpr auto cFuncServiceMaxCount = AOS_CONFIG_TYPES_FUNC_SERVICE_MAX_COUNT;
 
+/**
+ * Max number of outdated items.
+ */
+static constexpr auto cMaxNumOutdatedItems = AOS_CONFIG_TYPES_MAX_OUTDATED_ITEMS;
path: include/aos/common/types.hpp
user: login: al1img
body: It looks like it could be private member of Partition. No need to add it to types.hpp
created_at: 2025-05-15T11:21:46Z
author_association: COLLABORATOR
diff_hunk: @@ -373,6 +373,11 @@ static constexpr auto cFuncServiceLen = AOS_CONFIG_TYPES_FUNC_SERVICE_LEN;
  */
 static constexpr auto cFuncServiceMaxCount = AOS_CONFIG_TYPES_FUNC_SERVICE_MAX_COUNT;
 
+/**
+ * Max number of outdated items.
+ */
+static constexpr auto cMaxNumOutdatedItems = AOS_CONFIG_TYPES_MAX_OUTDATED_ITEMS;
path: include/aos/common/types.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T11:39:56Z
author_association: NONE
diff_hunk: @@ -157,29 +175,374 @@ class Space : public SpaceItf {
     /**
      * Returns space size.
      *
-     * @return uint64_t.
+     * @return size_t.
+     */
+    size_t Size() const override { return mSize; }
+
+private:
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+struct Partition;
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    size_t                                                                                                     mSize;
+    SpaceAllocatorItf*                      mAllocator {};
+    StaticFunction<cDefaultFunctionMaxSize> mFreeCallback;
+    Partition*                              mPartition {};
+    ItemRemoverItf*                         mRemover {};
+    Time                                    mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: class
created_at: 2025-05-15T14:16:19Z
author_association: COLLABORATOR
diff_hunk: @@ -157,29 +175,374 @@ class Space : public SpaceItf {
     /**
      * Returns space size.
      *
-     * @return uint64_t.
+     * @return size_t.
+     */
+    size_t Size() const override { return mSize; }
+
+private:
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+struct Partition;
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    size_t                                                                                                     mSize;
+    SpaceAllocatorItf*                      mAllocator {};
+    StaticFunction<cDefaultFunctionMaxSize> mFreeCallback;
+    Partition*                              mPartition {};
+    ItemRemoverItf*                         mRemover {};
+    Time                                    mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return Error.
+     */
+    Error AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return ErrorEnum::eNone;
+            }
+        }
+
+        Error err = mOutdatedItems.PushBack(item);
+        if (!err.IsNone()) {
+            mOutdatedItems.Sort(
+                [](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+            auto& oldestItem = mOutdatedItems[0];
+
+            if (auto removeErr = oldestItem.mRemover->RemoveItem(oldestItem.mID); !removeErr.IsNone()) {
+                return removeErr;
+            }
+
+            oldestItem.mFreeCallback();
+            mAvailableSize += oldestItem.mSize;
+
+            oldestItem = item;
+
+            return ErrorEnum::eNone;
+        }
+
+        return err;
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
      */
-    uint64_t Size() const override { return mSize; }
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+private:
+    static constexpr size_t cMaxNumOutdatedItems = AOS_CONFIG_TYPES_MAX_OUTDATED_ITEMS;
+
+public:
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: al1img
body: Just define public vars after public methods.
No need to mix public, private, public,private
created_at: 2025-05-15T14:16:57Z
author_association: COLLABORATOR
diff_hunk: @@ -519,6 +519,13 @@
 #define AOS_CONFIG_TYPES_FUNC_SERVICE_MAX_COUNT 16
 #endif
 
+/**
+ * Max number of outdated items.
+ */
+#ifndef AOS_CONFIG_TYPES_MAX_OUTDATED_ITEMS
path: include/aos/common/config.hpp
user: login: al1img
body: Rename to AOS_CONFIG_SPACEALLOCATOR_MAX_OUTDATED_ITEMS
created_at: 2025-05-15T14:17:29Z
author_association: COLLABORATOR
diff_hunk: @@ -157,29 +175,374 @@ class Space : public SpaceItf {
     /**
      * Returns space size.
      *
-     * @return uint64_t.
+     * @return size_t.
+     */
+    size_t Size() const override { return mSize; }
+
+private:
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+struct Partition;
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    size_t                                                                                                     mSize;
+    SpaceAllocatorItf*                      mAllocator {};
+    StaticFunction<cDefaultFunctionMaxSize> mFreeCallback;
+    Partition*                              mPartition {};
+    ItemRemoverItf*                         mRemover {};
+    Time                                    mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
+    /**
+     * Default constructor.
+     */
+    Partition() = default;
+
+    /**
+     * Add partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error AddLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit + limit > cMaxLimit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit += limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Remove partition limit.
+     *
+     * @param limit partition limit.
+     * @return Error.
+     */
+    Error RemoveLimit(size_t limit)
+    {
+        LockGuard lock {mMutex};
+
+        if (mLimit < limit) {
+            return Error(ErrorEnum::eNoMemory, "partition limit exceeded");
+        }
+
+        mLimit -= limit;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Allocate space.
+     *
+     * @param size size to allocate.
+     * @return Error.
+     */
+    Error Allocate(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            auto [availableSize, err] = mPlatformFS->GetAvailableSize(mMountPoint);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize = availableSize;
+        }
+
+        if (size > mAvailableSize) {
+            auto [freedSize, err] = RemoveOutdatedItems(size - mAvailableSize);
+            if (!err.IsNone()) {
+                return err;
+            }
+
+            mAvailableSize += freedSize;
+        }
+
+        mAvailableSize -= size;
+        mAllocationCount++;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Free space.
+     *
+     * @param size size to free.
+     * @return void.
+     */
+    void Free(size_t size)
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return;
+        }
+
+        mAvailableSize += size;
+    }
+
+    /**
+     * Allocate done.
+     *
+     * @return Error.
+     */
+    Error Done()
+    {
+        LockGuard lock {mMutex};
+
+        if (mAllocationCount == 0) {
+            return Error(ErrorEnum::eNotFound, "no allocation");
+        }
+
+        mAllocationCount--;
+
+        return ErrorEnum::eNone;
+    }
+
+    /**
+     * Add outdated item.
+     *
+     * @param item outdated item.
+     * @return Error.
+     */
+    Error AddOutdatedItem(const OutdatedItem& item)
+    {
+        LockGuard lock {mMutex};
+
+        for (auto& outdatedItem : mOutdatedItems) {
+            if (outdatedItem.mID == item.mID) {
+                outdatedItem = item;
+
+                return ErrorEnum::eNone;
+            }
+        }
+
+        Error err = mOutdatedItems.PushBack(item);
+        if (!err.IsNone()) {
+            mOutdatedItems.Sort(
+                [](const OutdatedItem& a, const OutdatedItem& b) { return a.mTimestamp < b.mTimestamp; });
+
+            auto& oldestItem = mOutdatedItems[0];
+
+            if (auto removeErr = oldestItem.mRemover->RemoveItem(oldestItem.mID); !removeErr.IsNone()) {
+                return removeErr;
+            }
+
+            oldestItem.mFreeCallback();
+            mAvailableSize += oldestItem.mSize;
+
+            oldestItem = item;
+
+            return ErrorEnum::eNone;
+        }
+
+        return err;
+    }
+
+    /**
+     * Remove outdated item.
+     *
+     * @param id item id.
+     * @return void.
      */
-    uint64_t Size() const override { return mSize; }
+    void RestoreOutdatedItem(const String& id)
+    {
+        LockGuard lock {mMutex};
+
+        for (size_t i = 0; i < mOutdatedItems.Size(); i++) {
+            if (mOutdatedItems[i].mID == id) {
+                mOutdatedItems.Erase(mOutdatedItems.begin() + i);
+
+                break;
+            }
+        }
+    }
+
+private:
+    static constexpr size_t cMaxNumOutdatedItems = AOS_CONFIG_TYPES_MAX_OUTDATED_ITEMS;
+
+public:
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: moved to public section
created_at: 2025-05-15T14:29:12Z
author_association: NONE
diff_hunk: @@ -157,29 +175,374 @@ class Space : public SpaceItf {
     /**
      * Returns space size.
      *
-     * @return uint64_t.
+     * @return size_t.
+     */
+    size_t Size() const override { return mSize; }
+
+private:
+    size_t             mSize;
+    SpaceAllocatorItf* mAllocator {};
+};
+
+struct Partition;
+
+/**
+ * Outdated item.
+ */
+struct OutdatedItem {
+    StaticString<Max(cProviderIDLen, cServiceIDLen, cSubjectIDLen, cLayerIDLen, cSystemIDLen, cInstanceIDLen)> mID;
+    size_t                                                                                                     mSize;
+    SpaceAllocatorItf*                      mAllocator {};
+    StaticFunction<cDefaultFunctionMaxSize> mFreeCallback;
+    Partition*                              mPartition {};
+    ItemRemoverItf*                         mRemover {};
+    Time                                    mTimestamp;
+};
+
+/**
+ * Partition.
+ */
+struct Partition {
path: include/aos/common/spaceallocator/spaceallocator.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T14:29:20Z
author_association: NONE
diff_hunk: @@ -519,6 +519,13 @@
 #define AOS_CONFIG_TYPES_FUNC_SERVICE_MAX_COUNT 16
 #endif
 
+/**
+ * Max number of outdated items.
+ */
+#ifndef AOS_CONFIG_TYPES_MAX_OUTDATED_ITEMS
path: include/aos/common/config.hpp
user: login: MykolaSuperman
body: Done
created_at: 2025-05-15T15:03:29Z
author_association: NONE

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-02-06T07:55:03Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=aosedge_aos_core_lib_cpp&pullRequest=255) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [36 New issues](https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&pullRequest=255&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&pullRequest=255&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=aosedge_aos_core_lib_cpp&pullRequest=255&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=aosedge_aos_core_lib_cpp&pullRequest=255&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=aosedge_aos_core_lib_cpp&pullRequest=255&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aosedge_aos_core_lib_cpp&pullRequest=255)


author_association: NONE
user: login: codecov[bot]
created_at: 2025-02-06T07:57:28Z
body: ## [Codecov](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/255?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) Report
Attention: Patch coverage is `91.39241%` with `34 lines` in your changes missing coverage. Please review.
> Project coverage is 84.38%. Comparing base [(`1b4d01f`)](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/commit/1b4d01f3e51b1442ed8b1bb92b100a4447243446?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) to head [(`9e53782`)](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/commit/9e53782df493ebac102e49b6ce9445e6f3bdc255?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge).
> Report is 2 commits behind head on feature_space_allocator.

| [Files with missing lines](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/255?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) | Patch % | Lines |
|---|---|---|
| [...clude/aos/common/spaceallocator/spaceallocator.hpp](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/255?src=pr&el=tree&filepath=include%2Faos%2Fcommon%2Fspaceallocator%2Fspaceallocator.hpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge#diff-aW5jbHVkZS9hb3MvY29tbW9uL3NwYWNlYWxsb2NhdG9yL3NwYWNlYWxsb2NhdG9yLmhwcA==) | 86.08% | [32 Missing :warning: ](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/255?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) |
| [tests/sm/stubs/spaceallocatorstub.hpp](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/255?src=pr&el=tree&filepath=tests%2Fsm%2Fstubs%2Fspaceallocatorstub.hpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge#diff-dGVzdHMvc20vc3R1YnMvc3BhY2VhbGxvY2F0b3JzdHViLmhwcA==) | 71.42% | [2 Missing :warning: ](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/255?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) |

<details><summary>Additional details and impacted files</summary>


```diff
@@                     Coverage Diff                     @@
##           feature_space_allocator     #255      +/-   ##
===========================================================
+ Coverage                    84.20%   84.38%   +0.17%     
===========================================================
  Files                          160      163       +3     
  Lines                        14926    15322     +396     
  Branches                      1849     1903      +54     
===========================================================
+ Hits                         12569    12930     +361     
- Misses                        2357     2392      +35     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/255?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-05-15T15:00:01Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=aosedge_aos_core_lib_cpp&pullRequest=255) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&pullRequest=255&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=aosedge_aos_core_lib_cpp&pullRequest=255&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=aosedge_aos_core_lib_cpp&pullRequest=255&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=aosedge_aos_core_lib_cpp&pullRequest=255&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=aosedge_aos_core_lib_cpp&pullRequest=255&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aosedge_aos_core_lib_cpp&pullRequest=255)


author_association: NONE