Skip to content

Commit 0728269

Browse files
committed
[#27677] docdb: Support lock_timeout for object locks
Summary: Added support for lock_timeout for object locks. When taking table-level locks (like LOCK TABLE), the command will now respect the timeout setting and return an error if it can’t get the lock in time. Note: Right now, only table-level locks support lock_timeout. Row-level locks are not yet covered. Jira: DB-17276 Test Plan: ./yb_build.sh --cxx-test pgwrapper_pg_object_locks-test --gtest_filter PgObjectLocksTest.VerifyLockTimeout Reviewers: bkolagani Reviewed By: bkolagani Subscribers: rthallam, ybase, yql Differential Revision: https://phorge.dev.yugabyte.com/D47331
1 parent 9908271 commit 0728269

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

src/yb/yql/pggate/pg_client.cc

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ ExchangeFuture<Data>::Result ExchangeFuture<Data>::get() {
225225

226226
template <class LWReqPB, class LWRespPB, class ResTp, tserver::PgSharedExchangeReqType ShExcReqType>
227227
struct PgClientData : public FetchBigDataCallback {
228+
using RequestType = LWReqPB;
228229
using ResultType = ResTp;
229230
static constexpr tserver::PgSharedExchangeReqType kSharedExchangeRequestType = ShExcReqType;
230231

@@ -874,9 +875,10 @@ class PgClient::Impl : public BigDataFetcher {
874875
auto& exchange = session_shared_mem_->exchange();
875876
auto out = exchange.Obtain(kHeaderSize + kMetadataSize + data->req.SerializedSize());
876877
if (out) {
878+
auto timeout = GetTimeout<typename Data::RequestType>();
877879
*reinterpret_cast<uint8_t *>(out) = Data::kSharedExchangeRequestType;
878880
out += sizeof(uint8_t);
879-
LittleEndian::Store64(out, timeout_.ToMilliseconds());
881+
LittleEndian::Store64(out, timeout.ToMilliseconds());
880882
out += sizeof(uint64_t);
881883
out = pointer_cast<std::byte*>(metadata.SerializeToArray(to_uchar_ptr(out)));
882884
const auto size = data->req.SerializedSize();
@@ -893,13 +895,14 @@ class PgClient::Impl : public BigDataFetcher {
893895
data->promise.set_value(MakeExchangeResult(*data, status));
894896
return data->promise.get_future();
895897
}
896-
data->SetupExchange(&exchange, this, timeout_);
898+
data->SetupExchange(&exchange, this, timeout);
897899
return ExchangeFuture<Data>(std::move(data));
898900
}
899901
}
900902
data->controller.set_invoke_callback_mode(rpc::InvokeCallbackMode::kReactorThread);
901903
(proxy_.get()->*method)(
902-
data->req, &data->resp, SetupController(&data->controller), [data] {
904+
data->req, &data->resp, SetupController<typename Data::RequestType>(&data->controller),
905+
[data] {
903906
data->promise.set_value(MakeExchangeResult(*data, data->controller.CheckedResponse()));
904907
});
905908
return data->promise.get_future();
@@ -1633,16 +1636,23 @@ class PgClient::Impl : public BigDataFetcher {
16331636
return Format("Session id $0: ", session_id_);
16341637
}
16351638

1639+
template <typename T = void>
1640+
MonoDelta GetTimeout() {
1641+
if constexpr (std::is_same_v<T, tserver::PgAcquireAdvisoryLockRequestPB> ||
1642+
std::is_same_v<T, tserver::LWPgAcquireObjectLockRequestPB>) {
1643+
return std::min(timeout_, lock_timeout_);
1644+
}
1645+
return timeout_;
1646+
}
1647+
16361648
template <typename T = void>
16371649
rpc::RpcController* SetupController(
16381650
rpc::RpcController* controller,
16391651
CoarseTimePoint deadline = CoarseTimePoint()) {
16401652
if (deadline != CoarseTimePoint()) {
16411653
controller->set_deadline(deadline);
1642-
} else if constexpr (std::is_same_v<T, tserver::PgAcquireAdvisoryLockRequestPB>) {
1643-
controller->set_timeout(std::min(timeout_, lock_timeout_));
16441654
} else {
1645-
controller->set_timeout(timeout_);
1655+
controller->set_timeout(GetTimeout<T>());
16461656
}
16471657
return controller;
16481658
}

src/yb/yql/pgwrapper/pg_object_locks-test.cc

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ DECLARE_bool(TEST_tserver_enable_ysql_lease_refresh);
5959
DECLARE_int64(olm_poll_interval_ms);
6060
DECLARE_string(vmodule);
6161
DECLARE_bool(ysql_enable_auto_analyze);
62+
DECLARE_int32(pg_client_extra_timeout_ms);
6263

6364
using namespace std::literals;
6465

@@ -817,6 +818,45 @@ TEST_F(PgObjectLocksTest, RetryExclusiveLockOnTserverLeaseRefresh) {
817818
ASSERT_OK(conn1.CommitTransaction());
818819
}
819820

821+
TEST_F(PgObjectLocksTest, VerifyLockTimeout) {
822+
constexpr int kLockTimeoutDurationMs = 3000;
823+
constexpr int kExtraTimeoutMs = 1000;
824+
825+
auto setup_conn = ASSERT_RESULT(Connect());
826+
ASSERT_OK(setup_conn.Execute("CREATE TABLE t (k INT PRIMARY KEY, v INT)"));
827+
ASSERT_OK(setup_conn.Execute("INSERT INTO t VALUES (1, 1)"));
828+
829+
auto conn1 = ASSERT_RESULT(Connect());
830+
auto conn2 = ASSERT_RESULT(Connect());
831+
832+
ASSERT_OK(conn1.StartTransaction(IsolationLevel::SNAPSHOT_ISOLATION));
833+
ASSERT_OK(conn1.Execute("LOCK TABLE t IN ACCESS EXCLUSIVE MODE;"));
834+
835+
ASSERT_OK(conn2.ExecuteFormat("SET lock_timeout='$0ms';", kLockTimeoutDurationMs));
836+
ASSERT_OK(conn2.StartTransaction(IsolationLevel::SNAPSHOT_ISOLATION));
837+
838+
std::future<Status> conn2_lock_future = std::async(std::launch::async, [&]() -> Status {
839+
return conn2.Execute("LOCK TABLE t IN ACCESS EXCLUSIVE MODE;");
840+
});
841+
842+
// Wait briefly to confirm that conn2 is actually blocking on the lock.
843+
ASSERT_EQ(conn2_lock_future.wait_for(
844+
std::chrono::seconds(1)), std::future_status::timeout);
845+
846+
auto expected_timeout_ms =
847+
kLockTimeoutDurationMs + FLAGS_pg_client_extra_timeout_ms + kExtraTimeoutMs;
848+
ASSERT_EQ(conn2_lock_future.wait_for(
849+
std::chrono::milliseconds(expected_timeout_ms * kTimeMultiplier)), std::future_status::ready);
850+
851+
// Verify the lock attempt fails with lock timeout error.
852+
Status result = conn2_lock_future.get();
853+
ASSERT_NOK(result);
854+
ASSERT_STR_CONTAINS(result.ToString(), "Timed out");
855+
856+
// Conn1 should still be able to commit
857+
ASSERT_OK(conn1.CommitTransaction());
858+
}
859+
820860
YB_STRONGLY_TYPED_BOOL(DoMasterFailover);
821861
YB_STRONGLY_TYPED_BOOL(UseExplicitLocksInsteadOfDdl);
822862
class PgObjecLocksTestOutOfOrderMessageHandling

0 commit comments

Comments
 (0)