2222
2323#pragma once
2424
25+ #include < atomic>
2526#include < vector>
2627
2728#include " shared.hpp"
2829#include " utils/managed_allocator.hpp"
2930
31+ namespace arangodb ::iresearch
32+ {
33+ class IResearchFeature ;
34+ };
35+
3036namespace irs {
3137
3238struct IResourceManager {
@@ -68,6 +74,65 @@ struct ResourceManagementOptions {
6874 IResourceManager* cached_columns{&IResourceManager::kNoop };
6975};
7076
77+ struct IResearchMemoryManager : public IResourceManager {
78+ protected:
79+ IResearchMemoryManager () = default ;
80+
81+ public:
82+ virtual ~IResearchMemoryManager () = default ;
83+
84+ virtual void Increase ([[maybe_unused]] uint64_t value) override {
85+
86+ IRS_ASSERT (this != &kForbidden );
87+ IRS_ASSERT (value >= 0 );
88+
89+ if (0 == IResearchMemoryManager::_memory_limit) {
90+ // since we have no limit, we can simply use fetch-add for the increment
91+ IResearchMemoryManager::_current.fetch_add (value, std::memory_order_relaxed);
92+ } else {
93+ // we only want to perform the update if we don't exceed the limit!
94+ std::uint64_t cur = IResearchMemoryManager::_current.load (std::memory_order_relaxed);
95+ std::uint64_t next;
96+ do {
97+ next = cur + value;
98+ if (IRS_UNLIKELY (next > IResearchMemoryManager::_memory_limit.load (std::memory_order_relaxed))) {
99+ throw std::bad_alloc ();
100+ }
101+ } while (!IResearchMemoryManager::_current.compare_exchange_weak (
102+ cur, next, std::memory_order_relaxed));
103+ }
104+ }
105+
106+ virtual void Decrease ([[maybe_unused]] uint64_t value) noexcept override {
107+ IRS_ASSERT (this != &kForbidden );
108+ IRS_ASSERT (value >= 0 );
109+ _current.fetch_sub (value, std::memory_order_relaxed);
110+ }
111+
112+ protected:
113+ // This limit can be set only by IResearchFeature.
114+ // During IResearchFeature::prepare() it is set to a pre-defined
115+ // percentage of the total available physical memory or to the value
116+ // of ARANGODB_OVERRIDE_DETECTED_TOTAL_MEMORY option if specified.
117+ static inline std::atomic<std::uint64_t > _memory_limit = { 0 };
118+
119+ // Singleton
120+ static inline std::shared_ptr<IResourceManager> _instance;
121+
122+ private:
123+ static inline std::atomic<std::uint64_t > _current = { 0 };
124+
125+ public:
126+ static std::shared_ptr<IResourceManager> GetInstance () {
127+ if (!_instance.get ())
128+ _instance.reset (new IResearchMemoryManager ());
129+
130+ return _instance;
131+ }
132+
133+ friend class arangodb ::iresearch::IResearchFeature;
134+ };
135+
71136template <typename T>
72137struct ManagedTypedAllocator
73138 : ManagedAllocator<std::allocator<T>, IResourceManager> {
@@ -77,7 +142,7 @@ struct ManagedTypedAllocator
77142#if !defined(_MSC_VER) && defined(IRESEARCH_DEBUG)
78143 IResourceManager::kForbidden
79144#else
80- IResourceManager:: kNoop
145+ * IResearchMemoryManager::GetInstance ()
81146#endif
82147 ) {
83148 }
0 commit comments