summaryrefslogtreecommitdiff
path: root/src/mongo/util/shared_buffer_fragment.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/shared_buffer_fragment.h')
-rw-r--r--src/mongo/util/shared_buffer_fragment.h74
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