Skip to content

Commit cfeed59

Browse files
committed
[#29186] docdb: refactor some acquisitions of CatalogManager::mutex_ away
Summary: We've seen larger clusters have serious issues with contention on the `CatalogManager::mutex_`. To make understanding the code that uses this mutex easier, I've refactored several locations that directly acquire the mutex into calls to helper functions. This change will also simplify a future refactor of the COW object maps into a specialized container class. This diff also adds TODOs to code that does too much work while holding `CatalogManager::mutex_`, either in shared mode or exclusively. Jira: DB-18946 Test Plan: existing tests Reviewers: asrivastava, xCluster, hsunder Reviewed By: asrivastava Subscribers: ybase, rthallam Differential Revision: https://phorge.dev.yugabyte.com/D47931
1 parent 8c47f6e commit cfeed59

File tree

5 files changed

+149
-197
lines changed

5 files changed

+149
-197
lines changed

src/yb/integration-tests/delete_table-test.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,11 @@ TEST_F(DeleteTableTest, TestDeleteEmptyTable) {
429429
req, &resp, &rpc));
430430
SCOPED_TRACE(resp.DebugString());
431431
ASSERT_EQ(1, resp.errors_size());
432-
ASSERT_STR_CONTAINS(resp.errors(0).ShortDebugString(), "code: NOT_FOUND");
432+
auto error_msg = resp.errors(0).ShortDebugString();
433+
if (error_msg.find("code: NOT_FOUND") == error_msg.npos &&
434+
error_msg.find("code: DELETED") == error_msg.npos) {
435+
FAIL() << "Expected NOT_FOUND or DELETED, instead got: " << error_msg;
436+
}
433437
}
434438

435439
// 4) The master 'dump-entities' page should not list the deleted table or tablets.

src/yb/master/catalog_manager.cc

