Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
buffer_pool.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5#include "buffer_pool.h"
7
8#include <atomic>
9#include <deque>
10#include <mutex>
11
13{
14
16 {
17 public:
18 explicit impl(size_t pool_size, size_t default_capacity)
19 : pool_size_(pool_size), default_capacity_(default_capacity), total_allocated_(0)
20 {
21 NETWORK_LOG_DEBUG("[buffer_pool] Created with pool_size=" +
22 std::to_string(pool_size) +
23 ", default_capacity=" + std::to_string(default_capacity));
24 }
25
26 auto acquire(size_t min_capacity, buffer_pool* parent) -> std::shared_ptr<std::vector<uint8_t>>
27 {
28 std::unique_lock<std::mutex> lock(mutex_);
29
30 // Try to find a suitable buffer in the pool
31 for (auto it = available_buffers_.begin(); it != available_buffers_.end(); ++it)
32 {
33 if ((*it)->capacity() >= min_capacity)
34 {
35 auto buffer = std::move(*it);
36 available_buffers_.erase(it);
37
38 // Clear the buffer but keep capacity
39 buffer->clear();
40
41 NETWORK_LOG_TRACE("[buffer_pool] Acquired buffer from pool, capacity=" +
42 std::to_string(buffer->capacity()));
43
44 // Return with custom deleter that returns buffer to pool
45 return std::shared_ptr<std::vector<uint8_t>>(
46 buffer.release(), [parent](std::vector<uint8_t>* buf) {
47 if (parent)
48 {
49 parent->release(buf);
50 }
51 else
52 {
53 delete buf;
54 }
55 });
56 }
57 }
58
59 // No suitable buffer found, create a new one
60 size_t capacity = std::max(min_capacity, default_capacity_);
61 auto buffer = std::make_unique<std::vector<uint8_t>>();
62 buffer->reserve(capacity);
63
64 total_allocated_.fetch_add(1);
65
66 NETWORK_LOG_TRACE("[buffer_pool] Created new buffer, capacity=" +
67 std::to_string(capacity) +
68 ", total_allocated=" + std::to_string(total_allocated_.load()));
69
70 // Return with custom deleter
71 return std::shared_ptr<std::vector<uint8_t>>(
72 buffer.release(), [parent](std::vector<uint8_t>* buf) {
73 if (parent)
74 {
75 parent->release(buf);
76 }
77 else
78 {
79 delete buf;
80 }
81 });
82 }
83
84 auto release(std::vector<uint8_t>* buffer) -> void
85 {
86 if (!buffer)
87 return;
88
89 std::unique_lock<std::mutex> lock(mutex_);
90
91 // If pool is full, just delete the buffer
92 if (available_buffers_.size() >= pool_size_)
93 {
94 NETWORK_LOG_TRACE("[buffer_pool] Pool full, deleting buffer");
95 delete buffer;
96 total_allocated_.fetch_sub(1);
97 return;
98 }
99
100 // Return buffer to pool
101 available_buffers_.emplace_back(buffer);
102
103 NETWORK_LOG_TRACE("[buffer_pool] Returned buffer to pool, available=" +
104 std::to_string(available_buffers_.size()));
105 }
106
107 auto get_stats() const -> std::pair<size_t, size_t>
108 {
109 std::lock_guard<std::mutex> lock(mutex_);
110 return {available_buffers_.size(), total_allocated_.load()};
111 }
112
113 auto clear() -> void
114 {
115 std::unique_lock<std::mutex> lock(mutex_);
116
117 size_t cleared = available_buffers_.size();
118 available_buffers_.clear();
119
120 total_allocated_.fetch_sub(cleared);
121
122 NETWORK_LOG_INFO("[buffer_pool] Cleared " + std::to_string(cleared) + " buffers");
123 }
124
125 private:
128 std::atomic<size_t> total_allocated_;
129
130 mutable std::mutex mutex_;
131 std::deque<std::unique_ptr<std::vector<uint8_t>>> available_buffers_;
132 };
133
134 buffer_pool::buffer_pool(size_t pool_size, size_t default_capacity)
135 : pimpl_(std::make_unique<impl>(pool_size, default_capacity))
136 {
137 }
138
140 {
141 try
142 {
143 pimpl_->clear();
144 }
145 catch (...)
146 {
147 // Destructor must not throw
148 }
149 }
150
151 auto buffer_pool::acquire(size_t min_capacity) -> std::shared_ptr<std::vector<uint8_t>>
152 {
153 return pimpl_->acquire(min_capacity, this);
154 }
155
156 auto buffer_pool::release(std::vector<uint8_t>* buffer) -> void
157 {
158 pimpl_->release(buffer);
159 }
160
161 auto buffer_pool::get_stats() const -> std::pair<size_t, size_t>
162 {
163 return pimpl_->get_stats();
164 }
165
166 auto buffer_pool::clear() -> void { pimpl_->clear(); }
167
168} // namespace kcenon::network::utils
auto release(std::vector< uint8_t > *buffer) -> void
auto acquire(size_t min_capacity, buffer_pool *parent) -> std::shared_ptr< std::vector< uint8_t > >
std::deque< std::unique_ptr< std::vector< uint8_t > > > available_buffers_
impl(size_t pool_size, size_t default_capacity)
auto get_stats() const -> std::pair< size_t, size_t >
Thread-safe memory pool for reusable byte buffers.
Definition buffer_pool.h:47
buffer_pool(size_t pool_size=32, size_t default_capacity=8192)
Constructs a buffer pool.
auto get_stats() const -> std::pair< size_t, size_t >
Gets current pool statistics.
auto clear() -> void
Clears the pool and releases all cached buffers.
std::unique_ptr< impl > pimpl_
Definition buffer_pool.h:93
auto release(std::vector< uint8_t > *buffer) -> void
Returns a buffer to the pool.
auto acquire(size_t min_capacity=0) -> std::shared_ptr< std::vector< uint8_t > >
Acquires a buffer from the pool.
Logger system integration interface for network_system.
#define NETWORK_LOG_TRACE(msg)
#define NETWORK_LOG_INFO(msg)
#define NETWORK_LOG_DEBUG(msg)
Utility components for network_system.