| // 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 <functional> |
| #include <string> |
| |
| #include "kudu/rpc/response_callback.h" |
| #include "kudu/rpc/rpc.h" |
| #include "kudu/util/status_callback.h" |
| |
| namespace kudu { |
| |
| class MonoTime; |
| class Status; |
| namespace rpc { |
| class RpcController; |
| } // namespace rpc |
| |
| namespace transactions { |
| class TxnManagerServiceProxy; |
| } // namespace transactions |
| |
| namespace client { |
| |
| class KuduClient; |
| |
| namespace internal { |
| |
| // Encapsulates RPCs that target a randomly chosen TxnManager, handling retries |
| // and reconnections. |
| // |
| // TODO(aserbin): implement the re-connection to TxnManagers |
| template <class ReqClass, class RespClass> |
| class AsyncRandomTxnManagerRpc : public rpc::Rpc { |
| public: |
| // The input 'client' will be used to call the asynchonous TxnManager's proxy |
| // function 'func' on the currently used random TxnManager, sending over |
| // 'req'. 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'. |
| AsyncRandomTxnManagerRpc( |
| const MonoTime& deadline, |
| KuduClient* client, |
| rpc::BackoffType backoff, |
| ReqClass req, |
| RespClass* resp, |
| const std::function<void(transactions::TxnManagerServiceProxy*, |
| const ReqClass&, RespClass*, |
| rpc::RpcController*, |
| const rpc::ResponseCallback&)>& func, |
| std::string rpc_name, |
| StatusCallback user_cb); |
| |
| // Send the RPC using the TxnManagerService proxy's asynchonous API, ensuring |
| // that neither the per-RPC deadline nor the overall deadline has passed. |
| void SendRpc() override; |
| |
| std::string ToString() const override; |
| |
| protected: |
| // Handles 'status', retrying if necessary, and calling the user-provided |
| // callback as appropriate. |
| void SendRpcCb(const Status& status) override; |
| |
| void ResetTxnManagerAndRetry(const Status& status); |
| |
| // 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 |
| // |
| // 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 RetryIfNecessary(Status* status); |
| |
| KuduClient* client_; |
| const ReqClass req_; |
| RespClass* resp_; |
| |
| // Asynchronous function that sends an RPC to current TxnManager. |
| const std::function<void(transactions::TxnManagerServiceProxy*, |
| 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_; |
| |
| // Whether this is a multi-master cluster to work with. |
| const bool multi_txn_manager_; |
| }; |
| |
| } // namespace internal |
| } // namespace client |
| } // namespace kudu |