/Users/deen/code/yugabyte-db/src/yb/master/catalog_manager_util.h
Line | Count | Source |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | |
14 | | #ifndef YB_MASTER_CATALOG_MANAGER_UTIL_H |
15 | | #define YB_MASTER_CATALOG_MANAGER_UTIL_H |
16 | | |
17 | | #include <unordered_map> |
18 | | #include <vector> |
19 | | |
20 | | #include "yb/consensus/consensus_fwd.h" |
21 | | #include "yb/master/catalog_entity_info.h" |
22 | | #include "yb/master/master_fwd.h" |
23 | | #include "yb/master/ts_descriptor.h" |
24 | | |
25 | | DECLARE_bool(transaction_tables_use_preferred_zones); |
26 | | |
27 | | // Utility functions that can be shared between test and code for catalog manager. |
28 | | namespace yb { |
29 | | namespace master { |
30 | | |
31 | | using ZoneToDescMap = std::unordered_map<string, TSDescriptorVector>; |
32 | | |
33 | | struct Comparator; |
34 | | |
35 | | class CatalogManagerUtil { |
36 | | public: |
37 | | // For the given set of descriptors, checks if the load is considered balanced across AZs in |
38 | | // multi AZ setup, else checks load distribution across tservers (single AZ). |
39 | | static CHECKED_STATUS IsLoadBalanced(const TSDescriptorVector& ts_descs); |
40 | | |
41 | | // For the given set of descriptors, checks if every tserver that shouldn't have leader load |
42 | | // actually has no leader load. |
43 | | // If transaction_tables_use_preferred_zones = false, then we also check if txn status tablet |
44 | | // leaders are spread evenly based on the information in `tables`. |
45 | | static CHECKED_STATUS AreLeadersOnPreferredOnly( |
46 | | const TSDescriptorVector& ts_descs, |
47 | | const ReplicationInfoPB& replication_info, |
48 | | const vector<scoped_refptr<TableInfo>>& tables = {}); |
49 | | |
50 | | // Creates a mapping from tserver uuid to the number of transaction leaders present. |
51 | | static void CalculateTxnLeaderMap(std::map<std::string, int>* txn_map, |
52 | | int* num_txn_tablets, |
53 | | vector<scoped_refptr<TableInfo>> tables); |
54 | | |
55 | | // For the given set of descriptors, returns the map from each placement AZ to list of tservers |
56 | | // running in that zone. |
57 | | static CHECKED_STATUS GetPerZoneTSDesc(const TSDescriptorVector& ts_descs, |
58 | | ZoneToDescMap* zone_to_ts); |
59 | | |
60 | | // Checks whether two given cloud infos are identical. |
61 | | static bool IsCloudInfoEqual(const CloudInfoPB& lhs, const CloudInfoPB& rhs); |
62 | | |
63 | | // For the given placement info, checks whether a given cloud info is contained within it. |
64 | | static bool DoesPlacementInfoContainCloudInfo(const PlacementInfoPB& placement_info, |
65 | | const CloudInfoPB& cloud_info); |
66 | | |
67 | | // Checks whether the given placement info spans more than one region. |
68 | | static bool DoesPlacementInfoSpanMultipleRegions(const PlacementInfoPB& placement_info); |
69 | | |
70 | | // Called when registering a ts from raft, deduce a tservers placement from the peer's role |
71 | | // and cloud info. |
72 | | static Result<std::string> GetPlacementUuidFromRaftPeer( |
73 | | const ReplicationInfoPB& replication_info, const consensus::RaftPeerPB& peer); |
74 | | |
75 | | // Returns error if tablet partition is not covered by running inner tablets partitions. |
76 | | static CHECKED_STATUS CheckIfCanDeleteSingleTablet(const scoped_refptr<TabletInfo>& tablet); |
77 | | |
78 | | enum CloudInfoSimilarity { |
79 | | NO_MATCH = 0, |
80 | | CLOUD_MATCH = 1, |
81 | | REGION_MATCH = 2, |
82 | | ZONE_MATCH = 3 |
83 | | }; |
84 | | |
85 | | // Computes a similarity score between two cloudinfos (which may be prefixes). |
86 | | // 0: different clouds |
87 | | // 1: same cloud, different region |
88 | | // 2: same cloud and region, different zone |
89 | | // 3: same cloud and region and zone, or prefix matches |
90 | | static CloudInfoSimilarity ComputeCloudInfoSimilarity(const CloudInfoPB& ci1, |
91 | | const CloudInfoPB& ci2); |
92 | | |
93 | | // Checks if one cloudinfo is a prefix of another. This assumes that ci1 and ci2 are |
94 | | // prefixes. |
95 | | static bool IsCloudInfoPrefix(const CloudInfoPB& ci1, const CloudInfoPB& ci2); |
96 | | |
97 | | // Validate if the specified placement information conforms to the rules. |
98 | | // Currently, the following assumption about placement blocks is made. |
99 | | // Every TS should have a unique placement block to which it can be mapped. |
100 | | // This translates to placement blocks being disjoint i.e. no placement |
101 | | // block string (C.R.Z format) should be proper prefix of another. |
102 | | // Validate placement information if passed. |
103 | | static CHECKED_STATUS IsPlacementInfoValid(const PlacementInfoPB& placement_info); |
104 | | |
105 | | template<class LoadState> |
106 | 54.6k | static void FillTableLoadState(const scoped_refptr<TableInfo>& table_info, LoadState* state) { |
107 | 54.6k | auto tablets = table_info->GetTablets(IncludeInactive::kTrue); |
108 | | |
109 | 445k | for (const auto& tablet : tablets) { |
110 | | // Ignore if tablet is not running. |
111 | 445k | { |
112 | 445k | auto tablet_lock = tablet->LockForRead(); |
113 | 445k | if (!tablet_lock->is_running()) { |
114 | 112k | continue; |
115 | 112k | } |
116 | 333k | } |
117 | 333k | auto replica_locs = tablet->GetReplicaLocations(); |
118 | | |
119 | 996k | for (const auto& loc : *replica_locs) { |
120 | | // Ignore replica if not present in the tserver list passed. |
121 | 996k | if (state->per_ts_load_.count(loc.first) == 0) { |
122 | 378 | continue; |
123 | 378 | } |
124 | | // Account for this load. |
125 | 996k | state->per_ts_load_[loc.first]++; |
126 | 996k | } |
127 | 333k | } |
128 | 54.6k | } _ZN2yb6master18CatalogManagerUtil18FillTableLoadStateINS0_19CMPerTableLoadStateEEEvRK13scoped_refptrINS0_9TableInfoEEPT_ Line | Count | Source | 106 | 12.6k | static void FillTableLoadState(const scoped_refptr<TableInfo>& table_info, LoadState* state) { | 107 | 12.6k | auto tablets = table_info->GetTablets(IncludeInactive::kTrue); | 108 | | | 109 | 137k | for (const auto& tablet : tablets) { | 110 | | // Ignore if tablet is not running. | 111 | 137k | { | 112 | 137k | auto tablet_lock = tablet->LockForRead(); | 113 | 137k | if (!tablet_lock->is_running()) { | 114 | 56.0k | continue; | 115 | 56.0k | } | 116 | 81.2k | } | 117 | 81.2k | auto replica_locs = tablet->GetReplicaLocations(); | 118 | | | 119 | 246k | for (const auto& loc : *replica_locs) { | 120 | | // Ignore replica if not present in the tserver list passed. | 121 | 246k | if (state->per_ts_load_.count(loc.first) == 0) { | 122 | 0 | continue; | 123 | 0 | } | 124 | | // Account for this load. | 125 | 246k | state->per_ts_load_[loc.first]++; | 126 | 246k | } | 127 | 81.2k | } | 128 | 12.6k | } |
_ZN2yb6master18CatalogManagerUtil18FillTableLoadStateINS0_17CMGlobalLoadStateEEEvRK13scoped_refptrINS0_9TableInfoEEPT_ Line | Count | Source | 106 | 42.0k | static void FillTableLoadState(const scoped_refptr<TableInfo>& table_info, LoadState* state) { | 107 | 42.0k | auto tablets = table_info->GetTablets(IncludeInactive::kTrue); | 108 | | | 109 | 307k | for (const auto& tablet : tablets) { | 110 | | // Ignore if tablet is not running. | 111 | 307k | { | 112 | 307k | auto tablet_lock = tablet->LockForRead(); | 113 | 307k | if (!tablet_lock->is_running()) { | 114 | 56.0k | continue; | 115 | 56.0k | } | 116 | 251k | } | 117 | 251k | auto replica_locs = tablet->GetReplicaLocations(); | 118 | | | 119 | 750k | for (const auto& loc : *replica_locs) { | 120 | | // Ignore replica if not present in the tserver list passed. | 121 | 750k | if (state->per_ts_load_.count(loc.first) == 0) { | 122 | 378 | continue; | 123 | 378 | } | 124 | | // Account for this load. | 125 | 749k | state->per_ts_load_[loc.first]++; | 126 | 749k | } | 127 | 251k | } | 128 | 42.0k | } |
|
129 | | |
130 | | private: |
131 | | CatalogManagerUtil(); |
132 | | |
133 | | DISALLOW_COPY_AND_ASSIGN(CatalogManagerUtil); |
134 | | }; |
135 | | |
136 | | class CMGlobalLoadState { |
137 | | public: |
138 | 351k | uint32_t GetGlobalLoad(const TabletServerId& id) { |
139 | 351k | return per_ts_load_[id]; |
140 | 351k | } |
141 | | std::unordered_map<TabletServerId, uint32_t> per_ts_load_; |
142 | | }; |
143 | | |
144 | | class CMPerTableLoadState { |
145 | | public: |
146 | | explicit CMPerTableLoadState(CMGlobalLoadState* global_state) |
147 | 12.6k | : global_load_state_(global_state) {} |
148 | | |
149 | | bool CompareLoads(const TabletServerId& ts1, const TabletServerId& ts2); |
150 | | |
151 | | void SortLoad(); |
152 | | |
153 | | std::vector<TabletServerId> sorted_load_; |
154 | | std::unordered_map<TabletServerId, uint32_t> per_ts_load_; |
155 | | CMGlobalLoadState* global_load_state_; |
156 | | }; |
157 | | |
158 | | struct Comparator { |
159 | 94.8k | explicit Comparator(CMPerTableLoadState* state) : state_(state) {} |
160 | | |
161 | 288k | bool operator()(const TabletServerId& id1, const TabletServerId& id2) { |
162 | 288k | return state_->CompareLoads(id1, id2); |
163 | 288k | } |
164 | | |
165 | | CMPerTableLoadState* state_; |
166 | | }; |
167 | | |
168 | | } // namespace master |
169 | | } // namespace yb |
170 | | |
171 | | #endif // YB_MASTER_CATALOG_MANAGER_UTIL_H |