blob: 22548fbb5b8c7563b9f6a1783e8af2bf88a059e8 [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 <functional>
#include <string>
#include <vector>
#include "kudu/rpc/response_callback.h"
#include "kudu/rpc/rpc.h"
#include "kudu/rpc/rpc_controller.h"
#include "kudu/util/status_callback.h"
namespace kudu {
class MonoTime;
class Status;
namespace master {
class MasterServiceProxy;
} // namespace master
namespace client {
class KuduClient;
namespace internal {
// Encapsulates RPCs that target the leader master, handling retries and
// reconnection to the master(s).
template <class ReqClass, class RespClass>
class AsyncLeaderMasterRpc : public rpc::Rpc {
public:
// The input 'client' will be used to call the asynchonous master proxy
// function 'func' on the currently-known leader master, sending over 'req',
// and expecting the features specified by 'required_feature_flags' to be
// present on the master. Upon successful completion of the RPC, 'resp' is
// populated with the RPC response. Various errors (e.g. from the RPC layer
// or from the application layer) will direct the RPC to be retried until
// 'deadline' is reached. If the final result is an error, 'resp' may not be
// set, or may have an application error set.
//
// 'user_cb' will be called on the final result of the RPC (either OK,
// TimedOut, or some other non-retriable error).
//
// 'rpc_name' is a descriptor for the RPC used to add more context to logs
// and error messages.
//
// Retries will be done according to the backoff type specified by 'backoff'.
AsyncLeaderMasterRpc(const MonoTime& deadline,
KuduClient* client,
rpc::BackoffType backoff,
const ReqClass& req,
RespClass* resp,
const std::function<void(master::MasterServiceProxy*,
const ReqClass&, RespClass*,
rpc::RpcController*,
const rpc::ResponseCallback&)>& func,
std::string rpc_name,
StatusCallback user_cb,
std::vector<uint32_t> required_feature_flags);
// Sends the RPC using the master proxy's asynchonous API, ensuring that
// neither the per-RPC deadline nor the overall deadline has passed.
//
// Resets the RPC controller before sending out a new RPC.
void SendRpc() override;
std::string ToString() const override;
// Uses 'status' and the contents of the RPC controller and RPC response to
// determine whether reconnections or retries should be performed, and if so,
// performs them. Additionally, updates 'status' to include more information
// based on the state of the RPC.
//
// Retries take the following kinds of errors into account:
// - TimedOut errors that indicate the operation retrier has passed its
// deadline (distinct from TimedOut errors that surface in the RPC layer)
// - RPC errors that come from a failed connection, in which case the
// controller status will be non-OK
// - generic RPC errors, in which case the controller status will be a
// RemoteError and the controller will have an error response
// - generic Master application errors, in which case the controller status
// will be OK, and the response will have an ErrorStatusPB
//
// Returns true if a reconnection and/or retry was required and has been
// scheduled, in which case callers should ensure that this object remains
// alive.
bool RetryOrReconnectIfNecessary(Status* status);
protected:
// Handles 'status', retrying if necessary, and calling the user-provided
// callback as appropriate.
void SendRpcCb(const Status& status) override;
// Attempts to reconnect with the masters and find the leader master, and
// attempts to retry the RPC.
virtual void ResetMasterLeaderAndRetry(rpc::CredentialsPolicy creds_policy);
// With a new leader found, resends the RPC. 'creds_policy' is the policy
// with which the reconnection was attempted.
void NewLeaderMasterDeterminedCb(rpc::CredentialsPolicy creds_policy,
const Status& status);
KuduClient* client_;
const ReqClass* req_;
RespClass* resp_;
// Asynchronous function that sends an RPC to the master.
const std::function<void(master::MasterServiceProxy*,
const ReqClass&, RespClass*,
rpc::RpcController*,
const rpc::ResponseCallback&)> func_;
// Name of the RPC being sent. Since multiple template instantiations may
// exist for the same proxy function, this need not be exactly the proxy
// function name.
const std::string rpc_name_;
// Callback to call upon completion of the operation (whether the RPC itself
// was successful or not).
const StatusCallback user_cb_;
// List of master-side feature flags required to send this RPC. If the
// master(s) is missing any of these flags, the RPC will yield an error.
const std::vector<uint32_t> required_feature_flags_;
};
} // namespace internal
} // namespace client
} // namespace kudu