/Users/deen/code/yugabyte-db/src/yb/integration-tests/mini_cluster.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | |
33 | | #ifndef YB_INTEGRATION_TESTS_MINI_CLUSTER_H_ |
34 | | #define YB_INTEGRATION_TESTS_MINI_CLUSTER_H_ |
35 | | |
36 | | #include <chrono> |
37 | | #include <memory> |
38 | | #include <string> |
39 | | #include <thread> |
40 | | #include <unordered_set> |
41 | | #include <vector> |
42 | | |
43 | | #include "yb/client/client_fwd.h" |
44 | | |
45 | | #include "yb/gutil/macros.h" |
46 | | |
47 | | #include "yb/integration-tests/mini_cluster_base.h" |
48 | | |
49 | | #include "yb/master/master_fwd.h" |
50 | | #include "yb/master/master_client.fwd.h" |
51 | | |
52 | | #include "yb/tablet/tablet_fwd.h" |
53 | | |
54 | | #include "yb/tserver/tserver_fwd.h" |
55 | | #include "yb/tserver/tablet_server_options.h" |
56 | | |
57 | | #include "yb/util/env.h" |
58 | | #include "yb/util/port_picker.h" |
59 | | #include "yb/util/tsan_util.h" |
60 | | |
61 | | namespace yb { |
62 | | |
63 | | namespace master { |
64 | | class MiniMaster; |
65 | | } |
66 | | |
67 | | namespace server { |
68 | | class SkewedClockDeltaChanger; |
69 | | } |
70 | | |
71 | | namespace tserver { |
72 | | class MiniTabletServer; |
73 | | } |
74 | | |
75 | | struct MiniClusterOptions { |
76 | | // Number of master servers. |
77 | | size_t num_masters = 1; |
78 | | |
79 | | // Number of TS to start. |
80 | | size_t num_tablet_servers = 1; |
81 | | |
82 | | // Number of drives to use on TS. |
83 | | int num_drives = 1; |
84 | | |
85 | | Env* master_env = Env::Default(); |
86 | | |
87 | | // Custom Env and rocksdb::Env to be used by MiniTabletServer, |
88 | | // otherwise MiniTabletServer will use own Env and rocksdb::Env. |
89 | | Env* ts_env = nullptr; |
90 | | rocksdb::Env* ts_rocksdb_env = nullptr; |
91 | | |
92 | | // Directory in which to store data. |
93 | | // Default: empty string, which auto-generates a unique path for this cluster. |
94 | | // The default may only be used from a gtest unit test. |
95 | | std::string data_root{}; |
96 | | |
97 | | // Cluster id used to create fs path when we create tests with multiple clusters. |
98 | | std::string cluster_id{}; |
99 | | }; |
100 | | |
101 | | // An in-process cluster with a MiniMaster and a configurable |
102 | | // number of MiniTabletServers for use in tests. |
103 | | class MiniCluster : public MiniClusterBase { |
104 | | public: |
105 | | typedef std::vector<std::shared_ptr<master::MiniMaster> > MiniMasters; |
106 | | typedef std::vector<std::shared_ptr<tserver::MiniTabletServer> > MiniTabletServers; |
107 | | typedef std::vector<uint16_t> Ports; |
108 | | typedef MiniClusterOptions Options; |
109 | | |
110 | | explicit MiniCluster(const MiniClusterOptions& options); |
111 | | ~MiniCluster(); |
112 | | |
113 | | // Start a cluster with a Master and 'num_tablet_servers' TabletServers. |
114 | | // All servers run on the loopback interface with ephemeral ports. |
115 | | CHECKED_STATUS Start( |
116 | | const std::vector<tserver::TabletServerOptions>& extra_tserver_options = |
117 | | std::vector<tserver::TabletServerOptions>()); |
118 | | |
119 | | // Like the previous method but performs initialization synchronously, i.e. |
120 | | // this will wait for all TS's to be started and initialized. Tests should |
121 | | // use this if they interact with tablets immediately after Start(); |
122 | | CHECKED_STATUS StartSync(); |
123 | | |
124 | | // Stop and restart the mini cluster synchronously. The cluster's persistent state will be kept. |
125 | | CHECKED_STATUS RestartSync(); |
126 | | |
127 | | void Shutdown(); |
128 | | CHECKED_STATUS FlushTablets( |
129 | | tablet::FlushMode mode = tablet::FlushMode::kSync, |
130 | | tablet::FlushFlags flags = tablet::FlushFlags::kAllDbs); |
131 | | CHECKED_STATUS CompactTablets(); |
132 | | CHECKED_STATUS SwitchMemtables(); |
133 | | CHECKED_STATUS CleanTabletLogs(); |
134 | | |
135 | | // Shuts down masters only. |
136 | | void ShutdownMasters(); |
137 | | |
138 | | // Setup a consensus configuration of distributed masters, with count specified in |
139 | | // 'options'. Requires that a reserve RPC port is specified in |
140 | | // 'options' for each master. |
141 | | CHECKED_STATUS StartMasters(); |
142 | | |
143 | | // Add a new TS to the cluster. The new TS is started. |
144 | | // Requires that the master is already running. |
145 | | CHECKED_STATUS AddTabletServer(const tserver::TabletServerOptions& extra_opts); |
146 | | |
147 | | // Same as above, but get options from flags. |
148 | | CHECKED_STATUS AddTabletServer(); |
149 | | |
150 | | CHECKED_STATUS AddTServerToBlacklist(const tserver::MiniTabletServer& ts); |
151 | | CHECKED_STATUS ClearBlacklist(); |
152 | | |
153 | | // If this cluster is configured for a single non-distributed |
154 | | // master, return the single master. Exits with a CHECK failure if |
155 | | // there are multiple masters. |
156 | 165 | master::MiniMaster* mini_master() { |
157 | 165 | CHECK_EQ(mini_masters_.size(), 1); |
158 | 165 | return mini_master(0); |
159 | 165 | } |
160 | | |
161 | | // Returns the leader Master for this MiniCluster or error if none can be |
162 | | // elected within kMasterLeaderElectionWaitTimeSeconds. May block until a leader Master is ready. |
163 | | Result<master::MiniMaster*> GetLeaderMiniMaster(); |
164 | | |
165 | | ssize_t LeaderMasterIdx(); |
166 | | |
167 | | // Returns the Master at index 'idx' for this MiniCluster. |
168 | | master::MiniMaster* mini_master(size_t idx); |
169 | | |
170 | | // Return number of mini masters. |
171 | 3.45k | size_t num_masters() const { return mini_masters_.size(); } |
172 | | |
173 | | // Returns the TabletServer at index 'idx' of this MiniCluster. |
174 | | // 'idx' must be between 0 and 'num_tablet_servers' -1. |
175 | | tserver::MiniTabletServer* mini_tablet_server(size_t idx); |
176 | | |
177 | | tserver::MiniTabletServer* find_tablet_server(const std::string& uuid); |
178 | | |
179 | 4 | const MiniTabletServers& mini_tablet_servers() { return mini_tablet_servers_; } |
180 | | |
181 | 1.98k | size_t num_tablet_servers() const { return mini_tablet_servers_.size(); } |
182 | | |
183 | 0 | const Ports& tserver_web_ports() const { return tserver_web_ports_; } |
184 | | |
185 | | std::string GetMasterFsRoot(size_t indx); |
186 | | |
187 | | std::string GetTabletServerFsRoot(size_t idx); |
188 | | |
189 | | std::string GetTabletServerDrive(size_t idx, int drive_index); |
190 | | |
191 | | // The comma separated string of the master adresses host/ports from current list of masters. |
192 | | std::string GetMasterAddresses() const; |
193 | | |
194 | | // The comma separated string of the tserver adresses host/ports from current list of tservers. |
195 | | std::string GetTserverHTTPAddresses() const; |
196 | | |
197 | | std::vector<std::shared_ptr<tablet::TabletPeer>> GetTabletPeers(size_t idx); |
198 | | |
199 | | tserver::TSTabletManager* GetTabletManager(size_t idx); |
200 | | |
201 | | // Wait for the given tablet to have 'expected_count' replicas |
202 | | // reported on the master. Returns the locations in '*locations'. |
203 | | // Requires that the master has started; |
204 | | // Returns a bad Status if the tablet does not reach the required count |
205 | | // within kTabletReportWaitTimeSeconds. |
206 | | CHECKED_STATUS WaitForReplicaCount(const std::string& tablet_id, |
207 | | int expected_count, |
208 | | master::TabletLocationsPB* locations); |
209 | | |
210 | | // Wait until the number of registered tablet servers reaches the given |
211 | | // count. Returns Status::TimedOut if the desired count is not achieved |
212 | | // within kRegistrationWaitTimeSeconds. |
213 | | CHECKED_STATUS WaitForTabletServerCount(size_t count); |
214 | | CHECKED_STATUS WaitForTabletServerCount( |
215 | | size_t count, std::vector<std::shared_ptr<master::TSDescriptor>>* descs); |
216 | | |
217 | | // Wait for all tablet servers to be registered. Returns Status::TimedOut if the desired count is |
218 | | // not achieved within kRegistrationWaitTimeSeconds. |
219 | | CHECKED_STATUS WaitForAllTabletServers(); |
220 | | |
221 | 15 | uint16_t AllocateFreePort() { |
222 | 15 | return port_picker_.AllocateFreePort(); |
223 | 15 | } |
224 | | |
225 | | private: |
226 | | |
227 | | void ConfigureClientBuilder(client::YBClientBuilder* builder) override; |
228 | | |
229 | | Result<HostPort> DoGetLeaderMasterBoundRpcAddr() override; |
230 | | |
231 | | // Allocates ports for the given daemon type and saves them to the ports vector. Does not |
232 | | // overwrite values in the ports vector that are non-zero already. |
233 | | void AllocatePortsForDaemonType(std::string daemon_type, |
234 | | size_t num_daemons, |
235 | | std::string port_type, |
236 | | std::vector<uint16_t>* ports); |
237 | | |
238 | | // Picks free ports for the necessary number of masters / tservers and saves those ports in |
239 | | // {master,tserver}_{rpc,web}_ports_ vectors. Values of 0 for the number of masters / tservers |
240 | | // mean we pick the maximum number of masters/tservers that we already know we'll need. |
241 | | void EnsurePortsAllocated(size_t new_num_masters = 0, size_t num_tservers = 0); |
242 | | |
243 | | const MiniClusterOptions options_; |
244 | | const std::string fs_root_; |
245 | | |
246 | | Ports master_rpc_ports_; |
247 | | Ports master_web_ports_; |
248 | | Ports tserver_rpc_ports_; |
249 | | Ports tserver_web_ports_; |
250 | | |
251 | | MiniMasters mini_masters_; |
252 | | MiniTabletServers mini_tablet_servers_; |
253 | | |
254 | | PortPicker port_picker_; |
255 | | }; |
256 | | |
257 | | MUST_USE_RESULT std::vector<server::SkewedClockDeltaChanger> SkewClocks( |
258 | | MiniCluster* cluster, std::chrono::milliseconds clock_skew); |
259 | | |
260 | | MUST_USE_RESULT std::vector<server::SkewedClockDeltaChanger> JumpClocks( |
261 | | MiniCluster* cluster, std::chrono::milliseconds delta); |
262 | | |
263 | | void StepDownAllTablets(MiniCluster* cluster); |
264 | | void StepDownRandomTablet(MiniCluster* cluster); |
265 | | |
266 | | YB_DEFINE_ENUM(ListPeersFilter, (kAll)(kLeaders)(kNonLeaders)); |
267 | | |
268 | | std::unordered_set<std::string> ListTabletIdsForTable( |
269 | | MiniCluster* cluster, const std::string& table_id); |
270 | | |
271 | | std::unordered_set<std::string> ListActiveTabletIdsForTable( |
272 | | MiniCluster* cluster, const std::string& table_id); |
273 | | |
274 | | std::vector<std::shared_ptr<tablet::TabletPeer>> ListTabletPeers( |
275 | | MiniCluster* cluster, ListPeersFilter filter); |
276 | | |
277 | | std::vector<std::shared_ptr<tablet::TabletPeer>> ListTabletPeers( |
278 | | MiniCluster* cluster, |
279 | | const std::function<bool(const std::shared_ptr<tablet::TabletPeer>&)>& filter); |
280 | | |
281 | | std::vector<tablet::TabletPeerPtr> ListTableTabletPeers( |
282 | | MiniCluster* cluster, const TableId& table_id); |
283 | | |
284 | | // By active tablet here we mean tablet is ready or going to be ready to serve read/write requests, |
285 | | // i.e. not yet completed split or deleted (tombstoned). |
286 | | std::vector<tablet::TabletPeerPtr> ListTableActiveTabletLeadersPeers( |
287 | | MiniCluster* cluster, const TableId& table_id); |
288 | | |
289 | | std::vector<tablet::TabletPeerPtr> ListTableActiveTabletPeers( |
290 | | MiniCluster* cluster, const TableId& table_id); |
291 | | std::vector<tablet::TabletPeerPtr> ListTableInactiveSplitTabletPeers( |
292 | | MiniCluster* cluster, const TableId& table_id); |
293 | | |
294 | | std::vector<tablet::TabletPeerPtr> ListActiveTabletLeadersPeers( |
295 | | MiniCluster* cluster); |
296 | | |
297 | | Result<std::vector<tablet::TabletPeerPtr>> WaitForTableActiveTabletLeadersPeers( |
298 | | MiniCluster* cluster, const TableId& table_id, size_t num_active_leaders, |
299 | | MonoDelta timeout = std::chrono::seconds(30) * kTimeMultiplier); |
300 | | |
301 | | CHECKED_STATUS WaitUntilTabletHasLeader( |
302 | | MiniCluster* cluster, const std::string& tablet_id, MonoTime deadline); |
303 | | |
304 | | CHECKED_STATUS WaitForLeaderOfSingleTablet( |
305 | | MiniCluster* cluster, tablet::TabletPeerPtr leader, MonoDelta duration, |
306 | | const std::string& description); |
307 | | |
308 | | CHECKED_STATUS WaitUntilMasterHasLeader(MiniCluster* cluster, MonoDelta deadline); |
309 | | |
310 | | YB_STRONGLY_TYPED_BOOL(ForceStepDown); |
311 | | |
312 | | CHECKED_STATUS StepDown( |
313 | | tablet::TabletPeerPtr leader, const std::string& new_leader_uuid, |
314 | | ForceStepDown force_step_down); |
315 | | |
316 | | // Waits until all tablet peers of the specified cluster are in the Running state. |
317 | | // And total number of those peers equals to the number of tablet servers for each known tablet. |
318 | | CHECKED_STATUS WaitAllReplicasReady(MiniCluster* cluster, MonoDelta timeout); |
319 | | |
320 | | // Waits until all tablet peers of specified cluster have the specified index in their log. |
321 | | // And total number of those peers equals to the number of tablet servers for each known tablet. |
322 | | CHECKED_STATUS WaitAllReplicasHaveIndex(MiniCluster* cluster, int64_t index, MonoDelta timeout); |
323 | | |
324 | | std::thread RestartsThread( |
325 | | MiniCluster* cluster, CoarseDuration interval, std::atomic<bool>* stop_flag); |
326 | | |
327 | | std::vector<rocksdb::DB*> GetAllRocksDbs(MiniCluster* cluster, bool include_intents = true); |
328 | | |
329 | | int NumTotalRunningCompactions(MiniCluster* cluster); |
330 | | |
331 | | int NumRunningFlushes(MiniCluster* cluster); |
332 | | |
333 | | Result<scoped_refptr<master::TableInfo>> FindTable( |
334 | | MiniCluster* cluster, const client::YBTableName& table_name); |
335 | | |
336 | | CHECKED_STATUS WaitForInitDb(MiniCluster* cluster); |
337 | | |
338 | | using TabletPeerFilter = std::function<bool(const tablet::TabletPeer*)>; |
339 | | size_t CountIntents(MiniCluster* cluster, const TabletPeerFilter& filter = TabletPeerFilter()); |
340 | | |
341 | | tserver::MiniTabletServer* FindTabletLeader(MiniCluster* cluster, const TabletId& tablet_id); |
342 | | |
343 | | void ShutdownAllTServers(MiniCluster* cluster); |
344 | | CHECKED_STATUS StartAllTServers(MiniCluster* cluster); |
345 | | void ShutdownAllMasters(MiniCluster* cluster); |
346 | | CHECKED_STATUS StartAllMasters(MiniCluster* cluster); |
347 | | |
348 | | YB_DEFINE_ENUM(Connectivity, (kOn)(kOff)); |
349 | | |
350 | | CHECKED_STATUS BreakConnectivity(MiniCluster* cluster, size_t idx1, size_t idx2); |
351 | | CHECKED_STATUS SetupConnectivity( |
352 | | MiniCluster* cluster, size_t idx1, size_t idx2, Connectivity connectivity); |
353 | | Result<size_t> ServerWithLeaders(MiniCluster* cluster); |
354 | | |
355 | | // Sets FLAGS_rocksdb_compact_flush_rate_limit_bytes_per_sec and also adjusts rate limiter |
356 | | // for already created tablets. |
357 | | void SetCompactFlushRateLimitBytesPerSec(MiniCluster* cluster, size_t bytes_per_sec); |
358 | | |
359 | | CHECKED_STATUS WaitAllReplicasSynchronizedWithLeader( |
360 | | MiniCluster* cluster, CoarseTimePoint deadline); |
361 | | |
362 | | } // namespace yb |
363 | | |
364 | | #endif /* YB_INTEGRATION_TESTS_MINI_CLUSTER_H_ */ |