blob: 95716161b1604e2414d478597a9c7265fd0b26a0 [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.
#ifndef KUDU_CLIENT_CLIENT_INTERNAL_H
#define KUDU_CLIENT_CLIENT_INTERNAL_H
#include <boost/function.hpp>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>
#include "kudu/client/client.h"
#include "kudu/util/atomic.h"
#include "kudu/util/locks.h"
#include "kudu/util/monotime.h"
#include "kudu/util/net/net_util.h"
namespace kudu {
class DnsResolver;
class HostPort;
namespace master {
class AlterTableRequestPB;
class CreateTableRequestPB;
class GetLeaderMasterRpc;
class MasterServiceProxy;
} // namespace master
namespace rpc {
class Messenger;
class RpcController;
} // namespace rpc
namespace client {
class KuduClient::Data {
public:
Data();
~Data();
// Selects a TS replica from the given RemoteTablet subject
// to liveness and the provided selection criteria and blacklist.
//
// If no appropriate replica can be found, a non-OK status is returned and 'ts' is untouched.
//
// The 'candidates' return parameter indicates tservers that are live and meet the selection
// criteria, but are possibly filtered by the blacklist. This is useful for implementing
// retry logic.
Status GetTabletServer(KuduClient* client,
const scoped_refptr<internal::RemoteTablet>& rt,
ReplicaSelection selection,
const std::set<std::string>& blacklist,
std::vector<internal::RemoteTabletServer*>* candidates,
internal::RemoteTabletServer** ts);
Status CreateTable(KuduClient* client,
const master::CreateTableRequestPB& req,
const KuduSchema& schema,
const MonoTime& deadline);
Status IsCreateTableInProgress(KuduClient* client,
const std::string& table_name,
const MonoTime& deadline,
bool *create_in_progress);
Status WaitForCreateTableToFinish(KuduClient* client,
const std::string& table_name,
const MonoTime& deadline);
Status DeleteTable(KuduClient* client,
const std::string& table_name,
const MonoTime& deadline);
Status AlterTable(KuduClient* client,
const master::AlterTableRequestPB& req,
const MonoTime& deadline);
Status IsAlterTableInProgress(KuduClient* client,
const std::string& table_name,
const MonoTime& deadline,
bool *alter_in_progress);
Status WaitForAlterTableToFinish(KuduClient* client,
const std::string& alter_name,
const MonoTime& deadline);
Status GetTableSchema(KuduClient* client,
const std::string& table_name,
const MonoTime& deadline,
KuduSchema* schema,
PartitionSchema* partition_schema,
std::string* table_id);
Status InitLocalHostNames();
bool IsLocalHostPort(const HostPort& hp) const;
bool IsTabletServerLocal(const internal::RemoteTabletServer& rts) const;
// Returns a non-failed replica of the specified tablet based on the provided selection criteria
// and tablet server blacklist.
//
// Returns NULL if there are no valid tablet servers.
internal::RemoteTabletServer* SelectTServer(
const scoped_refptr<internal::RemoteTablet>& rt,
const ReplicaSelection selection,
const std::set<std::string>& blacklist,
std::vector<internal::RemoteTabletServer*>* candidates) const;
// Sets 'master_proxy_' from the address specified by
// 'leader_master_hostport_'. Called by
// GetLeaderMasterRpc::SendRpcCb() upon successful completion.
//
// See also: SetMasterServerProxyAsync.
void LeaderMasterDetermined(const Status& status,
const HostPort& host_port);
// Asynchronously sets 'master_proxy_' to the leader master by
// cycling through servers listed in 'master_server_addrs_' until
// one responds with a Raft configuration that contains the leader
// master or 'deadline' expires.
//
// Invokes 'cb' with the appropriate status when finished.
//
// Works with both a distributed and non-distributed configuration.
void SetMasterServerProxyAsync(KuduClient* client,
const MonoTime& deadline,
const StatusCallback& cb);
// Synchronous version of SetMasterServerProxyAsync method above.
//
// NOTE: since this uses a Synchronizer, this may not be invoked by
// a method that's on a reactor thread.
//
// TODO (KUDU-492): Get rid of this method and re-factor the client
// to lazily initialize 'master_proxy_'.
Status SetMasterServerProxy(KuduClient* client,
const MonoTime& deadline);
std::shared_ptr<master::MasterServiceProxy> master_proxy() const;
HostPort leader_master_hostport() const;
uint64_t GetLatestObservedTimestamp() const;
void UpdateLatestObservedTimestamp(uint64_t timestamp);
// Retry 'func' until either:
//
// 1) Methods succeeds on a leader master.
// 2) Method fails for a reason that is not related to network
// errors, timeouts, or leadership issues.
// 3) 'deadline' (if initialized) elapses.
//
// If 'num_attempts' is not NULL, it will be incremented on every
// attempt (successful or not) to call 'func'.
//
// NOTE: 'rpc_timeout' is a per-call timeout, while 'deadline' is a
// per operation deadline. If 'deadline' is not initialized, 'func' is
// retried forever. If 'deadline' expires, 'func_name' is included in
// the resulting Status.
template<class ReqClass, class RespClass>
Status SyncLeaderMasterRpc(
const MonoTime& deadline,
KuduClient* client,
const ReqClass& req,
RespClass* resp,
int* num_attempts,
const char* func_name,
const boost::function<Status(master::MasterServiceProxy*,
const ReqClass&, RespClass*,
rpc::RpcController*)>& func);
std::shared_ptr<rpc::Messenger> messenger_;
gscoped_ptr<DnsResolver> dns_resolver_;
scoped_refptr<internal::MetaCache> meta_cache_;
// Set of hostnames and IPs on the local host.
// This is initialized at client startup.
std::unordered_set<std::string> local_host_names_;
// Options the client was built with.
std::vector<std::string> master_server_addrs_;
MonoDelta default_admin_operation_timeout_;
MonoDelta default_rpc_timeout_;
// The host port of the leader master. This is set in
// LeaderMasterDetermined, which is invoked as a callback by
// SetMasterServerProxyAsync.
HostPort leader_master_hostport_;
// Proxy to the leader master.
std::shared_ptr<master::MasterServiceProxy> master_proxy_;
// Ref-counted RPC instance: since 'SetMasterServerProxyAsync' call
// is asynchronous, we need to hold a reference in this class
// itself, as to avoid a "use-after-free" scenario.
scoped_refptr<master::GetLeaderMasterRpc> leader_master_rpc_;
std::vector<StatusCallback> leader_master_callbacks_;
// Protects 'leader_master_rpc_', 'leader_master_hostport_',
// and master_proxy_
//
// See: KuduClient::Data::SetMasterServerProxyAsync for a more
// in-depth explanation of why this is needed and how it works.
mutable simple_spinlock leader_master_lock_;
AtomicInt<uint64_t> latest_observed_timestamp_;
DISALLOW_COPY_AND_ASSIGN(Data);
};
// Retry helper, takes a function like: Status funcName(const MonoTime& deadline, bool *retry, ...)
// The function should set the retry flag (default true) if the function should
// be retried again. On retry == false the return status of the function will be
// returned to the caller, otherwise a Status::Timeout() will be returned.
// If the deadline is already expired, no attempt will be made.
Status RetryFunc(const MonoTime& deadline,
const std::string& retry_msg,
const std::string& timeout_msg,
const boost::function<Status(const MonoTime&, bool*)>& func);
} // namespace client
} // namespace kudu
#endif