| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #pragma once |
| |
| #include <cstdint> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include <glog/logging.h> |
| |
| #include "kudu/client/shared_ptr.h" |
| #include "kudu/gutil/macros.h" |
| #include "kudu/mini-cluster/mini_cluster.h" |
| |
| namespace kudu { |
| |
| class Env; |
| class HostPort; |
| class Status; |
| |
| namespace client { |
| class KuduClient; |
| class KuduClientBuilder; |
| } // namespace client |
| |
| namespace master { |
| class MasterServiceProxy; |
| class MiniMaster; |
| class TSDescriptor; |
| } // namespace master |
| |
| namespace rpc { |
| class Messenger; |
| } // namespace rpc |
| |
| namespace tserver { |
| class MiniTabletServer; |
| class TabletServerServiceProxy; |
| } // namespace tserver |
| |
| namespace cluster { |
| |
| struct InternalMiniClusterOptions { |
| InternalMiniClusterOptions(); |
| |
| // Number of master servers. |
| // Default: 1 |
| int num_masters; |
| |
| // Number of TS to start. |
| // Default: 1 |
| int num_tablet_servers; |
| |
| // Number of data dirs for each daemon. |
| // Default: 1 (this will place the wals in the same dir) |
| int num_data_dirs; |
| |
| // Directory in which to store the cluster's data. |
| // Default: "", which auto-generates a unique path for this cluster. |
| // The default may only be used from a gtest unit test. |
| std::string cluster_root; |
| |
| MiniCluster::BindMode bind_mode; |
| |
| // List of RPC ports for the tservers to run on. |
| // Defaults to an empty list. |
| // When adding a tablet server to the cluster via AddTabletServer(), if the |
| // index of that tablet server in the cluster is greater than the number of |
| // elements in this list, a transient port (port 0) will be used. |
| std::vector<uint16_t> tserver_rpc_ports; |
| }; |
| |
| // An in-process cluster with a MiniMaster and a configurable |
| // number of MiniTabletServers for use in tests. |
| class InternalMiniCluster : public MiniCluster { |
| public: |
| InternalMiniCluster(Env* env, InternalMiniClusterOptions options); |
| virtual ~InternalMiniCluster(); |
| |
| // Start a cluster with a Master and 'num_tablet_servers' TabletServers. |
| // All servers run on the loopback interface with ephemeral ports. |
| Status Start() override; |
| |
| // Like the previous method but performs initialization synchronously, i.e. |
| // this will wait for all TS's to be started and initialized. Tests should |
| // use this if they interact with tablets immediately after Start(); |
| Status StartSync(); |
| |
| void ShutdownNodes(ClusterNodes nodes) override; |
| |
| // Add a new TS to the cluster. The new TS is started. |
| // Requires that the master is already running. |
| Status AddTabletServer(); |
| |
| // If this cluster is configured for a single non-distributed |
| // master, return the single master. Exits with a CHECK failure if |
| // there are multiple masters. |
| master::MiniMaster* mini_master() const { |
| CHECK_EQ(mini_masters_.size(), 1); |
| return mini_master(0); |
| } |
| |
| // Returns the Master at index 'idx' for this InternalMiniCluster. |
| master::MiniMaster* mini_master(int idx) const; |
| |
| // Return number of mini masters. |
| int num_masters() const override { |
| return mini_masters_.size(); |
| } |
| |
| // Returns the TabletServer at index 'idx' of this InternalMiniCluster. |
| // 'idx' must be between 0 and 'num_tablet_servers' -1. |
| tserver::MiniTabletServer* mini_tablet_server(int idx) const; |
| |
| // Returns the TabletServer with uuid 'uuid', or nullptr if not found. |
| tserver::MiniTabletServer* mini_tablet_server_by_uuid(const std::string& uuid) const; |
| |
| // Return the index of the tablet server that has the given 'uuid', or |
| // -1 if no such UUID can be found. |
| int tablet_server_index_by_uuid(const std::string& uuid) const; |
| |
| int num_tablet_servers() const override { |
| return mini_tablet_servers_.size(); |
| } |
| |
| // Returns the WALs root directory for the tablet server 'ts_idx'. |
| std::string WalRootForTS(int ts_idx) const override; |
| |
| // Returns the UUID for the tablet server 'ts_idx'. |
| std::string UuidForTS(int ts_idx) const override; |
| |
| // Returns the Env on which the cluster operates. |
| Env* env() const override { |
| return env_; |
| } |
| |
| BindMode bind_mode() const override { |
| return opts_.bind_mode; |
| } |
| |
| std::vector<HostPort> master_rpc_addrs() const override; |
| |
| std::string GetMasterFsRoot(int idx) const; |
| |
| std::string GetTabletServerFsRoot(int idx) const; |
| |
| // Wait until the number of registered tablet servers reaches the given |
| // count on all masters. Returns Status::TimedOut if the desired count is not |
| // achieved within kRegistrationWaitTimeSeconds. |
| enum class MatchMode { |
| // Ensure that the tservers retrieved from each master match up against the |
| // tservers defined in this cluster. The matching is done via |
| // NodeInstancePBs comparisons. If even one match fails, the retrieved |
| // response is considered to be malformed and is retried. |
| // |
| // Note: tservers participate in matching even if they are shut down. |
| MATCH_TSERVERS, |
| |
| // Do not perform any matching on the retrieved tservers. |
| DO_NOT_MATCH_TSERVERS, |
| }; |
| Status WaitForTabletServerCount(int count) const; |
| Status WaitForTabletServerCount(int count, MatchMode mode, |
| std::vector<std::shared_ptr<master::TSDescriptor>>* descs) const; |
| |
| Status CreateClient(client::KuduClientBuilder* builder, |
| client::sp::shared_ptr<client::KuduClient>* client) const override; |
| |
| // Determine the leader master of the cluster. Upon successful completion, |
| // sets 'idx' to the leader master's index. The result index index can be used |
| // as an argument for calls to mini_master(). |
| // |
| // It's possible to use 'nullptr' instead of providing a valid placeholder |
| // for the result master index. That's for use cases when it's enough |
| // to determine if the cluster has established leader master |
| // without intent to get the actual index. |
| // |
| // Note: if a leader election occurs after this method is executed, the |
| // last result may not be valid. |
| Status GetLeaderMasterIndex(int* idx) const; |
| |
| std::shared_ptr<rpc::Messenger> messenger() const override; |
| std::shared_ptr<master::MasterServiceProxy> master_proxy() const override; |
| std::shared_ptr<master::MasterServiceProxy> master_proxy(int idx) const override; |
| std::shared_ptr<tserver::TabletServerServiceProxy> tserver_proxy(int idx) const override; |
| |
| private: |
| |
| // Creates and starts the cluster masters. |
| Status StartMasters(); |
| |
| enum { |
| kRegistrationWaitTimeSeconds = 15, |
| kMasterStartupWaitTimeSeconds = 30, |
| }; |
| |
| Env* const env_; |
| |
| InternalMiniClusterOptions opts_; |
| |
| bool running_; |
| |
| std::vector<std::shared_ptr<master::MiniMaster>> mini_masters_; |
| std::vector<std::shared_ptr<tserver::MiniTabletServer>> mini_tablet_servers_; |
| |
| std::shared_ptr<rpc::Messenger> messenger_; |
| |
| DISALLOW_COPY_AND_ASSIGN(InternalMiniCluster); |
| }; |
| |
| } // namespace cluster |
| } // namespace kudu |