summaryrefslogtreecommitdiff
path: root/src/mongo/bson
diff options
context:
space:
mode:
authorMohammad Dashti <mdashti@gmail.com>2021-10-26 16:02:19 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-10-26 17:37:23 +0000
commit4bc5be3bad41c21ee729dd700c64b22c1bdb1c12 (patch)
tree59fdb3940c9086dce99892782680d0dbed2872b4 /src/mongo/bson
parent05ee839a82125135f6640de3a62f937abbdbb3bc (diff)
downloadmongo-4bc5be3bad41c21ee729dd700c64b22c1bdb1c12.tar.gz
SERVER-60116 Used a 3-pointer implementation of BasicBufBuilder to optimize for common usage.
Co-authored-by: Mathias Stearn <redbeard0531@gmail.com>
Diffstat (limited to 'src/mongo/bson')
-rw-r--r--src/mongo/bson/util/builder.h121
1 files changed, 77 insertions, 44 deletions
diff --git a/src/mongo/bson/util/builder.h b/src/mongo/bson/util/builder.h
index ff9b7bb9478..5201c30535e 100644
--- a/src/mongo/bson/util/builder.h
+++ b/src/mongo/bson/util/builder.h
@@ -168,7 +168,7 @@ public:
_fragmentBuilder.start(sz);
}
- SharedBufferFragment finish(int sz) {
+ SharedBufferFragment finish(size_t sz) {
return _fragmentBuilder.finish(sz);
}
@@ -299,23 +299,25 @@ template <class BufferAllocator>
class BasicBufBuilder {
public:
template <typename... AllocatorArgs>
- BasicBufBuilder(AllocatorArgs&&... args) : _buf(std::forward<AllocatorArgs>(args)...) {}
+ BasicBufBuilder(AllocatorArgs&&... args)
+ : _buf(std::forward<AllocatorArgs>(args)...),
+ _nextByte(_buf.get()),
+ _end(_nextByte + _buf.capacity()) {}
void kill() {
_buf.free();
}
void reset() {
- l = 0;
- reservedBytes = 0;
+ _nextByte = _buf.get();
+ _end = _nextByte + _buf.capacity();
}
void reset(size_t maxSize) {
- l = 0;
- reservedBytes = 0;
if (maxSize && _buf.capacity() > maxSize) {
_buf.free();
_buf.malloc(maxSize);
}
+ reset();
}
/** leave room for some stuff later
@@ -406,10 +408,13 @@ public:
/** Returns the length of data in the current buffer */
int len() const {
- return l;
+ if (MONGO_unlikely(!_nextByte || !_end)) {
+ return 0;
+ }
+ return _nextByte - _buf.get();
}
void setlen(int newLen) {
- l = newLen;
+ _nextByte = _buf.get() + newLen;
}
/** Returns the capacity of the buffer */
int capacity() const {
@@ -418,26 +423,30 @@ public:
/* returns the pre-grow write position */
inline char* grow(int by) {
- int oldlen = l;
- int newLen = l + by;
- size_t minSize = newLen + reservedBytes;
- if (minSize > _buf.capacity()) {
- _growReallocate(minSize);
+ if (MONGO_likely(_nextByte + by <= _end)) {
+ char* oldNextByte = _nextByte;
+ _nextByte += by;
+ return oldNextByte;
}
- l = newLen;
- return _buf.get() + oldlen;
+ return _growReallocate(by);
}
/**
* Reserve room for some number of bytes to be claimed at a later time via claimReservedBytes.
*/
void reserveBytes(size_t bytes) {
- size_t minSize = l + reservedBytes + bytes;
- if (minSize > _buf.capacity())
- _growReallocate(minSize);
+ dassert(_nextByte && _end);
+ if (MONGO_likely((_end - bytes) >= _nextByte)) {
+ _end -= bytes;
+ return;
+ }
- // This must happen *after* any attempt to grow.
- reservedBytes += bytes;
+ _growReallocate(bytes);
+
+ // _growReallocate adds to _nextByte to speed up the common case of grow(). Now remove
+ // those bytes, and put them after _end.
+ _nextByte -= bytes;
+ _end -= bytes;
}
/**
@@ -445,9 +454,9 @@ public:
* reserved. Appends of up to this many bytes immediately following a claim are
* guaranteed to succeed without a need to reallocate.
*/
- void claimReservedBytes(int bytes) {
- invariant(reservedBytes >= bytes);
- reservedBytes -= bytes;
+ void claimReservedBytes(size_t bytes) {
+ invariant(reservedBytes() >= bytes);
+ _end += bytes;
}
/**
@@ -456,12 +465,23 @@ public:
*/
REQUIRES_FOR_NON_TEMPLATE(std::is_same_v<BufferAllocator, SharedBufferAllocator>)
void useSharedBuffer(SharedBuffer buf) {
- invariant(l == 0); // Can only do this while empty.
- invariant(reservedBytes == 0);
+ invariant(len() == 0); // Can only do this while empty.
+ invariant(reservedBytes() == 0);
_buf = SharedBufferAllocator(std::move(buf));
+ reset();
}
protected:
+ /**
+ * Returns the reservedBytes in this buffer
+ */
+ size_t reservedBytes() const {
+ if (MONGO_unlikely(!_nextByte || !_end)) {
+ return 0;
+ }
+ return _buf.capacity() - (_end - _buf.get());
+ }
+
template <typename T>
void appendNumImpl(T t) {
// NOTE: For now, we assume that all things written
@@ -471,7 +491,10 @@ protected:
DataView(grow(sizeof(t))).write(tagLittleEndian(t));
}
/* "slow" portion of 'grow()' */
- void _growReallocate(size_t minSize) {
+ char* _growReallocate(size_t by) {
+ const size_t oldLen = len();
+ const size_t oldReserved = reservedBytes();
+ size_t minSize = oldLen + by + oldReserved;
// Going beyond the maximum buffer size is not likely.
if (MONGO_unlikely(minSize > BufferMaxSize)) {
growFailure(minSize);
@@ -514,6 +537,14 @@ protected:
// next power of two for being friendly to the system memory allocators and avoid memory
// fragmentation.
_buf.realloc(reallocSize - BufferAllocator::kBuffHolderSize);
+ _nextByte = _buf.get() + oldLen + by;
+ _end = _buf.get() + _buf.capacity() - oldReserved;
+
+ invariant(_nextByte >= _buf.get());
+ invariant(_end >= _nextByte);
+ invariant(_buf.get() + _buf.capacity() >= _end);
+
+ return _buf.get() + oldLen;
}
/*
@@ -527,8 +558,8 @@ protected:
}
BufferAllocator _buf;
- int l{0};
- int reservedBytes{0}; // eagerly _growReallocate to keep this many bytes of spare room.
+ char* _nextByte;
+ char* _end;
template <class Builder>
friend class StringBuilderImpl;
@@ -539,7 +570,10 @@ public:
static constexpr size_t kDefaultInitSizeBytes = 512;
BufBuilder(size_t initsize = kDefaultInitSizeBytes) : BasicBufBuilder(initsize) {}
- /* assume ownership of the buffer */
+ /**
+ * Assume ownership of the buffer.
+ * Note: There should not be any other method calls on this object after a call to 'release'.
+ */
SharedBuffer release() {
return _buf.release();
}
@@ -547,14 +581,10 @@ public:
class PooledFragmentBuilder : public BasicBufBuilder<SharedBufferFragmentAllocator> {
public:
PooledFragmentBuilder(SharedBufferFragmentBuilder& fragmentBuilder)
- : BasicBufBuilder(fragmentBuilder) {
- // Indicate that we are starting to build a fragment but rely on the builder for the block
- // size
- _buf.start(0);
- }
+ : BasicBufBuilder(fragmentBuilder.start(0)) {}
SharedBufferFragment done() {
- return _buf.finish(l);
+ return _buf.finish(len());
}
};
MONGO_STATIC_ASSERT(std::is_move_constructible_v<BufBuilder>);
@@ -564,7 +594,10 @@ public:
static constexpr size_t kDefaultInitSizeBytes = 512;
UniqueBufBuilder(size_t initsize = kDefaultInitSizeBytes) : BasicBufBuilder(initsize) {}
- /* assume ownership of the buffer */
+ /**
+ * Assume ownership of the buffer.
+ * Note: There should not be any other method calls on this object after a call to 'release'.
+ */
UniqueBuffer release() {
return _buf.release();
}
@@ -670,13 +703,13 @@ public:
StringBuilderImpl& operator<<(R (*val)(Args...)) = delete;
void appendDoubleNice(double x) {
- const int prev = _buf.l;
+ const int prev = _buf.len();
const int maxSize = 32;
char* start = _buf.grow(maxSize);
int z = snprintf(start, maxSize, "%.16g", x);
verify(z >= 0);
verify(z < maxSize);
- _buf.l = prev + z;
+ _buf.setlen(prev + z);
if (strchr(start, '.') == nullptr && strchr(start, 'E') == nullptr &&
strchr(start, 'N') == nullptr) {
write(".0", 2);
@@ -696,7 +729,7 @@ public:
}
std::string str() const {
- return std::string(_buf.buf(), _buf.l);
+ return std::string(_buf.buf(), _buf.len());
}
/**
@@ -705,7 +738,7 @@ public:
* WARNING: The view is invalidated when this StringBuilder is modified or destroyed.
*/
std::string_view stringView() const {
- return std::string_view(_buf.buf(), _buf.l);
+ return std::string_view(_buf.buf(), _buf.len());
}
/**
@@ -714,12 +747,12 @@ public:
* WARNING: The view is invalidated when this StringBuilder is modified or destroyed.
*/
StringData stringData() const {
- return StringData(_buf.buf(), _buf.l);
+ return StringData(_buf.buf(), _buf.len());
}
/** size of current std::string */
int len() const {
- return _buf.l;
+ return _buf.len();
}
private:
@@ -740,11 +773,11 @@ private:
template <typename T>
StringBuilderImpl& SBNUM(T val, int maxSize, const char* macro) {
- int prev = _buf.l;
+ int prev = _buf.len();
int z = snprintf(_buf.grow(maxSize), maxSize, macro, (val));
verify(z >= 0);
verify(z < maxSize);
- _buf.l = prev + z;
+ _buf.setlen(prev + z);
return *this;
}