couchbase 3.8.1 → 3.8.2
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/README.md +2 -2
- data/ext/cache/extconf_include.rb +4 -4
- data/ext/cache/mozilla-ca-bundle.crt +95 -102
- data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
- data/ext/couchbase/CMakeLists.txt +1 -1
- data/ext/couchbase/core/impl/public_cluster.cxx +118 -5
- data/ext/couchbase/core/io/configuration_belongs_to_session.hxx +67 -0
- data/ext/couchbase/core/io/mcbp_session.cxx +7 -16
- data/ext/couchbase/core/io/streams.cxx +143 -12
- data/ext/couchbase/core/io/streams.hxx +6 -0
- data/ext/couchbase/core/operations/management/bucket_create.cxx +37 -38
- data/ext/couchbase/core/operations/management/bucket_update.cxx +26 -28
- data/ext/couchbase/core/transactions/attempt_context_impl.cxx +254 -178
- data/ext/couchbase/core/transactions/attempt_context_impl.hxx +5 -1
- data/ext/couchbase/core/transactions/transactions_cleanup.cxx +42 -7
- data/ext/couchbase/core/transactions/waitable_op_list.hxx +13 -2
- data/ext/couchbase/couchbase/cluster.hxx +33 -0
- data/lib/couchbase/cluster.rb +16 -14
- data/lib/couchbase/options.rb +7 -2
- data/lib/couchbase/version.rb +1 -1
- metadata +6 -5
|
@@ -23,12 +23,128 @@
|
|
|
23
23
|
#include <asio/error.hpp>
|
|
24
24
|
#include <asio/ssl.hpp>
|
|
25
25
|
|
|
26
|
+
#include <cerrno>
|
|
27
|
+
|
|
28
|
+
#if defined(_WIN32)
|
|
29
|
+
#include <process.h>
|
|
30
|
+
#else
|
|
31
|
+
#include <unistd.h>
|
|
32
|
+
#endif
|
|
33
|
+
|
|
26
34
|
namespace couchbase::core::io
|
|
27
35
|
{
|
|
36
|
+
namespace
|
|
37
|
+
{
|
|
38
|
+
auto
|
|
39
|
+
current_process_id() -> long long
|
|
40
|
+
{
|
|
41
|
+
#if defined(_WIN32)
|
|
42
|
+
return static_cast<long long>(::_getpid());
|
|
43
|
+
#else
|
|
44
|
+
return static_cast<long long>(::getpid());
|
|
45
|
+
#endif
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Release a socket this process inherited across fork(2), without disturbing the
|
|
50
|
+
* connection the parent is still using.
|
|
51
|
+
*
|
|
52
|
+
* Two things differ from the ordinary close path, and both matter:
|
|
53
|
+
*
|
|
54
|
+
* * No shutdown(2). It acts on the open file description, which fork(2) shares,
|
|
55
|
+
* so it would send FIN and break the parent's connection. close(2) drops only
|
|
56
|
+
* our own descriptor; the peer sees nothing.
|
|
57
|
+
* * release() before closing, rather than asio's close(). asio's close() skips
|
|
58
|
+
* EPOLL_CTL_DEL on the assumption that closing a descriptor removes its epoll
|
|
59
|
+
* registration. Per epoll(7) that happens only once *every* descriptor
|
|
60
|
+
* referring to the description is closed -- and the parent still holds one --
|
|
61
|
+
* so the registration would outlive the descriptor_state asio recycles, which
|
|
62
|
+
* is precisely the stale-pointer shape the reactor faults on. release() emits
|
|
63
|
+
* the EPOLL_CTL_DEL explicitly and hands back the raw descriptor to close.
|
|
64
|
+
*
|
|
65
|
+
* release() also completes any outstanding asynchronous operations on this socket
|
|
66
|
+
* with operation_aborted, which is what we want: those reads belong to the parent.
|
|
67
|
+
*/
|
|
68
|
+
// Takes the basic_socket base rather than tcp::socket so the same code serves both
|
|
69
|
+
// the plain socket and a TLS stream's lowest_layer(), whose type is that base.
|
|
70
|
+
void
|
|
71
|
+
detach_inherited_socket(asio::basic_socket<asio::ip::tcp>& socket, asio::error_code& ec)
|
|
72
|
+
{
|
|
73
|
+
if (!socket.is_open()) {
|
|
74
|
+
ec = asio::error::bad_descriptor;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const auto handle = socket.release(ec);
|
|
79
|
+
if (ec) {
|
|
80
|
+
// Report it. Do not reach for asio's close() here: that is the very call
|
|
81
|
+
// whose epoll behaviour makes it unsafe on an inherited descriptor, and the
|
|
82
|
+
// descriptor goes away when this process exits anyway.
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
#if defined(_WIN32)
|
|
87
|
+
// Unreachable: without fork(2) no socket is ever inherited, so the owner pid
|
|
88
|
+
// always matches and close() never takes this path.
|
|
89
|
+
(void)handle;
|
|
90
|
+
ec = asio::error::operation_not_supported;
|
|
91
|
+
#else
|
|
92
|
+
if (::close(handle) != 0) {
|
|
93
|
+
ec.assign(errno, asio::error::get_system_category());
|
|
94
|
+
}
|
|
95
|
+
#endif
|
|
96
|
+
}
|
|
97
|
+
} // namespace
|
|
98
|
+
|
|
99
|
+
auto
|
|
100
|
+
configure_tls_handshake(asio::ssl::stream<asio::ip::tcp::socket>& stream,
|
|
101
|
+
const std::string& hostname) -> std::error_code
|
|
102
|
+
{
|
|
103
|
+
if (hostname.empty()) {
|
|
104
|
+
// Fail closed: a TLS client connection must have a hostname to verify the
|
|
105
|
+
// server's identity against. Returning success here would silently fall back
|
|
106
|
+
// to CA-only validation -- the CWE-297 problem this function exists to prevent.
|
|
107
|
+
return asio::error::make_error_code(asio::error::invalid_argument);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Send SNI so that name-based / multi-tenant TLS endpoints present the correct
|
|
111
|
+
// certificate for this hostname.
|
|
112
|
+
{
|
|
113
|
+
// SSL_set_tlsext_host_name() is a macro that expands to an internal C-style
|
|
114
|
+
// cast to void*, which trips -Wold-style-cast; suppress it locally.
|
|
115
|
+
#if defined(__GNUC__) || defined(__clang__)
|
|
116
|
+
#pragma GCC diagnostic push
|
|
117
|
+
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
|
118
|
+
#endif
|
|
119
|
+
ERR_clear_error();
|
|
120
|
+
const auto sni_result = SSL_set_tlsext_host_name(stream.native_handle(), hostname.c_str());
|
|
121
|
+
#if defined(__GNUC__) || defined(__clang__)
|
|
122
|
+
#pragma GCC diagnostic pop
|
|
123
|
+
#endif
|
|
124
|
+
if (sni_result != 1) {
|
|
125
|
+
// Prefer the underlying SSL reason (if any) so failures are diagnosable,
|
|
126
|
+
// and fall back to a generic error when the SSL error queue is empty.
|
|
127
|
+
if (const auto reason = ERR_get_error(); reason != 0) {
|
|
128
|
+
return { static_cast<int>(reason), asio::error::get_ssl_category() };
|
|
129
|
+
}
|
|
130
|
+
return asio::error::make_error_code(asio::error::invalid_argument);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Verify that the presented certificate actually identifies `hostname`
|
|
135
|
+
// (SAN/CN). asio::ssl::verify_peer on its own only validates the certificate
|
|
136
|
+
// chain, not the name. In verify_none mode OpenSSL ignores the callback
|
|
137
|
+
// result, so this has no effect there.
|
|
138
|
+
std::error_code ec{};
|
|
139
|
+
stream.set_verify_callback(asio::ssl::host_name_verification(hostname), ec);
|
|
140
|
+
return ec;
|
|
141
|
+
}
|
|
142
|
+
|
|
28
143
|
stream_impl::stream_impl(asio::io_context& ctx, bool is_tls)
|
|
29
144
|
: strand_(asio::make_strand(ctx))
|
|
30
145
|
, tls_(is_tls)
|
|
31
146
|
, id_(uuid::to_string(uuid::random()))
|
|
147
|
+
, owner_pid_(current_process_id())
|
|
32
148
|
{
|
|
33
149
|
}
|
|
34
150
|
|
|
@@ -79,12 +195,20 @@ plain_stream_impl::close(utils::movable_function<void(std::error_code)>&& handle
|
|
|
79
195
|
if (!stream_) {
|
|
80
196
|
return handler(asio::error::bad_descriptor);
|
|
81
197
|
}
|
|
82
|
-
return asio::post(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
198
|
+
return asio::post(
|
|
199
|
+
strand_, [stream = std::move(stream_), owner_pid = owner_pid_, handler = std::move(handler)]() {
|
|
200
|
+
asio::error_code ec{};
|
|
201
|
+
// Decide here rather than when this was posted: io_.stop() at fork_prepare
|
|
202
|
+
// does not drain the queue, so a close queued before the fork runs in the
|
|
203
|
+
// child once the io_context is restarted, and there the answer differs.
|
|
204
|
+
if (owner_pid != current_process_id()) {
|
|
205
|
+
detach_inherited_socket(*stream, ec);
|
|
206
|
+
} else {
|
|
207
|
+
stream->shutdown(asio::socket_base::shutdown_both, ec);
|
|
208
|
+
stream->close(ec);
|
|
209
|
+
}
|
|
210
|
+
handler(ec);
|
|
211
|
+
});
|
|
88
212
|
}
|
|
89
213
|
|
|
90
214
|
void
|
|
@@ -178,12 +302,19 @@ tls_stream_impl::close(utils::movable_function<void(std::error_code)>&& handler)
|
|
|
178
302
|
if (!stream_) {
|
|
179
303
|
return handler(asio::error::bad_descriptor);
|
|
180
304
|
}
|
|
181
|
-
return asio::post(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
305
|
+
return asio::post(
|
|
306
|
+
strand_, [stream = std::move(stream_), owner_pid = owner_pid_, handler = std::move(handler)]() {
|
|
307
|
+
asio::error_code ec{};
|
|
308
|
+
// See plain_stream_impl::close(): the inheritance test belongs here, not at
|
|
309
|
+
// post time.
|
|
310
|
+
if (owner_pid != current_process_id()) {
|
|
311
|
+
detach_inherited_socket(stream->lowest_layer(), ec);
|
|
312
|
+
} else {
|
|
313
|
+
stream->lowest_layer().shutdown(asio::socket_base::shutdown_both, ec);
|
|
314
|
+
stream->lowest_layer().close(ec);
|
|
315
|
+
}
|
|
316
|
+
handler(ec);
|
|
317
|
+
});
|
|
187
318
|
}
|
|
188
319
|
|
|
189
320
|
void
|
|
@@ -65,6 +65,12 @@ protected:
|
|
|
65
65
|
asio::strand<asio::io_context::executor_type> strand_;
|
|
66
66
|
bool tls_;
|
|
67
67
|
std::string id_{};
|
|
68
|
+
// Identifies the process that opened this socket. close() compares it against
|
|
69
|
+
// the process running at that moment to tell a socket inherited across fork(2)
|
|
70
|
+
// apart from one this process opened itself, because an inherited socket must not
|
|
71
|
+
// be shut down: shutdown(2) acts on the open file description, which fork(2)
|
|
72
|
+
// shares, so it would tear down a connection the parent is still using.
|
|
73
|
+
long long owner_pid_;
|
|
68
74
|
|
|
69
75
|
public:
|
|
70
76
|
stream_impl(asio::io_context& ctx, bool is_tls);
|
|
@@ -30,104 +30,101 @@ namespace couchbase::core::operations::management
|
|
|
30
30
|
{
|
|
31
31
|
|
|
32
32
|
auto
|
|
33
|
-
bucket_create_request::encode_to(encoded_request_type& encoded,
|
|
34
|
-
|
|
33
|
+
bucket_create_request::encode_to(encoded_request_type& encoded, http_context& /* context */) const
|
|
34
|
+
-> std::error_code
|
|
35
35
|
{
|
|
36
36
|
encoded.method = "POST";
|
|
37
37
|
encoded.path = "/pools/default/buckets";
|
|
38
38
|
|
|
39
39
|
encoded.headers["content-type"] = "application/x-www-form-urlencoded";
|
|
40
|
-
|
|
40
|
+
|
|
41
|
+
std::map<std::string, std::string> values{};
|
|
42
|
+
values["name"] = bucket.name;
|
|
41
43
|
switch (bucket.bucket_type) {
|
|
42
44
|
case couchbase::core::management::cluster::bucket_type::couchbase:
|
|
43
|
-
|
|
45
|
+
values["bucketType"] = "couchbase";
|
|
44
46
|
break;
|
|
45
47
|
case couchbase::core::management::cluster::bucket_type::memcached:
|
|
46
|
-
|
|
48
|
+
values["bucketType"] = "memcached";
|
|
47
49
|
break;
|
|
48
50
|
case couchbase::core::management::cluster::bucket_type::ephemeral:
|
|
49
|
-
|
|
51
|
+
values["bucketType"] = "ephemeral";
|
|
50
52
|
break;
|
|
51
53
|
case couchbase::core::management::cluster::bucket_type::unknown:
|
|
52
54
|
break;
|
|
53
55
|
}
|
|
54
56
|
if (bucket.ram_quota_mb == 0) {
|
|
55
|
-
|
|
56
|
-
"&ramQuotaMB={}", 100)); // If not explicitly set, set to prior default value of 100
|
|
57
|
+
values["ramQuotaMB"] = "100"; // If not explicitly set, set to prior default value of 100
|
|
57
58
|
} else {
|
|
58
|
-
|
|
59
|
+
values["ramQuotaMB"] = std::to_string(bucket.ram_quota_mb);
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
if (bucket.bucket_type != couchbase::core::management::cluster::bucket_type::memcached &&
|
|
62
63
|
bucket.num_replicas.has_value()) {
|
|
63
|
-
|
|
64
|
+
values["replicaNumber"] = std::to_string(bucket.num_replicas.value());
|
|
64
65
|
}
|
|
65
66
|
if (bucket.max_expiry.has_value()) {
|
|
66
|
-
|
|
67
|
+
values["maxTTL"] = std::to_string(bucket.max_expiry.value());
|
|
67
68
|
}
|
|
68
69
|
if (bucket.bucket_type != couchbase::core::management::cluster::bucket_type::ephemeral &&
|
|
69
70
|
bucket.replica_indexes.has_value()) {
|
|
70
|
-
|
|
71
|
-
fmt::format("&replicaIndex={}", bucket.replica_indexes.value() ? "1" : "0"));
|
|
71
|
+
values["replicaIndex"] = bucket.replica_indexes.value() ? "1" : "0";
|
|
72
72
|
}
|
|
73
73
|
if (bucket.history_retention_collection_default.has_value()) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
bucket.history_retention_collection_default.value() ? "true" : "false"));
|
|
74
|
+
values["historyRetentionCollectionDefault"] =
|
|
75
|
+
bucket.history_retention_collection_default.value() ? "true" : "false";
|
|
77
76
|
}
|
|
78
77
|
if (bucket.history_retention_bytes.has_value()) {
|
|
79
|
-
|
|
80
|
-
fmt::format("&historyRetentionBytes={}", bucket.history_retention_bytes.value()));
|
|
78
|
+
values["historyRetentionBytes"] = std::to_string(bucket.history_retention_bytes.value());
|
|
81
79
|
}
|
|
82
80
|
if (bucket.history_retention_duration.has_value()) {
|
|
83
|
-
|
|
84
|
-
fmt::format("&historyRetentionSeconds={}", bucket.history_retention_duration.value()));
|
|
81
|
+
values["historyRetentionSeconds"] = std::to_string(bucket.history_retention_duration.value());
|
|
85
82
|
}
|
|
86
83
|
if (bucket.flush_enabled.has_value()) {
|
|
87
|
-
|
|
84
|
+
values["flushEnabled"] = bucket.flush_enabled.value() ? "1" : "0";
|
|
88
85
|
}
|
|
89
86
|
if (bucket.num_vbuckets.has_value()) {
|
|
90
|
-
|
|
87
|
+
values["numVBuckets"] = std::to_string(bucket.num_vbuckets.value());
|
|
91
88
|
}
|
|
92
89
|
|
|
93
90
|
switch (bucket.eviction_policy) {
|
|
94
91
|
case couchbase::core::management::cluster::bucket_eviction_policy::full:
|
|
95
|
-
|
|
92
|
+
values["evictionPolicy"] = "fullEviction";
|
|
96
93
|
break;
|
|
97
94
|
case couchbase::core::management::cluster::bucket_eviction_policy::value_only:
|
|
98
|
-
|
|
95
|
+
values["evictionPolicy"] = "valueOnly";
|
|
99
96
|
break;
|
|
100
97
|
case couchbase::core::management::cluster::bucket_eviction_policy::no_eviction:
|
|
101
|
-
|
|
98
|
+
values["evictionPolicy"] = "noEviction";
|
|
102
99
|
break;
|
|
103
100
|
case couchbase::core::management::cluster::bucket_eviction_policy::not_recently_used:
|
|
104
|
-
|
|
101
|
+
values["evictionPolicy"] = "nruEviction";
|
|
105
102
|
break;
|
|
106
103
|
case couchbase::core::management::cluster::bucket_eviction_policy::unknown:
|
|
107
104
|
break;
|
|
108
105
|
}
|
|
109
106
|
switch (bucket.compression_mode) {
|
|
110
107
|
case couchbase::core::management::cluster::bucket_compression::off:
|
|
111
|
-
|
|
108
|
+
values["compressionMode"] = "off";
|
|
112
109
|
break;
|
|
113
110
|
case couchbase::core::management::cluster::bucket_compression::active:
|
|
114
|
-
|
|
111
|
+
values["compressionMode"] = "active";
|
|
115
112
|
break;
|
|
116
113
|
case couchbase::core::management::cluster::bucket_compression::passive:
|
|
117
|
-
|
|
114
|
+
values["compressionMode"] = "passive";
|
|
118
115
|
break;
|
|
119
116
|
case couchbase::core::management::cluster::bucket_compression::unknown:
|
|
120
117
|
break;
|
|
121
118
|
}
|
|
122
119
|
switch (bucket.conflict_resolution_type) {
|
|
123
120
|
case couchbase::core::management::cluster::bucket_conflict_resolution::timestamp:
|
|
124
|
-
|
|
121
|
+
values["conflictResolutionType"] = "lww";
|
|
125
122
|
break;
|
|
126
123
|
case couchbase::core::management::cluster::bucket_conflict_resolution::sequence_number:
|
|
127
|
-
|
|
124
|
+
values["conflictResolutionType"] = "seqno";
|
|
128
125
|
break;
|
|
129
126
|
case couchbase::core::management::cluster::bucket_conflict_resolution::custom:
|
|
130
|
-
|
|
127
|
+
values["conflictResolutionType"] = "custom";
|
|
131
128
|
break;
|
|
132
129
|
case couchbase::core::management::cluster::bucket_conflict_resolution::unknown:
|
|
133
130
|
break;
|
|
@@ -135,16 +132,16 @@ bucket_create_request::encode_to(encoded_request_type& encoded,
|
|
|
135
132
|
if (bucket.minimum_durability_level.has_value()) {
|
|
136
133
|
switch (bucket.minimum_durability_level.value()) {
|
|
137
134
|
case durability_level::none:
|
|
138
|
-
|
|
135
|
+
values["durabilityMinLevel"] = "none";
|
|
139
136
|
break;
|
|
140
137
|
case durability_level::majority:
|
|
141
|
-
|
|
138
|
+
values["durabilityMinLevel"] = "majority";
|
|
142
139
|
break;
|
|
143
140
|
case durability_level::majority_and_persist_to_active:
|
|
144
|
-
|
|
141
|
+
values["durabilityMinLevel"] = "majorityAndPersistActive";
|
|
145
142
|
break;
|
|
146
143
|
case durability_level::persist_to_majority:
|
|
147
|
-
|
|
144
|
+
values["durabilityMinLevel"] = "persistToMajority";
|
|
148
145
|
break;
|
|
149
146
|
}
|
|
150
147
|
}
|
|
@@ -152,12 +149,14 @@ bucket_create_request::encode_to(encoded_request_type& encoded,
|
|
|
152
149
|
case couchbase::core::management::cluster::bucket_storage_backend::unknown:
|
|
153
150
|
break;
|
|
154
151
|
case couchbase::core::management::cluster::bucket_storage_backend::couchstore:
|
|
155
|
-
|
|
152
|
+
values["storageBackend"] = "couchstore";
|
|
156
153
|
break;
|
|
157
154
|
case couchbase::core::management::cluster::bucket_storage_backend::magma:
|
|
158
|
-
|
|
155
|
+
values["storageBackend"] = "magma";
|
|
159
156
|
break;
|
|
160
157
|
}
|
|
158
|
+
|
|
159
|
+
encoded.body = utils::string_codec::v2::form_encode(values);
|
|
161
160
|
return {};
|
|
162
161
|
}
|
|
163
162
|
auto
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
namespace couchbase::core::operations::management
|
|
31
31
|
{
|
|
32
32
|
auto
|
|
33
|
-
bucket_update_request::encode_to(encoded_request_type& encoded,
|
|
34
|
-
|
|
33
|
+
bucket_update_request::encode_to(encoded_request_type& encoded, http_context& /* context */) const
|
|
34
|
+
-> std::error_code
|
|
35
35
|
{
|
|
36
36
|
encoded.method = "POST";
|
|
37
37
|
encoded.path =
|
|
@@ -39,65 +39,61 @@ bucket_update_request::encode_to(encoded_request_type& encoded,
|
|
|
39
39
|
|
|
40
40
|
encoded.headers["content-type"] = "application/x-www-form-urlencoded";
|
|
41
41
|
|
|
42
|
+
std::map<std::string, std::string> values{};
|
|
42
43
|
if (bucket.ram_quota_mb > 0) {
|
|
43
|
-
|
|
44
|
+
values["ramQuotaMB"] = std::to_string(bucket.ram_quota_mb);
|
|
44
45
|
}
|
|
45
46
|
if (bucket.num_replicas.has_value()) {
|
|
46
|
-
|
|
47
|
+
values["replicaNumber"] = std::to_string(bucket.num_replicas.value());
|
|
47
48
|
}
|
|
48
|
-
|
|
49
49
|
if (bucket.max_expiry.has_value()) {
|
|
50
|
-
|
|
50
|
+
values["maxTTL"] = std::to_string(bucket.max_expiry.value());
|
|
51
51
|
}
|
|
52
52
|
if (bucket.history_retention_collection_default.has_value()) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
bucket.history_retention_collection_default.value() ? "true" : "false"));
|
|
53
|
+
values["historyRetentionCollectionDefault"] =
|
|
54
|
+
bucket.history_retention_collection_default.value() ? "true" : "false";
|
|
56
55
|
}
|
|
57
56
|
if (bucket.history_retention_bytes.has_value()) {
|
|
58
|
-
|
|
59
|
-
fmt::format("&historyRetentionBytes={}", bucket.history_retention_bytes.value()));
|
|
57
|
+
values["historyRetentionBytes"] = std::to_string(bucket.history_retention_bytes.value());
|
|
60
58
|
}
|
|
61
59
|
if (bucket.history_retention_duration.has_value()) {
|
|
62
|
-
|
|
63
|
-
fmt::format("&historyRetentionSeconds={}", bucket.history_retention_duration.value()));
|
|
60
|
+
values["historyRetentionSeconds"] = std::to_string(bucket.history_retention_duration.value());
|
|
64
61
|
}
|
|
65
62
|
if (bucket.replica_indexes.has_value()) {
|
|
66
|
-
|
|
67
|
-
fmt::format("&replicaIndex={}", bucket.replica_indexes.value() ? "1" : "0"));
|
|
63
|
+
values["replicaIndex"] = bucket.replica_indexes.value() ? "1" : "0";
|
|
68
64
|
}
|
|
69
65
|
if (bucket.flush_enabled.has_value()) {
|
|
70
|
-
|
|
66
|
+
values["flushEnabled"] = bucket.flush_enabled.value() ? "1" : "0";
|
|
71
67
|
}
|
|
72
68
|
if (bucket.num_vbuckets.has_value()) {
|
|
73
|
-
|
|
69
|
+
values["numVBuckets"] = std::to_string(bucket.num_vbuckets.value());
|
|
74
70
|
}
|
|
75
71
|
|
|
76
72
|
switch (bucket.eviction_policy) {
|
|
77
73
|
case couchbase::core::management::cluster::bucket_eviction_policy::full:
|
|
78
|
-
|
|
74
|
+
values["evictionPolicy"] = "fullEviction";
|
|
79
75
|
break;
|
|
80
76
|
case couchbase::core::management::cluster::bucket_eviction_policy::value_only:
|
|
81
|
-
|
|
77
|
+
values["evictionPolicy"] = "valueOnly";
|
|
82
78
|
break;
|
|
83
79
|
case couchbase::core::management::cluster::bucket_eviction_policy::no_eviction:
|
|
84
|
-
|
|
80
|
+
values["evictionPolicy"] = "noEviction";
|
|
85
81
|
break;
|
|
86
82
|
case couchbase::core::management::cluster::bucket_eviction_policy::not_recently_used:
|
|
87
|
-
|
|
83
|
+
values["evictionPolicy"] = "nruEviction";
|
|
88
84
|
break;
|
|
89
85
|
case couchbase::core::management::cluster::bucket_eviction_policy::unknown:
|
|
90
86
|
break;
|
|
91
87
|
}
|
|
92
88
|
switch (bucket.compression_mode) {
|
|
93
89
|
case couchbase::core::management::cluster::bucket_compression::off:
|
|
94
|
-
|
|
90
|
+
values["compressionMode"] = "off";
|
|
95
91
|
break;
|
|
96
92
|
case couchbase::core::management::cluster::bucket_compression::active:
|
|
97
|
-
|
|
93
|
+
values["compressionMode"] = "active";
|
|
98
94
|
break;
|
|
99
95
|
case couchbase::core::management::cluster::bucket_compression::passive:
|
|
100
|
-
|
|
96
|
+
values["compressionMode"] = "passive";
|
|
101
97
|
break;
|
|
102
98
|
case couchbase::core::management::cluster::bucket_compression::unknown:
|
|
103
99
|
break;
|
|
@@ -105,19 +101,21 @@ bucket_update_request::encode_to(encoded_request_type& encoded,
|
|
|
105
101
|
if (bucket.minimum_durability_level) {
|
|
106
102
|
switch (bucket.minimum_durability_level.value()) {
|
|
107
103
|
case durability_level::none:
|
|
108
|
-
|
|
104
|
+
values["durabilityMinLevel"] = "none";
|
|
109
105
|
break;
|
|
110
106
|
case durability_level::majority:
|
|
111
|
-
|
|
107
|
+
values["durabilityMinLevel"] = "majority";
|
|
112
108
|
break;
|
|
113
109
|
case durability_level::majority_and_persist_to_active:
|
|
114
|
-
|
|
110
|
+
values["durabilityMinLevel"] = "majorityAndPersistActive";
|
|
115
111
|
break;
|
|
116
112
|
case durability_level::persist_to_majority:
|
|
117
|
-
|
|
113
|
+
values["durabilityMinLevel"] = "persistToMajority";
|
|
118
114
|
break;
|
|
119
115
|
}
|
|
120
116
|
}
|
|
117
|
+
|
|
118
|
+
encoded.body = utils::string_codec::v2::form_encode(values);
|
|
121
119
|
return {};
|
|
122
120
|
}
|
|
123
121
|
|