/Users/deen/code/yugabyte-db/src/yb/client/tablet_rpc.h
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // Copyright (c) YugaByte, Inc. |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
5 | | // in compliance with the License. You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
10 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
11 | | // or implied. See the License for the specific language governing permissions and limitations |
12 | | // under the License. |
13 | | // |
14 | | // |
15 | | |
16 | | #ifndef YB_CLIENT_TABLET_RPC_H |
17 | | #define YB_CLIENT_TABLET_RPC_H |
18 | | |
19 | | #include <memory> |
20 | | #include <string> |
21 | | #include <unordered_set> |
22 | | |
23 | | #include <gflags/gflags_declare.h> |
24 | | #include <gtest/gtest_prod.h> |
25 | | |
26 | | #include "yb/client/client_fwd.h" |
27 | | |
28 | | #include "yb/common/hybrid_time.h" |
29 | | |
30 | | #include "yb/master/master_fwd.h" |
31 | | |
32 | | #include "yb/rpc/rpc_fwd.h" |
33 | | #include "yb/rpc/rpc.h" |
34 | | |
35 | | #include "yb/tserver/tserver_fwd.h" |
36 | | #include "yb/tserver/tserver_types.pb.h" |
37 | | |
38 | | #include "yb/util/status_fwd.h" |
39 | | #include "yb/util/net/net_fwd.h" |
40 | | |
41 | | namespace yb { |
42 | | |
43 | | namespace tserver { |
44 | | class TabletServerServiceProxy; |
45 | | class TabletServerForwardServiceProxy; |
46 | | } |
47 | | |
48 | | namespace rpc { |
49 | | class RpcController; |
50 | | } |
51 | | |
52 | | namespace client { |
53 | | namespace internal { |
54 | | |
55 | | class TabletRpc { |
56 | | public: |
57 | | virtual const tserver::TabletServerErrorPB* response_error() const = 0; |
58 | | virtual void Failed(const Status& status) = 0; |
59 | | |
60 | | // attempt_num starts with 1. |
61 | | virtual void SendRpcToTserver(int attempt_num) = 0; |
62 | | |
63 | 52.5k | virtual bool ShouldRetryExpiredRequest() { return false; } |
64 | | |
65 | | protected: |
66 | 7.26M | ~TabletRpc() {} |
67 | | }; |
68 | | |
69 | | tserver::TabletServerErrorPB_Code ErrorCode(const tserver::TabletServerErrorPB* error); |
70 | | |
71 | | class TabletInvoker { |
72 | | public: |
73 | | // If table is specified, TabletInvoker can detect that table partitions are stale in case tablet |
74 | | // is no longer available and return ClientErrorCode::kTablePartitionListIsStale. |
75 | | explicit TabletInvoker(const bool local_tserver_only, |
76 | | const bool consistent_prefix, |
77 | | YBClient* client, |
78 | | rpc::RpcCommand* command, |
79 | | TabletRpc* rpc, |
80 | | RemoteTablet* tablet, |
81 | | const std::shared_ptr<const YBTable>& table, |
82 | | rpc::RpcRetrier* retrier, |
83 | | Trace* trace, |
84 | | master::IncludeInactive include_inactive = |
85 | | master::IncludeInactive::kFalse); |
86 | | |
87 | | virtual ~TabletInvoker(); |
88 | | |
89 | | void Execute(const std::string& tablet_id, bool leader_only = false); |
90 | | |
91 | | // Returns true when whole operation is finished, false otherwise. |
92 | | bool Done(Status* status); |
93 | | |
94 | | bool IsLocalCall() const; |
95 | | |
96 | | void WriteAsync(const tserver::WriteRequestPB& req, tserver::WriteResponsePB *resp, |
97 | | rpc::RpcController *controller, std::function<void()>&& cb); |
98 | | |
99 | | void ReadAsync(const tserver::ReadRequestPB& req, tserver::ReadResponsePB *resp, |
100 | | rpc::RpcController *controller, std::function<void()>&& cb); |
101 | | |
102 | 14.6M | const RemoteTabletPtr& tablet() const { return tablet_; } |
103 | | std::shared_ptr<tserver::TabletServerServiceProxy> proxy() const; |
104 | | ::yb::HostPort ProxyEndpoint() const; |
105 | 0 | YBClient& client() const { return *client_; } |
106 | 6.03M | const RemoteTabletServer& current_ts() { return *current_ts_; } |
107 | 0 | bool local_tserver_only() const { return local_tserver_only_; } |
108 | | |
109 | 5.95M | bool is_consistent_prefix() const { return consistent_prefix_; } |
110 | | |
111 | | private: |
112 | | friend class TabletRpcTest; |
113 | | FRIEND_TEST(TabletRpcTest, TabletInvokerSelectTabletServerRace); |
114 | | |
115 | | void SelectTabletServer(); |
116 | | |
117 | | // This is an implementation of ReadRpc with consistency level as CONSISTENT_PREFIX. As a result, |
118 | | // there is no requirement that the read needs to hit the leader. |
119 | | void SelectTabletServerWithConsistentPrefix(); |
120 | | |
121 | | // This is for Redis ops which always prefer to invoke the local tablet server. In case when it |
122 | | // is not the leader, a MOVED response will be returned. |
123 | | void SelectLocalTabletServer(); |
124 | | |
125 | | // Marks all replicas on current_ts_ as failed and retries the write on a |
126 | | // new replica. |
127 | | CHECKED_STATUS FailToNewReplica(const Status& reason, |
128 | | const tserver::TabletServerErrorPB* error_code = nullptr); |
129 | | |
130 | | // Called when we finish a lookup (to find the new consensus leader). Retries |
131 | | // the rpc after a short delay. |
132 | | void LookupTabletCb(const Result<RemoteTabletPtr>& result); |
133 | | |
134 | | void InitialLookupTabletDone(const Result<RemoteTabletPtr>& result); |
135 | | |
136 | | // If we receive TABLET_NOT_FOUND and current_ts_ is set, that means we contacted a tserver |
137 | | // with a tablet_id, but the tserver no longer has that tablet. |
138 | | bool TabletNotFoundOnTServer(const tserver::TabletServerErrorPB* error_code, |
139 | 7.25M | const Status& status) { |
140 | 7.25M | return status.IsNotFound() && |
141 | 1.97k | ErrorCode(error_code) == tserver::TabletServerErrorPB::TABLET_NOT_FOUND && |
142 | 1.94k | current_ts_ != nullptr; |
143 | 7.25M | } |
144 | | |
145 | | bool ShouldUseNodeLocalForwardProxy(); |
146 | | |
147 | | YBClient* const client_; |
148 | | |
149 | | rpc::RpcCommand* const command_; |
150 | | |
151 | | TabletRpc* const rpc_; |
152 | | |
153 | | // The tablet that should receive this rpc. |
154 | | RemoteTabletPtr tablet_; |
155 | | |
156 | | std::string tablet_id_; |
157 | | |
158 | | const std::shared_ptr<const YBTable> table_; |
159 | | |
160 | | rpc::RpcRetrier* const retrier_; |
161 | | |
162 | | // Trace is provided externally and owner of this object should guarantee that it will be alive |
163 | | // while this object is alive. |
164 | | Trace* const trace_; |
165 | | |
166 | | // Whether or not to allow lookups of inactive (hidden) tablets. |
167 | | master::IncludeInactive const include_inactive_; |
168 | | |
169 | | // Used to retry some failed RPCs. |
170 | | // Tablet servers that refused the write because they were followers at the time. |
171 | | // Cleared when new consensus configuration information arrives from the master. |
172 | | struct FollowerData { |
173 | | // Last replica error, i.e. reason why it was marked as follower. |
174 | | Status status; |
175 | | // Error time. |
176 | | CoarseTimePoint time; |
177 | | |
178 | | std::string ToString() const; |
179 | | }; |
180 | | |
181 | | std::unordered_map<RemoteTabletServer*, FollowerData> followers_; |
182 | | |
183 | | const bool local_tserver_only_; |
184 | | |
185 | | const bool consistent_prefix_; |
186 | | |
187 | | // The TS receiving the write. May change if the write is retried. |
188 | | // RemoteTabletServer is taken from YBClient cache, so it is guaranteed that those objects are |
189 | | // alive while YBClient is alive. Because we don't delete them, but only add and update. |
190 | | RemoteTabletServer* current_ts_ = nullptr; |
191 | | |
192 | | // Should we assign new leader in meta cache when successful response is received. |
193 | | bool assign_new_leader_ = false; |
194 | | |
195 | | // Whether to use the local node proxy or to use the default remote proxy for communication to the |
196 | | // tablet servers. This flag is true if all of the following conditions are true: |
197 | | // 1. FLAGS_ysql_forward_rpcs_to_local_tserver is true |
198 | | // 2. The node local forward proxy is set in the client. |
199 | | // 3. The destination tserver is not the same as the node local tserver. |
200 | | // 4. The rpc is not intended for the master. |
201 | | bool should_use_local_node_proxy_ = false; |
202 | | }; |
203 | | |
204 | | CHECKED_STATUS ErrorStatus(const tserver::TabletServerErrorPB* error); |
205 | | template <class Response> |
206 | 5.99M | HybridTime GetPropagatedHybridTime(const Response& response) { |
207 | 5.87M | return response.has_propagated_hybrid_time() ? HybridTime(response.propagated_hybrid_time()) |
208 | 120k | : HybridTime::kInvalid; |
209 | 5.99M | } _ZN2yb6client8internal23GetPropagatedHybridTimeINS_7tserver15WriteResponsePBEEENS_10HybridTimeERKT_ Line | Count | Source | 206 | 1.32M | HybridTime GetPropagatedHybridTime(const Response& response) { | 207 | 1.24M | return response.has_propagated_hybrid_time() ? HybridTime(response.propagated_hybrid_time()) | 208 | 82.1k | : HybridTime::kInvalid; | 209 | 1.32M | } |
_ZN2yb6client8internal23GetPropagatedHybridTimeINS_7tserver14ReadResponsePBEEENS_10HybridTimeERKT_ Line | Count | Source | 206 | 4.67M | HybridTime GetPropagatedHybridTime(const Response& response) { | 207 | 4.63M | return response.has_propagated_hybrid_time() ? HybridTime(response.propagated_hybrid_time()) | 208 | 38.0k | : HybridTime::kInvalid; | 209 | 4.67M | } |
|
210 | | |
211 | | } // namespace internal |
212 | | } // namespace client |
213 | | } // namespace yb |
214 | | |
215 | | #endif // YB_CLIENT_TABLET_RPC_H |