summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/catalog/util/partitioned.h10
-rw-r--r--src/mongo/db/s/resharding/resharding_metrics.cpp8
-rw-r--r--src/mongo/db/stats/counters.cpp12
-rw-r--r--src/mongo/db/stats/counters.h77
-rw-r--r--src/mongo/util/aligned.h96
-rw-r--r--src/mongo/util/aligned_test.cpp6
6 files changed, 139 insertions, 70 deletions
diff --git a/src/mongo/db/catalog/util/partitioned.h b/src/mongo/db/catalog/util/partitioned.h
index 380ea5e21a9..f7fa6ea5aa8 100644
--- a/src/mongo/db/catalog/util/partitioned.h
+++ b/src/mongo/db/catalog/util/partitioned.h
@@ -102,7 +102,7 @@ struct Partitioner {
namespace partitioned_detail {
-using CacheAlignedMutex = CacheAligned<stdx::mutex>;
+using CacheExclusiveMutex = CacheExclusive<stdx::mutex>;
template <typename Key, typename Value>
Key getKey(const std::pair<Key, Value>& pair) {
@@ -300,7 +300,7 @@ public:
*/
Partitioned(std::size_t nPartitions, const AssociativeContainer& container)
: _mutexes(nPartitions),
- _partitions(nPartitions, CacheAlignedAssociativeContainer(container)) {
+ _partitions(nPartitions, CacheExclusiveAssociativeContainer(container)) {
invariant(nPartitions > 0);
}
@@ -383,14 +383,14 @@ public:
}
private:
- using CacheAlignedAssociativeContainer = CacheAligned<AssociativeContainer>;
+ using CacheExclusiveAssociativeContainer = CacheExclusive<AssociativeContainer>;
template <typename T>
using AlignedVector = std::vector<T, boost::alignment::aligned_allocator<T>>;
// These two vectors parallel each other, but we keep them separate so that we can return an
// iterator over `_partitions` from within All.
- mutable AlignedVector<partitioned_detail::CacheAlignedMutex> _mutexes;
- AlignedVector<CacheAlignedAssociativeContainer> _partitions;
+ mutable AlignedVector<partitioned_detail::CacheExclusiveMutex> _mutexes;
+ AlignedVector<CacheExclusiveAssociativeContainer> _partitions;
};
} // namespace mongo
diff --git a/src/mongo/db/s/resharding/resharding_metrics.cpp b/src/mongo/db/s/resharding/resharding_metrics.cpp
index 6a11be7e88f..627f36a89e4 100644
--- a/src/mongo/db/s/resharding/resharding_metrics.cpp
+++ b/src/mongo/db/s/resharding/resharding_metrics.cpp
@@ -124,7 +124,7 @@ public:
private:
// Increment member `counter` by n, resetting all counters if it was > 2^60.
- void _checkWrap(CacheAligned<AtomicWord<long long>> ReshardingOpCounters::*counter, int n) {
+ void _checkWrap(CacheExclusive<AtomicWord<long long>> ReshardingOpCounters::*counter, int n) {
static constexpr auto maxCount = 1LL << 60;
auto oldValue = (this->*counter)->fetchAndAddRelaxed(n);
if (oldValue > maxCount - n) {
@@ -139,9 +139,9 @@ private:
}
}
- CacheAligned<AtomicWord<long long>> _insert;
- CacheAligned<AtomicWord<long long>> _update;
- CacheAligned<AtomicWord<long long>> _delete;
+ CacheExclusive<AtomicWord<long long>> _insert;
+ CacheExclusive<AtomicWord<long long>> _update;
+ CacheExclusive<AtomicWord<long long>> _delete;
};
// Allows tracking elapsed time for the resharding operation and its sub operations (e.g.,
diff --git a/src/mongo/db/stats/counters.cpp b/src/mongo/db/stats/counters.cpp
index f8bead3f388..eb436737a4a 100644
--- a/src/mongo/db/stats/counters.cpp
+++ b/src/mongo/db/stats/counters.cpp
@@ -47,7 +47,7 @@ namespace {
using namespace fmt::literals;
}
-void OpCounters::_checkWrap(CacheAligned<AtomicWord<long long>> OpCounters::*counter, int n) {
+void OpCounters::_checkWrap(CacheExclusive<AtomicWord<long long>> OpCounters::*counter, int n) {
static constexpr auto maxCount = 1LL << 60;
auto oldValue = (this->*counter)->fetchAndAddRelaxed(n);
if (oldValue > maxCount) {
@@ -189,7 +189,7 @@ void NetworkCounter::incrementNumSlowSSLOperations() {
}
void NetworkCounter::acceptedTFOIngress() {
- _tfo->accepted.fetchAndAddRelaxed(1);
+ _tfoAccepted->fetchAndAddRelaxed(1);
}
void NetworkCounter::append(BSONObjBuilder& b) {
@@ -203,11 +203,11 @@ void NetworkCounter::append(BSONObjBuilder& b) {
BSONObjBuilder tfo;
#ifdef __linux__
- tfo.append("kernelSetting", _tfo->kernelSetting);
+ tfo.append("kernelSetting", _tfoKernelSetting);
#endif
- tfo.append("serverSupported", _tfo->kernelSupportServer);
- tfo.append("clientSupported", _tfo->kernelSupportClient);
- tfo.append("accepted", _tfo->accepted.loadRelaxed());
+ tfo.append("serverSupported", _tfoKernelSupportServer);
+ tfo.append("clientSupported", _tfoKernelSupportClient);
+ tfo.append("accepted", _tfoAccepted->loadRelaxed());
b.append("tcpFastOpen", tfo.obj());
}
diff --git a/src/mongo/db/stats/counters.h b/src/mongo/db/stats/counters.h
index 2e07b64fe3c..cb5915b7626 100644
--- a/src/mongo/db/stats/counters.h
+++ b/src/mongo/db/stats/counters.h
@@ -150,28 +150,28 @@ public:
private:
// Increment member `counter` by `n`, resetting all counters if it was > 2^60.
- void _checkWrap(CacheAligned<AtomicWord<long long>> OpCounters::*counter, int n);
+ void _checkWrap(CacheExclusive<AtomicWord<long long>> OpCounters::*counter, int n);
- CacheAligned<AtomicWord<long long>> _insert;
- CacheAligned<AtomicWord<long long>> _query;
- CacheAligned<AtomicWord<long long>> _update;
- CacheAligned<AtomicWord<long long>> _delete;
- CacheAligned<AtomicWord<long long>> _getmore;
- CacheAligned<AtomicWord<long long>> _command;
+ CacheExclusive<AtomicWord<long long>> _insert;
+ CacheExclusive<AtomicWord<long long>> _query;
+ CacheExclusive<AtomicWord<long long>> _update;
+ CacheExclusive<AtomicWord<long long>> _delete;
+ CacheExclusive<AtomicWord<long long>> _getmore;
+ CacheExclusive<AtomicWord<long long>> _command;
- CacheAligned<AtomicWord<long long>> _insertOnExistingDoc;
- CacheAligned<AtomicWord<long long>> _updateOnMissingDoc;
- CacheAligned<AtomicWord<long long>> _deleteWasEmpty;
- CacheAligned<AtomicWord<long long>> _deleteFromMissingNamespace;
- CacheAligned<AtomicWord<long long>> _acceptableErrorInCommand;
+ CacheExclusive<AtomicWord<long long>> _insertOnExistingDoc;
+ CacheExclusive<AtomicWord<long long>> _updateOnMissingDoc;
+ CacheExclusive<AtomicWord<long long>> _deleteWasEmpty;
+ CacheExclusive<AtomicWord<long long>> _deleteFromMissingNamespace;
+ CacheExclusive<AtomicWord<long long>> _acceptableErrorInCommand;
// Counters for deprecated opcodes.
- CacheAligned<AtomicWord<long long>> _insertDeprecated;
- CacheAligned<AtomicWord<long long>> _queryDeprecated;
- CacheAligned<AtomicWord<long long>> _updateDeprecated;
- CacheAligned<AtomicWord<long long>> _deleteDeprecated;
- CacheAligned<AtomicWord<long long>> _getmoreDeprecated;
- CacheAligned<AtomicWord<long long>> _killcursorsDeprecated;
+ CacheExclusive<AtomicWord<long long>> _insertDeprecated;
+ CacheExclusive<AtomicWord<long long>> _queryDeprecated;
+ CacheExclusive<AtomicWord<long long>> _updateDeprecated;
+ CacheExclusive<AtomicWord<long long>> _deleteDeprecated;
+ CacheExclusive<AtomicWord<long long>> _getmoreDeprecated;
+ CacheExclusive<AtomicWord<long long>> _killcursorsDeprecated;
};
extern OpCounters globalOpCounters;
@@ -198,48 +198,47 @@ public:
void acceptedTFOIngress();
void setTFOKernelSetting(std::int64_t val) {
- _tfo->kernelSetting = val;
+ _tfoKernelSetting = val;
}
void setTFOServerSupport(bool val) {
- _tfo->kernelSupportServer = val;
+ _tfoKernelSupportServer = val;
}
void setTFOClientSupport(bool val) {
- _tfo->kernelSupportClient = val;
+ _tfoKernelSupportClient = val;
}
void append(BSONObjBuilder& b);
private:
- CacheAligned<AtomicWord<long long>> _physicalBytesIn{0};
- CacheAligned<AtomicWord<long long>> _physicalBytesOut{0};
+ CacheExclusive<AtomicWord<long long>> _physicalBytesIn{0};
+ CacheExclusive<AtomicWord<long long>> _physicalBytesOut{0};
// These two counters are always incremented at the same time, so
- // we place them on the same cache line.
+ // we place them on the same cache line. We use
+ // CacheCombinedExclusive to ensure that they are combined within
+ // the scope of a constructive interference region, and protected
+ // from false sharing by padding out to destructive interference
+ // size.
struct Together {
AtomicWord<long long> logicalBytesIn{0};
AtomicWord<long long> requests{0};
};
- CacheAligned<Together> _together{};
- static_assert(sizeof(decltype(_together)) <= stdx::hardware_constructive_interference_size,
- "cache line spill");
+ CacheCombinedExclusive<Together> _together{};
- CacheAligned<AtomicWord<long long>> _logicalBytesOut{0};
+ CacheExclusive<AtomicWord<long long>> _logicalBytesOut{0};
- CacheAligned<AtomicWord<long long>> _numSlowDNSOperations{0};
- CacheAligned<AtomicWord<long long>> _numSlowSSLOperations{0};
+ CacheExclusive<AtomicWord<long long>> _numSlowDNSOperations{0};
+ CacheExclusive<AtomicWord<long long>> _numSlowSSLOperations{0};
- struct TFO {
- // Counter of inbound connections at runtime.
- AtomicWord<std::int64_t> accepted{0};
+ // Counter of inbound connections at runtime.
+ CacheExclusive<AtomicWord<std::int64_t>> _tfoAccepted{0};
- // Info determined at startup.
- std::int64_t kernelSetting;
- bool kernelSupportServer{false};
- bool kernelSupportClient{false};
- };
- CacheAligned<TFO> _tfo{};
+ // TFO info determined at startup.
+ std::int64_t _tfoKernelSetting;
+ bool _tfoKernelSupportServer{false};
+ bool _tfoKernelSupportClient{false};
};
extern NetworkCounter networkCounter;
diff --git a/src/mongo/util/aligned.h b/src/mongo/util/aligned.h
index bdab7f8cac1..3521202834e 100644
--- a/src/mongo/util/aligned.h
+++ b/src/mongo/util/aligned.h
@@ -37,16 +37,32 @@
namespace mongo {
+namespace aligned_detail {
+template <size_t step>
+constexpr size_t roundUpByStep(size_t value) {
+ return (((value + (step - 1)) / step) * step);
+}
+} // namespace aligned_detail
+
/**
- * A wrapper holding a `T` value aligned to `alignof(T)` or `MinAlign`,
- * whichever is greater (i.e. more strict). The value is accessed with a
- * pointer-like syntax.
+ * A wrapper holding a `T` value aligned to `alignof(T)` or
+ * `minAlign`, whichever is greater (i.e. more strict). The value is
+ * accessed with a pointer-like syntax. Additionally the object will
+ * be placed in a buffer no smaller than minStorageSize, of which the
+ * contained T object may use no more than maxObjectSize bytes.
*/
-template <typename T, size_t MinAlign>
+template <typename T,
+ size_t minAlign = alignof(T),
+ size_t minStorageSize = sizeof(T),
+ size_t maxObjectSize = minStorageSize>
class Aligned {
public:
using value_type = T;
- static constexpr size_t alignment = std::max(alignof(T), MinAlign);
+
+ static_assert(sizeof(value_type) <= maxObjectSize);
+
+ static constexpr size_t kAlignment = std::max(alignof(value_type), minAlign);
+ static constexpr size_t kStorageSize = std::max(sizeof(value_type), minStorageSize);
template <typename... As>
explicit Aligned(As&&... args) noexcept(std::is_nothrow_constructible_v<value_type, As&&...>) {
@@ -99,7 +115,7 @@ public:
}
private:
- static_assert((MinAlign & (MinAlign - 1)) == 0, "alignments must be a power of two");
+ static_assert((minAlign & (minAlign - 1)) == 0, "alignments must be a power of two");
const value_type* _raw() const noexcept {
return reinterpret_cast<const value_type*>(&_storage);
@@ -117,21 +133,75 @@ private:
return *stdx::launder(_raw());
}
- std::aligned_storage_t<sizeof(value_type), alignment> _storage;
+ std::aligned_storage_t<kStorageSize, kAlignment> _storage;
};
/**
- * Swap the values. Should not necessarily require they agreen on alignment.
- * defined out-of-class to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89612
+ * Swap the values. Defined out-of-class to work around
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89612
+ *
+ * TODO: It should be possible to swap Aligned<T> vs Aligned<U> if T
+ * and U can be swapped, as well to swap instances with varying
+ * alignment, padding, etc. However, defining that generic swap
+ * results in ambiguities.
*/
-template <typename T, size_t MinAlign>
-void swap(Aligned<T, MinAlign>& a,
- Aligned<T, MinAlign>& b) noexcept(std::is_nothrow_swappable_v<T>) {
+template <typename T, auto... Pack>
+void swap(Aligned<T, Pack...>& a, Aligned<T, Pack...>& b) noexcept(std::is_nothrow_swappable_v<T>) {
using std::swap;
swap(*a, *b);
}
+/**
+ * A `CacheExclusive` object is Aligned to the destructive
+ * interference size, ensuring that it will start at an address that
+ * will not exhibit false sharing with any objects that precede it in
+ * memory. Additionally, the storage for the object is padded to a
+ * sufficient multiple of the destructive interference size to ensure
+ * that it will not exhibit false sharing with any other objects that
+ * follow it in memory. However, it is not assured that the embedded T
+ * object will internally exhibit true sharing with all of itself, as
+ * the contained object is permitted to be larger than the
+ * constructive interference size.
+ */
+template <typename T>
+using CacheExclusive =
+ Aligned<T,
+ stdx::hardware_destructive_interference_size,
+ aligned_detail::roundUpByStep<stdx::hardware_destructive_interference_size>(sizeof(T))>;
+
+
+/**
+ * A `CacheCombined` object is Aligned to the constructive
+ * interference size, ensuring that it will start at an address that
+ * can exhibit true sharing for some forward extent. Additionally, the
+ * size of the object is constrained to ensure that all of its state
+ * is eligible for true sharing within the same region of constructive
+ * interference. However, there is no guarantee that the object will
+ * not exhibit false sharing with objects that either precede or
+ * follow it in memory, unless those objects are themselves protected
+ * from false sharing.
+ */
+template <typename T>
+using CacheCombined = Aligned<T,
+ stdx::hardware_constructive_interference_size,
+ sizeof(T),
+ stdx::hardware_constructive_interference_size>;
+
+
+/**
+ * A `CacheCombinedExclusive` object is Aligned to the destructive
+ * interference size, ensuring that it will start at an address that
+ * will not exhibit false sharing with objects that precede it in
+ * memory. Additionally, the storage for the object is padded to the
+ * destructive interference size, ensuring that it will not exhibit
+ * false sharing with objects that follow it. Finally, the size of the
+ * object is constrained to the constructive interference size,
+ * ensuring that the object will internally exhibit true sharing.
+ */
template <typename T>
-using CacheAligned = Aligned<T, stdx::hardware_destructive_interference_size>;
+using CacheCombinedExclusive = Aligned<T,
+ stdx::hardware_destructive_interference_size,
+ stdx::hardware_destructive_interference_size,
+ stdx::hardware_constructive_interference_size>;
} // namespace mongo
diff --git a/src/mongo/util/aligned_test.cpp b/src/mongo/util/aligned_test.cpp
index 2304877150c..f578ba75aee 100644
--- a/src/mongo/util/aligned_test.cpp
+++ b/src/mongo/util/aligned_test.cpp
@@ -104,10 +104,10 @@ TEST(Aligned, Swap) {
ASSERT_EQ(m2->val, 111);
}
-TEST(CacheAligned, IsAlignedToPlatformCacheLine) {
+TEST(CacheExclusive, IsAlignedToPlatformCacheLine) {
static constexpr size_t a = stdx::hardware_destructive_interference_size;
- MONGO_STATIC_ASSERT(alignof(CacheAligned<char>) == a);
- MONGO_STATIC_ASSERT(alignof(CacheAligned<char>) == a);
+ MONGO_STATIC_ASSERT(alignof(CacheExclusive<char>) == a);
+ MONGO_STATIC_ASSERT(alignof(CacheExclusive<char>) == a);
}
} // namespace