Skip to content

Commit 5e5c117

Browse files
committed
Implemented memory manager to use with allocators
1 parent c24abc1 commit 5e5c117

File tree

1 file changed

+66
-1
lines changed

1 file changed

+66
-1
lines changed

core/resource_manager.hpp

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,17 @@
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+
3036
namespace irs {
3137

3238
struct 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+
71136
template<typename T>
72137
struct 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

Comments
 (0)