@@ -127,7 +127,8 @@ class MasterTest : public MasterTestBase {
127127 Result<scoped_refptr<NamespaceInfo>> FindNamespaceByName (
128128 YQLDatabase db_type, const std::string& name);
129129
130- Result<TSHeartbeatResponsePB> SendNewTSRegistrationHeartbeat (const std::string& uuid);
130+ Result<TSHeartbeatResponsePB> SendNewTSRegistrationHeartbeat (
131+ const std::string& uuid, int64_t instance_seqno);
131132
132133 private:
133134 // Used by SendNewTSRegistrationHeartbeat to avoid host port collisions.
@@ -2775,16 +2776,16 @@ TEST_F(MasterTest, RefreshYsqlLeaseWithoutRegistration) {
27752776
27762777TEST_F (MasterTest, RefreshYsqlLease) {
27772778 ANNOTATE_UNPROTECTED_WRITE (FLAGS_enable_ysql_operation_lease) = true ;
2778- const std::string kTsUUID1 = " ts-uuid1" ;
2779- const std::string kTsUUID2 = " ts-uuid2 " ;
2779+ const std::string kTsUUID = " ts-uuid1" ;
2780+ constexpr uint64_t kSeqno = 1 ;
27802781
2781- auto reg_resp1 = ASSERT_RESULT (SendNewTSRegistrationHeartbeat (kTsUUID1 ));
2782+ auto reg_resp1 = ASSERT_RESULT (SendNewTSRegistrationHeartbeat (kTsUUID , kSeqno ));
27822783 ASSERT_FALSE (reg_resp1.needs_reregister ());
27832784
27842785 auto ddl_client = MasterDDLClient{std::move (*proxy_ddl_)};
27852786 auto lease_refresh_send_time_ms = MonoTime::Now ().GetDeltaSinceMin ().ToMilliseconds ();
2786- auto info = ASSERT_RESULT (ddl_client. RefreshYsqlLease (
2787- kTsUUID1 , /* instance_seqno */ 1 , lease_refresh_send_time_ms, {}));
2787+ auto info =
2788+ ASSERT_RESULT (ddl_client. RefreshYsqlLease ( kTsUUID , kSeqno , lease_refresh_send_time_ms, {}));
27882789 ASSERT_TRUE (info.new_lease ());
27892790 ASSERT_EQ (info.lease_epoch (), 1 );
27902791 ASSERT_GT (
@@ -2794,27 +2795,82 @@ TEST_F(MasterTest, RefreshYsqlLease) {
27942795 // todo(zdrudi): but we need to do this and check the bootstrap entries...
27952796 // Refresh lease again. Since we omitted current lease epoch, master leader should still say this
27962797 // is a new lease.
2797- info = ASSERT_RESULT (ddl_client. RefreshYsqlLease (
2798- kTsUUID1 , /* instance_seqno */ 1 , lease_refresh_send_time_ms, {}));
2798+ info =
2799+ ASSERT_RESULT (ddl_client. RefreshYsqlLease ( kTsUUID , kSeqno , lease_refresh_send_time_ms, {}));
27992800 ASSERT_TRUE (info.new_lease ());
28002801 ASSERT_EQ (info.lease_epoch (), 1 );
28012802 ASSERT_GT (info.lease_expiry_time_ms (), lease_refresh_send_time_ms);
28022803
28032804 // Refresh lease again. We included current lease epoch but it's incorrect.
2804- info = ASSERT_RESULT (
2805- ddl_client.RefreshYsqlLease (kTsUUID1 , /* instance_seqno */ 1 , lease_refresh_send_time_ms, 0 ));
2805+ info = ASSERT_RESULT (ddl_client.RefreshYsqlLease (kTsUUID , kSeqno , lease_refresh_send_time_ms, 0 ));
28062806 ASSERT_TRUE (info.new_lease ());
28072807 ASSERT_EQ (info.lease_epoch (), 1 );
28082808 ASSERT_GT (info.lease_expiry_time_ms (), lease_refresh_send_time_ms);
28092809
28102810 // Refresh lease again. Current lease epoch is correct so master leader should not set new lease
28112811 // bit.
2812- info = ASSERT_RESULT (
2813- ddl_client.RefreshYsqlLease (kTsUUID1 , /* instance_seqno */ 1 , lease_refresh_send_time_ms, 1 ));
2812+ info = ASSERT_RESULT (ddl_client.RefreshYsqlLease (kTsUUID , kSeqno , lease_refresh_send_time_ms, 1 ));
28142813 ASSERT_FALSE (info.new_lease ());
28152814 ASSERT_GT (info.lease_expiry_time_ms (), lease_refresh_send_time_ms);
28162815}
28172816
2817+ TEST_F (MasterTest, RelinquishLease) {
2818+ ANNOTATE_UNPROTECTED_WRITE (FLAGS_enable_ysql_operation_lease) = true ;
2819+ const std::string kTsUUID = " ts-uuid1" ;
2820+ constexpr uint64_t kSeqno1 = 1 ;
2821+ auto reg_resp1 = ASSERT_RESULT (SendNewTSRegistrationHeartbeat (kTsUUID , kSeqno1 ));
2822+ ASSERT_FALSE (reg_resp1.needs_reregister ());
2823+
2824+ auto ddl_client = MasterDDLClient{std::move (*proxy_ddl_)};
2825+ auto info1 = ASSERT_RESULT (ddl_client.RefreshYsqlLease (
2826+ kTsUUID , kSeqno1 , MonoTime::Now ().GetDeltaSinceMin ().ToMilliseconds (), {}));
2827+ ASSERT_TRUE (info1.new_lease ());
2828+ ASSERT_EQ (info1.lease_epoch (), 1 );
2829+
2830+ ASSERT_OK (ddl_client.RelinquishYsqlLease (kTsUUID , kSeqno1 ));
2831+ auto list_ts = ASSERT_RESULT (cluster_client_->ListTabletServers ());
2832+ ASSERT_EQ (list_ts.servers_size (), 1 );
2833+ ASSERT_FALSE (list_ts.servers (0 ).lease_info ().is_live ());
2834+
2835+ // We should be able to get a new lease for a new instance of the ts.
2836+ constexpr uint64_t kSeqno2 = 2 ;
2837+ auto reg_resp2 = ASSERT_RESULT (SendNewTSRegistrationHeartbeat (kTsUUID , kSeqno2 ));
2838+ ASSERT_FALSE (reg_resp2.needs_reregister ());
2839+ auto info2 = ASSERT_RESULT (ddl_client.RefreshYsqlLease (
2840+ kTsUUID , kSeqno2 , MonoTime::Now ().GetDeltaSinceMin ().ToMilliseconds (), {}));
2841+ ASSERT_TRUE (info2.new_lease ());
2842+ ASSERT_EQ (info2.lease_epoch (), 2 );
2843+ }
2844+
2845+ TEST_F (MasterTest, RelinquishLeaseOfReplacedTS) {
2846+ ANNOTATE_UNPROTECTED_WRITE (FLAGS_enable_ysql_operation_lease) = true ;
2847+ const std::string kTsUUID = " ts-uuid1" ;
2848+ constexpr uint64_t kSeqno1 = 1 ;
2849+ auto reg_resp1 = ASSERT_RESULT (SendNewTSRegistrationHeartbeat (kTsUUID , kSeqno1 ));
2850+ ASSERT_FALSE (reg_resp1.needs_reregister ());
2851+
2852+ auto ddl_client = MasterDDLClient{std::move (*proxy_ddl_)};
2853+ auto info1 = ASSERT_RESULT (ddl_client.RefreshYsqlLease (
2854+ kTsUUID , kSeqno1 , MonoTime::Now ().GetDeltaSinceMin ().ToMilliseconds (), {}));
2855+ ASSERT_TRUE (info1.new_lease ());
2856+ ASSERT_EQ (info1.lease_epoch (), 1 );
2857+
2858+ // Simulate a second ts process replacing the first.
2859+ constexpr uint64_t kSeqno2 = 2 ;
2860+ auto reg_resp2 = ASSERT_RESULT (SendNewTSRegistrationHeartbeat (kTsUUID , kSeqno2 ));
2861+ ASSERT_FALSE (reg_resp2.needs_reregister ());
2862+ auto info2 = ASSERT_RESULT (ddl_client.RefreshYsqlLease (
2863+ kTsUUID , kSeqno2 , MonoTime::Now ().GetDeltaSinceMin ().ToMilliseconds (), {}));
2864+ ASSERT_TRUE (info2.new_lease ());
2865+ ASSERT_EQ (info2.lease_epoch (), 2 );
2866+
2867+ // Send relinquish lease request from the first ts instance.
2868+ auto status = ddl_client.RelinquishYsqlLease (kTsUUID , kSeqno1 );
2869+ ASSERT_NOK (status);
2870+ ASSERT_STR_CONTAINS (
2871+ status.ToString (), " Relinquish lease request for a replaced tserver instance" );
2872+ }
2873+
28182874Result<TSHeartbeatResponsePB> MasterTest::SendHeartbeat (
28192875 TSToMasterCommonPB common, std::optional<TSRegistrationPB> registration,
28202876 std::optional<TabletReportPB> report) {
@@ -2839,7 +2895,8 @@ Result<TSHeartbeatResponsePB> MasterTest::SendHeartbeat(
28392895 return resp;
28402896}
28412897
2842- Result<TSHeartbeatResponsePB> MasterTest::SendNewTSRegistrationHeartbeat (const std::string& uuid) {
2898+ Result<TSHeartbeatResponsePB> MasterTest::SendNewTSRegistrationHeartbeat (
2899+ const std::string& uuid, int64_t instance_seqno) {
28432900 TSRegistrationPB reg;
28442901 *reg.mutable_common ()->add_private_rpc_addresses () =
28452902 MakeHostPortPB (" localhost" , 1000 + registered_ts_count_);
@@ -2849,7 +2906,7 @@ Result<TSHeartbeatResponsePB> MasterTest::SendNewTSRegistrationHeartbeat(const s
28492906
28502907 TSToMasterCommonPB common;
28512908 common.mutable_ts_instance ()->set_permanent_uuid (uuid);
2852- common.mutable_ts_instance ()->set_instance_seqno (1 );
2909+ common.mutable_ts_instance ()->set_instance_seqno (instance_seqno );
28532910 auto result = SendHeartbeat (common, reg);
28542911 if (result.ok ()) {
28552912 registered_ts_count_++;
0 commit comments