@@ -115,7 +115,6 @@ class ReplSetDistLockManagerFixture : public mongo::unittest::Test {
115115 _mgr.shutDown (true );
116116 }
117117
118- TickSourceMock _tickSource;
119118 std::unique_ptr<DistLockCatalogMock> _dummyDoNotUse; // dummy placeholder
120119 DistLockCatalogMock* _mockCatalog;
121120 string _processID;
@@ -1746,5 +1745,89 @@ TEST_F(ReplSetDistLockManagerFixture, CannotOvertakeIfConfigServerClockGoesBackw
17461745 }
17471746}
17481747
1748+ /* *
1749+ * Test scenario:
1750+ * 1. Attempt to grab lock fails because lock is already owned.
1751+ * 2. Try to get ping data (does not exist) and config server clock.
1752+ * 3. Since we don't have previous ping data to compare with, we cannot
1753+ * decide whether it's ok to overtake, so we can't.
1754+ * 4. Lock expiration has elapsed and the ping still does not exist.
1755+ * 5. 2nd attempt to grab lock still fails for the same reason.
1756+ * 6. But since the ping has not been updated, dist lock manager should overtake lock.
1757+ */
1758+ TEST_F (RSDistLockMgrWithMockTickSource, CanOvertakeIfNoPingDocument) {
1759+ getMockCatalog ()->expectGrabLock (
1760+ [](StringData, const OID&, StringData, StringData, Date_t, StringData) {
1761+ // Don't care
1762+ },
1763+ {ErrorCodes::LockStateChangeFailed, " nMod 0" });
1764+
1765+ LocksType currentLockDoc;
1766+ currentLockDoc.setName (" bar" );
1767+ currentLockDoc.setState (LocksType::LOCKED);
1768+ currentLockDoc.setProcess (" otherProcess" );
1769+ currentLockDoc.setLockID (OID (" 5572007fda9e476582bf3716" ));
1770+ currentLockDoc.setWho (" me" );
1771+ currentLockDoc.setWhy (" why" );
1772+
1773+ getMockCatalog ()->expectGetLockByName ([](StringData name) { ASSERT_EQUALS (" bar" , name); },
1774+ currentLockDoc);
1775+
1776+ getMockCatalog ()->expectGetPing ([](StringData process) {
1777+ ASSERT_EQUALS (" otherProcess" , process);
1778+ }, {ErrorCodes::NoMatchingDocument, " no ping" });
1779+
1780+ getMockCatalog ()->expectGetServerInfo ([]() {}, DistLockCatalog::ServerInfo (Date_t (), OID ()));
1781+
1782+ // First attempt will record the ping data.
1783+ {
1784+ auto status = getMgr ()->lock (" bar" , " " , Milliseconds (0 ), Milliseconds (0 )).getStatus ();
1785+ ASSERT_NOT_OK (status);
1786+ ASSERT_EQUALS (ErrorCodes::LockBusy, status.code ());
1787+ }
1788+
1789+ OID lastTS;
1790+ getMockCatalog ()->expectGrabLock (
1791+ [&lastTS](StringData, const OID& newTS, StringData, StringData, Date_t, StringData) {
1792+ lastTS = newTS;
1793+ },
1794+ {ErrorCodes::LockStateChangeFailed, " nMod 0" });
1795+
1796+ getMockCatalog ()->expectGetLockByName ([](StringData name) { ASSERT_EQUALS (" bar" , name); },
1797+ currentLockDoc);
1798+
1799+ getMockCatalog ()->expectGetPing ([](StringData process) {
1800+ ASSERT_EQUALS (" otherProcess" , process);
1801+ }, {ErrorCodes::NoMatchingDocument, " no ping" });
1802+
1803+ getMockCatalog ()->expectGetServerInfo (
1804+ []() {}, DistLockCatalog::ServerInfo (Date_t () + kLockExpiration + Milliseconds (1 ), OID ()));
1805+
1806+ getMockCatalog ()->expectOvertakeLock (
1807+ [this , &lastTS, ¤tLockDoc](StringData lockID,
1808+ const OID& lockSessionID,
1809+ const OID& currentHolderTS,
1810+ StringData who,
1811+ StringData processId,
1812+ Date_t time,
1813+ StringData why) {
1814+ ASSERT_EQUALS (" bar" , lockID);
1815+ ASSERT_EQUALS (lastTS, lockSessionID);
1816+ ASSERT_EQUALS (currentLockDoc.getLockID (), currentHolderTS);
1817+ ASSERT_EQUALS (getProcessID (), processId);
1818+ ASSERT_EQUALS (" foo" , why);
1819+ },
1820+ currentLockDoc); // return arbitrary valid lock document, for testing purposes only.
1821+
1822+ getMockCatalog ()->expectUnLock (
1823+ [](const OID&) {
1824+ // Don't care
1825+ },
1826+ Status::OK ());
1827+
1828+ // Second attempt should overtake lock.
1829+ { ASSERT_OK (getMgr ()->lock (" bar" , " foo" , Milliseconds (0 ), Milliseconds (0 )).getStatus ()); }
1830+ }
1831+
17491832} // unnamed namespace
17501833} // namespace mongo
0 commit comments