Skip to content

Commit 8fade92

Browse files
committed
SERVER-19897 Cannot overtake lock if ping document is deleted in RS config servers
1 parent fc05f77 commit 8fade92

File tree

2 files changed

+98
-12
lines changed

2 files changed

+98
-12
lines changed

src/mongo/s/catalog/replset/replset_dist_lock_manager.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,21 @@ void ReplSetDistLockManager::doTask() {
152152
StatusWith<bool> ReplSetDistLockManager::canOvertakeLock(LocksType lockDoc) {
153153
const auto& processID = lockDoc.getProcess();
154154
auto pingStatus = _catalog->getPing(processID);
155-
if (!pingStatus.isOK()) {
156-
return pingStatus.getStatus();
157-
}
158155

159-
const auto& pingDoc = pingStatus.getValue();
160-
Status pingDocValidationStatus = pingDoc.validate();
161-
if (!pingDocValidationStatus.isOK()) {
162-
return {ErrorCodes::UnsupportedFormat,
163-
str::stream() << "invalid ping document for " << processID << ": "
164-
<< pingDocValidationStatus.toString()};
165-
}
156+
Date_t pingValue;
157+
if (pingStatus.isOK()) {
158+
const auto& pingDoc = pingStatus.getValue();
159+
Status pingDocValidationStatus = pingDoc.validate();
160+
if (!pingDocValidationStatus.isOK()) {
161+
return {ErrorCodes::UnsupportedFormat,
162+
str::stream() << "invalid ping document for " << processID << ": "
163+
<< pingDocValidationStatus.toString()};
164+
}
165+
166+
pingValue = pingDoc.getPing();
167+
} else if (pingStatus.getStatus() != ErrorCodes::NoMatchingDocument) {
168+
return pingStatus.getStatus();
169+
} // else use default pingValue if ping document does not exist.
166170

167171
Timer timer(_serviceContext->getTickSource());
168172
auto serverInfoStatus = _catalog->getServerInfo();
@@ -175,7 +179,6 @@ StatusWith<bool> ReplSetDistLockManager::canOvertakeLock(LocksType lockDoc) {
175179
// time from the config server.
176180
milliseconds delay(timer.millis() / 2); // Assuming symmetrical delay.
177181

178-
Date_t pingValue = pingDoc.getPing();
179182
const auto& serverInfo = serverInfoStatus.getValue();
180183

181184
stdx::lock_guard<stdx::mutex> lk(_mutex);

src/mongo/s/catalog/replset/replset_dist_lock_manager_test.cpp

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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, &currentLockDoc](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

Comments
 (0)