1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 2018 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 #pragma once 19 20 #include "vbucket_test.h" 21 22 class MockCheckpointManager; 23 class ActiveDurabilityMonitor; 24 25 /* 26 * VBucket unit tests related to durability. 27 */ 28 class VBucketDurabilityTest : public VBucketTest { 29 public: 30 void SetUp(); 31 32 protected: 33 /// Specification of a SyncWrite to store, as used by storeSyncWrites. 34 struct SyncWriteSpec { SyncWriteSpecVBucketDurabilityTest::SyncWriteSpec35 explicit SyncWriteSpec(int64_t seqno) : seqno(seqno) { 36 } SyncWriteSpecVBucketDurabilityTest::SyncWriteSpec37 SyncWriteSpec(int64_t seqno, bool deletion = false) 38 : seqno(seqno), deletion(deletion) { 39 } SyncWriteSpecVBucketDurabilityTest::SyncWriteSpec40 SyncWriteSpec(int64_t seqno, 41 bool deletion, 42 cb::durability::Level level, 43 cb::durability::Timeout timeout = 44 cb::durability::Timeout::Infinity()) 45 : seqno(seqno), deletion(deletion), level(level), timeout(timeout) { 46 } 47 48 int64_t seqno; 49 bool deletion = false; 50 cb::durability::Level level = cb::durability::Level::Majority; 51 cb::durability::Timeout timeout = cb::durability::Timeout::Infinity(); 52 }; 53 54 /** 55 * Store the given Sync mutations into VBucket 56 * 57 * @param writes the mutations to be added 58 */ 59 void storeSyncWrites(const std::vector<SyncWriteSpec>& writes); 60 61 /** 62 * Simulate a SetVBucketState call, including processing any resolved 63 * SyncWrites which can now be Committed/Aborted. 64 */ 65 void simulateSetVBState(vbucket_state_t to, 66 const nlohmann::json& meta = {}); 67 68 /** 69 * Simulate the local (active) seqno acknowledgement. 70 * 71 * @param seqno The ack'ed seqno 72 */ 73 void simulateLocalAck(uint64_t seqno); 74 75 /** 76 * Tests: 77 * 1) mutations added to VBucket 78 * 2) mutations in state "pending" in both HashTable and CheckpointManager 79 * 80 * @param writes the set of mutations to test 81 */ 82 void testAddPrepare(const std::vector<SyncWriteSpec>& writes); 83 84 /** 85 * Tests the baseline progress of a set of SyncWrites in Vbucket: 86 * 1) mutations added to VBucket 87 * 2) mutations in state "pending" in both HashTable and CheckpointManager 88 * 3) VBucket receives a SeqnoAck that satisfies the DurReqs for all SWs 89 * 4) mutations in state "committed" in both HashTable and CheckpointManager 90 * 91 * @param writes the set of mutations to test 92 */ 93 void testAddPrepareAndCommit(const std::vector<SyncWriteSpec>& writes); 94 95 /** 96 * Tests that the Replication Topology is cleared when a VBucket transitions 97 * to the given state. 98 * 99 * @param state The new state for VBucket 100 */ 101 void testSetVBucketState_ClearTopology(vbucket_state_t state); 102 103 /** 104 * Tests that the PassiveDM queues incoming Prepares correctly when the 105 * owning VBucket is in the given state. 106 * 107 * @param state The state for VBucket 108 * @param writes The Prepares to be queued 109 */ 110 void testAddPrepareInPassiveDM(vbucket_state_t state, 111 const std::vector<SyncWriteSpec>& writes); 112 113 /** 114 * Tests that the PassiveDM is correctly converted to ActiveDM when a 115 * VBucket in the provided initial state transitions to vbstate-active when 116 * there are in-flight SyncWrites. 117 * 118 * @param initialState The initial state for VBucket 119 */ 120 void testConvertPassiveDMToActiveDM(vbucket_state_t initialState); 121 122 /** 123 * Tests that the PassiveDM is correctly converted to ActiveDM when a 124 * vBucket in the provided initial state transitions to vbstate-active when 125 * there are in-flight SyncWrites. This test mimics an actual takeover which 126 * will do the following set of state transitions: 127 * replica/pending->active with no topology->active with topology. Persists 128 * up to seqno 2 regardless of the writes passed in. 129 * 130 * @param initialState The initial state for the vBucket 131 * @param writes The prepares to be queued 132 */ 133 void testConvertPDMToADMWithNullTopologySetup( 134 vbucket_state_t initialState, std::vector<SyncWriteSpec>& writes); 135 136 /** 137 * Tests that the PassiveDM is correctly converted to ActiveDM when a 138 * vBucket in the provided initial state transitions to vbstate-active when 139 * there are in-flight SyncWrites. This test mimics an actual takeover which 140 * will do the following set of state transitions: 141 * replica/pending->active with no topology->active with topology 142 * 143 * @param initialState The initial state for the vBucket 144 */ 145 void testConvertPDMToADMWithNullTopology(vbucket_state_t initialState); 146 147 /** 148 * Tests that the PassiveDM is correctly converted to ActiveDM when a 149 * vBucket in the provided initial state transitions to vbstate-active when 150 * there are in-flight SyncWrites. This test mimics an actual takeover which 151 * will do the following set of state transitions: 152 * replica/pending->active with no topology->active with topology. This test 153 * tests that a PersistToMajority Prepare persisted after the final topology 154 * change is done correctly. 155 * 156 * @param initialState The initial state for the vBucket 157 */ 158 void testConvertPDMToADMWithNullTopologyPersistAfterTopologyChange( 159 vbucket_state_t initialState); 160 161 /** 162 * Tests that the PassiveDM is correctly converted to ActiveDM when a 163 * vBucket in the provided initial state transitions to vbstate-active when 164 * there are in-flight SyncWrites. This test mimics an actual takeover which 165 * will do the following set of state transitions: 166 * replica/pending->active with no topology->active with topology. This test 167 * tests that a PersistToMajority Prepare persisted between the null and 168 * final topology change is done correctly. 169 * 170 * @param initialState The initial state for the vBucket 171 */ 172 void testConvertPDMToADMWithNullTopologyPersistBeforeTopologyChange( 173 vbucket_state_t initialState); 174 175 /** 176 * Tests that the PassiveDM is correctly converted to ActiveDM when a 177 * vBucket in the provided initial state transitions to vbstate-active when 178 * there are in-flight SyncWrites. This test mimics an actual takeover which 179 * will do the following set of state transitions: 180 * replica/pending->active with no topology->active with topology. This test 181 * tests that a HPS that does not equal anything in trackedWrites is moved 182 * over the the ADM and that a subsequent prepare and commit can be 183 * performed successfully. 184 * 185 * @param initialState The initial state for the vBucket 186 */ 187 void testConvertPDMToADMWithNullTopologyPostDiskSnap( 188 vbucket_state_t initialState); 189 190 /** 191 * Tests that the PassiveDM is correctly converted to ActiveDM when a 192 * vBucket in the provided initial state transitions to vbstate-active when 193 * there is an in-flight PersistToMajority SyncWrite that has not yet been 194 * persisted. 195 * 196 * @param initialState The initial state for the vBucket 197 */ 198 void testConvertPassiveDMToActiveDMUnpersistedPrepare( 199 vbucket_state_t initialState); 200 201 /** 202 * Tests that the PassiveDM is correctly converted to ActiveDM when a 203 * vBucket in the provided initial state transitions to vbstate-active in 204 * the middle of a snapshot. 205 * 206 * @param initialState The initial state for the vBucket 207 */ 208 void testConvertPDMToADMMidSnapSetup(vbucket_state_t initialState); 209 210 /** 211 * Tests that the PassiveDM is correctly converted to ActiveDM when a 212 * vBucket in the provided initial state transitions to vbstate-active in 213 * the middle of a snapshot. Persists items before the topology change so 214 * that the topology change drives the commit. 215 * 216 * @param initialState The initial state for the vBucket 217 */ 218 void testConvertPDMToADMMidSnapSetupPersistBeforeChange( 219 vbucket_state_t initialState); 220 221 /** 222 * Tests that the PassiveDM is correctly converted to ActiveDM when a 223 * vBucket in the provided initial state transitions to vbstate-active in 224 * the middle of a snapshot. Persists items after the topology change so 225 * that a call to ADM::checkForCommit drives the commit. 226 * 227 * @param initialState The initial state for the vBucket 228 */ 229 void testConvertPDMToADMMidSnapSetupPersistAfterChange( 230 vbucket_state_t initialState); 231 232 /** 233 * Tests that the PassiveDM is correctly converted to ActiveDM when a 234 * vBucket in the provided initial state transitions to vbstate-active in 235 * the middle of a snapshot. Tests that the topology change is successful 236 * when we have completed all prepares in the PDM. 237 * 238 * @param initialState The initial state for the vBucket 239 */ 240 void testConvertPDMToADMMidSnapAllPreparesCompleted( 241 vbucket_state_t initialState); 242 243 /** 244 * Test that the PassiveDM is correctly converted to ActiveDM when a 245 * VBucket in the provided initial state transitions to vbstate-active when 246 * there are no in-flight SyncWrites. 247 * 248 * @param initialState The initial state for VBucket 249 */ 250 void testConvertPassiveDMToActiveDMNoPrepares(vbucket_state_t initialState); 251 252 /** 253 * Test that the state transition from active does or does not converts 254 * the prepares in the HashTable to PreparedMaybeVisible. 255 * 256 * @param toState The state to convert the vBucket to 257 * @param expectPreparedMaybeVisible should the conversion happen 258 */ 259 void testConvertADMMakesPreparesMaybeVisible( 260 vbucket_state_t toState, bool expectPreparedMaybeVisible); 261 262 enum class Resolution { Commit, Abort }; 263 264 /** 265 * Tests that the PassiveDM behaves correctly when VBucket notifies the 266 * PassiveDM of Prepare completion (ie, Commit or Abort). 267 * 268 * @param initialState The initial state for VBucket 269 * @param res The type of resolution, Commit/Abort 270 */ 271 void testCompleteSWInPassiveDM(vbucket_state_t initialState, 272 Resolution res); 273 274 /** 275 * Test a normal set followed by a pending SyncWrite; then committing the 276 * pending SyncWrite which should replace the previous committed. 277 */ 278 void testHTCommitExisting(); 279 280 /** 281 * Add a pending SyncDelete to the vBucket for the given key. 282 */ 283 void setupPendingDelete(StoredDocKey key); 284 285 /** 286 * Test a commit of a sync delete 287 */ 288 void testHTSyncDeleteCommit(); 289 290 void doSyncWriteAndCommit(); 291 void doSyncDelete(); 292 293 MutationStatus doPrepareSyncSet(const StoredDocKey& key, std::string value); 294 AddStatus doPrepareSyncAdd(const StoredDocKey& key, std::string value); 295 296 // All owned by VBucket 297 HashTable* ht; 298 MockCheckpointManager* ckptMgr; 299 300 const std::string active = "active"; 301 const std::string replica1 = "replica1"; 302 const std::string replica2 = "replica2"; 303 const std::string replica3 = "replica3"; 304 }; 305 306 class EPVBucketDurabilityTest : public VBucketDurabilityTest {}; 307 class EphemeralVBucketDurabilityTest : public VBucketDurabilityTest {}; 308