summaryrefslogtreecommitdiff
path: root/src/mongo/db/sorter
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
commit4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch)
tree1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/db/sorter
parentaa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff)
parent8f0827553e09872941945a093b647a4211a9db7f (diff)
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0' with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/db/sorter')
-rw-r--r--src/mongo/db/sorter/SConscript9
-rw-r--r--src/mongo/db/sorter/sorter.cpp107
-rw-r--r--src/mongo/db/sorter/sorter.h82
-rw-r--r--src/mongo/db/sorter/sorter_stats.cpp64
-rw-r--r--src/mongo/db/sorter/sorter_stats.h80
-rw-r--r--src/mongo/db/sorter/sorter_stats_test.cpp68
-rw-r--r--src/mongo/db/sorter/sorter_test.cpp158
7 files changed, 112 insertions, 456 deletions
diff --git a/src/mongo/db/sorter/SConscript b/src/mongo/db/sorter/SConscript
index a560eac0642..ae8184f222d 100644
--- a/src/mongo/db/sorter/SConscript
+++ b/src/mongo/db/sorter/SConscript
@@ -9,7 +9,6 @@ sorterEnv.CppUnitTest(
target='db_sorter_test',
source=[
'sorter_test.cpp',
- 'sorter_stats_test.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/exec/document_value/document_value',
@@ -19,16 +18,9 @@ sorterEnv.CppUnitTest(
'$BUILD_DIR/mongo/s/is_mongos',
'$BUILD_DIR/third_party/shim_snappy',
'sorter_idl',
- 'sorter_stats',
],
)
-sorterEnv.Library(target='sorter_stats', source=[
- 'sorter_stats.cpp',
-], LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/commands/server_status_core',
-])
-
env.Library(
target='sorter_idl',
source=[
@@ -36,7 +28,6 @@ env.Library(
],
LIBDEPS=[
"$BUILD_DIR/mongo/base",
- '$BUILD_DIR/mongo/db/sorter/sorter_stats',
'$BUILD_DIR/mongo/idl/idl_parser',
]
)
diff --git a/src/mongo/db/sorter/sorter.cpp b/src/mongo/db/sorter/sorter.cpp
index ce460b0fc89..db53ed53a1a 100644
--- a/src/mongo/db/sorter/sorter.cpp
+++ b/src/mongo/db/sorter/sorter.cpp
@@ -58,13 +58,11 @@
#include "mongo/db/service_context.h"
#include "mongo/db/storage/encryption_hooks.h"
#include "mongo/db/storage/storage_options.h"
-#include "mongo/db/storage/storage_parameters_gen.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/platform/overflow_arithmetic.h"
#include "mongo/s/is_mongos.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/destructor_guard.h"
-#include "mongo/util/file.h"
#include "mongo/util/str.h"
// As this file is included in various places we need to handle the case of having the log header
@@ -606,6 +604,7 @@ protected:
* following:
*
* {1, 2, 3, 4, 5}
+ * {12, 3, 4, 5}
* {12, 34, 5}
* {1234, 5}
*/
@@ -655,7 +654,7 @@ protected:
auto iteratorPtr = std::shared_ptr<Iterator>(writer.done());
mergeIterator->closeSource();
mergedIterators.push_back(std::move(iteratorPtr));
- this->_stats.incrementSpilledRanges();
+ this->_numSpills++;
}
LOGV2_DEBUG(6033101,
@@ -716,7 +715,7 @@ public:
this->_opts.dbName,
range.getChecksum());
});
- this->_stats.setSpilledRanges(this->_iters.size());
+ this->_numSpills = this->_iters.size();
}
void add(const Key& key, const Value& val) {
@@ -724,24 +723,12 @@ public:
_data.emplace_back(key.getOwned(), val.getOwned());
- auto& memPool = this->_memPool;
- if (memPool) {
- auto memUsedInsideSorter = (sizeof(Key) + sizeof(Value)) * (_data.size() + 1);
- _memUsed = memPool->memUsage() + memUsedInsideSorter;
- this->_totalDataSizeSorted = _memUsed;
- } else {
- auto memUsage = key.memUsageForSorter() + val.memUsageForSorter();
- _memUsed += memUsage;
- this->_totalDataSizeSorted += memUsage;
- }
+ auto memUsage = key.memUsageForSorter() + val.memUsageForSorter();
+ _memUsed += memUsage;
+ this->_totalDataSizeSorted += memUsage;
- if (_memUsed > this->_opts.maxMemoryUsageBytes) {
+ if (_memUsed > this->_opts.maxMemoryUsageBytes)
spill();
- if (memPool) {
- // We expect that all buffers are unused at this point.
- memPool->freeUnused();
- }
- }
}
void emplace(Key&& key, Value&& val) override {
@@ -820,7 +807,7 @@ private:
_memUsed = 0;
- this->_stats.incrementSpilledRanges();
+ this->_numSpills++;
}
bool _done = false;
@@ -837,7 +824,7 @@ public:
typedef SortIteratorInterface<Key, Value> Iterator;
LimitOneSorter(const SortOptions& opts, const Comparator& comp)
- : Sorter<Key, Value>(opts), _comp(comp), _haveData(false) {
+ : _comp(comp), _haveData(false) {
verify(opts.limit == 1);
}
@@ -1107,7 +1094,7 @@ private:
_memUsed = 0;
- this->_stats.incrementSpilledRanges();
+ this->_numSpills++;
}
bool _done = false;
@@ -1127,39 +1114,21 @@ private:
} // namespace sorter
-namespace {
-SharedBufferFragmentBuilder makeMemPool() {
- return SharedBufferFragmentBuilder(
- gOperationMemoryPoolBlockInitialSizeKB.loadRelaxed() * static_cast<size_t>(1024),
- SharedBufferFragmentBuilder::DoubleGrowStrategy(
- gOperationMemoryPoolBlockMaxSizeKB.loadRelaxed() * static_cast<size_t>(1024)));
-}
-} // namespace
-
template <typename Key, typename Value>
Sorter<Key, Value>::Sorter(const SortOptions& opts)
- : SorterBase(opts.sorterTracker),
- _opts(opts),
+ : _opts(opts),
_file(opts.extSortAllowed ? std::make_shared<Sorter<Key, Value>::File>(
opts.tempDir + "/" + nextFileName(), opts.sorterFileStats)
- : nullptr) {
- if (opts.useMemPool) {
- _memPool.emplace(makeMemPool());
- }
-}
+ : nullptr) {}
template <typename Key, typename Value>
Sorter<Key, Value>::Sorter(const SortOptions& opts, const std::string& fileName)
- : SorterBase(opts.sorterTracker),
- _opts(opts),
+ : _opts(opts),
_file(std::make_shared<Sorter<Key, Value>::File>(opts.tempDir + "/" + fileName,
opts.sorterFileStats)) {
invariant(opts.extSortAllowed);
invariant(!opts.tempDir.empty());
invariant(!fileName.empty());
- if (opts.useMemPool) {
- _memPool.emplace(makeMemPool());
- }
}
template <typename Key, typename Value>
@@ -1177,32 +1146,12 @@ typename Sorter<Key, Value>::PersistedState Sorter<Key, Value>::persistDataForSh
}
template <typename Key, typename Value>
-Sorter<Key, Value>::File::File(std::string path, SorterFileStats* stats)
- : _path(std::move(path)), _stats(stats) {
- invariant(!_path.empty());
- if (_stats && boost::filesystem::exists(_path) && boost::filesystem::is_regular_file(_path)) {
- _stats->addSpilledDataSize(boost::filesystem::file_size(_path));
- }
-}
-
-template <typename Key, typename Value>
Sorter<Key, Value>::File::~File() {
if (_stats && _file.is_open()) {
_stats->closed.addAndFetch(1);
}
if (_keep) {
- if (!_file.is_open()) {
- return;
- }
- DESTRUCTOR_GUARD(_file.flush());
-
- mongo::File fileForFsync;
- fileForFsync.open(_path.string().c_str());
- if (fileForFsync.is_open()) {
- fileForFsync.fsync();
- }
-
return;
}
@@ -1257,9 +1206,6 @@ void Sorter<Key, Value>::File::write(const char* data, std::streamsize size) {
try {
_file.write(data, size);
_offset += size;
- if (_stats) {
- this->_stats->addSpilledDataSize(size);
- };
} catch (const std::system_error& ex) {
if (ex.code() == std::errc::no_space_on_device) {
uasserted(ErrorCodes::OutOfDiskSpace,
@@ -1329,7 +1275,7 @@ SortedFileWriter<Key, Value>::SortedFileWriter(
: _settings(settings),
_file(std::move(file)),
_fileStartOffset(_file->currentOffset()),
- _opts(opts) {
+ _dbName(opts.dbName) {
// This should be checked by consumers, but if we get here don't allow writes.
uassert(
16946, "Attempting to use external sort from mongos. This is not allowed.", !isMongos());
@@ -1366,10 +1312,6 @@ void SortedFileWriter<Key, Value>::spill() {
if (size == 0)
return;
- if (_opts.sorterFileStats) {
- _opts.sorterFileStats->addSpilledDataSizeUncompressed(size);
- }
-
std::string compressed;
snappy::Compress(outBuffer, size, &compressed);
verify(compressed.size() <= size_t(std::numeric_limits<int32_t>::max()));
@@ -1390,7 +1332,7 @@ void SortedFileWriter<Key, Value>::spill() {
reinterpret_cast<uint8_t*>(out.get()),
protectedSizeMax,
&resultLen,
- _opts.dbName);
+ _dbName);
uassert(28842,
str::stream() << "Failed to compress data: " << status.toString(),
status.isOK());
@@ -1411,7 +1353,7 @@ SortIteratorInterface<Key, Value>* SortedFileWriter<Key, Value>::done() {
spill();
return new sorter::FileIterator<Key, Value>(
- _file, _fileStartOffset, _file->currentOffset(), _settings, _opts.dbName, _checksum);
+ _file, _fileStartOffset, _file->currentOffset(), _settings, _dbName, _checksum);
}
template <typename Key, typename Value, typename Comparator, typename BoundMaker>
@@ -1419,8 +1361,7 @@ BoundedSorter<Key, Value, Comparator, BoundMaker>::BoundedSorter(const SortOptio
Comparator comp,
BoundMaker makeBound,
bool checkInput)
- : BoundedSorterInterface<Key, Value>(opts),
- compare(comp),
+ : compare(comp),
makeBound(makeBound),
_comparePairs{compare},
_checkInput(checkInput),
@@ -1435,8 +1376,7 @@ void BoundedSorter<Key, Value, Comparator, BoundMaker>::add(Key key, Value value
invariant(!_done);
// If a new value violates what we thought was our min bound, something has gone wrong.
uassert(6369910,
- str::stream() << "BoundedSorter input is too out-of-order: with bound "
- << _min->toString() << ", did not expect input " << key.toString(),
+ "BoundedSorter input is too out-of-order.",
!_checkInput || !_min || compare(*_min, key) <= 0);
// Each new item can potentially give us a tighter bound (a higher min).
@@ -1521,11 +1461,10 @@ std::pair<Key, Value> BoundedSorter<Key, Value, Comparator, BoundMaker>::next()
_heap.pop();
auto memUsage = result.first.memUsageForSorter() + result.second.memUsageForSorter();
- if (static_cast<int64_t>(memUsage) > static_cast<int64_t>(_memUsed)) {
- _memUsed = 0;
- } else {
- _memUsed -= memUsage;
- }
+ tassert(6409301,
+ "Memory usage for BoundedSorter is invalid",
+ memUsage >= 0 && static_cast<size_t>(memUsage) <= _memUsed);
+ _memUsed -= memUsage;
};
auto pullFromSpilled = [this, &result]() {
@@ -1580,7 +1519,7 @@ void BoundedSorter<Key, Value, Comparator, BoundMaker>::_spill() {
<< " bytes, but did not opt in to external sorting.",
_opts.extSortAllowed);
- this->_stats.incrementSpilledRanges();
+ ++_numSpills;
// Write out all the values from the heap in sorted order.
SortedFileWriter<Key, Value> writer(_opts, _file, {});
diff --git a/src/mongo/db/sorter/sorter.h b/src/mongo/db/sorter/sorter.h
index 059d7b72f46..12bccee1178 100644
--- a/src/mongo/db/sorter/sorter.h
+++ b/src/mongo/db/sorter/sorter.h
@@ -42,9 +42,7 @@
#include "mongo/bson/util/builder.h"
#include "mongo/db/exec/document_value/document.h"
-#include "mongo/db/query/query_shape/serialization_options.h"
#include "mongo/db/sorter/sorter_gen.h"
-#include "mongo/db/sorter/sorter_stats.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/bufreader.h"
@@ -98,6 +96,14 @@
namespace mongo {
/**
+ * For collecting file usage metrics.
+ */
+struct SorterFileStats {
+ AtomicWord<long long> opened;
+ AtomicWord<long long> closed;
+};
+
+/**
* Runtime options that control the Sorter's behavior
*/
struct SortOptions {
@@ -124,14 +130,6 @@ struct SortOptions {
// If set, allows us to observe Sorter file handle usage.
SorterFileStats* sorterFileStats;
- // If set, allows us to observe aggregate Sorter behaviors.
- SorterTracker* sorterTracker;
-
- // When set, this sorter will own a memory pool that callers should used to allocate memory for
- // the keys we are sorting. If enabled, any values returned by memUsageForSorter() will be
- // ignored.
- bool useMemPool;
-
// If set to true and sorted data fits into memory, sorted data will be moved into iterator
// instead of copying.
bool moveSortedDataIntoIterator;
@@ -141,8 +139,6 @@ struct SortOptions {
maxMemoryUsageBytes(64 * 1024 * 1024),
extSortAllowed(false),
sorterFileStats(nullptr),
- sorterTracker(nullptr),
- useMemPool(false),
moveSortedDataIntoIterator(false) {}
// Fluent API to support expressions like SortOptions().Limit(1000).ExtSortAllowed(true)
@@ -177,20 +173,10 @@ struct SortOptions {
return *this;
}
- SortOptions& Tracker(SorterTracker* newSorterTracker) {
- sorterTracker = newSorterTracker;
- return *this;
- }
-
SortOptions& MoveSortedDataIntoIterator(bool newMoveSortedDataIntoIterator = true) {
moveSortedDataIntoIterator = newMoveSortedDataIntoIterator;
return *this;
}
-
- SortOptions& UseMemoryPool(bool usePool) {
- useMemPool = usePool;
- return *this;
- }
};
/**
@@ -255,18 +241,6 @@ protected:
SortIteratorInterface() {} // can only be constructed as a base
};
-class SorterBase {
-public:
- SorterBase(SorterTracker* sorterTracker = nullptr) : _stats(sorterTracker) {}
-
- const SorterStats& stats() const {
- return _stats;
- }
-
-protected:
- SorterStats _stats;
-};
-
/**
* This is the way to input data to the sorting framework.
*
@@ -283,7 +257,7 @@ protected:
* nextFileName() for example.
*/
template <typename Key, typename Value>
-class Sorter : public SorterBase {
+class Sorter {
Sorter(const Sorter&) = delete;
Sorter& operator=(const Sorter&) = delete;
@@ -305,7 +279,10 @@ public:
*/
class File {
public:
- File(std::string path, SorterFileStats* stats = nullptr);
+ File(std::string path, SorterFileStats* stats = nullptr)
+ : _path(std::move(path)), _stats(stats) {
+ invariant(!_path.empty());
+ }
~File();
@@ -388,6 +365,10 @@ public:
virtual ~Sorter() {}
+ size_t numSpills() const {
+ return _numSpills;
+ }
+
size_t numSorted() const {
return _numSorted;
}
@@ -398,12 +379,9 @@ public:
PersistedState persistDataForShutdown();
- SharedBufferFragmentBuilder& memPool() {
- invariant(_memPool);
- return _memPool.get();
- }
-
protected:
+ Sorter() {} // can only be constructed as a base
+
virtual void spill() = 0;
size_t _numSorted = 0; // Keeps track of the number of keys sorted.
@@ -413,18 +391,14 @@ protected:
std::shared_ptr<File> _file;
+ std::size_t _numSpills = 0; // Keeps track of the number of spills that have happened.
std::vector<std::shared_ptr<Iterator>> _iters; // Data that has already been spilled.
-
- boost::optional<SharedBufferFragmentBuilder> _memPool;
};
template <typename Key, typename Value>
-class BoundedSorterInterface : public SorterBase {
-
+class BoundedSorterInterface {
public:
- BoundedSorterInterface(const SortOptions& opts) : SorterBase(opts.sorterTracker) {}
-
virtual ~BoundedSorterInterface() {}
// Feed one item of input to the sorter.
@@ -462,9 +436,10 @@ public:
virtual std::pair<Key, Value> next() = 0;
// Serialize the bound for explain output
- virtual Document serializeBound(const SerializationOptions& opts) const = 0;
+ virtual Document serializeBound() const = 0;
virtual size_t totalDataSizeBytes() const = 0;
+ virtual size_t numSpills() const = 0;
virtual size_t limit() const = 0;
// By default, uassert that the input meets our assumptions of being almost-sorted.
@@ -542,14 +517,18 @@ public:
std::pair<Key, Value> next();
// Serialize the bound for explain output
- Document serializeBound(const SerializationOptions& opts) const {
- return {makeBound.serialize(opts)};
+ Document serializeBound() const {
+ return {makeBound.serialize()};
};
size_t totalDataSizeBytes() const {
return _totalDataSizeSorted;
}
+ size_t numSpills() const {
+ return _numSpills;
+ }
+
size_t limit() const {
return _opts.limit;
}
@@ -584,6 +563,7 @@ private:
std::shared_ptr<typename Sorter<Key, Value>::File> _file;
std::shared_ptr<SpillIterator> _spillIter;
+ std::size_t _numSpills = 0; // Keeps track of the number of spills that have happened.
boost::optional<Key> _min;
bool _done = false;
@@ -634,7 +614,7 @@ private:
// be given to the Iterator in done().
std::streamoff _fileStartOffset;
- SortOptions _opts;
+ boost::optional<std::string> _dbName;
};
} // namespace mongo
diff --git a/src/mongo/db/sorter/sorter_stats.cpp b/src/mongo/db/sorter/sorter_stats.cpp
deleted file mode 100644
index d651c4d70ad..00000000000
--- a/src/mongo/db/sorter/sorter_stats.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Copyright (C) 2022-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/db/sorter/sorter_stats.h"
-
-#include "mongo/util/assert_util_core.h"
-
-namespace mongo {
-SorterStats::SorterStats(SorterTracker* sorterTracker) : _sorterTracker(sorterTracker){};
-
-void SorterStats::incrementSpilledRanges() {
- _spilledRanges++;
- if (_sorterTracker) {
- _sorterTracker->spilledRanges.fetchAndAdd(1);
- }
-}
-
-void SorterStats::setSpilledRanges(long long spills) {
- invariant(_spilledRanges == 0);
- _spilledRanges = spills;
- if (_sorterTracker) {
- _sorterTracker->spilledRanges.fetchAndAdd(spills);
- }
-}
-
-SorterFileStats::SorterFileStats(SorterTracker* sorterTracker) : _sorterTracker(sorterTracker){};
-
-void SorterFileStats::addSpilledDataSize(long long data) {
- if (_sorterTracker) {
- _sorterTracker->bytesSpilled.fetchAndAdd(data);
- }
-}
-void SorterFileStats::addSpilledDataSizeUncompressed(long long data) {
- if (_sorterTracker) {
- _sorterTracker->bytesSpilledUncompressed.fetchAndAdd(data);
- }
-}
-} // namespace mongo
diff --git a/src/mongo/db/sorter/sorter_stats.h b/src/mongo/db/sorter/sorter_stats.h
deleted file mode 100644
index 5df022a6b3f..00000000000
--- a/src/mongo/db/sorter/sorter_stats.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Copyright (C) 2022-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/platform/atomic_word.h"
-
-namespace mongo {
-
-struct SorterTracker {
- AtomicWord<long long> spilledRanges;
- AtomicWord<long long> bytesSpilled;
- AtomicWord<long long> bytesSpilledUncompressed;
-};
-
-/**
- * For collecting file usage metrics.
- */
-class SorterFileStats {
-public:
- SorterFileStats(SorterTracker* sorterTracker);
-
- void addSpilledDataSize(long long data);
- void addSpilledDataSizeUncompressed(long long data);
-
- AtomicWord<long long> opened;
- AtomicWord<long long> closed;
-
-private:
- SorterTracker* _sorterTracker;
-};
-
-class SorterStats {
-public:
- SorterStats(SorterTracker* sorterTracker);
-
- void incrementSpilledRanges();
-
- /**
- * Sets the number of spilled ranges to the specified amount. Cannot be called after
- * incrementSpilledRanges.
- */
- void setSpilledRanges(long long spills);
-
- long long spilledRanges() const {
- return _spilledRanges;
- }
-
-private:
- long long _spilledRanges = 0;
-
- // All SorterStats update the SorterTracker to report sorter statistics for the
- // server.
- SorterTracker* _sorterTracker;
-};
-} // namespace mongo
diff --git a/src/mongo/db/sorter/sorter_stats_test.cpp b/src/mongo/db/sorter/sorter_stats_test.cpp
deleted file mode 100644
index e94d9d4efb8..00000000000
--- a/src/mongo/db/sorter/sorter_stats_test.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Copyright (C) 2022-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/db/sorter/sorter_stats.h"
-#include "mongo/unittest/death_test.h"
-#include "mongo/unittest/unittest.h"
-
-namespace mongo {
-namespace {
-TEST(SorterStatsTest, Basic) {
- SorterTracker sorterTracker;
- SorterStats sorterStats(&sorterTracker);
-
- sorterStats.incrementSpilledRanges();
- ASSERT_EQ(sorterTracker.spilledRanges.load(), 1);
-}
-
-TEST(SorterStatsTest, MultipleSorters) {
- SorterTracker sorterTracker;
- SorterStats sorterStats1(&sorterTracker);
- SorterStats sorterStats2(&sorterTracker);
- SorterStats sorterStats3(&sorterTracker);
-
- sorterStats1.incrementSpilledRanges();
- sorterStats2.incrementSpilledRanges();
- ASSERT_EQ(sorterTracker.spilledRanges.load(), 2);
-
- sorterStats3.setSpilledRanges(10);
- ASSERT_EQ(sorterTracker.spilledRanges.load(), 12);
-}
-
-DEATH_TEST(SorterStatsTest, SetNonZeroNumSpilledRanges, "invariant") {
- SorterTracker sorterTracker;
- SorterStats sorterStats(&sorterTracker);
-
- sorterStats.incrementSpilledRanges();
- ASSERT_EQ(sorterTracker.spilledRanges.load(), 1);
-
- sorterStats.setSpilledRanges(10);
-}
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/db/sorter/sorter_test.cpp b/src/mongo/db/sorter/sorter_test.cpp
index 328dcd256c1..3388d35b8f5 100644
--- a/src/mongo/db/sorter/sorter_test.cpp
+++ b/src/mongo/db/sorter/sorter_test.cpp
@@ -329,55 +329,41 @@ class SortedFileWriterAndFileIteratorTests {
public:
void run() {
unittest::TempDir tempDir("sortedFileWriterTests");
- SorterTracker sorterTracker;
- SorterFileStats sorterFileStats(&sorterTracker);
+ SorterFileStats sorterFileStats;
const SortOptions opts = SortOptions().TempDir(tempDir.path()).FileStats(&sorterFileStats);
+ auto makeFile = [&] {
+ return std::make_shared<Sorter<IntWrapper, IntWrapper>::File>(
+ opts.tempDir + "/" + nextFileName(), opts.sorterFileStats);
+ };
- int currentFileSize = 0;
-
- // small
- currentFileSize = _appendToFile(&opts, currentFileSize, 5);
+ { // small
+ SortedFileWriter<IntWrapper, IntWrapper> sorter(opts, makeFile());
+ sorter.addAlreadySorted(0, 0);
+ sorter.addAlreadySorted(1, -1);
+ sorter.addAlreadySorted(2, -2);
+ sorter.addAlreadySorted(3, -3);
+ sorter.addAlreadySorted(4, -4);
+ ASSERT_ITERATORS_EQUIVALENT(std::shared_ptr<IWIterator>(sorter.done()),
+ std::make_shared<IntIterator>(0, 5));
+ }
ASSERT_EQ(sorterFileStats.opened.load(), 1);
ASSERT_EQ(sorterFileStats.closed.load(), 1);
- ASSERT_LTE(sorterTracker.bytesSpilled.load(), currentFileSize);
- // big
- currentFileSize = _appendToFile(&opts, currentFileSize, 10 * 1000 * 1000);
+ { // big
+ SortedFileWriter<IntWrapper, IntWrapper> sorter(opts, makeFile());
+ for (int i = 0; i < 10 * 1000 * 1000; i++)
+ sorter.addAlreadySorted(i, -i);
+
+ ASSERT_ITERATORS_EQUIVALENT(std::shared_ptr<IWIterator>(sorter.done()),
+ std::make_shared<IntIterator>(0, 10 * 1000 * 1000));
+ }
ASSERT_EQ(sorterFileStats.opened.load(), 2);
ASSERT_EQ(sorterFileStats.closed.load(), 2);
- ASSERT_LTE(sorterTracker.bytesSpilled.load(), currentFileSize);
ASSERT(boost::filesystem::is_empty(tempDir.path()));
}
-
-private:
- int _appendToFile(const SortOptions* opts, int currentFileSize, int range) {
- auto makeFile = [&] {
- return std::make_shared<Sorter<IntWrapper, IntWrapper>::File>(
- opts->tempDir + "/" + nextFileName(), opts->sorterFileStats);
- };
-
- int currentBufSize = 0;
- SortedFileWriter<IntWrapper, IntWrapper> sorter(*opts, makeFile());
- for (int i = 0; i < range; ++i) {
- sorter.addAlreadySorted(i, -i);
- currentBufSize += sizeof(i) + sizeof(-i);
-
- if (currentBufSize > static_cast<int>(kSortedFileBufferSize)) {
- // File size only increases if buffer size exceeds limit and spills. Each spill
- // includes the buffer and the size of the spill.
- currentFileSize += currentBufSize + sizeof(uint32_t);
- currentBufSize = 0;
- }
- }
- ASSERT_ITERATORS_EQUIVALENT(std::shared_ptr<IWIterator>(sorter.done()),
- std::make_shared<IntIterator>(0, range));
- // Anything left in-memory is spilled to disk when sorter.done().
- currentFileSize += currentBufSize + sizeof(uint32_t);
- return currentFileSize;
- }
};
@@ -460,9 +446,7 @@ public:
void run() {
unittest::TempDir tempDir("sorterTests");
- SorterTracker sorterTracker;
- const SortOptions opts =
- SortOptions().TempDir(tempDir.path()).ExtSortAllowed().Tracker(&sorterTracker);
+ const SortOptions opts = SortOptions().TempDir(tempDir.path()).ExtSortAllowed();
{ // test empty (no limit)
ASSERT_ITERATORS_EQUIVALENT(done(makeSorter(opts).get()),
@@ -596,7 +580,7 @@ public:
return 0;
}
- virtual size_t correctSpilledRanges() const {
+ virtual size_t correctNumSpills() const {
return 0;
}
@@ -620,13 +604,13 @@ private:
if (numRanges == 0)
return;
- auto numSpilledRangesOccurred = correctSpilledRanges();
+ auto numSpillsOccurred = correctNumSpills();
auto state = sorter->persistDataForShutdown();
if (opts.extSortAllowed) {
ASSERT_NE(state.fileName, "");
}
ASSERT_EQ(state.ranges.size(), numRanges);
- ASSERT_EQ(sorter->stats().spilledRanges(), numSpilledRangesOccurred);
+ ASSERT_EQ(sorter->numSpills(), numSpillsOccurred);
}
};
@@ -726,7 +710,7 @@ public:
static_cast<std::size_t>(2));
}
- size_t correctSpilledRanges() const override {
+ size_t correctNumSpills() const override {
// We add 1 to the calculation since the call to persistDataForShutdown() spills the
// remaining in-memory Sorter data to disk, adding one extra range.
std::size_t spillsToMerge = NUM_ITEMS * sizeof(IWPair) / MEM_LIMIT + 1;
@@ -871,12 +855,11 @@ DEATH_TEST_F(SorterMakeFromExistingRangesTest, EmptyFileName, "!fileName.empty()
TEST_F(SorterMakeFromExistingRangesTest, SkipFileCheckingOnEmptyRanges) {
auto fileName = "unused_sorter_file";
- SorterTracker sorterTracker;
- auto opts = SortOptions().ExtSortAllowed().TempDir("unused_temp_dir").Tracker(&sorterTracker);
+ auto opts = SortOptions().ExtSortAllowed().TempDir("unused_temp_dir");
auto sorter = std::unique_ptr<IWSorter>(
IWSorter::makeFromExistingRanges(fileName, {}, opts, IWComparator(ASC)));
- ASSERT_EQ(0, sorter->stats().spilledRanges());
+ ASSERT_EQ(0, sorter->numSpills());
auto iter = std::unique_ptr<IWIterator>(sorter->done());
ASSERT_EQ(0, sorter->numSorted());
@@ -922,13 +905,12 @@ TEST_F(SorterMakeFromExistingRangesTest, CorruptedFile) {
ofs << "invalid sorter data";
}
auto fileName = tempFilePath.filename().string();
- SorterTracker sorterTracker;
- auto opts = SortOptions().ExtSortAllowed().TempDir(tempDir.path()).Tracker(&sorterTracker);
+ auto opts = SortOptions().ExtSortAllowed().TempDir(tempDir.path());
auto sorter = std::unique_ptr<IWSorter>(
IWSorter::makeFromExistingRanges(fileName, makeSampleRanges(), opts, IWComparator(ASC)));
// The number of spills is set when NoLimitSorter is constructed from existing ranges.
- ASSERT_EQ(makeSampleRanges().size(), sorter->stats().spilledRanges());
+ ASSERT_EQ(makeSampleRanges().size(), sorter->numSpills());
ASSERT_EQ(0, sorter->numSorted());
// 16817 - error reading file.
@@ -937,13 +919,11 @@ TEST_F(SorterMakeFromExistingRangesTest, CorruptedFile) {
TEST_F(SorterMakeFromExistingRangesTest, RoundTrip) {
unittest::TempDir tempDir(_agent.getSuiteName() + "_" + _agent.getTestName());
- SorterTracker sorterTracker;
auto opts = SortOptions()
.ExtSortAllowed()
.TempDir(tempDir.path())
- .MaxMemoryUsageBytes(sizeof(IWSorter::Data))
- .Tracker(&sorterTracker);
+ .MaxMemoryUsageBytes(sizeof(IWSorter::Data));
IWPair pairInsertedBeforeShutdown(1, 100);
@@ -967,7 +947,7 @@ TEST_F(SorterMakeFromExistingRangesTest, RoundTrip) {
IWSorter::makeFromExistingRanges(state.fileName, state.ranges, opts, IWComparator(ASC)));
// The number of spills is set when NoLimitSorter is constructed from existing ranges.
- ASSERT_EQ(state.ranges.size(), sorter->stats().spilledRanges());
+ ASSERT_EQ(state.ranges.size(), sorter->numSpills());
// Ensure that the restored sorter can accept additional data.
IWPair pairInsertedAfterStartup(2, 200);
@@ -1037,7 +1017,7 @@ public:
Key operator()(Key k, const Doc&) const {
return k - 10;
}
- Document serialize(const SerializationOptions& opts = {}) const {
+ Document serialize() const {
MONGO_UNREACHABLE;
}
};
@@ -1045,7 +1025,7 @@ public:
Key operator()(Key k, const Doc&) const {
return k + 10;
}
- Document serialize(const SerializationOptions& opts = {}) const {
+ Document serialize() const {
MONGO_UNREACHABLE;
}
};
@@ -1206,12 +1186,8 @@ TEST_F(BoundedSorterTest, MemoryLimitsNoExtSortAllowed) {
}
TEST_F(BoundedSorterTest, SpillSorted) {
- SorterTracker sorterTracker;
- auto options = SortOptions()
- .ExtSortAllowed()
- .TempDir("unused_temp_dir")
- .MaxMemoryUsageBytes(16)
- .Tracker(&sorterTracker);
+ auto options =
+ SortOptions().ExtSortAllowed().TempDir("unused_temp_dir").MaxMemoryUsageBytes(16);
sorter = makeAsc(options);
auto output = sort({
@@ -1227,7 +1203,7 @@ TEST_F(BoundedSorterTest, SpillSorted) {
});
assertSorted(output);
- ASSERT_EQ(sorter->stats().spilledRanges(), 3);
+ ASSERT_EQ(sorter->numSpills(), 3);
}
TEST_F(BoundedSorterTest, SpillSortedExceptOne) {
@@ -1249,16 +1225,12 @@ TEST_F(BoundedSorterTest, SpillSortedExceptOne) {
});
assertSorted(output);
- ASSERT_EQ(sorter->stats().spilledRanges(), 3);
+ ASSERT_EQ(sorter->numSpills(), 3);
}
TEST_F(BoundedSorterTest, SpillAlmostSorted) {
- SorterTracker sorterTracker;
- auto options = SortOptions()
- .ExtSortAllowed()
- .TempDir("unused_temp_dir")
- .MaxMemoryUsageBytes(16)
- .Tracker(&sorterTracker);
+ auto options =
+ SortOptions().ExtSortAllowed().TempDir("unused_temp_dir").MaxMemoryUsageBytes(16);
sorter = makeAsc(options);
auto output = sort({
@@ -1276,7 +1248,7 @@ TEST_F(BoundedSorterTest, SpillAlmostSorted) {
});
assertSorted(output);
- ASSERT_EQ(sorter->stats().spilledRanges(), 2);
+ ASSERT_EQ(sorter->numSpills(), 2);
}
TEST_F(BoundedSorterTest, SpillWrongInput) {
@@ -1310,7 +1282,7 @@ TEST_F(BoundedSorterTest, SpillWrongInput) {
ASSERT_EQ(output[5].time, 15);
ASSERT_EQ(output[6].time, 16);
- ASSERT_EQ(sorter->stats().spilledRanges(), 2);
+ ASSERT_EQ(sorter->numSpills(), 2);
// Test that by default, bad input like this would be detected.
sorter = makeAsc(options);
@@ -1319,13 +1291,8 @@ TEST_F(BoundedSorterTest, SpillWrongInput) {
}
TEST_F(BoundedSorterTest, LimitNoSpill) {
- SorterTracker sorterTracker;
- auto options = SortOptions()
- .ExtSortAllowed()
- .TempDir("unused_temp_dir")
- .MaxMemoryUsageBytes(40)
- .Tracker(&sorterTracker)
- .Limit(2);
+ auto options =
+ SortOptions().ExtSortAllowed().TempDir("unused_temp_dir").MaxMemoryUsageBytes(40).Limit(2);
sorter = makeAsc(options);
auto output = sort(
@@ -1348,17 +1315,12 @@ TEST_F(BoundedSorterTest, LimitNoSpill) {
ASSERT_EQ(output[0].time, 0);
ASSERT_EQ(output[1].time, 3);
- ASSERT_EQ(sorter->stats().spilledRanges(), 0);
+ ASSERT_EQ(sorter->numSpills(), 0);
}
TEST_F(BoundedSorterTest, LimitSpill) {
- SorterTracker sorterTracker;
- auto options = SortOptions()
- .ExtSortAllowed()
- .TempDir("unused_temp_dir")
- .MaxMemoryUsageBytes(40)
- .Tracker(&sorterTracker)
- .Limit(3);
+ auto options =
+ SortOptions().ExtSortAllowed().TempDir("unused_temp_dir").MaxMemoryUsageBytes(40).Limit(3);
sorter = makeAsc(options);
auto output = sort(
@@ -1382,7 +1344,7 @@ TEST_F(BoundedSorterTest, LimitSpill) {
ASSERT_EQ(output[1].time, 3);
ASSERT_EQ(output[2].time, 10);
- ASSERT_EQ(sorter->stats().spilledRanges(), 1);
+ ASSERT_EQ(sorter->numSpills(), 1);
}
TEST_F(BoundedSorterTest, DescSorted) {
@@ -1627,26 +1589,22 @@ TEST_F(BoundedSorterTest, CompoundLimit) {
}
TEST_F(BoundedSorterTest, CompoundSpill) {
- SorterTracker sorterTracker;
- auto options = SortOptions()
- .ExtSortAllowed()
- .TempDir("unused_temp_dir")
- .Tracker(&sorterTracker)
- .MaxMemoryUsageBytes(40);
+ auto options =
+ SortOptions().ExtSortAllowed().TempDir("unused_temp_dir").MaxMemoryUsageBytes(40);
sorter = makeAsc(options);
// When each partition is small enough, we don't spill.
- ASSERT_EQ(sorter->stats().spilledRanges(), 0);
+ ASSERT_EQ(sorter->numSpills(), 0);
auto output = sort({
{1001},
{1007},
});
assertSorted(output);
- ASSERT_EQ(sorter->stats().spilledRanges(), 0);
+ ASSERT_EQ(sorter->numSpills(), 0);
// If any individual partition is large enough, we do spill.
sorter->restart();
- ASSERT_EQ(sorter->stats().spilledRanges(), 0);
+ ASSERT_EQ(sorter->numSpills(), 0);
output = sort({
{1},
{5},
@@ -1661,17 +1619,17 @@ TEST_F(BoundedSorterTest, CompoundSpill) {
{7},
});
assertSorted(output);
- ASSERT_EQ(sorter->stats().spilledRanges(), 1);
+ ASSERT_EQ(sorter->numSpills(), 1);
// If later partitions are small again, they don't spill.
sorter->restart();
- ASSERT_EQ(sorter->stats().spilledRanges(), 1);
+ ASSERT_EQ(sorter->numSpills(), 1);
output = sort({
{11},
{17},
});
assertSorted(output);
- ASSERT_EQ(sorter->stats().spilledRanges(), 1);
+ ASSERT_EQ(sorter->numSpills(), 1);
}
} // namespace