couchbase 3.4.0 → 3.4.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/couchbase/CMakeLists.txt +10 -3
- data/ext/couchbase/cmake/CompilerWarnings.cmake +12 -4
- data/ext/couchbase/cmake/Documentation.cmake +4 -3
- data/ext/couchbase/cmake/OpenSSL.cmake +52 -7
- data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +4 -0
- data/ext/couchbase/cmake/VersionInfo.cmake +39 -3
- data/ext/couchbase/cmake/test_openssl.cxx +7 -0
- data/ext/couchbase/core/cluster_options.hxx +0 -1
- data/ext/couchbase/core/config_profile.cxx +23 -1
- data/ext/couchbase/core/config_profile.hxx +2 -12
- data/ext/couchbase/core/crypto/CMakeLists.txt +5 -1
- data/ext/couchbase/core/impl/analytics.cxx +236 -0
- data/ext/couchbase/core/impl/cluster.cxx +0 -1
- data/ext/couchbase/core/impl/collection_query_index_manager.cxx +3 -3
- data/ext/couchbase/core/impl/dns_srv_tracker.cxx +5 -3
- data/ext/couchbase/core/impl/get_all_query_indexes.cxx +3 -3
- data/ext/couchbase/core/impl/query.cxx +5 -5
- data/ext/couchbase/core/impl/transaction_get_result.cxx +54 -0
- data/ext/couchbase/core/io/dns_client.cxx +225 -0
- data/ext/couchbase/core/io/dns_client.hxx +19 -188
- data/ext/couchbase/core/meta/CMakeLists.txt +7 -5
- data/ext/couchbase/core/meta/version.cxx +19 -0
- data/ext/couchbase/core/operations/document_search.cxx +5 -2
- data/ext/couchbase/core/operations/document_search.hxx +0 -1
- data/ext/couchbase/core/transactions/active_transaction_record.hxx +2 -2
- data/ext/couchbase/core/transactions/atr_cleanup_entry.cxx +1 -0
- data/ext/couchbase/core/transactions/attempt_context_impl.cxx +65 -31
- data/ext/couchbase/core/transactions/attempt_context_impl.hxx +44 -23
- data/ext/couchbase/core/transactions/forward_compat.hxx +2 -2
- data/ext/couchbase/core/transactions/internal/transaction_context.hxx +13 -13
- data/ext/couchbase/core/transactions/internal/transaction_fields.hxx +1 -0
- data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +7 -1
- data/ext/couchbase/core/transactions/staged_mutation.cxx +1 -1
- data/ext/couchbase/core/transactions/staged_mutation.hxx +12 -2
- data/ext/couchbase/core/transactions/transaction_context.cxx +9 -11
- data/ext/couchbase/core/transactions/transaction_get_result.cxx +41 -31
- data/ext/couchbase/core/transactions/transaction_get_result.hxx +7 -3
- data/ext/couchbase/core/transactions/transaction_links.hxx +13 -1
- data/ext/couchbase/core/transactions/transactions_cleanup.cxx +144 -155
- data/ext/couchbase/core/transactions/waitable_op_list.hxx +1 -0
- data/ext/couchbase/core/utils/connection_string.cxx +10 -3
- data/ext/couchbase/core/utils/connection_string.hxx +3 -3
- data/ext/couchbase/couchbase/analytics_error_context.hxx +143 -0
- data/ext/couchbase/couchbase/analytics_meta_data.hxx +155 -0
- data/ext/couchbase/couchbase/analytics_metrics.hxx +163 -0
- data/ext/couchbase/couchbase/analytics_options.hxx +359 -0
- data/ext/couchbase/couchbase/analytics_result.hxx +102 -0
- data/ext/couchbase/couchbase/analytics_scan_consistency.hxx +46 -0
- data/ext/couchbase/couchbase/analytics_status.hxx +41 -0
- data/ext/couchbase/couchbase/analytics_warning.hxx +85 -0
- data/ext/couchbase/couchbase/cluster.hxx +35 -2
- data/ext/couchbase/couchbase/cluster_options.hxx +10 -10
- data/ext/couchbase/couchbase/collection.hxx +22 -17
- data/ext/couchbase/couchbase/collection_query_index_manager.hxx +1 -1
- data/ext/couchbase/couchbase/common_options.hxx +1 -1
- data/ext/couchbase/couchbase/configuration_profile.hxx +1 -1
- data/ext/couchbase/couchbase/configuration_profiles_registry.hxx +0 -1
- data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +1 -1
- data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +1 -1
- data/ext/couchbase/couchbase/drop_query_index_options.hxx +1 -1
- data/ext/couchbase/couchbase/fmt/analytics_status.hxx +76 -0
- data/ext/couchbase/couchbase/fmt/cas.hxx +12 -0
- data/ext/couchbase/couchbase/fmt/durability_level.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/key_value_extended_error_info.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/key_value_status_code.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/mutation_token.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/query_scan_consistency.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/query_status.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/retry_reason.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/tls_verify_mode.hxx +6 -0
- data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +5 -4
- data/ext/couchbase/couchbase/query_index_manager.hxx +4 -2
- data/ext/couchbase/couchbase/query_options.hxx +0 -1
- data/ext/couchbase/couchbase/scope.hxx +34 -1
- data/ext/couchbase/couchbase/subdoc/array_add_unique.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/array_append.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/array_insert.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/array_prepend.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/count.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/counter.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/exists.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/get.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/insert.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/remove.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/replace.hxx +3 -1
- data/ext/couchbase/couchbase/subdoc/upsert.hxx +2 -0
- data/ext/couchbase/couchbase/transaction_op_error_context.hxx +4 -4
- data/ext/couchbase/couchbase/transactions/attempt_context.hxx +1 -1
- data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +36 -51
- data/ext/couchbase/couchbase/transactions/transactions_config.hxx +1 -1
- data/ext/couchbase/test/CMakeLists.txt +3 -2
- data/ext/couchbase/test/test_helper.hxx +1 -1
- data/ext/couchbase/test/test_integration_analytics.cxx +289 -13
- data/ext/couchbase/test/test_integration_crud.cxx +8 -1
- data/ext/couchbase/test/test_integration_examples.cxx +182 -0
- data/ext/couchbase/test/test_integration_management.cxx +15 -3
- data/ext/couchbase/test/test_integration_search.cxx +601 -0
- data/ext/couchbase/test/test_transaction_transaction_simple.cxx +73 -0
- data/ext/couchbase/test/test_unit_config_profiles.cxx +12 -12
- data/ext/couchbase/test/test_unit_connection_string.cxx +35 -0
- data/ext/couchbase/test/test_unit_transaction_utils.cxx +76 -19
- data/ext/couchbase/third_party/snappy/CMakeLists.txt +150 -27
- data/ext/couchbase/third_party/snappy/cmake/config.h.in +28 -24
- data/ext/couchbase/third_party/snappy/snappy-internal.h +189 -25
- data/ext/couchbase/third_party/snappy/snappy-sinksource.cc +26 -9
- data/ext/couchbase/third_party/snappy/snappy-sinksource.h +11 -11
- data/ext/couchbase/third_party/snappy/snappy-stubs-internal.cc +1 -1
- data/ext/couchbase/third_party/snappy/snappy-stubs-internal.h +227 -308
- data/ext/couchbase/third_party/snappy/snappy-stubs-public.h.in +0 -11
- data/ext/couchbase/third_party/snappy/snappy.cc +1176 -410
- data/ext/couchbase/third_party/snappy/snappy.h +19 -4
- data/ext/couchbase.cxx +506 -26
- data/ext/extconf.rb +2 -1
- data/ext/revisions.rb +3 -2
- data/lib/couchbase/binary_collection.rb +4 -4
- data/lib/couchbase/cluster.rb +13 -9
- data/lib/couchbase/cluster_registry.rb +7 -2
- data/lib/couchbase/collection.rb +5 -0
- data/lib/couchbase/configuration.rb +3 -4
- data/lib/couchbase/errors.rb +10 -0
- data/lib/couchbase/management/collection_query_index_manager.rb +183 -0
- data/lib/couchbase/management/query_index_manager.rb +35 -3
- data/lib/couchbase/management.rb +1 -0
- data/lib/couchbase/options.rb +87 -5
- data/lib/couchbase/search_options.rb +158 -240
- data/lib/couchbase/version.rb +1 -1
- metadata +21 -6
- data/ext/couchbase/core/CMakeLists.txt +0 -0
|
@@ -25,6 +25,7 @@ transaction_get_result::create_from(const core::operations::lookup_in_response&
|
|
|
25
25
|
std::optional<std::string> atr_id;
|
|
26
26
|
std::optional<std::string> transaction_id;
|
|
27
27
|
std::optional<std::string> attempt_id;
|
|
28
|
+
std::optional<std::string> operation_id;
|
|
28
29
|
std::optional<std::vector<std::byte>> staged_content;
|
|
29
30
|
std::optional<std::string> atr_bucket_name;
|
|
30
31
|
std::optional<std::string> atr_scope_name;
|
|
@@ -56,46 +57,49 @@ transaction_get_result::create_from(const core::operations::lookup_in_response&
|
|
|
56
57
|
attempt_id = codec::tao_json_serializer::deserialize<std::string>(resp.fields[2].value);
|
|
57
58
|
}
|
|
58
59
|
if (resp.fields[3].status == key_value_status_code::success) {
|
|
59
|
-
|
|
60
|
+
operation_id = codec::tao_json_serializer::deserialize<std::string>(resp.fields[3].value);
|
|
60
61
|
}
|
|
61
62
|
if (resp.fields[4].status == key_value_status_code::success) {
|
|
62
|
-
|
|
63
|
+
staged_content = resp.fields[4].value;
|
|
63
64
|
}
|
|
64
65
|
if (resp.fields[5].status == key_value_status_code::success) {
|
|
65
|
-
|
|
66
|
+
atr_bucket_name = codec::tao_json_serializer::deserialize<std::string>(resp.fields[5].value);
|
|
66
67
|
}
|
|
67
68
|
if (resp.fields[6].status == key_value_status_code::success) {
|
|
68
|
-
|
|
69
|
+
atr_scope_name = codec::tao_json_serializer::deserialize<std::string>(resp.fields[6].value);
|
|
69
70
|
}
|
|
70
|
-
|
|
71
71
|
if (resp.fields[7].status == key_value_status_code::success) {
|
|
72
|
-
|
|
72
|
+
atr_collection_name = codec::tao_json_serializer::deserialize<std::string>(resp.fields[7].value);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (resp.fields[8].status == key_value_status_code::success) {
|
|
76
|
+
auto restore = core::utils::json::parse_binary(resp.fields[8].value);
|
|
73
77
|
cas_pre_txn = restore["CAS"].as<std::string>();
|
|
74
78
|
// only present in 6.5+
|
|
75
79
|
revid_pre_txn = restore["revid"].as<std::string>();
|
|
76
80
|
exptime_pre_txn = restore["exptime"].as<std::uint32_t>();
|
|
77
81
|
}
|
|
78
|
-
if (resp.fields[8].status == key_value_status_code::success) {
|
|
79
|
-
op = codec::tao_json_serializer::deserialize<std::string>(resp.fields[8].value);
|
|
80
|
-
}
|
|
81
82
|
if (resp.fields[9].status == key_value_status_code::success) {
|
|
82
|
-
|
|
83
|
+
op = codec::tao_json_serializer::deserialize<std::string>(resp.fields[9].value);
|
|
84
|
+
}
|
|
85
|
+
if (resp.fields[10].status == key_value_status_code::success) {
|
|
86
|
+
auto doc = core::utils::json::parse_binary(resp.fields[10].value);
|
|
83
87
|
cas_from_doc = doc["CAS"].as<std::string>();
|
|
84
88
|
// only present in 6.5+
|
|
85
89
|
revid_from_doc = doc["revid"].as<std::string>();
|
|
86
90
|
exptime_from_doc = doc["exptime"].as<std::uint32_t>();
|
|
87
91
|
crc32_from_doc = doc["value_crc32c"].as<std::string>();
|
|
88
92
|
}
|
|
89
|
-
if (resp.fields[10].status == key_value_status_code::success) {
|
|
90
|
-
crc32_of_staging = codec::tao_json_serializer::deserialize<std::string>(resp.fields[10].value);
|
|
91
|
-
}
|
|
92
93
|
if (resp.fields[11].status == key_value_status_code::success) {
|
|
93
|
-
|
|
94
|
+
crc32_of_staging = codec::tao_json_serializer::deserialize<std::string>(resp.fields[11].value);
|
|
95
|
+
}
|
|
96
|
+
if (resp.fields[12].status == key_value_status_code::success) {
|
|
97
|
+
forward_compat = core::utils::json::parse_binary(resp.fields[12].value);
|
|
94
98
|
} else {
|
|
95
99
|
forward_compat = tao::json::empty_object;
|
|
96
100
|
}
|
|
97
|
-
if (resp.fields[
|
|
98
|
-
content = resp.fields[
|
|
101
|
+
if (resp.fields[13].status == key_value_status_code::success) {
|
|
102
|
+
content = resp.fields[13].value;
|
|
99
103
|
}
|
|
100
104
|
|
|
101
105
|
transaction_links links(atr_id,
|
|
@@ -104,6 +108,7 @@ transaction_get_result::create_from(const core::operations::lookup_in_response&
|
|
|
104
108
|
atr_collection_name,
|
|
105
109
|
transaction_id,
|
|
106
110
|
attempt_id,
|
|
111
|
+
operation_id,
|
|
107
112
|
staged_content,
|
|
108
113
|
cas_pre_txn,
|
|
109
114
|
revid_pre_txn,
|
|
@@ -126,6 +131,7 @@ transaction_get_result::create_from(const core::document_id& id, const result& r
|
|
|
126
131
|
std::optional<std::string> atr_id;
|
|
127
132
|
std::optional<std::string> transaction_id;
|
|
128
133
|
std::optional<std::string> attempt_id;
|
|
134
|
+
std::optional<std::string> operation_id;
|
|
129
135
|
std::optional<std::vector<std::byte>> staged_content;
|
|
130
136
|
std::optional<std::string> atr_bucket_name;
|
|
131
137
|
std::optional<std::string> atr_scope_name;
|
|
@@ -157,45 +163,48 @@ transaction_get_result::create_from(const core::document_id& id, const result& r
|
|
|
157
163
|
attempt_id = res.values[2].content_as<std::string>();
|
|
158
164
|
}
|
|
159
165
|
if (res.values[3].has_value()) {
|
|
160
|
-
|
|
166
|
+
operation_id = res.values[3].content_as<std::string>();
|
|
161
167
|
}
|
|
162
168
|
if (res.values[4].has_value()) {
|
|
163
|
-
|
|
169
|
+
staged_content = res.values[4].raw_value;
|
|
164
170
|
}
|
|
165
171
|
if (res.values[5].has_value()) {
|
|
166
|
-
|
|
172
|
+
atr_bucket_name = res.values[5].content_as<std::string>();
|
|
167
173
|
}
|
|
168
174
|
if (res.values[6].has_value()) {
|
|
169
|
-
|
|
175
|
+
atr_scope_name = res.values[6].content_as<std::string>();
|
|
170
176
|
}
|
|
171
177
|
if (res.values[7].has_value()) {
|
|
172
|
-
|
|
178
|
+
atr_collection_name = res.values[7].content_as<std::string>();
|
|
179
|
+
}
|
|
180
|
+
if (res.values[8].has_value()) {
|
|
181
|
+
auto restore = res.values[8].content_as();
|
|
173
182
|
cas_pre_txn = restore["CAS"].as<std::string>();
|
|
174
183
|
// only present in 6.5+
|
|
175
184
|
revid_pre_txn = restore["revid"].as<std::string>();
|
|
176
185
|
exptime_pre_txn = restore["exptime"].as<std::uint32_t>();
|
|
177
186
|
}
|
|
178
|
-
if (res.values[8].has_value()) {
|
|
179
|
-
op = res.values[8].content_as<std::string>();
|
|
180
|
-
}
|
|
181
187
|
if (res.values[9].has_value()) {
|
|
182
|
-
|
|
188
|
+
op = res.values[9].content_as<std::string>();
|
|
189
|
+
}
|
|
190
|
+
if (res.values[10].has_value()) {
|
|
191
|
+
auto doc = res.values[10].content_as();
|
|
183
192
|
cas_from_doc = doc["CAS"].as<std::string>();
|
|
184
193
|
// only present in 6.5+
|
|
185
194
|
revid_from_doc = doc["revid"].as<std::string>();
|
|
186
195
|
exptime_from_doc = doc["exptime"].as<std::uint32_t>();
|
|
187
196
|
crc32_from_doc = doc["value_crc32c"].as<std::string>();
|
|
188
197
|
}
|
|
189
|
-
if (res.values[10].has_value()) {
|
|
190
|
-
crc32_of_staging = res.values[10].content_as<std::string>();
|
|
191
|
-
}
|
|
192
198
|
if (res.values[11].has_value()) {
|
|
193
|
-
|
|
199
|
+
crc32_of_staging = res.values[11].content_as<std::string>();
|
|
200
|
+
}
|
|
201
|
+
if (res.values[12].has_value()) {
|
|
202
|
+
forward_compat = res.values[12].content_as();
|
|
194
203
|
} else {
|
|
195
204
|
forward_compat = tao::json::empty_object;
|
|
196
205
|
}
|
|
197
|
-
if (res.values[
|
|
198
|
-
content = res.values[
|
|
206
|
+
if (res.values[13].has_value()) {
|
|
207
|
+
content = res.values[13].raw_value;
|
|
199
208
|
}
|
|
200
209
|
|
|
201
210
|
transaction_links links(atr_id,
|
|
@@ -204,6 +213,7 @@ transaction_get_result::create_from(const core::document_id& id, const result& r
|
|
|
204
213
|
atr_collection_name,
|
|
205
214
|
transaction_id,
|
|
206
215
|
attempt_id,
|
|
216
|
+
operation_id,
|
|
207
217
|
staged_content,
|
|
208
218
|
cas_pre_txn,
|
|
209
219
|
revid_pre_txn,
|
|
@@ -77,16 +77,19 @@ class transaction_get_result
|
|
|
77
77
|
{
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
transaction_get_result(const couchbase::transactions::transaction_get_result& res)
|
|
80
|
+
explicit transaction_get_result(const couchbase::transactions::transaction_get_result& res)
|
|
81
81
|
: cas_(res.cas())
|
|
82
82
|
, document_id_(res.bucket(), res.scope(), res.collection(), res.key())
|
|
83
|
-
,
|
|
83
|
+
, links_(res.base_->links())
|
|
84
|
+
, content_(std::move(res.content()))
|
|
85
|
+
, metadata_(res.base_->metadata_)
|
|
84
86
|
{
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
couchbase::transactions::transaction_get_result to_public_result()
|
|
88
90
|
{
|
|
89
|
-
return
|
|
91
|
+
return couchbase::transactions::transaction_get_result(
|
|
92
|
+
std::make_shared<transaction_get_result>(document_id_, std::move(content_), cas_.value(), links_, metadata_));
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
transaction_get_result(core::document_id id, const tao::json::value& json)
|
|
@@ -126,6 +129,7 @@ class transaction_get_result
|
|
|
126
129
|
document.links().atr_collection_name(),
|
|
127
130
|
document.links().staged_transaction_id(),
|
|
128
131
|
document.links().staged_attempt_id(),
|
|
132
|
+
document.links().staged_operation_id(),
|
|
129
133
|
document.links().staged_content(),
|
|
130
134
|
document.links().cas_pre_txn(),
|
|
131
135
|
document.links().revid_pre_txn(),
|
|
@@ -35,6 +35,7 @@ class transaction_links
|
|
|
35
35
|
// id of the transaction that has staged content
|
|
36
36
|
std::optional<std::string> staged_transaction_id_;
|
|
37
37
|
std::optional<std::string> staged_attempt_id_;
|
|
38
|
+
std::optional<std::string> staged_operation_id_;
|
|
38
39
|
std::optional<std::vector<std::byte>> staged_content_;
|
|
39
40
|
|
|
40
41
|
// for {BACKUP_FIELDS}
|
|
@@ -54,6 +55,7 @@ class transaction_links
|
|
|
54
55
|
std::optional<std::string> atr_collection_name,
|
|
55
56
|
std::optional<std::string> staged_transaction_id,
|
|
56
57
|
std::optional<std::string> staged_attempt_id,
|
|
58
|
+
std::optional<std::string> staged_operation_id,
|
|
57
59
|
std::optional<std::vector<std::byte>> staged_content,
|
|
58
60
|
std::optional<std::string> cas_pre_txn,
|
|
59
61
|
std::optional<std::string> revid_pre_txn,
|
|
@@ -68,6 +70,7 @@ class transaction_links
|
|
|
68
70
|
, atr_collection_name_(std::move(atr_collection_name))
|
|
69
71
|
, staged_transaction_id_(std::move(staged_transaction_id))
|
|
70
72
|
, staged_attempt_id_(std::move(staged_attempt_id))
|
|
73
|
+
, staged_operation_id_(std::move(staged_operation_id))
|
|
71
74
|
, staged_content_(std::move(staged_content))
|
|
72
75
|
, cas_pre_txn_(std::move(cas_pre_txn))
|
|
73
76
|
, revid_pre_txn_(std::move(revid_pre_txn))
|
|
@@ -111,6 +114,9 @@ class transaction_links
|
|
|
111
114
|
if (staged_transaction_id_) {
|
|
112
115
|
obj["txnMeta"]["txn"] = staged_transaction_id_.value();
|
|
113
116
|
}
|
|
117
|
+
if (staged_operation_id_) {
|
|
118
|
+
obj["txnMeta"]["txn"] = staged_operation_id_.value();
|
|
119
|
+
}
|
|
114
120
|
if (atr_id_) {
|
|
115
121
|
obj["txnMeta"]["atr"]["key"] = atr_id_.value();
|
|
116
122
|
}
|
|
@@ -181,6 +187,11 @@ class transaction_links
|
|
|
181
187
|
return staged_attempt_id_;
|
|
182
188
|
}
|
|
183
189
|
|
|
190
|
+
[[nodiscard]] std::optional<std::string> staged_operation_id() const
|
|
191
|
+
{
|
|
192
|
+
return staged_operation_id_;
|
|
193
|
+
}
|
|
194
|
+
|
|
184
195
|
[[nodiscard]] std::optional<std::string> cas_pre_txn() const
|
|
185
196
|
{
|
|
186
197
|
return cas_pre_txn_;
|
|
@@ -241,12 +252,13 @@ struct fmt::formatter<couchbase::core::transactions::transaction_links> {
|
|
|
241
252
|
constexpr auto format(const couchbase::core::transactions::transaction_links& r, FormatContext& ctx) const
|
|
242
253
|
{
|
|
243
254
|
return format_to(ctx.out(),
|
|
244
|
-
"transaction_links:{{ atr: {}.{}.{}.{}, txn_id: {}, attempt_id: {}, crc32_of_staging: {} }}",
|
|
255
|
+
"transaction_links:{{ atr: {}.{}.{}.{}, txn_id: {}, attempt_id: {}, operation_id: {}, crc32_of_staging: {} }}",
|
|
245
256
|
r.atr_bucket_name().value_or("none"),
|
|
246
257
|
r.atr_scope_name().value_or("none"),
|
|
247
258
|
r.atr_collection_name().value_or("none"),
|
|
248
259
|
r.atr_id().value_or("none"),
|
|
249
260
|
r.staged_attempt_id().value_or("none"),
|
|
261
|
+
r.staged_operation_id().value_or("none"),
|
|
250
262
|
r.crc32_of_staging().value_or("none"));
|
|
251
263
|
}
|
|
252
264
|
};
|
|
@@ -46,9 +46,8 @@ transactions_cleanup::transactions_cleanup(std::shared_ptr<core::cluster> cluste
|
|
|
46
46
|
: cluster_(cluster)
|
|
47
47
|
, config_(config)
|
|
48
48
|
, client_uuid_(uid_generator::next())
|
|
49
|
-
, running_(
|
|
49
|
+
, running_(config.cleanup_config.cleanup_client_attempts || config.cleanup_config.cleanup_lost_attempts)
|
|
50
50
|
{
|
|
51
|
-
running_ = config.cleanup_config.cleanup_client_attempts || config.cleanup_config.cleanup_lost_attempts;
|
|
52
51
|
if (config.cleanup_config.cleanup_client_attempts) {
|
|
53
52
|
cleanup_thr_ = std::thread(std::bind(&transactions_cleanup::attempts_loop, this));
|
|
54
53
|
}
|
|
@@ -61,14 +60,14 @@ transactions_cleanup::transactions_cleanup(std::shared_ptr<core::cluster> cluste
|
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
static uint64_t
|
|
65
|
-
byteswap64(uint64_t val)
|
|
63
|
+
static std::uint64_t
|
|
64
|
+
byteswap64(std::uint64_t val)
|
|
66
65
|
{
|
|
67
|
-
uint64_t ret = 0;
|
|
68
|
-
for (std::size_t ii = 0; ii < sizeof(uint64_t); ii++) {
|
|
69
|
-
ret <<=
|
|
70
|
-
ret |= val &
|
|
71
|
-
val >>=
|
|
66
|
+
std::uint64_t ret = 0;
|
|
67
|
+
for (std::size_t ii = 0; ii < sizeof(std::uint64_t); ii++) {
|
|
68
|
+
ret <<= 8ULL;
|
|
69
|
+
ret |= val & 0xffULL;
|
|
70
|
+
val >>= 8ULL;
|
|
72
71
|
}
|
|
73
72
|
return ret;
|
|
74
73
|
}
|
|
@@ -86,7 +85,7 @@ byteswap64(uint64_t val)
|
|
|
86
85
|
* Want: 0x155CD21DA7580000 (1539336197457313792 in base10, an epoch
|
|
87
86
|
* time in millionths of a second)
|
|
88
87
|
*/
|
|
89
|
-
static uint64_t
|
|
88
|
+
static std::uint64_t
|
|
90
89
|
parse_mutation_cas(const std::string& cas)
|
|
91
90
|
{
|
|
92
91
|
if (cas.empty()) {
|
|
@@ -114,18 +113,18 @@ transactions_cleanup::interruptable_wait(std::chrono::duration<R, P> delay)
|
|
|
114
113
|
{
|
|
115
114
|
// wait for specified time, _or_ until the condition variable changes
|
|
116
115
|
std::unique_lock<std::mutex> lock(mutex_);
|
|
117
|
-
if (!running_
|
|
116
|
+
if (!running_) {
|
|
118
117
|
return false;
|
|
119
118
|
}
|
|
120
|
-
cv_.wait_for(lock, delay, [&]() { return !running_
|
|
121
|
-
return running_
|
|
119
|
+
cv_.wait_for(lock, delay, [&]() { return !running_; });
|
|
120
|
+
return running_;
|
|
122
121
|
}
|
|
123
122
|
|
|
124
123
|
void
|
|
125
124
|
transactions_cleanup::clean_collection(const couchbase::transactions::transaction_keyspace& keyspace)
|
|
126
125
|
{
|
|
127
126
|
// first make sure the collection is in the list
|
|
128
|
-
while (
|
|
127
|
+
while (is_running()) {
|
|
129
128
|
{
|
|
130
129
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
131
130
|
if (collections_.end() == std::find(collections_.begin(), collections_.end(), keyspace)) {
|
|
@@ -158,7 +157,7 @@ transactions_cleanup::clean_collection(const couchbase::transactions::transactio
|
|
|
158
157
|
remaining_in_cleanup_window.count() / std::max<decltype(it)::difference_type>(1, atrs_left_for_this_client));
|
|
159
158
|
// clean the ATR entry
|
|
160
159
|
std::string atr_id = *it;
|
|
161
|
-
if (!
|
|
160
|
+
if (!is_running()) {
|
|
162
161
|
CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("cleanup of {} complete", keyspace);
|
|
163
162
|
return;
|
|
164
163
|
}
|
|
@@ -186,7 +185,9 @@ transactions_cleanup::clean_collection(const couchbase::transactions::transactio
|
|
|
186
185
|
atr_left.count());*/
|
|
187
186
|
|
|
188
187
|
if (atr_left.count() > 0 && atr_left.count() < 1000000000) { // safety check protects against bugs
|
|
189
|
-
|
|
188
|
+
if (!interruptable_wait(atr_left)) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
} catch (const std::exception& ex) {
|
|
@@ -212,16 +213,16 @@ transactions_cleanup::handle_atr_cleanup(const core::document_id& atr_id, std::v
|
|
|
212
213
|
// check_if_expired to false.
|
|
213
214
|
atr_cleanup_entry cleanup_entry(entry, atr_id, *this, results == nullptr);
|
|
214
215
|
try {
|
|
215
|
-
if (results) {
|
|
216
|
+
if (results != nullptr) {
|
|
216
217
|
results->emplace_back(cleanup_entry);
|
|
217
218
|
}
|
|
218
|
-
cleanup_entry.clean(results ? &results->back() : nullptr);
|
|
219
|
-
if (results) {
|
|
219
|
+
cleanup_entry.clean(results != nullptr ? &results->back() : nullptr);
|
|
220
|
+
if (results != nullptr) {
|
|
220
221
|
results->back().success(true);
|
|
221
222
|
}
|
|
222
223
|
} catch (const std::exception& e) {
|
|
223
224
|
CB_LOST_ATTEMPT_CLEANUP_LOG_ERROR("cleanup of {} failed: {}, moving on", cleanup_entry, e.what());
|
|
224
|
-
if (results) {
|
|
225
|
+
if (results != nullptr) {
|
|
225
226
|
results->back().success(false);
|
|
226
227
|
}
|
|
227
228
|
}
|
|
@@ -273,135 +274,127 @@ transactions_cleanup::create_client_record(const couchbase::transactions::transa
|
|
|
273
274
|
const client_record_details
|
|
274
275
|
transactions_cleanup::get_active_clients(const couchbase::transactions::transaction_keyspace& keyspace, const std::string& uuid)
|
|
275
276
|
{
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
auto id = document_id{ keyspace.bucket, keyspace.scope, keyspace.collection, CLIENT_RECORD_DOC_ID };
|
|
286
|
-
core::operations::lookup_in_request req{ id };
|
|
287
|
-
req.specs =
|
|
288
|
-
lookup_in_specs{
|
|
289
|
-
lookup_in_specs::get(FIELD_RECORDS).xattr(),
|
|
290
|
-
lookup_in_specs::get(subdoc::lookup_in_macro::vbucket).xattr(),
|
|
291
|
-
}
|
|
292
|
-
.specs();
|
|
293
|
-
wrap_request(req, config_);
|
|
294
|
-
auto barrier = std::make_shared<std::promise<result>>();
|
|
295
|
-
auto f = barrier->get_future();
|
|
296
|
-
auto ec = config_.cleanup_hooks->client_record_before_get(keyspace.bucket);
|
|
297
|
-
if (ec) {
|
|
298
|
-
throw client_error(*ec, "client_record_before_get hook raised error");
|
|
299
|
-
}
|
|
300
|
-
cluster_->execute(req, [barrier](core::operations::lookup_in_response resp) {
|
|
301
|
-
barrier->set_value(result::create_from_subdoc_response(resp));
|
|
302
|
-
});
|
|
303
|
-
auto res = wrap_operation_future(f);
|
|
304
|
-
std::vector<std::string> active_client_uids;
|
|
305
|
-
auto hlc = res.values[1].content_as();
|
|
306
|
-
auto now_ms = now_ns_from_vbucket(hlc) / 1000000;
|
|
307
|
-
details.override_enabled = false;
|
|
308
|
-
details.override_expires = 0;
|
|
309
|
-
if (res.values[0].status == subdoc_result::status_type::success) {
|
|
310
|
-
auto records = res.values[0].content_as();
|
|
311
|
-
CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("client records: {}", core::utils::json::generate(records));
|
|
312
|
-
for (const auto& [key, value] : records.get_object()) {
|
|
313
|
-
if (key == FIELD_OVERRIDE) {
|
|
314
|
-
for (const auto& [override, param] : value.get_object()) {
|
|
315
|
-
if (override == FIELD_OVERRIDE_ENABLED) {
|
|
316
|
-
details.override_enabled = param.get_boolean();
|
|
317
|
-
} else if (override == FIELD_OVERRIDE_EXPIRES) {
|
|
318
|
-
details.override_expires = param.as<std::uint64_t>();
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
} else if (key == FIELD_CLIENTS_ONLY) {
|
|
322
|
-
for (const auto& [other_client_uuid, cl] : value.get_object()) {
|
|
323
|
-
uint64_t heartbeat_ms = parse_mutation_cas(cl.at(FIELD_HEARTBEAT).get_string());
|
|
324
|
-
auto expires_ms = cl.at(FIELD_EXPIRES).as<std::uint64_t>();
|
|
325
|
-
auto expired_period = static_cast<int64_t>(now_ms) - static_cast<int64_t>(heartbeat_ms);
|
|
326
|
-
bool has_expired = expired_period >= static_cast<int64_t>(expires_ms) && now_ms > heartbeat_ms;
|
|
327
|
-
if (has_expired && other_client_uuid != uuid) {
|
|
328
|
-
details.expired_client_ids.push_back(other_client_uuid);
|
|
329
|
-
} else {
|
|
330
|
-
active_client_uids.push_back(other_client_uuid);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
if (std::find(active_client_uids.begin(), active_client_uids.end(), uuid) == active_client_uids.end()) {
|
|
337
|
-
active_client_uids.push_back(uuid);
|
|
338
|
-
}
|
|
339
|
-
std::sort(active_client_uids.begin(), active_client_uids.end());
|
|
340
|
-
auto this_idx =
|
|
341
|
-
std::distance(active_client_uids.begin(), std::find(active_client_uids.begin(), active_client_uids.end(), uuid));
|
|
342
|
-
details.num_active_clients = static_cast<std::uint32_t>(active_client_uids.size());
|
|
343
|
-
details.index_of_this_client = static_cast<std::uint32_t>(this_idx);
|
|
344
|
-
details.num_active_clients = static_cast<std::uint32_t>(active_client_uids.size());
|
|
345
|
-
details.num_expired_clients = static_cast<std::uint32_t>(details.expired_client_ids.size());
|
|
346
|
-
details.num_existing_clients = details.num_expired_clients + details.num_active_clients;
|
|
347
|
-
details.client_uuid = uuid;
|
|
348
|
-
details.cas_now_nanos = now_ms * 1000000;
|
|
349
|
-
details.override_active = (details.override_enabled && details.override_expires > details.cas_now_nanos);
|
|
350
|
-
CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("client details {}", details);
|
|
351
|
-
if (details.override_active) {
|
|
352
|
-
CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("override enabled, will not update record");
|
|
353
|
-
return details;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// update client record, maybe cleanup some as well...
|
|
357
|
-
core::operations::mutate_in_request mutate_req{ id };
|
|
358
|
-
auto mut_specs = couchbase::mutate_in_specs{
|
|
359
|
-
couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_HEARTBEAT, subdoc::mutate_in_macro::cas)
|
|
360
|
-
.xattr()
|
|
361
|
-
.create_path(),
|
|
362
|
-
couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_EXPIRES,
|
|
363
|
-
config_.cleanup_config.cleanup_window.count() / 2 + SAFETY_MARGIN_EXPIRY_MS)
|
|
364
|
-
.xattr()
|
|
365
|
-
.create_path(),
|
|
366
|
-
couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_NUM_ATRS, atr_ids::all().size())
|
|
367
|
-
.xattr()
|
|
368
|
-
.create_path(),
|
|
369
|
-
};
|
|
370
|
-
for (std::size_t idx = 0; idx < std::min(details.expired_client_ids.size(), static_cast<std::size_t>(12)); idx++) {
|
|
371
|
-
CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("adding {} to list of clients to be removed when updating this client",
|
|
372
|
-
details.expired_client_ids[idx]);
|
|
373
|
-
mut_specs.push_back(couchbase::mutate_in_specs::remove(FIELD_CLIENTS + "." + details.expired_client_ids[idx]).xattr());
|
|
374
|
-
}
|
|
375
|
-
mutate_req.specs = mut_specs.specs();
|
|
376
|
-
ec = config_.cleanup_hooks->client_record_before_update(keyspace.bucket);
|
|
377
|
-
if (ec) {
|
|
378
|
-
throw client_error(*ec, "client_record_before_update hook raised error");
|
|
379
|
-
}
|
|
380
|
-
wrap_durable_request(mutate_req, config_);
|
|
381
|
-
auto mutate_barrier = std::make_shared<std::promise<result>>();
|
|
382
|
-
auto mutate_f = mutate_barrier->get_future();
|
|
383
|
-
CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("updating record");
|
|
384
|
-
cluster_->execute(mutate_req, [mutate_barrier](core::operations::mutate_in_response resp) {
|
|
385
|
-
mutate_barrier->set_value(result::create_from_subdoc_response(resp));
|
|
386
|
-
});
|
|
387
|
-
res = wrap_operation_future(mutate_f);
|
|
388
|
-
|
|
389
|
-
// just update the cas, and return the details
|
|
390
|
-
details.cas_now_nanos = res.cas;
|
|
391
|
-
CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("get_active_clients found {}", details);
|
|
392
|
-
return details;
|
|
393
|
-
} catch (const client_error& e) {
|
|
394
|
-
auto ec = e.ec();
|
|
395
|
-
switch (ec) {
|
|
396
|
-
case FAIL_DOC_NOT_FOUND:
|
|
397
|
-
CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("client record not found, creating new one");
|
|
398
|
-
create_client_record(keyspace);
|
|
399
|
-
throw retry_operation("Client record didn't exist. Creating and retrying");
|
|
400
|
-
default:
|
|
401
|
-
throw;
|
|
402
|
-
}
|
|
277
|
+
client_record_details details;
|
|
278
|
+
// Write our client record, return details.
|
|
279
|
+
try {
|
|
280
|
+
auto id = document_id{ keyspace.bucket, keyspace.scope, keyspace.collection, CLIENT_RECORD_DOC_ID };
|
|
281
|
+
core::operations::lookup_in_request req{ id };
|
|
282
|
+
req.specs =
|
|
283
|
+
lookup_in_specs{
|
|
284
|
+
lookup_in_specs::get(FIELD_RECORDS).xattr(),
|
|
285
|
+
lookup_in_specs::get(subdoc::lookup_in_macro::vbucket).xattr(),
|
|
403
286
|
}
|
|
404
|
-
|
|
287
|
+
.specs();
|
|
288
|
+
wrap_request(req, config_);
|
|
289
|
+
auto barrier = std::make_shared<std::promise<result>>();
|
|
290
|
+
auto f = barrier->get_future();
|
|
291
|
+
auto ec = config_.cleanup_hooks->client_record_before_get(keyspace.bucket);
|
|
292
|
+
if (ec) {
|
|
293
|
+
throw client_error(*ec, "client_record_before_get hook raised error");
|
|
294
|
+
}
|
|
295
|
+
cluster_->execute(
|
|
296
|
+
req, [barrier](core::operations::lookup_in_response resp) { barrier->set_value(result::create_from_subdoc_response(resp)); });
|
|
297
|
+
auto res = wrap_operation_future(f);
|
|
298
|
+
|
|
299
|
+
std::vector<std::string> active_client_uids;
|
|
300
|
+
auto hlc = res.values[1].content_as();
|
|
301
|
+
auto now_ms = now_ns_from_vbucket(hlc) / 1000000;
|
|
302
|
+
details.override_enabled = false;
|
|
303
|
+
details.override_expires = 0;
|
|
304
|
+
if (res.values[0].status == subdoc_result::status_type::success) {
|
|
305
|
+
auto records = res.values[0].content_as();
|
|
306
|
+
CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("client records: {}", core::utils::json::generate(records));
|
|
307
|
+
for (const auto& [key, value] : records.get_object()) {
|
|
308
|
+
if (key == FIELD_OVERRIDE) {
|
|
309
|
+
for (const auto& [over_ride, param] : value.get_object()) {
|
|
310
|
+
if (over_ride == FIELD_OVERRIDE_ENABLED) {
|
|
311
|
+
details.override_enabled = param.get_boolean();
|
|
312
|
+
} else if (over_ride == FIELD_OVERRIDE_EXPIRES) {
|
|
313
|
+
details.override_expires = param.as<std::uint64_t>();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} else if (key == FIELD_CLIENTS_ONLY) {
|
|
317
|
+
for (const auto& [other_client_uuid, cl] : value.get_object()) {
|
|
318
|
+
std::uint64_t heartbeat_ms = parse_mutation_cas(cl.at(FIELD_HEARTBEAT).get_string());
|
|
319
|
+
auto expires_ms = cl.at(FIELD_EXPIRES).as<std::uint64_t>();
|
|
320
|
+
auto expired_period = static_cast<std::int64_t>(now_ms) - static_cast<std::int64_t>(heartbeat_ms);
|
|
321
|
+
bool has_expired = expired_period >= static_cast<std::int64_t>(expires_ms) && now_ms > heartbeat_ms;
|
|
322
|
+
if (has_expired && other_client_uuid != uuid) {
|
|
323
|
+
details.expired_client_ids.push_back(other_client_uuid);
|
|
324
|
+
} else {
|
|
325
|
+
active_client_uids.push_back(other_client_uuid);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (std::find(active_client_uids.begin(), active_client_uids.end(), uuid) == active_client_uids.end()) {
|
|
332
|
+
active_client_uids.push_back(uuid);
|
|
333
|
+
}
|
|
334
|
+
std::sort(active_client_uids.begin(), active_client_uids.end());
|
|
335
|
+
auto this_idx = std::distance(active_client_uids.begin(), std::find(active_client_uids.begin(), active_client_uids.end(), uuid));
|
|
336
|
+
details.num_active_clients = static_cast<std::uint32_t>(active_client_uids.size());
|
|
337
|
+
details.index_of_this_client = static_cast<std::uint32_t>(this_idx);
|
|
338
|
+
details.num_active_clients = static_cast<std::uint32_t>(active_client_uids.size());
|
|
339
|
+
details.num_expired_clients = static_cast<std::uint32_t>(details.expired_client_ids.size());
|
|
340
|
+
details.num_existing_clients = details.num_expired_clients + details.num_active_clients;
|
|
341
|
+
details.client_uuid = uuid;
|
|
342
|
+
details.cas_now_nanos = now_ms * 1000000;
|
|
343
|
+
details.override_active = (details.override_enabled && details.override_expires > details.cas_now_nanos);
|
|
344
|
+
CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("client details {}", details);
|
|
345
|
+
if (details.override_active) {
|
|
346
|
+
CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("override enabled, will not update record");
|
|
347
|
+
return details;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// update client record, maybe cleanup some as well...
|
|
351
|
+
core::operations::mutate_in_request mutate_req{ id };
|
|
352
|
+
auto mut_specs = couchbase::mutate_in_specs{
|
|
353
|
+
couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_HEARTBEAT, subdoc::mutate_in_macro::cas)
|
|
354
|
+
.xattr()
|
|
355
|
+
.create_path(),
|
|
356
|
+
couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_EXPIRES,
|
|
357
|
+
config_.cleanup_config.cleanup_window.count() / 2 + SAFETY_MARGIN_EXPIRY_MS)
|
|
358
|
+
.xattr()
|
|
359
|
+
.create_path(),
|
|
360
|
+
couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_NUM_ATRS, atr_ids::all().size())
|
|
361
|
+
.xattr()
|
|
362
|
+
.create_path(),
|
|
363
|
+
};
|
|
364
|
+
for (std::size_t idx = 0; idx < std::min(details.expired_client_ids.size(), static_cast<std::size_t>(12)); idx++) {
|
|
365
|
+
CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("adding {} to list of clients to be removed when updating this client",
|
|
366
|
+
details.expired_client_ids[idx]);
|
|
367
|
+
mut_specs.push_back(couchbase::mutate_in_specs::remove(FIELD_CLIENTS + "." + details.expired_client_ids[idx]).xattr());
|
|
368
|
+
}
|
|
369
|
+
mutate_req.specs = mut_specs.specs();
|
|
370
|
+
ec = config_.cleanup_hooks->client_record_before_update(keyspace.bucket);
|
|
371
|
+
if (ec) {
|
|
372
|
+
throw client_error(*ec, "client_record_before_update hook raised error");
|
|
373
|
+
}
|
|
374
|
+
wrap_durable_request(mutate_req, config_);
|
|
375
|
+
auto mutate_barrier = std::make_shared<std::promise<result>>();
|
|
376
|
+
auto mutate_f = mutate_barrier->get_future();
|
|
377
|
+
CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("updating record");
|
|
378
|
+
cluster_->execute(mutate_req, [mutate_barrier](core::operations::mutate_in_response resp) {
|
|
379
|
+
mutate_barrier->set_value(result::create_from_subdoc_response(resp));
|
|
380
|
+
});
|
|
381
|
+
res = wrap_operation_future(mutate_f);
|
|
382
|
+
|
|
383
|
+
// just update the cas, and return the details
|
|
384
|
+
details.cas_now_nanos = res.cas;
|
|
385
|
+
CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("get_active_clients found {}", details);
|
|
386
|
+
return details;
|
|
387
|
+
} catch (const client_error& e) {
|
|
388
|
+
auto ec = e.ec();
|
|
389
|
+
switch (ec) {
|
|
390
|
+
case FAIL_DOC_NOT_FOUND:
|
|
391
|
+
CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("client record not found, creating new one");
|
|
392
|
+
create_client_record(keyspace);
|
|
393
|
+
return get_active_clients(keyspace, uuid);
|
|
394
|
+
default:
|
|
395
|
+
throw;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
405
398
|
}
|
|
406
399
|
|
|
407
400
|
void
|
|
@@ -412,9 +405,7 @@ transactions_cleanup::remove_client_record_from_all_buckets(const std::string& u
|
|
|
412
405
|
retry_op_exponential_backoff_timeout<void>(
|
|
413
406
|
std::chrono::milliseconds(10), std::chrono::milliseconds(250), std::chrono::milliseconds(500), [this, keyspace, uuid]() {
|
|
414
407
|
try {
|
|
415
|
-
//
|
|
416
|
-
create_client_record(keyspace);
|
|
417
|
-
// now, proceed to remove the client uuid if it exists
|
|
408
|
+
// proceed to remove the client uuid if it exists
|
|
418
409
|
auto ec = config_.cleanup_hooks->client_record_before_remove_client(keyspace.bucket);
|
|
419
410
|
if (ec) {
|
|
420
411
|
throw client_error(*ec, "client_record_before_remove_client hook raised error");
|
|
@@ -502,7 +493,7 @@ transactions_cleanup::attempts_loop()
|
|
|
502
493
|
CB_ATTEMPT_CLEANUP_LOG_DEBUG("cleanup attempts loop starting...");
|
|
503
494
|
while (interruptable_wait(cleanup_loop_delay_)) {
|
|
504
495
|
while (auto entry = atr_queue_.pop()) {
|
|
505
|
-
if (!
|
|
496
|
+
if (!is_running()) {
|
|
506
497
|
CB_ATTEMPT_CLEANUP_LOG_DEBUG("loop stopping - {} entries on queue", atr_queue_.size());
|
|
507
498
|
return;
|
|
508
499
|
}
|
|
@@ -580,9 +571,7 @@ transactions_cleanup::close()
|
|
|
580
571
|
}
|
|
581
572
|
}
|
|
582
573
|
CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("all lost attempt cleanup threads closed");
|
|
583
|
-
|
|
584
|
-
remove_client_record_from_all_buckets(client_uuid_);
|
|
585
|
-
}
|
|
574
|
+
remove_client_record_from_all_buckets(client_uuid_);
|
|
586
575
|
}
|
|
587
576
|
|
|
588
577
|
transactions_cleanup::~transactions_cleanup()
|
|
@@ -119,6 +119,7 @@ class waitable_op_list
|
|
|
119
119
|
// calling the callback). So wait for that.
|
|
120
120
|
CB_TXN_LOG_TRACE("set_query_mode: mode already query, waiting for node to be set...");
|
|
121
121
|
cv_query_.wait(lock, [this]() { return !mode_.query_node.empty(); });
|
|
122
|
+
cv_in_flight_.wait(lock, [this]() { return 0 == in_flight_; });
|
|
122
123
|
in_flight_++;
|
|
123
124
|
CB_TXN_LOG_TRACE("set_query_mode: node set, continuing...");
|
|
124
125
|
lock.unlock();
|