blob: 18b2d152c40d7055d13e56a505c6b0d6133d9936 [file] [log] [blame]
// 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" // IWYU pragma: keep
#include "kudu/gutil/macros.h"
#include "kudu/mini-cluster/mini_cluster.h"
#include "kudu/util/net/net_util.h"
namespace kudu {
class Env;
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 TabletServerAdminServiceProxy;
class TabletServerServiceProxy;
} // namespace tserver
namespace cluster {
struct InternalMiniClusterOptions {
InternalMiniClusterOptions();
// Number of master servers.
// Default: 1
int num_masters;
// Whether to supply 'master_addresses' field for single master configuration.
// Default: False
bool supply_single_master_addr;
// 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;
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;
// Flush the specified tablet on all tablet replicas in the cluster.
Status FlushTablet(const std::string& tablet_id);
// 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;
std::shared_ptr<tserver::TabletServerAdminServiceProxy> tserver_admin_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