1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2020 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#include "dcp/backfill-manager.h"
19#include "evp_store_single_threaded_test.h"
20
21#include <folly/portability/GMock.h>
22#include <folly/portability/GTest.h>
23
24using ::testing::InSequence;
25using ::testing::Return;
26
27class GMockDCPBackfill : public DCPBackfillIface {
28public:
29    MOCK_METHOD0(run, backfill_status_t());
30    MOCK_METHOD0(cancel, void());
31    MOCK_CONST_METHOD0(getVBucketId, Vbid());
32    MOCK_CONST_METHOD0(isStreamDead, bool());
33};
34
35class GMockBackfillTracker : public BackfillTrackingIface {
36public:
37    MOCK_METHOD0(canAddBackfillToActiveQ, bool());
38    MOCK_METHOD0(decrNumActiveSnoozingBackfills, void());
39};
40
41class BackfillManagerTest : public SingleThreadedKVBucketTest {
42protected:
43    void SetUp() {
44        SingleThreadedKVBucketTest::SetUp();
45        backfillMgr =
46                std::make_shared<BackfillManager>(*engine->getKVBucket(),
47                                                  backfillTracker,
48                                                  engine->getConfiguration());
49    }
50
51    void TearDown() {
52        // Need to destroy engine & backfillManager objects before shutting
53        // down ExecutorPool.
54        backfillMgr.reset();
55        SingleThreadedKVBucketTest::TearDown();
56    }
57
58    /**
59     * For tests which are not interested in backfilLTracker, configure it
60     * to accept an arbirary number of concurrent backfills.
61     */
62    void ignoreBackfillTracker() {
63        EXPECT_CALL(backfillTracker, canAddBackfillToActiveQ())
64                .WillRepeatedly(Return(true));
65        EXPECT_CALL(backfillTracker, decrNumActiveSnoozingBackfills())
66                .WillRepeatedly(Return());
67    }
68
69    GMockBackfillTracker backfillTracker;
70    std::shared_ptr<BackfillManager> backfillMgr;
71};
72
73/*
74 * Check that active Backfills are scheduled in round-robin order
75 * (0, 1, 2, 0, 1, 2, ...) until they complete.
76 */
77TEST_F(BackfillManagerTest, RoundRobin) {
78    // Not interested in behaviour of backfillTracker for this test.
79    ignoreBackfillTracker();
80
81    auto backfill0 = std::make_unique<GMockDCPBackfill>();
82    auto backfill1 = std::make_unique<GMockDCPBackfill>();
83    auto backfill2 = std::make_unique<GMockDCPBackfill>();
84
85    // Expectation - two backfills should be scheduled in turn while they
86    // return backfill_success.
87    {
88        InSequence s;
89        EXPECT_CALL(*backfill0, run())
90                .WillOnce(Return(backfill_success))
91                .RetiresOnSaturation();
92        EXPECT_CALL(*backfill1, run())
93                .WillOnce(Return(backfill_success))
94                .RetiresOnSaturation();
95        EXPECT_CALL(*backfill2, run())
96                .WillOnce(Return(backfill_success))
97                .RetiresOnSaturation();
98        EXPECT_CALL(*backfill0, run())
99                .WillOnce(Return(backfill_finished))
100                .RetiresOnSaturation();
101        EXPECT_CALL(*backfill1, run())
102                .WillOnce(Return(backfill_finished))
103                .RetiresOnSaturation();
104        EXPECT_CALL(*backfill2, run())
105                .WillOnce(Return(backfill_finished))
106                .RetiresOnSaturation();
107    }
108
109    // Test: schedule both backfills, then instruct the backfill manager to
110    // backfill 6 times.
111    ASSERT_EQ(BackfillManager::ScheduleResult::Active,
112              backfillMgr->schedule(std::move(backfill0)));
113    ASSERT_EQ(BackfillManager::ScheduleResult::Active,
114              backfillMgr->schedule(std::move(backfill1)));
115    ASSERT_EQ(BackfillManager::ScheduleResult::Active,
116              backfillMgr->schedule(std::move(backfill2)));
117    backfillMgr->backfill();
118    backfillMgr->backfill();
119    backfillMgr->backfill();
120    backfillMgr->backfill();
121    backfillMgr->backfill();
122    backfillMgr->backfill();
123}
124
125/*
126 * MB-37680: Check that active backfills are scheduled in sequential order when
127 * backfillOrder is set to Sequential.
128 */
129TEST_F(BackfillManagerTest, Sequential) {
130    // Not interested in behaviour of backfillTracker for this test.
131    ignoreBackfillTracker();
132
133    auto backfill0 = std::make_unique<GMockDCPBackfill>();
134    auto backfill1 = std::make_unique<GMockDCPBackfill>();
135    auto backfill2 = std::make_unique<GMockDCPBackfill>();
136
137    // Expectation - each Backfill should be run once (to initialise and
138    // generate the snapshot_marker, then the first backfill should be run to
139    // completion before the next one starts.
140    //
141    {
142        InSequence s;
143
144        // each backfill called once for snapshot_marker
145        EXPECT_CALL(*backfill0, run())
146                .WillOnce(Return(backfill_success))
147                .RetiresOnSaturation();
148        EXPECT_CALL(*backfill1, run())
149                .WillOnce(Return(backfill_success))
150                .RetiresOnSaturation();
151        EXPECT_CALL(*backfill2, run())
152                .WillOnce(Return(backfill_success))
153                .RetiresOnSaturation();
154
155        // then each one sequential until finished.
156        EXPECT_CALL(*backfill0, run())
157                .WillOnce(Return(backfill_success))
158                .WillOnce(Return(backfill_finished))
159                .RetiresOnSaturation();
160        EXPECT_CALL(*backfill1, run())
161                .WillOnce(Return(backfill_success))
162                .WillOnce(Return(backfill_finished))
163                .RetiresOnSaturation();
164        EXPECT_CALL(*backfill2, run())
165                .WillOnce(Return(backfill_success))
166                .WillOnce(Return(backfill_finished))
167                .RetiresOnSaturation();
168    }
169
170    // Test: schedule all backfills, then instruct the backfill manager to
171    // backfill 9 times.
172    backfillMgr->setBackfillOrder(BackfillManager::ScheduleOrder::Sequential);
173    ASSERT_EQ(BackfillManager::ScheduleResult::Active,
174              backfillMgr->schedule(std::move(backfill0)));
175    ASSERT_EQ(BackfillManager::ScheduleResult::Active,
176              backfillMgr->schedule(std::move(backfill1)));
177    ASSERT_EQ(BackfillManager::ScheduleResult::Active,
178              backfillMgr->schedule(std::move(backfill2)));
179    for (int i = 0; i < 9; i++) {
180        backfillMgr->backfill();
181    }
182}
183