/** * 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 * . * * 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/basic.h" #include "mongo/db/snapshot_window_util.h" #include "mongo/db/client.h" #include "mongo/db/commands/test_commands_enabled.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_devnull_test_fixture.h" #include "mongo/db/snapshot_window_options.h" #include "mongo/db/storage/storage_options.h" #include "mongo/unittest/unittest.h" namespace mongo { namespace { using namespace SnapshotWindowUtil; /** * Tests the functions in snapshot_window_util.h using a devnull storage engine. */ class SnapshotWindowTest : public ServiceContextDevnullTestFixture { public: void setUp() override { ServiceContextDevnullTestFixture::setUp(); _opCtx = cc().makeOperationContext(); setTestCommandsEnabled(true); } void tearDown() override { _opCtx.reset(); ServiceContextDevnullTestFixture::tearDown(); } ServiceContext::UniqueOperationContext _opCtx; }; TEST_F(SnapshotWindowTest, DecreaseAndIncreaseSnapshotWindow) { auto engine = getServiceContext()->getStorageEngine(); invariant(engine); snapshotWindowParams.maxTargetSnapshotHistoryWindowInSeconds.store(100); snapshotWindowParams.targetSnapshotHistoryWindowInSeconds.store(100); // Lower the time enforced between function calls to speed up testing. // Dec must match Inc b/c increaseTargetWindowSize can call into decreaseTargetWindowSize. snapshotWindowParams.minMillisBetweenSnapshotWindowInc.store(100); snapshotWindowParams.minMillisBetweenSnapshotWindowDec.store(100); // Stabilize for the test so we know that we are testing things as expected. snapshotWindowParams.snapshotWindowAdditiveIncreaseSeconds.store(2); snapshotWindowParams.snapshotWindowMultiplicativeDecrease.store(0.75); auto maxTargetSnapshotWindowSeconds = snapshotWindowParams.maxTargetSnapshotHistoryWindowInSeconds.load(); auto snapshotWindowSeconds = snapshotWindowParams.targetSnapshotHistoryWindowInSeconds.load(); ASSERT_EQ(maxTargetSnapshotWindowSeconds, snapshotWindowSeconds); auto windowMultiplicativeDecrease = snapshotWindowParams.snapshotWindowMultiplicativeDecrease.load(); auto windowAdditiveIncrease = snapshotWindowParams.snapshotWindowAdditiveIncreaseSeconds.load(); auto cachePressureThreshold = snapshotWindowParams.cachePressureThreshold.load(); auto minTimeBetweenInc = snapshotWindowParams.minMillisBetweenSnapshotWindowInc.load(); /** * Test that decreasing the size succeeds when cache pressure is ABOVE the threshold */ engine->setCachePressureForTest(cachePressureThreshold + 5); decreaseTargetSnapshotWindowSize(_opCtx.get()); auto snapshotWindowSecondsOne = snapshotWindowParams.targetSnapshotHistoryWindowInSeconds.load(); ASSERT_GT(snapshotWindowSeconds, snapshotWindowSecondsOne); ASSERT_EQ(snapshotWindowSecondsOne, static_cast(snapshotWindowSeconds * windowMultiplicativeDecrease)); /** * Test that increasing the size SUCCEEDS when the cache pressure is BELOW the threshold. */ engine->setCachePressureForTest(cachePressureThreshold - 5); increaseTargetSnapshotWindowSize(_opCtx.get()); auto snapshotWindowSecondsTwo = snapshotWindowParams.targetSnapshotHistoryWindowInSeconds.load(); ASSERT_EQ(snapshotWindowSecondsTwo, snapshotWindowSecondsOne + windowAdditiveIncrease); /** * Test that increasing the size FAILS when the cache pressure is ABOVE the threshold, and * instead this causes the size to be decreased. */ engine->setCachePressureForTest(cachePressureThreshold + 5); // Sleep for a time because increaseTargetSnapshotWindowSize() enforces a wait time between // updates. sleepmillis(2 * minTimeBetweenInc); increaseTargetSnapshotWindowSize(_opCtx.get()); auto snapshotWindowSecondsThree = snapshotWindowParams.targetSnapshotHistoryWindowInSeconds.load(); ASSERT_EQ(snapshotWindowSecondsThree, static_cast(snapshotWindowSecondsTwo * windowMultiplicativeDecrease)); engine->setCachePressureForTest(cachePressureThreshold - 5); /** * Test that the size cannot be increased above the maximum size. */ // Integers round down, so add 1 to make sure it reaches the max. int numIncreasesToReachMax = (maxTargetSnapshotWindowSeconds - snapshotWindowSecondsThree) / windowAdditiveIncrease + 1; for (int i = 0; i < numIncreasesToReachMax; ++i) { sleepmillis(2 * minTimeBetweenInc); increaseTargetSnapshotWindowSize(_opCtx.get()); } // Should be at max. auto snapshotWindowSecondsFour = snapshotWindowParams.targetSnapshotHistoryWindowInSeconds.load(); ASSERT_EQ(snapshotWindowSecondsFour, maxTargetSnapshotWindowSeconds); // An attempt to increase beyond max should have no effect. sleepmillis(2 * minTimeBetweenInc); increaseTargetSnapshotWindowSize(_opCtx.get()); auto snapshotWindowSecondsFive = snapshotWindowParams.targetSnapshotHistoryWindowInSeconds.load(); ASSERT_EQ(snapshotWindowSecondsFive, maxTargetSnapshotWindowSeconds); } TEST_F(SnapshotWindowTest, IncrementSnapshotTooOldErrorCount) { auto beforeCount = snapshotWindowParams.snapshotTooOldErrorCount.load(); incrementSnapshotTooOldErrorCount(); incrementSnapshotTooOldErrorCount(); auto afterCount = snapshotWindowParams.snapshotTooOldErrorCount.load(); ASSERT_EQ(beforeCount + 2, afterCount); } } // namespace } // namespace mongo