diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
| commit | 4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch) | |
| tree | 1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/db/sorter | |
| parent | aa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff) | |
| parent | 8f0827553e09872941945a093b647a4211a9db7f (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/SConscript | 9 | ||||
| -rw-r--r-- | src/mongo/db/sorter/sorter.cpp | 107 | ||||
| -rw-r--r-- | src/mongo/db/sorter/sorter.h | 82 | ||||
| -rw-r--r-- | src/mongo/db/sorter/sorter_stats.cpp | 64 | ||||
| -rw-r--r-- | src/mongo/db/sorter/sorter_stats.h | 80 | ||||
| -rw-r--r-- | src/mongo/db/sorter/sorter_stats_test.cpp | 68 | ||||
| -rw-r--r-- | src/mongo/db/sorter/sorter_test.cpp | 158 |
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 |
