couchbase 3.0.0.beta.1-universal-darwin-19 → 3.0.0-universal-darwin-19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +227 -0
- data/.rubocop_todo.yml +47 -0
- data/CONTRIBUTING.md +110 -0
- data/Gemfile +4 -0
- data/README.md +3 -3
- data/Rakefile +1 -1
- data/couchbase.gemspec +40 -39
- data/examples/analytics.rb +123 -108
- data/examples/auth.rb +33 -0
- data/examples/crud.rb +16 -2
- data/examples/managing_analytics_indexes.rb +18 -4
- data/examples/managing_buckets.rb +17 -3
- data/examples/managing_collections.rb +22 -9
- data/examples/managing_query_indexes.rb +38 -18
- data/examples/managing_search_indexes.rb +21 -6
- data/examples/managing_view_indexes.rb +18 -4
- data/examples/query.rb +17 -3
- data/examples/query_with_consistency.rb +30 -20
- data/examples/search.rb +116 -101
- data/examples/search_with_consistency.rb +43 -30
- data/examples/subdocument.rb +42 -30
- data/examples/view.rb +19 -10
- data/ext/CMakeLists.txt +40 -2
- data/ext/build_version.hxx.in +1 -1
- data/ext/couchbase/bucket.hxx +190 -38
- data/ext/couchbase/cluster.hxx +22 -4
- data/ext/couchbase/configuration.hxx +14 -14
- data/ext/couchbase/couchbase.cxx +108 -12
- data/ext/couchbase/error_map.hxx +202 -2
- data/ext/couchbase/errors.hxx +8 -2
- data/ext/couchbase/io/dns_client.hxx +6 -6
- data/ext/couchbase/io/http_command.hxx +2 -2
- data/ext/couchbase/io/http_session.hxx +7 -11
- data/ext/couchbase/io/http_session_manager.hxx +3 -3
- data/ext/couchbase/io/mcbp_command.hxx +101 -44
- data/ext/couchbase/io/mcbp_session.hxx +144 -49
- data/ext/couchbase/io/retry_action.hxx +30 -0
- data/ext/couchbase/io/retry_context.hxx +39 -0
- data/ext/couchbase/io/retry_orchestrator.hxx +96 -0
- data/ext/couchbase/io/retry_reason.hxx +235 -0
- data/ext/couchbase/io/retry_strategy.hxx +156 -0
- data/ext/couchbase/operations/document_decrement.hxx +2 -0
- data/ext/couchbase/operations/document_exists.hxx +2 -0
- data/ext/couchbase/operations/document_get.hxx +2 -0
- data/ext/couchbase/operations/document_get_and_lock.hxx +2 -0
- data/ext/couchbase/operations/document_get_and_touch.hxx +2 -0
- data/ext/couchbase/operations/document_get_projected.hxx +2 -0
- data/ext/couchbase/operations/document_increment.hxx +2 -0
- data/ext/couchbase/operations/document_insert.hxx +2 -0
- data/ext/couchbase/operations/document_lookup_in.hxx +2 -0
- data/ext/couchbase/operations/document_mutate_in.hxx +3 -0
- data/ext/couchbase/operations/document_query.hxx +10 -0
- data/ext/couchbase/operations/document_remove.hxx +2 -0
- data/ext/couchbase/operations/document_replace.hxx +2 -0
- data/ext/couchbase/operations/document_search.hxx +8 -3
- data/ext/couchbase/operations/document_touch.hxx +2 -0
- data/ext/couchbase/operations/document_unlock.hxx +2 -0
- data/ext/couchbase/operations/document_upsert.hxx +2 -0
- data/ext/couchbase/operations/query_index_create.hxx +14 -4
- data/ext/couchbase/operations/query_index_drop.hxx +12 -2
- data/ext/couchbase/operations/query_index_get_all.hxx +11 -2
- data/ext/couchbase/origin.hxx +47 -17
- data/ext/couchbase/platform/backtrace.c +189 -0
- data/ext/couchbase/platform/backtrace.h +54 -0
- data/ext/couchbase/platform/terminate_handler.cc +122 -0
- data/ext/couchbase/platform/terminate_handler.h +36 -0
- data/ext/couchbase/protocol/cmd_get_cluster_config.hxx +6 -1
- data/ext/couchbase/protocol/status.hxx +14 -4
- data/ext/couchbase/version.hxx +2 -2
- data/ext/extconf.rb +39 -36
- data/ext/test/main.cxx +64 -16
- data/lib/couchbase.rb +0 -1
- data/lib/couchbase/analytics_options.rb +2 -4
- data/lib/couchbase/authenticator.rb +14 -0
- data/lib/couchbase/binary_collection.rb +9 -9
- data/lib/couchbase/binary_collection_options.rb +8 -6
- data/lib/couchbase/bucket.rb +18 -18
- data/lib/couchbase/cluster.rb +121 -90
- data/lib/couchbase/collection.rb +36 -38
- data/lib/couchbase/collection_options.rb +31 -17
- data/lib/couchbase/common_options.rb +1 -1
- data/lib/couchbase/datastructures/couchbase_list.rb +16 -16
- data/lib/couchbase/datastructures/couchbase_map.rb +18 -18
- data/lib/couchbase/datastructures/couchbase_queue.rb +13 -13
- data/lib/couchbase/datastructures/couchbase_set.rb +8 -7
- data/lib/couchbase/errors.rb +10 -3
- data/lib/couchbase/json_transcoder.rb +2 -2
- data/lib/couchbase/libcouchbase.bundle +0 -0
- data/lib/couchbase/management/analytics_index_manager.rb +37 -37
- data/lib/couchbase/management/bucket_manager.rb +25 -25
- data/lib/couchbase/management/collection_manager.rb +3 -3
- data/lib/couchbase/management/query_index_manager.rb +59 -14
- data/lib/couchbase/management/search_index_manager.rb +15 -12
- data/lib/couchbase/management/user_manager.rb +1 -1
- data/lib/couchbase/management/view_index_manager.rb +11 -5
- data/lib/couchbase/mutation_state.rb +12 -0
- data/lib/couchbase/query_options.rb +23 -9
- data/lib/couchbase/scope.rb +61 -1
- data/lib/couchbase/search_options.rb +40 -27
- data/lib/couchbase/subdoc.rb +31 -28
- data/lib/couchbase/version.rb +2 -2
- data/lib/couchbase/view_options.rb +0 -1
- metadata +20 -7
@@ -0,0 +1,30 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <chrono>
|
21
|
+
#include <optional>
|
22
|
+
|
23
|
+
namespace couchbase::io
|
24
|
+
{
|
25
|
+
struct retry_action {
|
26
|
+
bool retry_requested{ false };
|
27
|
+
std::chrono::milliseconds duration{};
|
28
|
+
};
|
29
|
+
|
30
|
+
} // namespace couchbase::io
|
@@ -0,0 +1,39 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <set>
|
21
|
+
#include <chrono>
|
22
|
+
|
23
|
+
#include <io/retry_reason.hxx>
|
24
|
+
#include <io/retry_strategy.hxx>
|
25
|
+
|
26
|
+
namespace couchbase::io
|
27
|
+
{
|
28
|
+
|
29
|
+
template<class RetryStrategy>
|
30
|
+
struct retry_context
|
31
|
+
{
|
32
|
+
bool idempotent;
|
33
|
+
int retry_attempts{ 0 };
|
34
|
+
std::chrono::milliseconds last_duration{ 0 };
|
35
|
+
std::set<retry_reason> reasons{};
|
36
|
+
RetryStrategy strategy{};
|
37
|
+
};
|
38
|
+
|
39
|
+
} // namespace couchbase::io
|
@@ -0,0 +1,96 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <spdlog/spdlog.h>
|
21
|
+
|
22
|
+
#include <io/retry_reason.hxx>
|
23
|
+
#include <io/retry_action.hxx>
|
24
|
+
|
25
|
+
namespace couchbase::io::retry_orchestrator
|
26
|
+
{
|
27
|
+
|
28
|
+
namespace priv
|
29
|
+
{
|
30
|
+
template<class Command>
|
31
|
+
std::chrono::milliseconds
|
32
|
+
cap_duration(std::chrono::milliseconds uncapped, std::shared_ptr<Command> command)
|
33
|
+
{
|
34
|
+
auto theoretical_deadline = std::chrono::steady_clock::now() + uncapped;
|
35
|
+
auto absolute_deadline = command->deadline.expiry();
|
36
|
+
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(theoretical_deadline - absolute_deadline);
|
37
|
+
if (delta.count() > 0) {
|
38
|
+
auto capped = uncapped - delta;
|
39
|
+
if (capped.count() < 0) {
|
40
|
+
return uncapped; // something went wrong, return the uncapped one as a safety net
|
41
|
+
}
|
42
|
+
return capped;
|
43
|
+
}
|
44
|
+
return uncapped;
|
45
|
+
}
|
46
|
+
|
47
|
+
std::chrono::milliseconds
|
48
|
+
controlled_backoff(int retry_attempts)
|
49
|
+
{
|
50
|
+
switch (retry_attempts) {
|
51
|
+
case 0:
|
52
|
+
return std::chrono::milliseconds(1);
|
53
|
+
case 1:
|
54
|
+
return std::chrono::milliseconds(10);
|
55
|
+
case 2:
|
56
|
+
return std::chrono::milliseconds(50);
|
57
|
+
case 3:
|
58
|
+
return std::chrono::milliseconds(100);
|
59
|
+
case 4:
|
60
|
+
return std::chrono::milliseconds(500);
|
61
|
+
default:
|
62
|
+
return std::chrono::milliseconds(1000);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
template<class Manager, class Command>
|
67
|
+
void
|
68
|
+
retry_with_duration(std::shared_ptr<Manager> manager,
|
69
|
+
std::shared_ptr<Command> command,
|
70
|
+
retry_reason reason,
|
71
|
+
std::chrono::milliseconds duration)
|
72
|
+
{
|
73
|
+
++command->request.retries.retry_attempts;
|
74
|
+
command->request.retries.reasons.insert(reason);
|
75
|
+
command->request.retries.last_duration = duration;
|
76
|
+
manager->schedule_for_retry(command, duration);
|
77
|
+
}
|
78
|
+
|
79
|
+
} // namespace priv
|
80
|
+
|
81
|
+
template<class Manager, class Command>
|
82
|
+
void
|
83
|
+
maybe_retry(std::shared_ptr<Manager> manager, std::shared_ptr<Command> command, retry_reason reason, std::error_code ec)
|
84
|
+
{
|
85
|
+
if (always_retry(reason)) {
|
86
|
+
return priv::retry_with_duration(manager, command, reason, priv::controlled_backoff(command->request.retries.retry_attempts));
|
87
|
+
}
|
88
|
+
|
89
|
+
retry_action action = command->request.retries.strategy.should_retry(command->request, reason);
|
90
|
+
if (action.retry_requested) {
|
91
|
+
return priv::retry_with_duration(manager, command, reason, priv::cap_duration(action.duration, command));
|
92
|
+
}
|
93
|
+
return command->invoke_handler(ec);
|
94
|
+
}
|
95
|
+
|
96
|
+
} // namespace couchbase::io::retry_orchestrator
|
@@ -0,0 +1,235 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <spdlog/fmt/fmt.h>
|
21
|
+
|
22
|
+
namespace couchbase::io
|
23
|
+
{
|
24
|
+
enum class retry_reason {
|
25
|
+
/**
|
26
|
+
* default value, e.g. when we don't need to retry
|
27
|
+
*/
|
28
|
+
do_not_retry,
|
29
|
+
|
30
|
+
/**
|
31
|
+
* All unexpected/unknown retry errors must not be retried to avoid accidental data loss and non-deterministic behavior.
|
32
|
+
*/
|
33
|
+
unknown,
|
34
|
+
|
35
|
+
/**
|
36
|
+
* The socket is not available into which the operation should’ve been written.
|
37
|
+
*/
|
38
|
+
socket_not_available,
|
39
|
+
|
40
|
+
/**
|
41
|
+
* The service on a node (i.e. kv, query) is not available.
|
42
|
+
*/
|
43
|
+
service_not_available,
|
44
|
+
|
45
|
+
/**
|
46
|
+
* The node where the operation is supposed to be dispatched to is not available.
|
47
|
+
*/
|
48
|
+
node_not_available,
|
49
|
+
|
50
|
+
/**
|
51
|
+
* A not my vbucket response has been received.
|
52
|
+
*/
|
53
|
+
kv_not_my_vbucket,
|
54
|
+
|
55
|
+
/**
|
56
|
+
* A KV response has been received which signals an outdated collection.
|
57
|
+
*/
|
58
|
+
kv_collection_outdated,
|
59
|
+
|
60
|
+
/**
|
61
|
+
* An unknown response was returned and the consulted KV error map indicated a retry.
|
62
|
+
*/
|
63
|
+
kv_error_map_retry_indicated,
|
64
|
+
|
65
|
+
kv_locked,
|
66
|
+
|
67
|
+
kv_temporary_failure,
|
68
|
+
|
69
|
+
kv_sync_write_in_progress,
|
70
|
+
|
71
|
+
kv_sync_write_re_commit_in_progress,
|
72
|
+
|
73
|
+
service_response_code_indicated,
|
74
|
+
|
75
|
+
/**
|
76
|
+
* While an operation was in-flight, the underlying socket has been closed.
|
77
|
+
*/
|
78
|
+
socket_closed_while_in_flight,
|
79
|
+
|
80
|
+
/**
|
81
|
+
* The circuit breaker is open for the given socket/endpoint and as a result the operation is not sent into it.
|
82
|
+
*/
|
83
|
+
circuit_breaker_open,
|
84
|
+
|
85
|
+
query_prepared_statement_failure,
|
86
|
+
|
87
|
+
query_index_not_found,
|
88
|
+
|
89
|
+
analytics_temporary_failure,
|
90
|
+
|
91
|
+
search_too_many_requests,
|
92
|
+
|
93
|
+
views_temporary_failure,
|
94
|
+
|
95
|
+
views_no_active_partition,
|
96
|
+
};
|
97
|
+
|
98
|
+
constexpr inline bool
|
99
|
+
allows_non_idempotent_retry(retry_reason reason)
|
100
|
+
{
|
101
|
+
switch (reason) {
|
102
|
+
case retry_reason::socket_not_available:
|
103
|
+
case retry_reason::service_not_available:
|
104
|
+
case retry_reason::node_not_available:
|
105
|
+
case retry_reason::kv_not_my_vbucket:
|
106
|
+
case retry_reason::kv_collection_outdated:
|
107
|
+
case retry_reason::kv_error_map_retry_indicated:
|
108
|
+
case retry_reason::kv_locked:
|
109
|
+
case retry_reason::kv_temporary_failure:
|
110
|
+
case retry_reason::kv_sync_write_in_progress:
|
111
|
+
case retry_reason::kv_sync_write_re_commit_in_progress:
|
112
|
+
case retry_reason::service_response_code_indicated:
|
113
|
+
case retry_reason::circuit_breaker_open:
|
114
|
+
case retry_reason::query_prepared_statement_failure:
|
115
|
+
case retry_reason::query_index_not_found:
|
116
|
+
case retry_reason::analytics_temporary_failure:
|
117
|
+
case retry_reason::search_too_many_requests:
|
118
|
+
case retry_reason::views_temporary_failure:
|
119
|
+
case retry_reason::views_no_active_partition:
|
120
|
+
return true;
|
121
|
+
case retry_reason::do_not_retry:
|
122
|
+
case retry_reason::socket_closed_while_in_flight:
|
123
|
+
case retry_reason::unknown:
|
124
|
+
return false;
|
125
|
+
}
|
126
|
+
return false;
|
127
|
+
}
|
128
|
+
|
129
|
+
constexpr inline bool
|
130
|
+
always_retry(retry_reason reason)
|
131
|
+
{
|
132
|
+
switch (reason) {
|
133
|
+
case retry_reason::kv_not_my_vbucket:
|
134
|
+
case retry_reason::kv_collection_outdated:
|
135
|
+
case retry_reason::views_no_active_partition:
|
136
|
+
return true;
|
137
|
+
case retry_reason::do_not_retry:
|
138
|
+
case retry_reason::socket_not_available:
|
139
|
+
case retry_reason::service_not_available:
|
140
|
+
case retry_reason::node_not_available:
|
141
|
+
case retry_reason::kv_error_map_retry_indicated:
|
142
|
+
case retry_reason::kv_locked:
|
143
|
+
case retry_reason::kv_temporary_failure:
|
144
|
+
case retry_reason::kv_sync_write_in_progress:
|
145
|
+
case retry_reason::kv_sync_write_re_commit_in_progress:
|
146
|
+
case retry_reason::service_response_code_indicated:
|
147
|
+
case retry_reason::socket_closed_while_in_flight:
|
148
|
+
case retry_reason::circuit_breaker_open:
|
149
|
+
case retry_reason::query_prepared_statement_failure:
|
150
|
+
case retry_reason::query_index_not_found:
|
151
|
+
case retry_reason::analytics_temporary_failure:
|
152
|
+
case retry_reason::search_too_many_requests:
|
153
|
+
case retry_reason::views_temporary_failure:
|
154
|
+
case retry_reason::unknown:
|
155
|
+
return false;
|
156
|
+
}
|
157
|
+
return false;
|
158
|
+
}
|
159
|
+
|
160
|
+
} // namespace couchbase::io
|
161
|
+
|
162
|
+
template<>
|
163
|
+
struct fmt::formatter<couchbase::io::retry_reason> : formatter<string_view> {
|
164
|
+
template<typename FormatContext>
|
165
|
+
auto format(couchbase::io::retry_reason reason, FormatContext& ctx)
|
166
|
+
{
|
167
|
+
string_view name = "unknown";
|
168
|
+
switch (reason) {
|
169
|
+
case couchbase::io::retry_reason::do_not_retry:
|
170
|
+
name = "do_not_retry";
|
171
|
+
break;
|
172
|
+
case couchbase::io::retry_reason::unknown:
|
173
|
+
name = "unknown";
|
174
|
+
break;
|
175
|
+
case couchbase::io::retry_reason::socket_not_available:
|
176
|
+
name = "socket_not_available";
|
177
|
+
break;
|
178
|
+
case couchbase::io::retry_reason::service_not_available:
|
179
|
+
name = "service_not_available";
|
180
|
+
break;
|
181
|
+
case couchbase::io::retry_reason::node_not_available:
|
182
|
+
name = "node_not_available";
|
183
|
+
break;
|
184
|
+
case couchbase::io::retry_reason::kv_not_my_vbucket:
|
185
|
+
name = "kv_not_my_vbucket";
|
186
|
+
break;
|
187
|
+
case couchbase::io::retry_reason::kv_collection_outdated:
|
188
|
+
name = "kv_collection_outdated";
|
189
|
+
break;
|
190
|
+
case couchbase::io::retry_reason::kv_error_map_retry_indicated:
|
191
|
+
name = "kv_error_map_retry_indicated";
|
192
|
+
break;
|
193
|
+
case couchbase::io::retry_reason::kv_locked:
|
194
|
+
name = "kv_locked";
|
195
|
+
break;
|
196
|
+
case couchbase::io::retry_reason::kv_temporary_failure:
|
197
|
+
name = "kv_temporary_failure";
|
198
|
+
break;
|
199
|
+
case couchbase::io::retry_reason::kv_sync_write_in_progress:
|
200
|
+
name = "kv_sync_write_in_progress";
|
201
|
+
break;
|
202
|
+
case couchbase::io::retry_reason::kv_sync_write_re_commit_in_progress:
|
203
|
+
name = "kv_sync_write_re_commit_in_progress";
|
204
|
+
break;
|
205
|
+
case couchbase::io::retry_reason::service_response_code_indicated:
|
206
|
+
name = "service_response_code_indicated";
|
207
|
+
break;
|
208
|
+
case couchbase::io::retry_reason::socket_closed_while_in_flight:
|
209
|
+
name = "socket_closed_while_in_flight";
|
210
|
+
break;
|
211
|
+
case couchbase::io::retry_reason::circuit_breaker_open:
|
212
|
+
name = "circuit_breaker_open";
|
213
|
+
break;
|
214
|
+
case couchbase::io::retry_reason::query_prepared_statement_failure:
|
215
|
+
name = "query_prepared_statement_failure";
|
216
|
+
break;
|
217
|
+
case couchbase::io::retry_reason::query_index_not_found:
|
218
|
+
name = "query_index_not_found";
|
219
|
+
break;
|
220
|
+
case couchbase::io::retry_reason::analytics_temporary_failure:
|
221
|
+
name = "analytics_temporary_failure";
|
222
|
+
break;
|
223
|
+
case couchbase::io::retry_reason::search_too_many_requests:
|
224
|
+
name = "search_too_many_requests";
|
225
|
+
break;
|
226
|
+
case couchbase::io::retry_reason::views_temporary_failure:
|
227
|
+
name = "views_temporary_failure";
|
228
|
+
break;
|
229
|
+
case couchbase::io::retry_reason::views_no_active_partition:
|
230
|
+
name = "views_no_active_partition";
|
231
|
+
break;
|
232
|
+
}
|
233
|
+
return formatter<string_view>::format(name, ctx);
|
234
|
+
}
|
235
|
+
};
|
@@ -0,0 +1,156 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <gsl/gsl_assert>
|
21
|
+
|
22
|
+
#include <io/retry_reason.hxx>
|
23
|
+
#include <io/retry_action.hxx>
|
24
|
+
|
25
|
+
namespace couchbase::io::retry_strategy
|
26
|
+
{
|
27
|
+
namespace backoff
|
28
|
+
{
|
29
|
+
struct backoff_delay {
|
30
|
+
std::chrono::milliseconds delay;
|
31
|
+
std::chrono::milliseconds min_delay;
|
32
|
+
std::chrono::milliseconds max_delay;
|
33
|
+
};
|
34
|
+
|
35
|
+
class fixed
|
36
|
+
{
|
37
|
+
private:
|
38
|
+
backoff_delay delay_;
|
39
|
+
|
40
|
+
public:
|
41
|
+
explicit fixed(std::chrono::milliseconds delay)
|
42
|
+
: delay_{ delay, delay, delay }
|
43
|
+
{
|
44
|
+
}
|
45
|
+
|
46
|
+
template<class Request>
|
47
|
+
backoff_delay operator()(Request&)
|
48
|
+
{
|
49
|
+
return delay_;
|
50
|
+
}
|
51
|
+
};
|
52
|
+
|
53
|
+
class exponential
|
54
|
+
{
|
55
|
+
public:
|
56
|
+
/**
|
57
|
+
* Backoff function with exponential backoff delay. Retries are performed after a backoff interval of
|
58
|
+
*
|
59
|
+
* first_backoff * (factor^n)
|
60
|
+
*
|
61
|
+
* where n is the iteration. If max_backoff is not zero, the maximum backoff applied will be limited to max_backoff.
|
62
|
+
*
|
63
|
+
* If based_on_previous_value is true, backoff will be calculated using
|
64
|
+
*
|
65
|
+
* prev_backoff * factor
|
66
|
+
*
|
67
|
+
* When backoffs are combined with jitter, this value will be different from the actual exponential value for the iteration.
|
68
|
+
*
|
69
|
+
* @param first_backoff First backoff duration
|
70
|
+
* @param factor The multiplicand for calculating backoff
|
71
|
+
* @param max_backoff Maximum backoff duration
|
72
|
+
* @param based_on_previous_value If true, calculation is based on previous value which may be a backoff with jitter applied
|
73
|
+
*/
|
74
|
+
exponential(std::chrono::milliseconds first_backoff,
|
75
|
+
int factor,
|
76
|
+
std::chrono::milliseconds max_backoff = {},
|
77
|
+
bool based_on_previous_value = false)
|
78
|
+
{
|
79
|
+
Expects(first_backoff.count() > 0);
|
80
|
+
if (max_backoff.count() <= 0) {
|
81
|
+
max_backoff = std::chrono::milliseconds{ std::numeric_limits<std::chrono::milliseconds::rep>::max() };
|
82
|
+
}
|
83
|
+
Expects(max_backoff > first_backoff);
|
84
|
+
first_backoff_ = first_backoff;
|
85
|
+
max_backoff_ = max_backoff;
|
86
|
+
factor_ = factor;
|
87
|
+
based_on_previous_value_ = based_on_previous_value;
|
88
|
+
}
|
89
|
+
|
90
|
+
template<class Request>
|
91
|
+
backoff_delay operator()(Request& request)
|
92
|
+
{
|
93
|
+
std::chrono::milliseconds previous_backoff = request.retries.last_duration;
|
94
|
+
std::chrono::milliseconds next_backoff;
|
95
|
+
|
96
|
+
if (based_on_previous_value_) {
|
97
|
+
if (previous_backoff >= max_backoff_) {
|
98
|
+
next_backoff = max_backoff_;
|
99
|
+
} else {
|
100
|
+
next_backoff = previous_backoff * factor_;
|
101
|
+
}
|
102
|
+
if (next_backoff < first_backoff_) {
|
103
|
+
next_backoff = first_backoff_;
|
104
|
+
}
|
105
|
+
} else {
|
106
|
+
if (previous_backoff >= max_backoff_) {
|
107
|
+
next_backoff = max_backoff_;
|
108
|
+
} else {
|
109
|
+
next_backoff = first_backoff_ * static_cast<int>(std::pow(factor_, request.retries.retry_attempts - 1));
|
110
|
+
}
|
111
|
+
}
|
112
|
+
return { next_backoff, first_backoff_, max_backoff_ };
|
113
|
+
}
|
114
|
+
|
115
|
+
private:
|
116
|
+
std::chrono::milliseconds first_backoff_;
|
117
|
+
std::chrono::milliseconds max_backoff_;
|
118
|
+
int factor_;
|
119
|
+
bool based_on_previous_value_;
|
120
|
+
};
|
121
|
+
|
122
|
+
} // namespace backoff
|
123
|
+
|
124
|
+
class best_effort
|
125
|
+
{
|
126
|
+
public:
|
127
|
+
best_effort()
|
128
|
+
: backoff_(std::chrono::milliseconds(1), 2, std::chrono::milliseconds(500))
|
129
|
+
{
|
130
|
+
}
|
131
|
+
|
132
|
+
template<class Request>
|
133
|
+
retry_action should_retry(Request& request, retry_reason reason)
|
134
|
+
{
|
135
|
+
if (request.retries.idempotent || allows_non_idempotent_retry(reason)) {
|
136
|
+
backoff::backoff_delay delay = backoff_(request);
|
137
|
+
return { true, delay.delay };
|
138
|
+
}
|
139
|
+
return { false };
|
140
|
+
}
|
141
|
+
|
142
|
+
private:
|
143
|
+
backoff::exponential backoff_;
|
144
|
+
};
|
145
|
+
|
146
|
+
class fail_fast
|
147
|
+
{
|
148
|
+
public:
|
149
|
+
template<class Request>
|
150
|
+
retry_action should_retry(Request&, retry_reason)
|
151
|
+
{
|
152
|
+
return { false };
|
153
|
+
}
|
154
|
+
};
|
155
|
+
|
156
|
+
} // namespace couchbase::io::retry_strategy
|