SERVER-102295 Simplify DatabaseName storage flags implementation (#34512)

GitOrigin-RevId: e4a57ab232b840be280419ad7a5cc301a1c5c60b
This commit is contained in:
Aitor Esteve Alvarado 2025-04-04 18:21:06 +02:00 committed by MongoDB Bot
parent cf879d2ede
commit 336b6bbc8d
3 changed files with 48 additions and 60 deletions

View File

@ -367,11 +367,7 @@ class DatabaseNamePrinter(object):
def _get_storage_data(self):
"""Return the data pointer from the _data Storage class."""
data = self.val["_data"]
footer = data["_footer"]
f_size = footer.type.sizeof
# The last byte of _footer contain the flags (and the size when using small string).
flags = footer.cast(gdb.lookup_type("char").array(f_size))[f_size - 1]
flags = data["_flags"]
data_ptr = data["_data"]
if is_small_string(flags):

View File

@ -429,8 +429,8 @@
</Type>
<Type Name="mongo::DatabaseName">
<!-- (((const char *)&_footer)[sizeof(size_t) - 1]) & 2 -->
<DisplayString Condition="(((const char*)&amp; _data._footer)[sizeof(size_t) - 1]) &amp; 2">{ ((const char *)&amp;(_data._data)),[(((const char*)&amp; _data._footer)[sizeof(size_t) - 1]) &gt;&gt; 2]s8 }</DisplayString>
<!-- _data._flags & 2 -->
<DisplayString Condition="_data._flags &amp; 2">{ ((const char *)&amp;(_data._data)),[_data._flags &gt;&gt; 2]s8 }</DisplayString>
<DisplayString>{_data._data,[_data._length]s8}</DisplayString>
</Type>

View File

@ -108,8 +108,7 @@ public:
_data = Storage(dbName._data, dbName.sizeWithTenant() + kDataOffset);
} else if (dbName._data.isSmallString()) {
_data = dbName._data;
_data.updateFooter(database_name::kSmallStringFlag,
dbName.sizeWithTenant() + kDataOffset);
_data.setFlags(database_name::kSmallStringFlag, dbName.sizeWithTenant() + kDataOffset);
} else {
_data = dbName._data;
}
@ -457,20 +456,17 @@ protected:
constexpr Storage(const char* data, size_t length) noexcept
: _data(data),
_length(length),
_footer(createFooter(database_name::kStaticAllocFlag, 0)) {}
_flags(createFlags(database_name::kStaticAllocFlag, 0)) {}
Storage() noexcept
: _data(nullptr),
_length(0),
_footer(createFooter(database_name::kSmallStringFlag, kDataOffset)) {}
_flags(createFlags(database_name::kSmallStringFlag, kDataOffset)) {}
constexpr ~Storage() {
if (!std::is_constant_evaluated()) {
if (isDynamicAlloc() && _data != nullptr) {
MONGO_COMPILER_DIAGNOSTIC_PUSH
MONGO_COMPILER_DIAGNOSTIC_IGNORED_TRANSITIONAL("-Wfree-nonheap-object")
delete[] _data;
MONGO_COMPILER_DIAGNOSTIC_POP
}
}
}
@ -482,14 +478,18 @@ protected:
* a collection and we are only trying to copy the database part from it.
*/
Storage(const Storage& other, const size_t newSize)
: _data(other._data), _length(other._length), _footer(other._footer) {
: _data(other._data),
_length(other._length),
_padding(other._padding),
_flags(other._flags) {
if (other.isStaticAlloc() && other.size() == newSize) {
return;
} else if (other.isSmallString()) {
updateFooter(database_name::kSmallStringFlag, newSize);
setFlags(database_name::kSmallStringFlag, newSize);
} else if (newSize < kSmallStringSize) {
setFooter(database_name::kSmallStringFlag, newSize);
memcpy(mutableDataptr(), other._data, newSize);
setFlags(database_name::kSmallStringFlag, newSize);
clearPadding();
memcpy(smallStringDataptr(), other._data, newSize);
} else if (other.isDynamicAlloc()) {
char* dataptr = new char[newSize];
_data = dataptr;
@ -499,7 +499,10 @@ protected:
}
Storage(Storage&& other) noexcept
: _data(other._data), _length(other._length), _footer(other._footer) {
: _data(other._data),
_length(other._length),
_padding(other._padding),
_flags(other._flags) {
if (other.isDynamicAlloc()) {
other.reset();
}
@ -531,39 +534,33 @@ protected:
void copy(const Storage& other) noexcept {
_data = other._data;
_length = other._length;
_footer = other._footer;
_padding = other._padding;
_flags = other._flags;
}
/**
* Returns a word with a valid flag byte and the rest of the data cleared.
* Returns flagsIn, optionally with the length mixed-in if flagsIn indicate small string
* optimization.
*/
constexpr size_t createFooter(unsigned char flagsIn, unsigned char length) {
constexpr unsigned char createFlags(unsigned char flagsIn, unsigned char length) {
if (flagsIn & database_name::kSmallStringFlag) {
flagsIn |= (length << 2);
}
char byteflags[sizeof(size_t)] = {0};
byteflags[sizeof(size_t) - 1] = flagsIn;
return absl::bit_cast<size_t>(byteflags);
return flagsIn;
}
/**
* Sets the footer field with the correct flags and length. Clear the first sizeof(_footer)
* - 1 bytes which might store data when using the small string optimisation.
* Clear _padding, which might store data when using the small string optimisation.
*/
void setFooter(unsigned char flagsIn, unsigned char length = 0) {
_footer = createFooter(flagsIn, length);
void clearPadding() {
std::fill(_padding.begin(), _padding.end(), 0);
}
/**
* Sets the flag and length of the footer field without changing the first sizeof(_footer) -
* 1 bytes which might contain data.
* Sets the flags and length of the _flags field.
*/
void updateFooter(unsigned char flagsIn, unsigned char length) {
if (flagsIn & database_name::kSmallStringFlag) {
flagsIn |= (length << 2);
}
reinterpret_cast<unsigned char*>(&_footer)[sizeof(size_t) - 1] = flagsIn;
void setFlags(unsigned char flagsIn, unsigned char length) {
_flags = createFlags(flagsIn, length);
}
/**
@ -628,12 +625,13 @@ protected:
dataptr = new char[length];
data._data = dataptr;
data._length = length;
data._footer = 0;
data._flags = 0;
} else {
data.setFooter(database_name::kSmallStringFlag, static_cast<unsigned char>(length));
dataptr = data.mutableDataptr();
data.setFlags(database_name::kSmallStringFlag, static_cast<unsigned char>(length));
data.clearPadding();
dataptr = data.smallStringDataptr();
}
invariant(dataptr == data.mutableDataptr());
invariant(dataptr == data.data());
*dataptr = details;
if (hasTenant) {
@ -688,17 +686,12 @@ protected:
}
private:
/**
* Extracts the flags's byte from the _footer field.
*/
constexpr unsigned char getFlags() const {
return absl::bit_cast<std::array<char, sizeof(size_t)>>(_footer)[sizeof(size_t) - 1];
return _flags;
}
char* mutableDataptr() {
if (isSmallString())
return reinterpret_cast<char*>(&_data);
return const_cast<char*>(_data);
char* smallStringDataptr() {
return reinterpret_cast<char*>(&_data);
}
/**
@ -707,23 +700,22 @@ protected:
void reset() {
_data = nullptr;
_length = 0;
setFooter(database_name::kSmallStringFlag, kDataOffset);
setFlags(database_name::kSmallStringFlag, kDataOffset);
clearPadding();
}
void deallocate() {
if (isDynamicAlloc() && _data != nullptr) {
MONGO_COMPILER_DIAGNOSTIC_PUSH
MONGO_COMPILER_DIAGNOSTIC_IGNORED_TRANSITIONAL("-Wfree-nonheap-object")
delete[] _data;
MONGO_COMPILER_DIAGNOSTIC_POP
reset();
}
}
/**
* Storage can work in three different mode (dynamic allocation, static allocation or
* small-string optimisation) depending on the flag bits (the last two bits of _footer) :
* Flags value given by _footer[sizeof(_footer) - 1] & 0x00000011:
* Storage can work in three different modes (dynamic allocation, static allocation or
* small-string optimisation) depending on the flag bits (the two least significant bits of
* _flags):
* Flags value given by _flags & 0b11:
* 0: the data is dynamically allocated.
* 1: the data is statically allocated.
* 2: the data is packed using the small string optimisation
@ -731,13 +723,13 @@ protected:
* When using static of dynamic allocation, _data is a pointer to the actual data and
* _length contains its size.
*
* When using the small string optimisation the data is packed in _data, _length and the
* first sizeof(_footer)-1 bytes of _footer. The size of the data is contained in the first
* 6 bits of the last byte of _footer :
* When using the small string optimisation the data is packed in _data, _length and
* _padding. The size of the data is contained in 6 most significant bits of _flags.
*/
const char* _data;
size_t _length;
size_t _footer;
std::array<char, sizeof(size_t) - 1> _padding{};
unsigned char _flags;
};
Storage _data;