Skip to content

Commit 67ef8e8

Browse files
BenHuddlestondaverigby
authored andcommitted
MB-35366: Move HPS when persisting with ADM null topology
We may be able to move the HPS when we get the persistence of a completed prepare (grandfathered into the ADM from the PDM). We should do so to ensure that if we go back to PDM without ever getting a topology then we ack back the accurate HPS. Change-Id: I1324a60621e3cbb24e0874cbb560ef9c8a6721aa Reviewed-on: http://review.couchbase.org/113428 Tested-by: Build Bot <[email protected]> Reviewed-by: Dave Rigby <[email protected]>
1 parent 7fdb98a commit 67ef8e8

File tree

2 files changed

+112
-3
lines changed

2 files changed

+112
-3
lines changed

engines/ep/src/durability/active_durability_monitor.cc

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,9 +1587,36 @@ void ActiveDurabilityMonitor::State::updateHighPreparedSeqno(
15871587
// An ActiveDM _may_ legitimately have no topology information, if
15881588
// for example it has just been created from a PassiveDM during takeover
15891589
// and ns_server has not yet updated the VBucket's topology.
1590-
// In this case it's not yet possible update HPS; so simply skip.
1591-
// Note: when topology *is* set via setReplicationTopology() then this
1592-
// function is called again to update HPS as appropriate.
1590+
// In this case, it may be possible to update the HPS and we should do
1591+
// so to ensure that any subsequent state change back to
1592+
// replica/PassiveDM acks correctly if we never got a topology. We can
1593+
// update the highPreparedSeqno for anything that the PDM completed
1594+
// (we should have nothing in trackedWrites not completed as we have no
1595+
// topology) by using the store value instead of the iterator. Given
1596+
// we only keep these completed SyncWrites in trackedWrites to correctly
1597+
// set the HPS when we DO get a topology, we can remove them once we
1598+
// have advanced past them.
1599+
auto itr = trackedWrites.begin();
1600+
while (itr != trackedWrites.end()) {
1601+
if (!itr->isCompleted()) {
1602+
return;
1603+
}
1604+
1605+
// Don't advance past anything not persisted.
1606+
auto level = itr->getDurabilityReqs().getLevel();
1607+
if ((level == cb::durability::Level::PersistToMajority ||
1608+
level == cb::durability::Level::MajorityAndPersistOnMaster) &&
1609+
static_cast<uint64_t>(itr->getBySeqno()) <
1610+
adm.vb.getPersistenceSeqno()) {
1611+
return;
1612+
}
1613+
1614+
highPreparedSeqno = itr->getBySeqno();
1615+
1616+
auto next = std::next(itr);
1617+
trackedWrites.erase(itr);
1618+
itr = next;
1619+
}
15931620
return;
15941621
}
15951622

engines/ep/tests/module_tests/vbucket_durability_test.cc

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2098,6 +2098,88 @@ TEST_P(EPVBucketDurabilityTest, ReplicaToActiveToReplica) {
20982098
}
20992099
}
21002100

2101+
/**
2102+
* Check that converting from Replica to Active back to Replica correctly
2103+
* preserves completed SyncWrites in trackedWrites which cannot yet be removed
2104+
* (if persistMajority and not locally persisted).
2105+
*
2106+
* Scenario:
2107+
* Replica (PassiveDM):
2108+
* 1:prepare(persistToMajority)
2109+
* 2:prepare(majority)
2110+
* 3:commit(1) -> cannot locally remove 1 as not persisted yet.
2111+
* 4:commit(2) -> cannot locally remove 2 as seqno:1 not persisted yet
2112+
* (in-order commit).
2113+
* -> trackedWrites=[1,2]
2114+
* HPS=0
2115+
* HCS=2 (want HCS higher than the first element in the trackedWrites)
2116+
*
2117+
* Convert to ADM (null topology):
2118+
* -> trackedWrites=[1,2]
2119+
* HPS=0
2120+
* HCS=2
2121+
* (i.e. same as previous PassiveDM)
2122+
*
2123+
* Persist seqnos 1:
2124+
* Calls notifyLocalPersistence, but no-op as null topology.
2125+
*
2126+
* Convert to PDM:
2127+
* (seqnos 1 has been persisted previously...)
2128+
* State should be updated to reflect completion of seqno:1:
2129+
* -> trackedWrites=[2]
2130+
* HPS=2
2131+
* HCS=2
2132+
*/
2133+
TEST_P(EPVBucketDurabilityTest, ReplicaToActiveToReplica2) {
2134+
// Setup: PassiveDM with
2135+
// 1:PRE(persistMajority), 2:PRE(majority), 3:COMMIT(1), 4:COMMIT(2)
2136+
vbucket->setState(vbucket_state_replica);
2137+
using namespace cb::durability;
2138+
std::vector<SyncWriteSpec> seqnos{{1, false, Level::PersistToMajority}, 2};
2139+
testAddPrepare(seqnos);
2140+
auto& pdm = VBucketTestIntrospector::public_getPassiveDM(*vbucket);
2141+
pdm.completeSyncWrite(makeStoredDocKey("key1"),
2142+
PassiveDurabilityMonitor::Resolution::Commit,
2143+
1);
2144+
pdm.completeSyncWrite(makeStoredDocKey("key2"),
2145+
PassiveDurabilityMonitor::Resolution::Commit,
2146+
2);
2147+
pdm.notifySnapshotEndReceived(4);
2148+
2149+
// Sanity: Check PassiveDM state as expected - HPS is still zero as haven't
2150+
// locally prepared the persistMajority, but globally that's been
2151+
// committed (HCS=1).
2152+
ASSERT_EQ(2, pdm.getNumTracked());
2153+
ASSERT_EQ(0, pdm.getHighPreparedSeqno());
2154+
ASSERT_EQ(2, pdm.getHighCompletedSeqno());
2155+
2156+
// Setup(2): Convert to ActiveDM (null topology).
2157+
vbucket->setState(vbucket_state_active);
2158+
auto& adm = VBucketTestIntrospector::public_getActiveDM(*vbucket);
2159+
EXPECT_EQ(2, adm.getNumTracked());
2160+
EXPECT_EQ(0, adm.getHighPreparedSeqno());
2161+
EXPECT_EQ(2, adm.getHighCompletedSeqno());
2162+
2163+
// Setup(3): Persist seqno 1 (so locally prepared now), but no-op
2164+
// as without topology.
2165+
simulateLocalAck(1);
2166+
EXPECT_EQ(0, adm.getNumTracked());
2167+
EXPECT_EQ(2, adm.getHighPreparedSeqno());
2168+
EXPECT_EQ(2, adm.getHighCompletedSeqno());
2169+
2170+
// Test: Convert back to PassiveDM. Should remove completed
2171+
// SyncWrites from trackedWrites as have been persisted.
2172+
2173+
// Test: Convert back to PassiveDM.
2174+
vbucket->setState(vbucket_state_replica);
2175+
{
2176+
auto& pdm = VBucketTestIntrospector::public_getPassiveDM(*vbucket);
2177+
EXPECT_EQ(0, pdm.getNumTracked());
2178+
EXPECT_EQ(2, pdm.getHighPreparedSeqno());
2179+
EXPECT_EQ(2, pdm.getHighCompletedSeqno());
2180+
}
2181+
}
2182+
21012183
// Test that a double set_vb_state with identical state & topology is handled
21022184
// correctly.
21032185
// MB-35189: ns_server can send such set_vb_state messages, and in the

0 commit comments

Comments
 (0)