diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
| commit | 4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch) | |
| tree | 1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/util/shared_buffer_fragment.h | |
| parent | aa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff) | |
| parent | 8f0827553e09872941945a093b647a4211a9db7f (diff) | |
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0'
with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/util/shared_buffer_fragment.h')
| -rw-r--r-- | src/mongo/util/shared_buffer_fragment.h | 74 |
1 files changed, 17 insertions, 57 deletions
diff --git a/src/mongo/util/shared_buffer_fragment.h b/src/mongo/util/shared_buffer_fragment.h index d94acd096aa..05f453c9f60 100644 --- a/src/mongo/util/shared_buffer_fragment.h +++ b/src/mongo/util/shared_buffer_fragment.h @@ -32,7 +32,6 @@ #include "mongo/util/shared_buffer.h" #include <functional> -#include <vector> namespace mongo { @@ -44,7 +43,7 @@ class SharedBufferFragment { public: SharedBufferFragment() : _offset(0), _size(0) {} explicit SharedBufferFragment(SharedBuffer buffer, size_t size) - : SharedBufferFragment(std::move(buffer), 0, size) {} + : _buffer(std::move(buffer)), _offset(0), _size(size) {} explicit SharedBufferFragment(SharedBuffer buffer, ptrdiff_t offset, size_t size) : _buffer(std::move(buffer)), _offset(offset), _size(size) {} @@ -87,14 +86,10 @@ private: size_t _size; }; + /** * Builder of SharedBufferFragment where multiple fragments are using different parts of the same - * underlying buffer or multiple buffers. Can only build one fragment at a time. - * - * Warning: This builder will hold references to all allocated buffers and will not release them - * until freeUnused() is called. Memory is not reused. This means that failing to call this function - * will result in an unbounded amount of memory usage for the lifetime of the builder. Even after - * this builder is destructed, SharedBufferFragments can prevent memory from being freed. + * underlying buffer. Can only build one fragment at a time */ class SharedBufferFragmentBuilder { public: @@ -104,9 +99,6 @@ public: size_t blockSize, GrowStrategy growStrategy = DoubleGrowStrategy(kDefaultMaxBlockSize)) : _offset(0), _blockSize(blockSize), _growStrategy(growStrategy) {} - SharedBufferFragmentBuilder(SharedBufferFragmentBuilder&& other) = default; - SharedBufferFragmentBuilder& operator=(SharedBufferFragmentBuilder&& other) = default; - struct ConstantGrowStrategy { size_t operator()(size_t current) const { return current; @@ -127,20 +119,13 @@ public: // May only be called if we are not currently building a fragment SharedBufferFragmentBuilder& start(size_t initialSize) { invariant(!_inUse); - if (!_buffer.isShared()) { - // Since there are no fragments sharing with this buffer, we can reset the offset to 0 - // to reuse unused space. - _offset = 0; - } - if (_buffer.capacity() < (_offset + initialSize)) { - // If the capacity is 0, this is our initial allocation and we should not use the grow - // strategy. + // If capacity is 0, then this is our initial allocation and we should not use the grow + // strategy if (_buffer.capacity() > 0) _blockSize = _growStrategy(_blockSize); - size_t allocSize = std::max(_blockSize, initialSize); - _buffer = _alloc(std::move(_buffer), allocSize); + _buffer = SharedBuffer::allocate(allocSize); _offset = 0; } _inUse = true; @@ -153,18 +138,18 @@ public: invariant(_inUse); auto currentCapacity = capacity(); if (currentCapacity < size) { - // If the capacity is 0, this is our initial allocation and we should not use the grow - // strategy. - if (currentCapacity > 0) { - _blockSize = _growStrategy(_blockSize); - } + _blockSize = _growStrategy(_blockSize); size_t allocSize = std::max(_blockSize, size); - if (_buffer) { - _buffer = _realloc(std::move(_buffer), _offset, currentCapacity, allocSize); - } else { - _buffer = _alloc(std::move(_buffer), allocSize); - } + // If nothing else is using the internal buffer it would be safe to use realloc. But as + // this potentially is a large buffer realloc would need copy all of it as it doesn't + // know how much is actually used. So we create a new buffer in all cases and reset the + // offset to 0. We only need to copy the memory of the fragment we are currently + // building. + auto newBuffer = SharedBuffer::allocate(allocSize); + if (_buffer) + memcpy(newBuffer.get(), _buffer.get() + _offset, currentCapacity); + _buffer = std::move(newBuffer); _offset = 0; } } @@ -206,38 +191,13 @@ public: return _inUse; } - // Returns the memory used by all allocated buffers that are being tracked. - size_t memUsage() { - return _memUsage; - } - - // Frees all unreferenced buffers except for the most recently allocated one. The caller must - // ensure that no references to any shared buffers remain to maintain useful memory usage - // information. - void freeUnused(); - private: - SharedBuffer _alloc(SharedBuffer&& existing, size_t allocSize) { - return _realloc(std::move(existing), 0, 0, allocSize); - } - - SharedBuffer _realloc(SharedBuffer&& existing, - size_t offset, - size_t existingSize, - size_t newSize); - - // The current working buffer of this builder. SharedBuffer _buffer; ptrdiff_t _offset; size_t _blockSize; GrowStrategy _growStrategy; bool _inUse{false}; - - // This is a list of old buffers that may still be in use by other fragments. Counts towards - // total memory usage and buffers must be freed by calling using freeUnused() when buffers are - // no longer needed. - std::vector<SharedBuffer> _activeBuffers; - size_t _memUsage = 0; }; + } // namespace mongo |