Lines changed: 83 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,6 +2522,7 @@ Status CatalogManager::UpdateTransactionStatusTableTablespaces(
25222522
if (tablespace_id && !tablespace_info.count(*tablespace_id)) {
25232523
LOG(INFO) << "Found transaction status table for tablespace id " << *tablespace_id
25242524
<< " which doesn't exist, clearing tablespace id and deleting";
2525+
// todo(GH29185): acquires a COW write lock while holding mutex_ exclusively.
25252526
ClearTransactionStatusTableTablespace(table);
25262527
RETURN_NOT_OK(ScheduleDeleteTable(table, epoch));
25272528
}
@@ -2938,6 +2939,7 @@ Status CatalogManager::DoSplitTablet(
29382939
// mutex_ -> table -> tablet is required to prevent deadlocks.
29392940
// TODO: Pass the table and tablet locks in directly to the validation functions.
29402941
SharedLock lock(mutex_);
2942+
// todo(GH29185): Acquiring a write lock while holding mutex_.
29412943
auto source_table_lock = table->LockForWrite();
29422944
TabletInfo::WriteLock source_tablet_lock;
29432945
{
@@ -3118,6 +3120,11 @@ TabletInfos CatalogManager::GetTabletInfos(const std::vector<TabletId>& ids) {
31183120
return result;
31193121
}
31203122

3123+
bool CatalogManager::IsColocatedNamespace(const NamespaceId& ns_id) const {
3124+
SharedLock lock(mutex_);
3125+
return colocated_db_tablets_map_.contains(ns_id);
3126+
}
3127+
31213128
void CatalogManager::SplitTabletWithKey(
31223129
const TabletInfoPtr& tablet, const std::string& split_encoded_key,
31233130
const std::string& split_partition_key, const ManualSplit is_manual_split,
@@ -4006,10 +4013,9 @@ Status CatalogManager::CreateTable(const CreateTableRequestPB* orig_req,
40064013
namespace_id = ns->id();
40074014
namespace_name = ns->name();
40084015
}
4009-
SharedLock lock(mutex_);
40104016
is_colocated_via_database =
40114017
(IsColocatedDbParentTableId(req.table_id()) ||
4012-
colocated_db_tablets_map_.contains(namespace_id)) &&
4018+
IsColocatedNamespace(namespace_id)) &&
40134019
// Opt out of colocation if the request says so.
40144020
(!req.has_is_colocated_via_database() || req.is_colocated_via_database()) &&
40154021
// Opt out of colocation if the indexed table opted out of colocation.
@@ -4899,6 +4905,7 @@ Status CatalogManager::AddTransactionStatusTablet(
48994905
{
49004906
LockGuard lock(mutex_);
49014907
table = VERIFY_RESULT(FindTableByIdUnlocked(req->table_id()));
4908+
// todo(GH29185): acquires COW write lock while holding mutex_ exclusively.
49024909
write_lock = table->LockForWrite();
49034910

49044911
auto schema = VERIFY_RESULT(table->GetSchema());
@@ -5774,23 +5781,31 @@ Result<scoped_refptr<NamespaceInfo>> CatalogManager::FindNamespaceByIdUnlocked(
57745781
return it->second;
57755782
}
57765783

5784+
Result<scoped_refptr<NamespaceInfo>> CatalogManager::FindNamespaceByName(
5785+
YQLDatabase db_type, const std::string& name) const {
5786+
SharedLock lock(mutex_);
5787+
return FindNamespaceByNameUnlocked(db_type, name);
5788+
}
5789+
5790+
Result<scoped_refptr<NamespaceInfo>> CatalogManager::FindNamespaceByNameUnlocked(
5791+
YQLDatabase db_type, const std::string& name) const {
5792+
auto it = namespace_names_mapper_[db_type].find(name);
5793+
if (it == namespace_names_mapper_[db_type].end()) {
5794+
return STATUS(
5795+
NotFound, Format("$0 keyspace name not found", ShortDatabaseType(db_type)), name,
5796+
MasterError(MasterErrorPB::NAMESPACE_NOT_FOUND));
5797+
}
5798+
return it->second;
5799+
}
5800+
57775801
Result<scoped_refptr<NamespaceInfo>> CatalogManager::FindNamespaceUnlocked(
57785802
const NamespaceIdentifierPB& ns_identifier) const {
57795803
if (ns_identifier.has_id()) {
57805804
return FindNamespaceByIdUnlocked(ns_identifier.id());
57815805
}
57825806

57835807
if (ns_identifier.has_name()) {
5784-
auto db = GetDatabaseType(ns_identifier);
5785-
auto it = namespace_names_mapper_[db].find(ns_identifier.name());
5786-
if (it == namespace_names_mapper_[db].end()) {
5787-
return STATUS(
5788-
NotFound,
5789-
Format("$0 keyspace name not found", ShortDatabaseType(db)),
5790-
ns_identifier.name(),
5791-
MasterError(MasterErrorPB::NAMESPACE_NOT_FOUND));
5792-
}
5793-
return it->second;
5808+
return FindNamespaceByNameUnlocked(GetDatabaseType(ns_identifier), ns_identifier.name());
57945809
}
57955810

57965811
LOG(DFATAL) << __func__ << ": " << ns_identifier.ShortDebugString() << ", \n" << GetStackTrace();
@@ -5907,15 +5922,12 @@ Status CatalogManager::TruncateTable(const TableId& table_id,
59075922
const LeaderEpoch& epoch) {
59085923
// Lookup the table and verify if it exists.
59095924
TRACE(Substitute("Looking up object by id $0", table_id));
5910-
scoped_refptr<TableInfo> table;
5911-
{
5912-
SharedLock lock(mutex_);
5913-
table = tables_->FindTableOrNull(table_id);
5914-
if (table == nullptr) {
5915-
Status s = STATUS_SUBSTITUTE(NotFound, "The object with id $0 does not exist", table_id);
5916-
return SetupError(resp->mutable_error(), MasterErrorPB::OBJECT_NOT_FOUND, s);
5917-
}
5925+
auto table_result = FindTableById(table_id);
5926+
if (!table_result.ok()) {
5927+
return SetupError(
5928+
resp->mutable_error(), MasterErrorPB::OBJECT_NOT_FOUND, table_result.status());
59185929
}
5930+
auto& table = *table_result;
59195931

59205932
TRACE(Substitute("Locking object with id $0", table_id));
59215933
RETURN_NOT_OK(CatalogManagerUtil::CheckIfTableDeletedOrNotVisibleToClient(
@@ -6023,17 +6035,13 @@ Status CatalogManager::IsTruncateTableDone(const IsTruncateTableDoneRequestPB* r
60236035

60246036
// Lookup the truncated table.
60256037
TRACE("Looking up table $0", req->table_id());
6026-
scoped_refptr<TableInfo> table;
6027-
{
6028-
SharedLock lock(mutex_);
6029-
table = tables_->FindTableOrNull(req->table_id());
6030-
}
6038+
auto table_result = FindTableById(req->table_id());
60316039

6032-
if (table == nullptr) {
6040+
if (!table_result.ok()) {
60336041
Status s = STATUS(NotFound, "The object does not exist: table with id", req->table_id());
60346042
return SetupError(resp->mutable_error(), MasterErrorPB::OBJECT_NOT_FOUND, s);
60356043
}
6036-
6044+
const auto& table = *table_result;
60376045
TRACE("Locking table");
60386046
RETURN_NOT_OK(
60396047
CatalogManagerUtil::CheckIfTableDeletedOrNotVisibleToClient(table->LockForRead(), resp));
@@ -6541,7 +6549,6 @@ Status CatalogManager::DeleteTable(
65416549
DCHECK(req->transaction().has_transaction_id());
65426550
}
65436551

6544-
scoped_refptr<TableInfo> indexed_table;
65456552
if (req->is_index_table()) {
65466553
TRACE("Looking up index");
65476554
TableId table_id = table->id();
@@ -6555,24 +6562,20 @@ Status CatalogManager::DeleteTable(
65556562
is_transactional = l->schema().table_properties().is_transactional();
65566563
index_table_type = l->table_type();
65576564
}
6558-
NamespaceInfoPtr ns_info;
6559-
{
6560-
SharedLock lock(mutex_);
6561-
indexed_table = GetTableInfoUnlocked(indexed_table_id);
6562-
ns_info = VERIFY_RESULT(FindNamespaceByIdUnlocked(indexed_table->namespace_id()));
6563-
}
6564-
const bool is_pg_table = indexed_table != nullptr &&
6565-
indexed_table->GetTableType() == PGSQL_TABLE_TYPE;
6566-
if (!is_pg_table && IsIndexBackfillEnabled(index_table_type, is_transactional)) {
6565+
auto indexed_table = GetTableInfo(indexed_table_id);
6566+
bool is_pg_table =
6567+
indexed_table != nullptr && indexed_table->GetTableType() == PGSQL_TABLE_TYPE;
6568+
bool is_non_pg_table =
6569+
indexed_table != nullptr && indexed_table->GetTableType() != PGSQL_TABLE_TYPE;
6570+
if (is_non_pg_table && IsIndexBackfillEnabled(index_table_type, is_transactional)) {
65676571
return MarkIndexInfoFromTableForDeletion(
65686572
indexed_table_id, table_id, /*multi_stage=*/true, epoch, resp, /*data_map_ptr=*/nullptr,
6569-
ns_info);
6570-
}
6571-
6572-
// If DDL Rollback is enabled, we will not delete the index now, but merely mark it for
6573-
// deletion when the transaction commits. Thus set the response fields required by the client
6574-
// right away.
6575-
if (is_pg_table && req->ysql_yb_ddl_rollback_enabled()) {
6573+
VERIFY_RESULT(FindNamespaceById(indexed_table->namespace_id())));
6574+
} else if (is_pg_table && req->ysql_yb_ddl_rollback_enabled()) {
6575+
// If DDL Rollback is enabled, we will not delete the index now, but merely mark it for
6576+
// deletion when the transaction commits. Thus set the response fields required by the client
6577+
// right away.
6578+
auto ns_info = VERIFY_RESULT(FindNamespaceById(indexed_table->namespace_id()));
65766579
auto* resp_indexed_table = resp->mutable_indexed_table();
65776580
resp_indexed_table->mutable_namespace_()->set_name(ns_info->name());
65786581
resp_indexed_table->mutable_namespace_()->set_id(ns_info->id());
@@ -6672,14 +6675,8 @@ Status CatalogManager::DeleteTable(
66726675
Status CatalogManager::DeleteTableInternal(
66736676
const DeleteTableRequestPB* req, DeleteTableResponsePB* resp, rpc::RpcContext* rpc,
66746677
const LeaderEpoch& epoch) {
6675-
TableInfoPtr table;
6676-
NamespaceInfoPtr ns_info;
6677-
{
6678-
SharedLock lock(mutex_);
6679-
table = VERIFY_RESULT(FindTableUnlocked(req->table()));
6680-
ns_info = VERIFY_RESULT(FindNamespaceByIdUnlocked(table->namespace_id()));
6681-
}
6682-
6678+
auto table = VERIFY_RESULT(FindTable(req->table()));
6679+
auto ns_info = VERIFY_RESULT(FindNamespaceById(table->namespace_id()));
66836680
if (table->IgnoreHideRequest()) {
66846681
return Status::OK();
66856682
}
@@ -7188,18 +7185,14 @@ Status CatalogManager::IsDeleteTableDone(const IsDeleteTableDoneRequestPB* req,
71887185
IsDeleteTableDoneResponsePB* resp) {
71897186
// Lookup the deleted table.
71907187
TRACE("Looking up table $0", req->table_id());
7191-
scoped_refptr<TableInfo> table;
7192-
{
7193-
SharedLock lock(mutex_);
7194-
table = tables_->FindTableOrNull(req->table_id());
7195-
}
7196-
7197-
if (table == nullptr) {
7188+
auto table_result = FindTableById(req->table_id());
7189+
if (!table_result.ok()) {
71987190
LOG(INFO) << "Servicing IsDeleteTableDone request for table id "
71997191
<< req->table_id() << ": deleted (not found)";
72007192
resp->set_done(true);
72017193
return Status::OK();
72027194
}
7195+
auto& table = (*table_result);
72037196

72047197
TRACE("Locking table");
72057198
bool deleted;
@@ -7512,6 +7505,7 @@ Status CatalogManager::AlterTable(const AlterTableRequestPB* req,
75127505
xcluster_manager_.get()->IsNamespaceInAutomaticDDLMode(table->namespace_id());
75137506
}
75147507

7508+
// todo(GH29185): too much happens here under the cm mutex.
75157509
UniqueLock lock(mutex_);
75167510
VLOG_WITH_FUNC(3) << "Acquired the catalog manager lock";
75177511

@@ -8013,17 +8007,12 @@ Status CatalogManager::GetTableSchemaInternal(const GetTableSchemaRequestPB* req
80138007
}
80148008
}
80158009

8016-
// Get namespace name by id.
8017-
SharedLock lock(mutex_);
8018-
TRACE("Looking up namespace");
8019-
const scoped_refptr<NamespaceInfo> ns = FindPtrOrNull(namespace_ids_map_, table->namespace_id());
8020-
8021-
if (ns == nullptr) {
8022-
Status s = STATUS_SUBSTITUTE(
8023-
NotFound, "Could not find namespace by namespace id $0 for request $1.",
8024-
table->namespace_id(), req->DebugString());
8025-
return SetupError(resp->mutable_error(), MasterErrorPB::NAMESPACE_NOT_FOUND, s);
8010+
auto ns_result = FindNamespaceById(table->namespace_id());
8011+
if (!ns_result.ok()) {
8012+
return SetupError(
8013+
resp->mutable_error(), MasterErrorPB::NAMESPACE_NOT_FOUND, ns_result.status());
80268014
}
8015+
auto& ns = *ns_result;
80278016

80288017
resp->mutable_identifier()->mutable_namespace_()->set_name(ns->name());
80298018

@@ -8064,7 +8053,6 @@ Status CatalogManager::GetTablegroupSchema(const GetTablegroupSchemaRequestPB* r
80648053
std::unordered_set<TableId> table_ids;
80658054
{
80668055
SharedLock lock(mutex_);
8067-
80688056
const auto* tablegroup = tablegroup_manager_->Find(tablegroup_id);
80698057
SCHECK(tablegroup, NotFound, Substitute("Tablegroup with ID $0 not found", tablegroup_id));
80708058
table_ids = tablegroup->ChildTableIds();
@@ -8507,22 +8495,18 @@ Status CatalogManager::CreateTablegroup(
85078495
// Use the tablegroup id as the prefix for the parent table id.
85088496
TableId parent_table_id;
85098497
TableName parent_table_name;
8510-
{
8511-
LockGuard lock(mutex_);
8512-
scoped_refptr<NamespaceInfo> ns = FindPtrOrNull(namespace_ids_map_, req->namespace_id());
8513-
if (ns == nullptr) {
8514-
Status s = STATUS_SUBSTITUTE(
8515-
NotFound, "Could not find namespace by namespace id $0 for request $1.",
8516-
req->namespace_id(), req->DebugString());
8517-
return SetupError(resp->mutable_error(), MasterErrorPB::NAMESPACE_NOT_FOUND, s);
8518-
}
8519-
if (ns->colocated()) {
8520-
parent_table_id = GetColocationParentTableId(req->id());
8521-
parent_table_name = GetColocationParentTableName(req->id());
8522-
} else {
8523-
parent_table_id = GetTablegroupParentTableId(req->id());
8524-
parent_table_name = GetTablegroupParentTableName(req->id());
8525-
}
8498+
auto ns_result = FindNamespaceById(req->namespace_id());
8499+
if (!ns_result.ok()) {
8500+
return SetupError(
8501+
resp->mutable_error(), MasterErrorPB::NAMESPACE_NOT_FOUND, ns_result.status());
8502+
}
8503+
auto& ns = *ns_result;
8504+
if (ns->colocated()) {
8505+
parent_table_id = GetColocationParentTableId(req->id());
8506+
parent_table_name = GetColocationParentTableName(req->id());
8507+
} else {
8508+
parent_table_id = GetTablegroupParentTableId(req->id());
8509+
parent_table_name = GetTablegroupParentTableName(req->id());
85268510
}
85278511
if (req->has_transaction()) {
85288512
ctreq.mutable_transaction()->CopyFrom(req->transaction());
@@ -9888,9 +9872,7 @@ Status CatalogManager::GetNamespaceInfo(const GetNamespaceInfoRequestPB* req,
98889872
resp->mutable_namespace_()->set_database_type(ns->database_type());
98899873
resp->set_colocated(ns->colocated());
98909874
if (ns->colocated()) {
9891-
LockGuard lock(mutex_);
9892-
resp->set_legacy_colocated_database(colocated_db_tablets_map_.find(ns->id())
9893-
!= colocated_db_tablets_map_.end());
9875+
resp->set_legacy_colocated_database(IsColocatedNamespace(ns->id()));
98949876
}
98959877
return Status::OK();
98969878
}
@@ -12081,15 +12063,13 @@ Result<shared_ptr<tablet::AbstractTablet>> CatalogManager::GetSystemTablet(const
1208112063

1208212064
Status CatalogManager::GetTabletLocations(
1208312065
const TabletId& tablet_id, TabletLocationsPB* locs_pb, IncludeHidden include_hidden) {
12084-
TabletInfoPtr tablet_info;
12085-
{
12086-
SharedLock lock(mutex_);
12087-
if (!FindCopy(*tablet_map_, tablet_id, &tablet_info)) {
12088-
return STATUS_SUBSTITUTE(NotFound, "Unknown tablet $0", tablet_id);
12089-
}
12066+
auto tablet_info_result = GetTabletInfo(tablet_id);
12067+
if (!tablet_info_result.ok()) {
12068+
// Some clients expect non-ok statuses to have a certain form.
12069+
return STATUS_FORMAT(NotFound, "Unknown tablet $0", tablet_id);
1209012070
}
12071+
const auto& tablet_info = *tablet_info_result;
1209112072
Status s = GetTabletLocations(tablet_info, locs_pb, include_hidden);
12092-
1209312073
auto num_replicas = GetNumTabletReplicas(tablet_info);
1209412074
if (num_replicas.ok() && *num_replicas > 0 &&
1209512075
implicit_cast<size_t>(locs_pb->replicas().size()) != *num_replicas) {
@@ -12486,14 +12466,13 @@ Result<size_t> CatalogManager::GetNumTabletReplicas(const TabletInfoPtr& tablet)
1248612466

1248712467
Status CatalogManager::GetExpectedNumberOfReplicasForTablet(
1248812468
const TabletId& tablet_id, int* num_live_replicas, int* num_read_replicas) {
12489-
TabletInfoPtr tablet_info;
12490-
{
12491-
SharedLock lock(mutex_);
12492-
if (!FindCopy(*tablet_map_, tablet_id, &tablet_info)) {
12493-
return STATUS_SUBSTITUTE(NotFound, "Unknown tablet $0", tablet_id);
12494-
}
12469+
auto tablet_info_result = GetTabletInfo(tablet_id);
12470+
if (!tablet_info_result.ok()) {
12471+
// Some clients expect non-ok statuses to have a certain form.
12472+
return STATUS_FORMAT(NotFound, "Unknown tablet $0", tablet_id);
1249512473
}
12496-
GetExpectedNumberOfReplicasForTable(tablet_info->table(), num_live_replicas, num_read_replicas);
12474+
GetExpectedNumberOfReplicasForTable(
12475+
(*tablet_info_result)->table(), num_live_replicas, num_read_replicas);
1249712476
return Status::OK();
1249812477
}
1249912478

@@ -13006,6 +12985,7 @@ Result<CMGlobalLoadState> CatalogManager::InitializeGlobalLoadState(
1300612985
}
1300712986

1300812987
SharedLock l(mutex_);
12988+
// todo(zdrudi): replace this with a better index
1300912989
for (const auto& info : tables_->GetAllTables()) {
1301012990
// Ignore system, colocated and deleting/deleted tables.
1301112991
{

0 commit comments

Comments
 (0)