1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // 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
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_POLLING_POLICY_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_POLLING_POLICY_H
17 
18 #include "google/cloud/bigtable/rpc_backoff_policy.h"
19 #include "google/cloud/bigtable/rpc_retry_policy.h"
20 #include "google/cloud/bigtable/version.h"
21 #include "google/cloud/grpc_error_delegate.h"
22 #include <grpcpp/grpcpp.h>
23 
24 namespace google {
25 namespace cloud {
26 namespace bigtable {
27 inline namespace BIGTABLE_CLIENT_NS {
28 /**
29  * Define the interface for providing asynchronous repetitive call rules
30  *
31  */
32 class PollingPolicy {
33  public:
34   virtual ~PollingPolicy() = default;
35 
36   /**
37    * Return a new copy of this object.
38    *
39    * Typically implemented as
40    * @code
41    *   return std::unique_ptr<PollingPolicy>(new Foo(*this));
42    * @endcode
43    */
44   virtual std::unique_ptr<PollingPolicy> clone() const = 0;
45 
46   virtual void Setup(grpc::ClientContext& context) = 0;
47 
48   /**
49    * Return true if `status` represents a permanent error that cannot be
50    * retried.
51    * TODO(#2344): remove `grpc::Status` version.
52    */
IsPermanentError(grpc::Status const & status)53   virtual bool IsPermanentError(grpc::Status const& status) {
54     return IsPermanentError(MakeStatusFromRpcError(status));
55   }
56 
57   /**
58    * Return true if `status` represents a permanent error that cannot be
59    * retried.
60    */
61   virtual bool IsPermanentError(google::cloud::Status const& status) = 0;
62 
63   /**
64    * Handle an RPC failure.
65    * TODO(#2344): remove `grpc::Status` version.
66    *
67    * @return true if the RPC operation should be retried.
68    */
OnFailure(grpc::Status const & status)69   virtual bool OnFailure(grpc::Status const& status) {
70     return OnFailure(MakeStatusFromRpcError(status));
71   }
72 
73   /**
74    * Handle an RPC failure.
75    *
76    * @return true if the RPC operation should be retried.
77    */
78   virtual bool OnFailure(google::cloud::Status const& status) = 0;
79 
80   /**
81    * Return true if we cannot try again.
82    */
83   virtual bool Exhausted() = 0;
84 
85   /**
86    * Return for how long we should wait before trying again.
87    */
88   virtual std::chrono::milliseconds WaitPeriod() = 0;
89 };
90 
91 /**
92  * Construct a polling policy from existing Retry and Backoff policies.
93  *
94  * A polling policy can be built by composing a retry and backoff policy. For
95  * example, to create a polling policy that "retries N times, waiting a fixed
96  * period between retries" you could compose the "try N times" retry policy with
97  * the "wait a fixed period between retries".
98  *
99  * This class makes it easier to create such composed polling policies.
100  *
101  * @tparam Retry the RPC retry strategy used to limit the number or the total
102  *     duration of the polling strategy.
103  * @tparam Backoff the RPC backoff strategy used to control how often the
104  *     library polls.
105  */
106 template <typename Retry = LimitedTimeRetryPolicy,
107           typename Backoff = ExponentialBackoffPolicy>
108 class GenericPollingPolicy : public PollingPolicy {
109  public:
GenericPollingPolicy(internal::RPCPolicyParameters defaults)110   explicit GenericPollingPolicy(internal::RPCPolicyParameters defaults)
111       : rpc_retry_policy_(Retry(defaults)),
112         rpc_backoff_policy_(Backoff(defaults)) {}
GenericPollingPolicy(Retry retry,Backoff backoff)113   GenericPollingPolicy(Retry retry, Backoff backoff)
114       : rpc_retry_policy_(std::move(retry)),
115         rpc_backoff_policy_(std::move(backoff)) {}
116 
clone()117   std::unique_ptr<PollingPolicy> clone() const override {
118     return std::unique_ptr<PollingPolicy>(new GenericPollingPolicy(*this));
119   }
120 
Setup(grpc::ClientContext & context)121   void Setup(grpc::ClientContext& context) override {
122     rpc_retry_policy_.Setup(context);
123     rpc_backoff_policy_.Setup(context);
124   }
125 
IsPermanentError(google::cloud::Status const & status)126   bool IsPermanentError(google::cloud::Status const& status) override {
127     return RPCRetryPolicy::IsPermanentFailure(status);
128   }
129 
OnFailure(google::cloud::Status const & status)130   bool OnFailure(google::cloud::Status const& status) override {
131     return rpc_retry_policy_.OnFailure(status);
132   }
133 
Exhausted()134   bool Exhausted() override { return !OnFailure(google::cloud::Status()); }
135 
WaitPeriod()136   std::chrono::milliseconds WaitPeriod() override {
137     return rpc_backoff_policy_.OnCompletion(grpc::Status::OK);
138   }
139 
140  private:
141   Retry rpc_retry_policy_;
142   Backoff rpc_backoff_policy_;
143 };
144 
145 std::unique_ptr<PollingPolicy> DefaultPollingPolicy(
146     internal::RPCPolicyParameters defaults);
147 
148 }  // namespace BIGTABLE_CLIENT_NS
149 }  // namespace bigtable
150 }  // namespace cloud
151 }  // namespace google
152 
153 #endif  // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_POLLING_POLICY_H
154