Skip to content

Commit 321857c

Browse files
committed
[#28828] docdb: Perform initial is-region-local checks on tserver side
Summary: When using region local transactions, there are two times we check for region locality: 1. We perform a check in postgres code (YBCIsRegionLocal) that takes the relation's tablespace oid, calculates the tablespace cost, and checks this is at most the interzone cost. This value is propagated up through pggate and eventually passed to the tserver in the Perform RPC, where it is checked only if the Perform RPC starts a transaction. 2. We perform checks at the tablet level in YBTransaction to decide whether we need to promote the the transaction to global. (1) does nothing when table-level locking is enabled, because the transaction is now always started before the Perform RPC (always done during an AcquireObjectLocks RPC), forcing us to use (2) instead, which has performance implications (#28317). Additionally, as part of work for tablespace locality, we now pass tablespace oid for read/write operations inside the Perform, and additionally have tablespace information on the tserver for any tablespace with transaction tables. So the calculation for (1) can be done entirely on tserver side. This revision adds calculation of region locality on the tserver side using the above information. A future change will address #28317 by pushing tablespace oid up in AcquireObjectLocks RPC and reusing this logic. The old logic (YBCIsRegionLocal) is left intact for now to avoid severe performance regressions during upgrade, since the new logic only works after finalizing an upgrade to a version with the enable_tablespace_based_transaction_placement autoflag (this controls availability of tablespace information on the tserver). It can be removed once we have a guarantee that all upgrades come from a verison with this autoflag (2025.1.1.1/2025.1.2/2025.2.0+). There is also a potential for performance regression if the auto_create_transaction_tables is off (since the new calculation is based off of tablespaces with transaction tables), but this flag is on by default and turning it off is ill-advised in general (manual creation of transaction tables via yb-admin becomes required). Jira: DB-18538 Test Plan: Jenkins Reviewers: bkolagani Reviewed By: bkolagani Subscribers: yql, ybase Tags: #jenkins-ready Differential Revision: https://phorge.dev.yugabyte.com/D47241
1 parent 92f0f30 commit 321857c

12 files changed

+185
-52
lines changed

src/yb/client/transaction_manager.cc

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@ namespace client {
7777

7878
namespace {
7979

80+
const CloudInfoPB& GetPlacementFromGFlags() {
81+
static GoogleOnceType once = GOOGLE_ONCE_INIT;
82+
static CloudInfoPB cloud_info;
83+
auto set_placement_from_gflags = [](CloudInfoPB* cloud_info) {
84+
cloud_info->set_placement_cloud(FLAGS_placement_cloud);
85+
cloud_info->set_placement_region(FLAGS_placement_region);
86+
cloud_info->set_placement_zone(FLAGS_placement_zone);
87+
};
88+
GoogleOnceInitArg(
89+
&once, static_cast<void (*)(CloudInfoPB*)>(set_placement_from_gflags), &cloud_info);
90+
91+
return cloud_info;
92+
}
93+
8094
// Cache of tablet ids of the global transaction table and any transaction tables with
8195
// the same placement.
8296
class TransactionTableState {
@@ -110,6 +124,7 @@ class TransactionTableState {
110124
std::lock_guard lock(mutex_);
111125
if (!initialized_.load() || status_tablets_version_ < new_version) {
112126
tablets_ = std::move(tablets);
127+
tablespace_region_local_.clear();
113128
tablespace_contains_tablespace_.clear();
114129
has_region_local_tablets_.store(!tablets_.region_local_tablets.empty());
115130
status_tablets_version_ = new_version;
@@ -126,6 +141,32 @@ class TransactionTableState {
126141
return tablets_.tablespaces.contains(tablespace_oid);
127142
}
128143

144+
bool TablespaceIsRegionLocal(PgTablespaceOid tablespace_oid) {
145+
if (tablespace_oid == kPgInvalidOid) {
146+
return false;
147+
}
148+
149+
{
150+
SharedLock lock(mutex_);
151+
auto itr = tablespace_region_local_.find(tablespace_oid);
152+
if (itr != tablespace_region_local_.end()) {
153+
return itr->second;
154+
}
155+
}
156+
157+
std::lock_guard lock(mutex_);
158+
auto itr = tablets_.tablespaces.find(tablespace_oid);
159+
if (itr == tablets_.tablespaces.end()) {
160+
return false;
161+
}
162+
163+
auto& placement = itr->second.placement_info;
164+
return tablespace_region_local_.try_emplace(
165+
tablespace_oid,
166+
PlacementInfoContainsCloudInfo(placement, GetPlacementFromGFlags()) &&
167+
!PlacementInfoSpansMultipleRegions(placement)).first->second;
168+
}
169+
129170
bool TablespaceContainsTablespace(PgTablespaceOid lhs, PgTablespaceOid rhs) {
130171
if (lhs == rhs) {
131172
return true;
@@ -241,6 +282,8 @@ class TransactionTableState {
241282

242283
TransactionStatusTablets tablets_ GUARDED_BY(mutex_);
243284

285+
std::unordered_map<PgTablespaceOid, bool> tablespace_region_local_ GUARDED_BY(mutex_);
286+
244287
struct TablespaceOidPair {
245288
PgTablespaceOid first;
246289
PgTablespaceOid second;
@@ -251,20 +294,6 @@ class TransactionTableState {
251294
std::unordered_map<TablespaceOidPair, bool> tablespace_contains_tablespace_ GUARDED_BY(mutex_);
252295
};
253296

254-
const CloudInfoPB& GetPlacementFromGFlags() {
255-
static GoogleOnceType once = GOOGLE_ONCE_INIT;
256-
static CloudInfoPB cloud_info;
257-
auto set_placement_from_gflags = [](CloudInfoPB* cloud_info) {
258-
cloud_info->set_placement_cloud(FLAGS_placement_cloud);
259-
cloud_info->set_placement_region(FLAGS_placement_region);
260-
cloud_info->set_placement_zone(FLAGS_placement_zone);
261-
};
262-
GoogleOnceInitArg(
263-
&once, static_cast<void (*)(CloudInfoPB*)>(set_placement_from_gflags), &cloud_info);
264-
265-
return cloud_info;
266-
}
267-
268297
// Loads transaction tablets list to cache.
269298
class LoadStatusTabletsTask {
270299
public:
@@ -460,6 +489,10 @@ class TransactionManager::Impl {
460489
return table_state_.HasAnyRegionLocalStatusTablets();
461490
}
462491

492+
bool TablespaceIsRegionLocal(PgTablespaceOid tablespace_oid) {
493+
return table_state_.TablespaceIsRegionLocal(tablespace_oid);
494+
}
495+
463496
bool TablespaceLocalTransactionsPossible(PgTablespaceOid tablespace_oid) {
464497
return table_state_.HasAnyTransactionLocalStatusTablets(tablespace_oid);
465498
}
@@ -560,6 +593,10 @@ bool TransactionManager::RegionLocalTransactionsPossible() {
560593
return impl_->RegionLocalTransactionsPossible();
561594
}
562595

596+
bool TransactionManager::TablespaceIsRegionLocal(PgTablespaceOid tablespace_oid) {
597+
return impl_->TablespaceIsRegionLocal(tablespace_oid);
598+
}
599+
563600
bool TransactionManager::TablespaceLocalTransactionsPossible(PgTablespaceOid tablespace_oid) {
564601
return impl_->TablespaceLocalTransactionsPossible(tablespace_oid);
565602
}

src/yb/client/transaction_manager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ class TransactionManager {
6666

6767
bool RegionLocalTransactionsPossible();
6868

69+
bool TablespaceIsRegionLocal(PgTablespaceOid tablespace_oid);
70+
6971
bool TablespaceLocalTransactionsPossible(PgTablespaceOid tablespace_oid);
7072

7173
bool TablespaceContainsTablespace(PgTablespaceOid lhs, PgTablespaceOid rhs);

src/yb/master/master.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,8 @@ Status Master::RegisterServices() {
335335
FLAGS_master_svc_queue_length,
336336
std::make_shared<tserver::PgClientServiceImpl>(
337337
*master_tablet_server_, client_future(), clock(),
338-
std::bind(&Master::TransactionPool, this), mem_tracker(), metric_entity(), messenger(),
339-
fs_manager_->uuid(), options())));
338+
std::bind(&Master::TransactionManager, this), std::bind(&Master::TransactionPool, this),
339+
mem_tracker(), metric_entity(), messenger(), fs_manager_->uuid(), options())));
340340

341341
return Status::OK();
342342
}

src/yb/tserver/pg_client_service.cc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -540,14 +540,17 @@ class PgClientServiceImpl::Impl : public SessionProvider {
540540
explicit Impl(
541541
std::reference_wrapper<const TabletServerIf> tablet_server,
542542
const std::shared_future<client::YBClient*>& client_future,
543-
const scoped_refptr<ClockBase>& clock, TransactionPoolProvider transaction_pool_provider,
543+
const scoped_refptr<ClockBase>& clock,
544+
TransactionManagerProvider transaction_manager_provider,
545+
TransactionPoolProvider transaction_pool_provider,
544546
rpc::Messenger* messenger, const TserverXClusterContextIf* xcluster_context,
545547
PgMutationCounter* pg_node_level_mutation_counter, MetricEntity* metric_entity,
546548
const MemTrackerPtr& parent_mem_tracker, const std::string& permanent_uuid,
547549
const server::ServerBaseOptions& tablet_server_opts)
548550
: tablet_server_(tablet_server.get()),
549551
client_future_(client_future),
550552
clock_(clock),
553+
transaction_manager_provider_(std::move(transaction_manager_provider)),
551554
transaction_pool_provider_(std::move(transaction_pool_provider)),
552555
messenger_(*messenger),
553556
table_cache_(client_future_),
@@ -577,7 +580,8 @@ class PgClientServiceImpl::Impl : public SessionProvider {
577580
.lock_owner_registry =
578581
tablet_server_.ObjectLockSharedStateManager()
579582
? &tablet_server_.ObjectLockSharedStateManager()->registry()
580-
: nullptr},
583+
: nullptr,
584+
.transaction_manager_provider = transaction_manager_provider_},
581585
cdc_state_table_(client_future_),
582586
txn_snapshot_manager_(
583587
instance_id_,
@@ -2715,6 +2719,7 @@ class PgClientServiceImpl::Impl : public SessionProvider {
27152719
const TabletServerIf& tablet_server_;
27162720
std::shared_future<client::YBClient*> client_future_;
27172721
const scoped_refptr<ClockBase> clock_;
2722+
TransactionManagerProvider transaction_manager_provider_;
27182723
TransactionPoolProvider transaction_pool_provider_;
27192724
rpc::Messenger& messenger_;
27202725
PgTableCache table_cache_;
@@ -2791,15 +2796,17 @@ class PgClientServiceImpl::Impl : public SessionProvider {
27912796
PgClientServiceImpl::PgClientServiceImpl(
27922797
std::reference_wrapper<const TabletServerIf> tablet_server,
27932798
const std::shared_future<client::YBClient*>& client_future,
2794-
const scoped_refptr<ClockBase>& clock, TransactionPoolProvider transaction_pool_provider,
2799+
const scoped_refptr<ClockBase>& clock, TransactionManagerProvider transaction_manager_provider,
2800+
TransactionPoolProvider transaction_pool_provider,
27952801
const std::shared_ptr<MemTracker>& parent_mem_tracker,
27962802
const scoped_refptr<MetricEntity>& entity, rpc::Messenger* messenger,
27972803
const std::string& permanent_uuid, const server::ServerBaseOptions& tablet_server_opts,
27982804
const TserverXClusterContextIf* xcluster_context,
27992805
PgMutationCounter* pg_node_level_mutation_counter)
28002806
: PgClientServiceIf(entity),
28012807
impl_(new Impl(
2802-
tablet_server, client_future, clock, std::move(transaction_pool_provider), messenger,
2808+
tablet_server, client_future, clock, std::move(transaction_manager_provider),
2809+
std::move(transaction_pool_provider), messenger,
28032810
xcluster_context, pg_node_level_mutation_counter, entity.get(), parent_mem_tracker,
28042811
permanent_uuid, tablet_server_opts)) {}
28052812

src/yb/tserver/pg_client_service.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ class PgClientServiceImpl : public PgClientServiceIf {
121121
explicit PgClientServiceImpl(
122122
std::reference_wrapper<const TabletServerIf> tablet_server,
123123
const std::shared_future<client::YBClient*>& client_future,
124-
const scoped_refptr<ClockBase>& clock, TransactionPoolProvider transaction_pool_provider,
124+
const scoped_refptr<ClockBase>& clock,
125+
TransactionManagerProvider transaction_manager_provider,
126+
TransactionPoolProvider transaction_pool_provider,
125127
const std::shared_ptr<MemTracker>& parent_mem_tracker,
126128
const scoped_refptr<MetricEntity>& entity, rpc::Messenger* messenger,
127129
const std::string& permanent_uuid, const server::ServerBaseOptions& tablet_server_opts,

src/yb/tserver/pg_client_session.cc

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "yb/client/table.h"
3939
#include "yb/client/table_alterer.h"
4040
#include "yb/client/transaction.h"
41+
#include "yb/client/transaction_manager.h"
4142
#include "yb/client/yb_op.h"
4243

4344
#include "yb/common/common.pb.h"
@@ -117,6 +118,11 @@ DEFINE_test_flag(
117118
"Add several unknown tables while processing perfrom request. "
118119
"It is expected that opening of such tables will fail");
119120

121+
DEFINE_test_flag(bool, perform_ignore_pg_is_region_local, false,
122+
"Ignore the is_all_region_local field of PgPerformOptionsPB. The intended state is for "
123+
"everything to work when this field is not set, as the field is only left in for upgrade from "
124+
"older versions and to be removed in the future.");
125+
120126
DECLARE_bool(vector_index_dump_stats);
121127
DECLARE_bool(yb_enable_cdc_consistent_snapshot_streams);
122128
DECLARE_bool(ysql_enable_db_catalog_version_mode);
@@ -1518,6 +1524,10 @@ template <>
15181524
return DoTrackSharedMemoryPgMethodExecution(wait_state, metadata, "AcquireObjectLock");
15191525
}
15201526

1527+
PgTablespaceOid GetOpTablespaceOid(const PgPerformOpPB& op) {
1528+
return op.has_write() ? op.write().tablespace_oid() : op.read().tablespace_oid();
1529+
}
1530+
15211531
} // namespace
15221532

15231533
class PgClientSession::Impl {
@@ -3681,23 +3691,52 @@ class PgClientSession::Impl {
36813691
}
36823692

36833693
TransactionFullLocality GetTargetTransactionLocality(const PgPerformRequestPB& request) const {
3684-
if (!FLAGS_use_tablespace_based_transaction_placement &&
3685-
!request.options().force_tablespace_locality()) {
3686-
return request.options().is_all_region_local()
3687-
? TransactionFullLocality::RegionLocal() : TransactionFullLocality::Global();
3694+
auto tablespace_oids = request.ops() | std::views::transform(GetOpTablespaceOid);
3695+
3696+
if (FLAGS_use_tablespace_based_transaction_placement ||
3697+
request.options().force_tablespace_locality()) {
3698+
if (auto oid = request.options().force_tablespace_locality_oid()) {
3699+
return TransactionFullLocality::TablespaceLocal(oid);
3700+
}
3701+
return CalculateTablespaceBasedLocality(tablespace_oids);
36883702
}
36893703

3690-
if (auto oid = request.options().force_tablespace_locality_oid()) {
3691-
return TransactionFullLocality::TablespaceLocal(oid);
3704+
// TODO: is_all_region_local() handles exactly two cases that tablespace oid check does not:
3705+
// 1. until upgrade is finalized (enable_tablespace_based_transaction_placement autoflag on
3706+
// master), tablespace oid check does not work, so it is needed to avoid global latencies
3707+
// during the upgrade. This is only for upgrades from before 2025.1.2/2025.2.0.
3708+
// 2. if auto_create_local_transaction_tables is OFF (not default), and transaction tables
3709+
// are manually created, tablespace oid will not be mapped to a transaction table, and
3710+
// TablespaceIsRegionLocal() returns false. But this case is not really supported, aside
3711+
// from use setting up some unit tests.
3712+
// Once these are no longer of concern, is_all_region_local and corresponding code in
3713+
// pggate/pg can be removed.
3714+
if (!FLAGS_TEST_perform_ignore_pg_is_region_local && request.options().is_all_region_local()) {
3715+
return TransactionFullLocality::RegionLocal();
36923716
}
3717+
return CalculateRegionBasedLocality(tablespace_oids);
3718+
}
3719+
3720+
TransactionFullLocality CalculateRegionBasedLocality(
3721+
std::ranges::range auto&& tablespace_oids) const {
3722+
auto& transaction_manager = context_.transaction_manager_provider();
3723+
bool all_region_local = transaction_manager.RegionLocalTransactionsPossible();
3724+
for (PgTablespaceOid oid : tablespace_oids) {
3725+
all_region_local = all_region_local && transaction_manager.TablespaceIsRegionLocal(oid);
3726+
}
3727+
return all_region_local
3728+
? TransactionFullLocality::RegionLocal() : TransactionFullLocality::Global();
3729+
}
36933730

3731+
TransactionFullLocality CalculateTablespaceBasedLocality(
3732+
std::ranges::range auto&& tablespace_oids) const {
3733+
auto& transaction_manager = context_.transaction_manager_provider();
36943734
PgTablespaceOid tablespace_oid = kInvalidOid;
3695-
for (const auto& op : request.ops()) {
3696-
PgTablespaceOid oid =
3697-
op.has_write() ? op.write().tablespace_oid() : op.read().tablespace_oid();
3698-
if (tablespace_oid == kInvalidOid) {
3735+
for (PgTablespaceOid oid : tablespace_oids) {
3736+
if (tablespace_oid == kInvalidOid ||
3737+
transaction_manager.TablespaceContainsTablespace(oid, tablespace_oid)) {
36993738
tablespace_oid = oid;
3700-
} else if (tablespace_oid != oid) {
3739+
} else if (!transaction_manager.TablespaceContainsTablespace(tablespace_oid, oid)) {
37013740
return TransactionFullLocality::Global();
37023741
}
37033742
}

src/yb/tserver/pg_client_session.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ struct PgClientSessionContext {
9898
const EventStatsPtr& stats_exchange_response_size;
9999
const std::string& instance_uuid;
100100
docdb::ObjectLockOwnerRegistry* lock_owner_registry;
101+
const TransactionManagerProvider transaction_manager_provider;
101102
};
102103

103104
class PgClientSession final {

src/yb/tserver/tablet_server.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,7 @@ Status TabletServer::RegisterServices() {
679679

680680
auto pg_client_service_holder = std::make_shared<PgClientServiceHolder>(
681681
*this, tablet_manager_->client_future(), clock(),
682+
std::bind(&TabletServer::TransactionManager, this),
682683
std::bind(&TabletServer::TransactionPool, this), mem_tracker(), metric_entity(),
683684
messenger(), permanent_uuid(), options(), xcluster_context_.get(),
684685
&pg_node_level_mutation_counter_);

src/yb/tserver/tserver_fwd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace yb {
2828

2929
namespace client {
3030

31+
class TransactionManager;
3132
class TransactionPool;
3233
class YBPgsqlOp;
3334

@@ -69,6 +70,7 @@ enum class TabletServerServiceRpcMethodIndexes;
6970
YB_STRONGLY_TYPED_BOOL(AllowSplitTablet);
7071

7172
using TSLocalLockManagerPtr = std::shared_ptr<TSLocalLockManager>;
73+
using TransactionManagerProvider = std::function<client::TransactionManager&()>;
7274
using TransactionPoolProvider = std::function<client::TransactionPool&()>;
7375

7476
template <typename, typename = std::void_t<>>

0 commit comments

Comments
 (0)