summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct7
-rw-r--r--src/mongo/db/catalog/util/partitioned.h26
-rw-r--r--src/mongo/db/catalog/util/partitioned_test.cpp2
-rw-r--r--src/mongo/db/cursor_manager.cpp8
-rw-r--r--src/mongo/db/s/resharding/resharding_metrics.cpp22
-rw-r--r--src/mongo/db/stats/counters.cpp110
-rw-r--r--src/mongo/db/stats/counters.h30
-rw-r--r--src/mongo/stdx/new.h20
-rw-r--r--src/mongo/util/SConscript1
-rw-r--r--src/mongo/util/aligned.h137
-rw-r--r--src/mongo/util/aligned_test.cpp114
-rw-r--r--src/mongo/util/with_alignment.h66
12 files changed, 373 insertions, 170 deletions
diff --git a/SConstruct b/SConstruct
index fafda675b84..db86ae11ddf 100644
--- a/SConstruct
+++ b/SConstruct
@@ -2193,7 +2193,12 @@ elif env.TargetOSIs('windows'):
# object called lock on the stack.
env.Append( CCFLAGS=["/we4013", "/we4099", "/we4930"] )
- env.Append( CPPDEFINES=["_CONSOLE","_CRT_SECURE_NO_WARNINGS", "_SCL_SECURE_NO_WARNINGS"] )
+ env.Append(CPPDEFINES=[
+ "_CONSOLE",
+ "_CRT_SECURE_NO_WARNINGS",
+ "_ENABLE_EXTENDED_ALIGNED_STORAGE",
+ "_SCL_SECURE_NO_WARNINGS",
+ ])
# this would be for pre-compiled headers, could play with it later
#env.Append( CCFLAGS=['/Yu"pch.h"'] )
diff --git a/src/mongo/db/catalog/util/partitioned.h b/src/mongo/db/catalog/util/partitioned.h
index e6966e30ce3..621bee65d7f 100644
--- a/src/mongo/db/catalog/util/partitioned.h
+++ b/src/mongo/db/catalog/util/partitioned.h
@@ -40,8 +40,8 @@
#include <boost/align/aligned_allocator.hpp>
#include "mongo/platform/mutex.h"
+#include "mongo/util/aligned.h"
#include "mongo/util/assert_util.h"
-#include "mongo/util/with_alignment.h"
namespace mongo {
@@ -119,7 +119,7 @@ inline std::vector<stdx::unique_lock<stdx::mutex>> lockAllPartitions(T& mutexes)
std::vector<stdx::unique_lock<stdx::mutex>> result;
result.reserve(mutexes.size());
std::transform(mutexes.begin(), mutexes.end(), std::back_inserter(result), [](auto&& mutex) {
- return stdx::unique_lock<stdx::mutex>{mutex};
+ return stdx::unique_lock<stdx::mutex>{*mutex};
});
return result;
}
@@ -200,7 +200,7 @@ public:
this->_partitionedContainer->_partitions.begin(),
this->_partitionedContainer->_partitions.end(),
std::size_t{0},
- [](auto&& total, auto&& partition) { return total + partition.size(); });
+ [](auto&& total, auto&& partition) { return total + partition->size(); });
}
/**
@@ -209,7 +209,7 @@ public:
bool empty() const {
return std::all_of(this->_partitionedContainer->_partitions.begin(),
this->_partitionedContainer->_partitions.end(),
- [](auto&& partition) { return partition.empty(); });
+ [](auto&& partition) { return partition->empty(); });
}
/**
@@ -217,7 +217,7 @@ public:
*/
std::size_t count(const key_type& key) const {
auto partitionId = KeyPartitioner()(key, nPartitions);
- return this->_partitionedContainer->_partitions[partitionId].count(key);
+ return this->_partitionedContainer->_partitions[partitionId]->count(key);
}
/**
@@ -225,7 +225,7 @@ public:
*/
void clear() {
for (auto&& partition : this->_partitionedContainer->_partitions) {
- partition.clear();
+ partition->clear();
}
}
@@ -235,7 +235,7 @@ public:
void insert(value_type value) & {
const auto partitionId =
KeyPartitioner()(partitioned_detail::getKey(value), nPartitions);
- this->_partitionedContainer->_partitions[partitionId].insert(std::move(value));
+ this->_partitionedContainer->_partitions[partitionId]->insert(std::move(value));
}
void insert(value_type) && = delete;
@@ -244,7 +244,7 @@ public:
*/
std::size_t erase(const key_type& key) & {
const auto partitionId = KeyPartitioner()(key, nPartitions);
- return this->_partitionedContainer->_partitions[partitionId].erase(key);
+ return this->_partitionedContainer->_partitions[partitionId]->erase(key);
}
void erase(const key_type&) && = delete;
@@ -266,7 +266,7 @@ public:
* Returns a pointer to the structure in this partition.
*/
AssociativeContainer* operator->() const& {
- return &this->_partitioned->_partitions[_id];
+ return &*this->_partitioned->_partitions[_id];
}
void operator->() && = delete;
@@ -274,7 +274,7 @@ public:
* Returns a reference to the structure in this partition.
*/
AssociativeContainer& operator*() const& {
- return this->_partitioned->_partitions[_id];
+ return *this->_partitioned->_partitions[_id];
}
void operator*() && = delete;
@@ -287,7 +287,7 @@ public:
* use GuardedAssociativeContainer, or acquire them in ascending order.
*/
OnePartition(Partitioned& partitioned, PartitionId partitionId)
- : _partitionLock(partitioned._mutexes[partitionId]),
+ : _partitionLock(*partitioned._mutexes[partitionId]),
_partitioned(&partitioned),
_id(partitionId) {}
@@ -315,7 +315,7 @@ public:
const auto all = partitioned_detail::lockAllPartitions(this->_mutexes);
return std::all_of(this->_partitions.begin(),
this->_partitions.end(),
- [](auto&& partition) { return partition.empty(); });
+ [](auto&& partition) { return partition->empty(); });
}
/**
@@ -328,7 +328,7 @@ public:
this->_partitions.begin(),
this->_partitions.end(),
std::size_t{0},
- [](auto&& total, auto&& partition) { return total + partition.size(); });
+ [](auto&& total, auto&& partition) { return total + partition->size(); });
}
/**
diff --git a/src/mongo/db/catalog/util/partitioned_test.cpp b/src/mongo/db/catalog/util/partitioned_test.cpp
index 1cd235c95d6..afd370bb567 100644
--- a/src/mongo/db/catalog/util/partitioned_test.cpp
+++ b/src/mongo/db/catalog/util/partitioned_test.cpp
@@ -201,7 +201,7 @@ TEST(PartitionedConcurrency, ModificationsFromAllShouldBeVisible) {
all.insert(1);
all.insert(2);
for (auto&& partition : all) {
- ASSERT_EQ(1UL, partition.size());
+ ASSERT_EQ(1UL, partition->size());
}
}
diff --git a/src/mongo/db/cursor_manager.cpp b/src/mongo/db/cursor_manager.cpp
index ebc83827027..c1728d78586 100644
--- a/src/mongo/db/cursor_manager.cpp
+++ b/src/mongo/db/cursor_manager.cpp
@@ -156,7 +156,7 @@ CursorManager::CursorManager(ClockSource* preciseClockSource)
CursorManager::~CursorManager() {
auto allPartitions = _cursorMap->lockAllPartitions();
for (auto&& partition : allPartitions) {
- for (auto&& cursor : partition) {
+ for (auto&& cursor : *partition) {
// Callers must ensure that no cursors are in use.
invariant(!cursor.second->_operationUsingCursor);
cursor.second->dispose(nullptr);
@@ -290,7 +290,7 @@ void CursorManager::unpin(OperationContext* opCtx,
void CursorManager::appendActiveSessions(LogicalSessionIdSet* lsids) const {
auto allPartitions = _cursorMap->lockAllPartitions();
for (auto&& partition : allPartitions) {
- for (auto&& entry : partition) {
+ for (auto&& entry : *partition) {
auto cursor = entry.second;
if (auto id = cursor->getSessionId()) {
lsids->insert(id.value());
@@ -306,7 +306,7 @@ std::vector<GenericCursor> CursorManager::getIdleCursors(
auto allPartitions = _cursorMap->lockAllPartitions();
for (auto&& partition : allPartitions) {
- for (auto&& entry : partition) {
+ for (auto&& entry : *partition) {
auto cursor = entry.second;
// Exclude cursors that this user does not own if auth is enabled.
@@ -331,7 +331,7 @@ stdx::unordered_set<CursorId> CursorManager::getCursorsForSession(LogicalSession
auto allPartitions = _cursorMap->lockAllPartitions();
for (auto&& partition : allPartitions) {
- for (auto&& entry : partition) {
+ for (auto&& entry : *partition) {
auto cursor = entry.second;
if (cursor->getSessionId() == lsid) {
cursors.insert(cursor->cursorid());
diff --git a/src/mongo/db/s/resharding/resharding_metrics.cpp b/src/mongo/db/s/resharding/resharding_metrics.cpp
index be231bce447..a49c577cd28 100644
--- a/src/mongo/db/s/resharding/resharding_metrics.cpp
+++ b/src/mongo/db/s/resharding/resharding_metrics.cpp
@@ -35,9 +35,9 @@
#include "mongo/db/s/resharding/resharding_metrics.h"
#include "mongo/logv2/log.h"
#include "mongo/platform/compiler.h"
+#include "mongo/util/aligned.h"
#include "mongo/util/duration.h"
#include "mongo/util/integer_histogram.h"
-#include "mongo/util/with_alignment.h"
namespace mongo {
@@ -134,9 +134,9 @@ public:
BSONObj getObj() const noexcept {
BSONObjBuilder b;
- b.append("insert", _insert.loadRelaxed());
- b.append("update", _update.loadRelaxed());
- b.append("delete", _delete.loadRelaxed());
+ b.append("insert", _insert->loadRelaxed());
+ b.append("update", _update->loadRelaxed());
+ b.append("delete", _delete->loadRelaxed());
return b.obj();
}
@@ -144,16 +144,16 @@ private:
// Increment member `counter` by n, resetting all counters if it was > 2^60.
void _checkWrap(CacheAligned<AtomicWord<long long>> ReshardingOpCounters::*counter, int n) {
static constexpr auto maxCount = 1LL << 60;
- auto oldValue = (this->*counter).fetchAndAddRelaxed(n);
+ auto oldValue = (this->*counter)->fetchAndAddRelaxed(n);
if (oldValue > maxCount - n) {
LOGV2(5776000,
"ReshardingOpCounters exceeded maximum value, resetting all to 0",
- "insert"_attr = _insert.loadRelaxed(),
- "update"_attr = _update.loadRelaxed(),
- "delete"_attr = _delete.loadRelaxed());
- _insert.store(0);
- _update.store(0);
- _delete.store(0);
+ "insert"_attr = _insert->loadRelaxed(),
+ "update"_attr = _update->loadRelaxed(),
+ "delete"_attr = _delete->loadRelaxed());
+ _insert->store(0);
+ _update->store(0);
+ _delete->store(0);
}
}
diff --git a/src/mongo/db/stats/counters.cpp b/src/mongo/db/stats/counters.cpp
index 2f9b070b888..c1d7b6f7ec8 100644
--- a/src/mongo/db/stats/counters.cpp
+++ b/src/mongo/db/stats/counters.cpp
@@ -47,39 +47,39 @@ using namespace fmt::literals;
void OpCounters::_checkWrap(CacheAligned<AtomicWord<long long>> OpCounters::*counter, int n) {
static constexpr auto maxCount = 1LL << 60;
- auto oldValue = (this->*counter).fetchAndAddRelaxed(n);
+ auto oldValue = (this->*counter)->fetchAndAddRelaxed(n);
if (oldValue > maxCount) {
- _insert.store(0);
- _query.store(0);
- _update.store(0);
- _delete.store(0);
- _getmore.store(0);
- _command.store(0);
-
- _insertDeprecated.store(0);
- _queryDeprecated.store(0);
- _updateDeprecated.store(0);
- _deleteDeprecated.store(0);
- _getmoreDeprecated.store(0);
- _killcursorsDeprecated.store(0);
+ _insert->store(0);
+ _query->store(0);
+ _update->store(0);
+ _delete->store(0);
+ _getmore->store(0);
+ _command->store(0);
+
+ _insertDeprecated->store(0);
+ _queryDeprecated->store(0);
+ _updateDeprecated->store(0);
+ _deleteDeprecated->store(0);
+ _getmoreDeprecated->store(0);
+ _killcursorsDeprecated->store(0);
}
}
BSONObj OpCounters::getObj() const {
BSONObjBuilder b;
- b.append("insert", _insert.loadRelaxed());
- b.append("query", _query.loadRelaxed());
- b.append("update", _update.loadRelaxed());
- b.append("delete", _delete.loadRelaxed());
- b.append("getmore", _getmore.loadRelaxed());
- b.append("command", _command.loadRelaxed());
-
- auto queryDep = _queryDeprecated.loadRelaxed();
- auto getmoreDep = _getmoreDeprecated.loadRelaxed();
- auto killcursorsDep = _killcursorsDeprecated.loadRelaxed();
- auto updateDep = _updateDeprecated.loadRelaxed();
- auto deleteDep = _deleteDeprecated.loadRelaxed();
- auto insertDep = _insertDeprecated.loadRelaxed();
+ b.append("insert", _insert->loadRelaxed());
+ b.append("query", _query->loadRelaxed());
+ b.append("update", _update->loadRelaxed());
+ b.append("delete", _delete->loadRelaxed());
+ b.append("getmore", _getmore->loadRelaxed());
+ b.append("command", _command->loadRelaxed());
+
+ auto queryDep = _queryDeprecated->loadRelaxed();
+ auto getmoreDep = _getmoreDeprecated->loadRelaxed();
+ auto killcursorsDep = _killcursorsDeprecated->loadRelaxed();
+ auto updateDep = _updateDeprecated->loadRelaxed();
+ auto deleteDep = _deleteDeprecated->loadRelaxed();
+ auto insertDep = _insertDeprecated->loadRelaxed();
auto totalDep = queryDep + getmoreDep + killcursorsDep + updateDep + deleteDep + insertDep;
if (totalDep > 0) {
@@ -101,12 +101,12 @@ void NetworkCounter::hitPhysicalIn(long long bytes) {
static const int64_t MAX = 1ULL << 60;
// don't care about the race as its just a counter
- const bool overflow = _physicalBytesIn.loadRelaxed() > MAX;
+ const bool overflow = _physicalBytesIn->loadRelaxed() > MAX;
if (overflow) {
- _physicalBytesIn.store(bytes);
+ _physicalBytesIn->store(bytes);
} else {
- _physicalBytesIn.fetchAndAdd(bytes);
+ _physicalBytesIn->fetchAndAdd(bytes);
}
}
@@ -114,12 +114,12 @@ void NetworkCounter::hitPhysicalOut(long long bytes) {
static const int64_t MAX = 1ULL << 60;
// don't care about the race as its just a counter
- const bool overflow = _physicalBytesOut.loadRelaxed() > MAX;
+ const bool overflow = _physicalBytesOut->loadRelaxed() > MAX;
if (overflow) {
- _physicalBytesOut.store(bytes);
+ _physicalBytesOut->store(bytes);
} else {
- _physicalBytesOut.fetchAndAdd(bytes);
+ _physicalBytesOut->fetchAndAdd(bytes);
}
}
@@ -127,17 +127,17 @@ void NetworkCounter::hitLogicalIn(long long bytes) {
static const int64_t MAX = 1ULL << 60;
// don't care about the race as its just a counter
- const bool overflow = _together.logicalBytesIn.loadRelaxed() > MAX;
+ const bool overflow = _together->logicalBytesIn.loadRelaxed() > MAX;
if (overflow) {
- _together.logicalBytesIn.store(bytes);
+ _together->logicalBytesIn.store(bytes);
// The requests field only gets incremented here (and not in hitPhysical) because the
// hitLogical and hitPhysical are each called for each operation. Incrementing it in both
// functions would double-count the number of operations.
- _together.requests.store(1);
+ _together->requests.store(1);
} else {
- _together.logicalBytesIn.fetchAndAdd(bytes);
- _together.requests.fetchAndAdd(1);
+ _together->logicalBytesIn.fetchAndAdd(bytes);
+ _together->requests.fetchAndAdd(1);
}
}
@@ -145,43 +145,43 @@ void NetworkCounter::hitLogicalOut(long long bytes) {
static const int64_t MAX = 1ULL << 60;
// don't care about the race as its just a counter
- const bool overflow = _logicalBytesOut.loadRelaxed() > MAX;
+ const bool overflow = _logicalBytesOut->loadRelaxed() > MAX;
if (overflow) {
- _logicalBytesOut.store(bytes);
+ _logicalBytesOut->store(bytes);
} else {
- _logicalBytesOut.fetchAndAdd(bytes);
+ _logicalBytesOut->fetchAndAdd(bytes);
}
}
void NetworkCounter::incrementNumSlowDNSOperations() {
- _numSlowDNSOperations.fetchAndAdd(1);
+ _numSlowDNSOperations->fetchAndAdd(1);
}
void NetworkCounter::incrementNumSlowSSLOperations() {
- _numSlowSSLOperations.fetchAndAdd(1);
+ _numSlowSSLOperations->fetchAndAdd(1);
}
void NetworkCounter::acceptedTFOIngress() {
- _tfo.accepted.fetchAndAddRelaxed(1);
+ _tfo->accepted.fetchAndAddRelaxed(1);
}
void NetworkCounter::append(BSONObjBuilder& b) {
- b.append("bytesIn", static_cast<long long>(_together.logicalBytesIn.loadRelaxed()));
- b.append("bytesOut", static_cast<long long>(_logicalBytesOut.loadRelaxed()));
- b.append("physicalBytesIn", static_cast<long long>(_physicalBytesIn.loadRelaxed()));
- b.append("physicalBytesOut", static_cast<long long>(_physicalBytesOut.loadRelaxed()));
- b.append("numSlowDNSOperations", static_cast<long long>(_numSlowDNSOperations.loadRelaxed()));
- b.append("numSlowSSLOperations", static_cast<long long>(_numSlowSSLOperations.loadRelaxed()));
- b.append("numRequests", static_cast<long long>(_together.requests.loadRelaxed()));
+ b.append("bytesIn", static_cast<long long>(_together->logicalBytesIn.loadRelaxed()));
+ b.append("bytesOut", static_cast<long long>(_logicalBytesOut->loadRelaxed()));
+ b.append("physicalBytesIn", static_cast<long long>(_physicalBytesIn->loadRelaxed()));
+ b.append("physicalBytesOut", static_cast<long long>(_physicalBytesOut->loadRelaxed()));
+ b.append("numSlowDNSOperations", static_cast<long long>(_numSlowDNSOperations->loadRelaxed()));
+ b.append("numSlowSSLOperations", static_cast<long long>(_numSlowSSLOperations->loadRelaxed()));
+ b.append("numRequests", static_cast<long long>(_together->requests.loadRelaxed()));
BSONObjBuilder tfo;
#ifdef __linux__
- tfo.append("kernelSetting", _tfo.kernelSetting);
+ tfo.append("kernelSetting", _tfo->kernelSetting);
#endif
- tfo.append("serverSupported", _tfo.kernelSupportServer);
- tfo.append("clientSupported", _tfo.kernelSupportClient);
- tfo.append("accepted", _tfo.accepted.loadRelaxed());
+ tfo.append("serverSupported", _tfo->kernelSupportServer);
+ tfo.append("clientSupported", _tfo->kernelSupportClient);
+ tfo.append("accepted", _tfo->accepted.loadRelaxed());
b.append("tcpFastOpen", tfo.obj());
}
diff --git a/src/mongo/db/stats/counters.h b/src/mongo/db/stats/counters.h
index 18e39b1366a..bec806d7005 100644
--- a/src/mongo/db/stats/counters.h
+++ b/src/mongo/db/stats/counters.h
@@ -36,10 +36,10 @@
#include "mongo/platform/atomic_word.h"
#include "mongo/platform/basic.h"
#include "mongo/rpc/message.h"
+#include "mongo/util/aligned.h"
#include "mongo/util/concurrency/spin_lock.h"
#include "mongo/util/processinfo.h"
#include "mongo/util/string_map.h"
-#include "mongo/util/with_alignment.h"
namespace mongo {
@@ -114,37 +114,37 @@ public:
// thse are used by snmp, and other things, do not remove
const AtomicWord<long long>* getInsert() const {
- return &_insert;
+ return &*_insert;
}
const AtomicWord<long long>* getQuery() const {
- return &_query;
+ return &*_query;
}
const AtomicWord<long long>* getUpdate() const {
- return &_update;
+ return &*_update;
}
const AtomicWord<long long>* getDelete() const {
- return &_delete;
+ return &*_delete;
}
const AtomicWord<long long>* getGetMore() const {
- return &_getmore;
+ return &*_getmore;
}
const AtomicWord<long long>* getCommand() const {
- return &_command;
+ return &*_command;
}
const AtomicWord<long long>* getInsertOnExistingDoc() const {
- return &_insertOnExistingDoc;
+ return &*_insertOnExistingDoc;
}
const AtomicWord<long long>* getUpdateOnMissingDoc() const {
- return &_updateOnMissingDoc;
+ return &*_updateOnMissingDoc;
}
const AtomicWord<long long>* getDeleteWasEmpty() const {
- return &_deleteWasEmpty;
+ return &*_deleteWasEmpty;
}
const AtomicWord<long long>* getDeleteFromMissingNamespace() const {
- return &_deleteFromMissingNamespace;
+ return &*_deleteFromMissingNamespace;
}
const AtomicWord<long long>* getAcceptableErrorInCommand() const {
- return &_acceptableErrorInCommand;
+ return &*_acceptableErrorInCommand;
}
private:
@@ -197,15 +197,15 @@ public:
void acceptedTFOIngress();
void setTFOKernelSetting(std::int64_t val) {
- _tfo.kernelSetting = val;
+ _tfo->kernelSetting = val;
}
void setTFOServerSupport(bool val) {
- _tfo.kernelSupportServer = val;
+ _tfo->kernelSupportServer = val;
}
void setTFOClientSupport(bool val) {
- _tfo.kernelSupportClient = val;
+ _tfo->kernelSupportClient = val;
}
void append(BSONObjBuilder& b);
diff --git a/src/mongo/stdx/new.h b/src/mongo/stdx/new.h
index 1219454df11..11dfd48179f 100644
--- a/src/mongo/stdx/new.h
+++ b/src/mongo/stdx/new.h
@@ -29,11 +29,13 @@
#pragma once
-#include "mongo/config.h"
-
#include <cstddef>
+#include <cstdint>
#include <new>
+#include "mongo/config.h"
+#include "mongo/platform/compiler.h"
+
namespace mongo {
namespace stdx {
@@ -42,7 +44,8 @@ namespace stdx {
!(defined(__cpp_lib_hardware_interference_size) && !defined(_LIBCPP_VERSION))
#if defined(MONGO_CONFIG_MAX_EXTENDED_ALIGNMENT)
-static_assert(MONGO_CONFIG_MAX_EXTENDED_ALIGNMENT >= sizeof(uint64_t), "Bad extended alignment");
+static_assert(MONGO_CONFIG_MAX_EXTENDED_ALIGNMENT >= sizeof(std::uint64_t),
+ "Bad extended alignment");
constexpr std::size_t hardware_destructive_interference_size = MONGO_CONFIG_MAX_EXTENDED_ALIGNMENT;
#else
constexpr std::size_t hardware_destructive_interference_size = alignof(std::max_align_t);
@@ -55,7 +58,16 @@ constexpr auto hardware_constructive_interference_size = hardware_destructive_in
using std::hardware_constructive_interference_size;
using std::hardware_destructive_interference_size;
-#endif
+#endif // hardware_interference_size
+
+#if __cpp_lib_launder >= 201606
+using std::launder;
+#else
+template <typename T>
+MONGO_WARN_UNUSED_RESULT_FUNCTION constexpr T* launder(T* p) noexcept {
+ return p;
+}
+#endif // launder
} // namespace stdx
} // namespace mongo
diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript
index 32beff83c2c..3196846636f 100644
--- a/src/mongo/util/SConscript
+++ b/src/mongo/util/SConscript
@@ -622,6 +622,7 @@ icuEnv.CppUnitTest(
target='util_test',
source=[
'alarm_test.cpp',
+ 'aligned_test.cpp',
'assert_util_test.cpp',
'background_job_test.cpp',
'background_thread_clock_source_test.cpp',
diff --git a/src/mongo/util/aligned.h b/src/mongo/util/aligned.h
new file mode 100644
index 00000000000..bdab7f8cac1
--- /dev/null
+++ b/src/mongo/util/aligned.h
@@ -0,0 +1,137 @@
+/**
+ * Copyright (C) 2021-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <new>
+#include <type_traits>
+
+#include "mongo/stdx/new.h"
+
+namespace mongo {
+
+/**
+ * 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.
+ */
+template <typename T, size_t MinAlign>
+class Aligned {
+public:
+ using value_type = T;
+ static constexpr size_t alignment = std::max(alignof(T), MinAlign);
+
+ template <typename... As>
+ explicit Aligned(As&&... args) noexcept(std::is_nothrow_constructible_v<value_type, As&&...>) {
+ new (_raw()) value_type(std::forward<As>(args)...);
+ }
+
+ Aligned(const Aligned& that) noexcept(std::is_nothrow_copy_constructible_v<value_type>) {
+ new (_raw()) value_type(*that);
+ }
+
+ Aligned& operator=(const Aligned& that) noexcept(
+ std::is_nothrow_copy_assignable_v<value_type>) {
+ if (this != &that)
+ **this = *that;
+ return *this;
+ }
+
+ Aligned(Aligned&& that) noexcept(std::is_nothrow_move_constructible_v<value_type>) {
+ new (_raw()) value_type(std::move(*that));
+ }
+
+ Aligned& operator=(Aligned&& that) noexcept(std::is_nothrow_move_assignable_v<value_type>) {
+ if (this != &that)
+ **this = std::move(*that);
+ return *this;
+ }
+
+ ~Aligned() {
+ _value().~value_type();
+ }
+
+ const value_type& operator*() const& noexcept {
+ return _value();
+ }
+
+ value_type& operator*() & noexcept {
+ return _value();
+ }
+
+ value_type&& operator*() && noexcept {
+ return std::move(_value());
+ }
+
+ const value_type* operator->() const noexcept {
+ return &_value();
+ }
+
+ value_type* operator->() noexcept {
+ return &_value();
+ }
+
+private:
+ 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);
+ }
+
+ value_type* _raw() noexcept {
+ return reinterpret_cast<value_type*>(&_storage);
+ }
+
+ const value_type& _value() const noexcept {
+ return *stdx::launder(_raw());
+ }
+
+ value_type& _value() noexcept {
+ return *stdx::launder(_raw());
+ }
+
+ std::aligned_storage_t<sizeof(value_type), alignment> _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
+ */
+template <typename T, size_t MinAlign>
+void swap(Aligned<T, MinAlign>& a,
+ Aligned<T, MinAlign>& b) noexcept(std::is_nothrow_swappable_v<T>) {
+ using std::swap;
+ swap(*a, *b);
+}
+
+template <typename T>
+using CacheAligned = Aligned<T, stdx::hardware_destructive_interference_size>;
+
+} // namespace mongo
diff --git a/src/mongo/util/aligned_test.cpp b/src/mongo/util/aligned_test.cpp
new file mode 100644
index 00000000000..2304877150c
--- /dev/null
+++ b/src/mongo/util/aligned_test.cpp
@@ -0,0 +1,114 @@
+/**
+ * Copyright (C) 2021-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/util/aligned.h"
+
+#include <utility>
+
+#include "mongo/base/static_assert.h"
+#include "mongo/unittest/unittest.h"
+
+namespace mongo {
+namespace {
+
+struct MoveOnly {
+ static constexpr int kEmpty = -1;
+
+ MoveOnly() = default;
+ explicit MoveOnly(int val) : val(val) {}
+
+ MoveOnly(const MoveOnly&) = delete;
+ MoveOnly& operator=(const MoveOnly& that) = delete;
+
+ MoveOnly(MoveOnly&& that) : val{std::exchange(that.val, kEmpty)} {}
+ MoveOnly& operator=(MoveOnly&& that) {
+ val = std::exchange(that.val, kEmpty);
+ return *this;
+ }
+
+ int val = 12345;
+};
+
+struct Final final {};
+MONGO_STATIC_ASSERT(alignof(Aligned<Final, 1>) == 1);
+
+MONGO_STATIC_ASSERT(alignof(Aligned<char, 1>) == 1);
+MONGO_STATIC_ASSERT(alignof(Aligned<char, 2>) == 2);
+MONGO_STATIC_ASSERT(alignof(Aligned<char, 4>) == 4);
+MONGO_STATIC_ASSERT(alignof(Aligned<char, 8>) == 8);
+MONGO_STATIC_ASSERT(alignof(Aligned<char, 16>) == 16);
+MONGO_STATIC_ASSERT(alignof(Aligned<char, 32>) == 32);
+
+MONGO_STATIC_ASSERT(alignof(Aligned<uint64_t, 8>) == 8);
+MONGO_STATIC_ASSERT(alignof(Aligned<uint64_t, 16>) == 16);
+MONGO_STATIC_ASSERT(alignof(Aligned<uint64_t, 32>) == 32);
+
+
+TEST(Aligned, ConstructorForwarding) {
+ struct NeedsArg {
+ explicit NeedsArg(int v) : v(v) {}
+ int v;
+ };
+ Aligned<NeedsArg, sizeof(NeedsArg)> a{123};
+ ASSERT_EQ(a->v, 123);
+};
+
+TEST(Aligned, MoveConstruct) {
+ Aligned<MoveOnly, sizeof(MoveOnly)> m1{1};
+ Aligned<MoveOnly, sizeof(MoveOnly)> m2{std::move(m1)};
+ ASSERT_EQ(m1->val, MoveOnly::kEmpty); // NOLINT(bugprone-use-after-move)
+ ASSERT_EQ(m2->val, 1);
+}
+
+TEST(Aligned, MoveAssign) {
+ Aligned<MoveOnly, sizeof(MoveOnly)> m1{111};
+ Aligned<MoveOnly, sizeof(MoveOnly)> m2{222};
+ auto&& ret = (m2 = std::move(m1));
+ ASSERT(&ret == &m2);
+ ASSERT_EQ(m1->val, MoveOnly::kEmpty); // NOLINT(bugprone-use-after-move)
+ ASSERT_EQ(m2->val, 111);
+}
+
+TEST(Aligned, Swap) {
+ Aligned<MoveOnly, sizeof(MoveOnly)> m1{111};
+ Aligned<MoveOnly, sizeof(MoveOnly)> m2{222};
+ using std::swap;
+ swap(m1, m2);
+ ASSERT_EQ(m1->val, 222);
+ ASSERT_EQ(m2->val, 111);
+}
+
+TEST(CacheAligned, 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);
+}
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/util/with_alignment.h b/src/mongo/util/with_alignment.h
deleted file mode 100644
index 8d207d94687..00000000000
--- a/src/mongo/util/with_alignment.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <algorithm>
-
-#include "mongo/stdx/new.h"
-
-namespace mongo {
-
-/**
- * Creates a new type with the same interface as T, but having the
- * given alignment. Note that if the given alignment is less than
- * alignof(T), the program is ill-formed. To ensure that your program
- * is well formed, see WithAligmentAtLeast, which will not reduce
- * alignment below the natural alignment of T.
- */
-template <typename T, size_t alignment>
-struct alignas(alignment) WithAlignment : T {
- using T::T;
-};
-
-/**
- * Creates a new type with the same interface as T, but having an
- * alignment greater than or equal to the given alignment. To ensure
- * that the program remains well formed, the alignment will not be
- * reduced below the natural alignment for T.
- */
-template <typename T, size_t alignment>
-using WithAlignmentAtLeast = WithAlignment<T, std::max(alignof(T), alignment)>;
-
-/**
- * Creates a new type with the same interface as T but guaranteed to
- * be aligned to at least the size of a cache line.
- */
-template <typename T>
-using CacheAligned = WithAlignmentAtLeast<T, stdx::hardware_destructive_interference_size>;
-
-} // namespace mongo