From ab9eebcecf40f254e12da8f3480a0baaa75b3d86 Mon Sep 17 00:00:00 2001 From: Julia CP Date: Tue, 12 Aug 2025 12:14:18 -0300 Subject: [PATCH 01/10] Add SupervisedBuffer for centralized memory accounting --- arangod/Aql/SupervisedBuffer.h | 68 ++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 arangod/Aql/SupervisedBuffer.h diff --git a/arangod/Aql/SupervisedBuffer.h b/arangod/Aql/SupervisedBuffer.h new file mode 100644 index 000000000000..9f0af77f613f --- /dev/null +++ b/arangod/Aql/SupervisedBuffer.h @@ -0,0 +1,68 @@ +#pragma once + + +#include "Aql/ResourceMonitor.h" +#include "Aql/ResourceUsageScope.h" + +#include + + + +namespace arangodb { + +template +class SupervisedBuffer { + public: + + explicit SupervisedBuffer(ResourceUsageScope& scope) + : _usageScope(&scope), _resourceMonitor(nullptr) {} + + + explicit SupervisedBuffer(ResourceMonitor& monitor) + : _usageScope(nullptr), _resourceMonitor(&monitor) {} + + + SupervisedBuffer() : _usageScope(nullptr), _resourceMonitor(nullptr) {} + + void appendByte(Byte byte) { + reserve(_data.size() + 1); + _data.push_back(byte); + } + + void append(Byte const* data, size_t length) { + reserve(_data.size() + length); + _data.insert(_data.end(), data, data + length); + } + + + void reserve(size_t amountBytes) { + size_t currentCapacity = _data.capacity(); + if (amountBytes > currentCapacity) { + if (_usageScope) { + _usageScope->increase(n - oldCap); + } else if (_resourceMonitor) { + _resourceMonitor->increaseMemoryUsage(n - oldCap); + } + _data.reserve(amountBytes); + } + } + + + + + void steal() { + if (_usageScope) { + _usageScope->steal(); + } + } + + const Byte* data() const noexcept { return _data.data(); } + size_t size() const noexcept { return _data.size(); } + size_t capacity() const noexcept { return _data.capacity(); } + + private: + std::vector _data; + ResourceUsageScope* _usageScope; + ResourceMonitor* _resourceMonitor; +}; +} // namespace arangodb From 94d795218d424673b8a688ba8fd75902139d11c7 Mon Sep 17 00:00:00 2001 From: Julia CP Date: Wed, 13 Aug 2025 11:36:06 -0300 Subject: [PATCH 02/10] Introduced overriding of Buffer functions to account memory automatically in the supervised buffer --- arangod/Aql/SupervisedBuffer.h | 68 ---------------------------------- lib/Basics/SupervisedBuffer.h | 40 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 68 deletions(-) delete mode 100644 arangod/Aql/SupervisedBuffer.h create mode 100644 lib/Basics/SupervisedBuffer.h diff --git a/arangod/Aql/SupervisedBuffer.h b/arangod/Aql/SupervisedBuffer.h deleted file mode 100644 index 9f0af77f613f..000000000000 --- a/arangod/Aql/SupervisedBuffer.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - - -#include "Aql/ResourceMonitor.h" -#include "Aql/ResourceUsageScope.h" - -#include - - - -namespace arangodb { - -template -class SupervisedBuffer { - public: - - explicit SupervisedBuffer(ResourceUsageScope& scope) - : _usageScope(&scope), _resourceMonitor(nullptr) {} - - - explicit SupervisedBuffer(ResourceMonitor& monitor) - : _usageScope(nullptr), _resourceMonitor(&monitor) {} - - - SupervisedBuffer() : _usageScope(nullptr), _resourceMonitor(nullptr) {} - - void appendByte(Byte byte) { - reserve(_data.size() + 1); - _data.push_back(byte); - } - - void append(Byte const* data, size_t length) { - reserve(_data.size() + length); - _data.insert(_data.end(), data, data + length); - } - - - void reserve(size_t amountBytes) { - size_t currentCapacity = _data.capacity(); - if (amountBytes > currentCapacity) { - if (_usageScope) { - _usageScope->increase(n - oldCap); - } else if (_resourceMonitor) { - _resourceMonitor->increaseMemoryUsage(n - oldCap); - } - _data.reserve(amountBytes); - } - } - - - - - void steal() { - if (_usageScope) { - _usageScope->steal(); - } - } - - const Byte* data() const noexcept { return _data.data(); } - size_t size() const noexcept { return _data.size(); } - size_t capacity() const noexcept { return _data.capacity(); } - - private: - std::vector _data; - ResourceUsageScope* _usageScope; - ResourceMonitor* _resourceMonitor; -}; -} // namespace arangodb diff --git a/lib/Basics/SupervisedBuffer.h b/lib/Basics/SupervisedBuffer.h new file mode 100644 index 000000000000..c4d216aaa14e --- /dev/null +++ b/lib/Basics/SupervisedBuffer.h @@ -0,0 +1,40 @@ +#pragma once + +#include "velocypack/Buffer.h" +#include "Basics/ResourceMonitor.h" +#include "Basics/ResourceUsage.h" + +namespace arangodb { + +class SupervisedBuffer : public arangodb::velocypack::Buffer { + public: + SupervisedBuffer() = default; + + explicit SupervisedBuffer(ResourceMonitor& monitor) + : _usageScope(std::make_unique(monitor)), + _usageScopeRaw(_usageScope.get()) {} + + protected: + void grow(ValueLength length) override { + auto currentCapacity = this->capacity(); + velocypack::Buffer::grow(length); + auto newCapacity = this->capacity(); + if (_usageScope && newCapacity > currentCapacity) { + _usageScope->increase(newCapacity - currentCapacity); + } + } + + uint8_t* steal() noexcept override { + uint8_t* ptr = velocypack::Buffer::steal(); + if (_usageScope) { // assume it exists without checking? + _usageScope->steal(); + } + return ptr; + } + + private: + std::unique_ptr _usageScope; + ResourceUsageScope* _usageScopeRaw{nullptr}; +}; + +} // namespace arangodb \ No newline at end of file From ae8b6381ab5da128e030067fe2b1556015de7c76 Mon Sep 17 00:00:00 2001 From: Julia CP Date: Wed, 13 Aug 2025 11:42:10 -0300 Subject: [PATCH 03/10] add new file to CMakeLists --- lib/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 0047e35b8390..53f662b3901e 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -79,6 +79,7 @@ add_library(arango_basic_utils STATIC Basics/NumberUtils.cpp Basics/ReadWriteSpinLock.cpp Basics/ResourceUsage.cpp + Basics/SupervisedBuffer.h Basics/StringBufferAdvanced.cpp Basics/Utf8Helper.cpp Basics/VelocyPackHelper.cpp From b0794434876a6e2b19a89d72966e313b09d464c6 Mon Sep 17 00:00:00 2001 From: Julia CP Date: Mon, 18 Aug 2025 10:38:42 -0300 Subject: [PATCH 04/10] Override the clear method to account for released memory --- lib/Basics/SupervisedBuffer.h | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/Basics/SupervisedBuffer.h b/lib/Basics/SupervisedBuffer.h index c4d216aaa14e..d47957af1d70 100644 --- a/lib/Basics/SupervisedBuffer.h +++ b/lib/Basics/SupervisedBuffer.h @@ -1,12 +1,11 @@ #pragma once #include "velocypack/Buffer.h" -#include "Basics/ResourceMonitor.h" #include "Basics/ResourceUsage.h" +// Julia +namespace arangodb::velocypack { -namespace arangodb { - -class SupervisedBuffer : public arangodb::velocypack::Buffer { +class SupervisedBuffer : private arangodb::velocypack::Buffer { public: SupervisedBuffer() = default; @@ -14,7 +13,7 @@ class SupervisedBuffer : public arangodb::velocypack::Buffer { : _usageScope(std::make_unique(monitor)), _usageScopeRaw(_usageScope.get()) {} - protected: + private: void grow(ValueLength length) override { auto currentCapacity = this->capacity(); velocypack::Buffer::grow(length); @@ -32,9 +31,18 @@ class SupervisedBuffer : public arangodb::velocypack::Buffer { return ptr; } - private: + void clear() noexcept override { + auto before = this->capacity(); + Buffer::clear(); + auto after = this->capacity(); + // if before > after, means that it has released usage from the heap + if (_usageScope && before > after) { + _usageScope->decrease(before - after); + } + } + std::unique_ptr _usageScope; ResourceUsageScope* _usageScopeRaw{nullptr}; }; -} // namespace arangodb \ No newline at end of file +} // namespace arangodb::velocypack \ No newline at end of file From c924075a4b97ab6c6b99f0a82f7216eb21677829 Mon Sep 17 00:00:00 2001 From: Julia CP Date: Mon, 18 Aug 2025 11:14:12 -0300 Subject: [PATCH 05/10] Remove noecept from overriden methods as now can throw --- lib/Basics/SupervisedBuffer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Basics/SupervisedBuffer.h b/lib/Basics/SupervisedBuffer.h index d47957af1d70..bd47ee6712ac 100644 --- a/lib/Basics/SupervisedBuffer.h +++ b/lib/Basics/SupervisedBuffer.h @@ -23,7 +23,7 @@ class SupervisedBuffer : private arangodb::velocypack::Buffer { } } - uint8_t* steal() noexcept override { + uint8_t* steal() override { uint8_t* ptr = velocypack::Buffer::steal(); if (_usageScope) { // assume it exists without checking? _usageScope->steal(); @@ -31,7 +31,7 @@ class SupervisedBuffer : private arangodb::velocypack::Buffer { return ptr; } - void clear() noexcept override { + void clear() override { auto before = this->capacity(); Buffer::clear(); auto after = this->capacity(); From ee48752fc0647bbce73b04b095442280688d66c5 Mon Sep 17 00:00:00 2001 From: Julia CP Date: Mon, 18 Aug 2025 11:15:16 -0300 Subject: [PATCH 06/10] Remove comment --- lib/Basics/SupervisedBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Basics/SupervisedBuffer.h b/lib/Basics/SupervisedBuffer.h index bd47ee6712ac..8ed4646123f3 100644 --- a/lib/Basics/SupervisedBuffer.h +++ b/lib/Basics/SupervisedBuffer.h @@ -2,7 +2,7 @@ #include "velocypack/Buffer.h" #include "Basics/ResourceUsage.h" -// Julia + namespace arangodb::velocypack { class SupervisedBuffer : private arangodb::velocypack::Buffer { From 462cb413db234c00e923c8c48f768d3695dbaff6 Mon Sep 17 00:00:00 2001 From: Julia CP Date: Mon, 18 Aug 2025 11:52:10 -0300 Subject: [PATCH 07/10] Give back the noexcept because methods don't actually throw as don't increase memory --- lib/Basics/SupervisedBuffer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Basics/SupervisedBuffer.h b/lib/Basics/SupervisedBuffer.h index 8ed4646123f3..cfb51efaf091 100644 --- a/lib/Basics/SupervisedBuffer.h +++ b/lib/Basics/SupervisedBuffer.h @@ -23,7 +23,7 @@ class SupervisedBuffer : private arangodb::velocypack::Buffer { } } - uint8_t* steal() override { + uint8_t* steal() override noexcept { uint8_t* ptr = velocypack::Buffer::steal(); if (_usageScope) { // assume it exists without checking? _usageScope->steal(); @@ -31,7 +31,7 @@ class SupervisedBuffer : private arangodb::velocypack::Buffer { return ptr; } - void clear() override { + void clear() override noexcept { auto before = this->capacity(); Buffer::clear(); auto after = this->capacity(); From 77fa9f9de1cded5645069b8ae47989486d65a7ea Mon Sep 17 00:00:00 2001 From: Julia CP Date: Mon, 18 Aug 2025 16:28:23 -0300 Subject: [PATCH 08/10] Get rid of raw pointer --- lib/Basics/SupervisedBuffer.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Basics/SupervisedBuffer.h b/lib/Basics/SupervisedBuffer.h index cfb51efaf091..fbde650653de 100644 --- a/lib/Basics/SupervisedBuffer.h +++ b/lib/Basics/SupervisedBuffer.h @@ -10,8 +10,7 @@ class SupervisedBuffer : private arangodb::velocypack::Buffer { SupervisedBuffer() = default; explicit SupervisedBuffer(ResourceMonitor& monitor) - : _usageScope(std::make_unique(monitor)), - _usageScopeRaw(_usageScope.get()) {} + : _usageScope(std::make_unique(monitor)) {} private: void grow(ValueLength length) override { @@ -42,7 +41,6 @@ class SupervisedBuffer : private arangodb::velocypack::Buffer { } std::unique_ptr _usageScope; - ResourceUsageScope* _usageScopeRaw{nullptr}; }; } // namespace arangodb::velocypack \ No newline at end of file From ca43a7d6c1cfad0bbf6eac0b48999483b3c6b9a3 Mon Sep 17 00:00:00 2001 From: Julia CP Date: Tue, 19 Aug 2025 00:54:21 -0300 Subject: [PATCH 09/10] made steal method public --- lib/Basics/SupervisedBuffer.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/Basics/SupervisedBuffer.h b/lib/Basics/SupervisedBuffer.h index fbde650653de..a1df01b3df62 100644 --- a/lib/Basics/SupervisedBuffer.h +++ b/lib/Basics/SupervisedBuffer.h @@ -12,6 +12,14 @@ class SupervisedBuffer : private arangodb::velocypack::Buffer { explicit SupervisedBuffer(ResourceMonitor& monitor) : _usageScope(std::make_unique(monitor)) {} + uint8_t* steal() override noexcept { + uint8_t* ptr = velocypack::Buffer::steal(); + if (_usageScope) { // assume it exists without checking? + _usageScope->steal(); + } + return ptr; + } + private: void grow(ValueLength length) override { auto currentCapacity = this->capacity(); @@ -22,14 +30,6 @@ class SupervisedBuffer : private arangodb::velocypack::Buffer { } } - uint8_t* steal() override noexcept { - uint8_t* ptr = velocypack::Buffer::steal(); - if (_usageScope) { // assume it exists without checking? - _usageScope->steal(); - } - return ptr; - } - void clear() override noexcept { auto before = this->capacity(); Buffer::clear(); From aa4a377d09575c42b9c7d03997d0df5355831cc1 Mon Sep 17 00:00:00 2001 From: Julia CP Date: Tue, 19 Aug 2025 00:58:38 -0300 Subject: [PATCH 10/10] Made inheritance public --- lib/Basics/SupervisedBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Basics/SupervisedBuffer.h b/lib/Basics/SupervisedBuffer.h index a1df01b3df62..e46f70093aa2 100644 --- a/lib/Basics/SupervisedBuffer.h +++ b/lib/Basics/SupervisedBuffer.h @@ -5,7 +5,7 @@ namespace arangodb::velocypack { -class SupervisedBuffer : private arangodb::velocypack::Buffer { +class SupervisedBuffer : public arangodb::velocypack::Buffer { public: SupervisedBuffer() = default;