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
@@ -1,6 +1,20 @@
|
|
1
|
-
|
1
|
+
# Copyright 2020 Couchbase, Inc.
|
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.
|
2
14
|
|
3
|
-
|
15
|
+
require "couchbase"
|
16
|
+
|
17
|
+
include Couchbase # rubocop:disable Style/MixinUsage for brevity
|
4
18
|
|
5
19
|
options = Cluster::ClusterOptions.new
|
6
20
|
options.authenticate("Administrator", "password")
|
@@ -18,27 +32,27 @@ rescue Error::IndexNotFound
|
|
18
32
|
index.source_type = "couchbase"
|
19
33
|
index.source_name = bucket_name
|
20
34
|
index.params = {
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
mapping: {
|
36
|
+
types: {
|
37
|
+
"knob" => {
|
38
|
+
properties: {
|
39
|
+
"name" => {
|
40
|
+
fields: [
|
41
|
+
{
|
42
|
+
name: "name",
|
43
|
+
type: "text",
|
44
|
+
include_in_all: true,
|
45
|
+
include_term_vectors: true,
|
46
|
+
index: true,
|
47
|
+
store: true,
|
48
|
+
docvalues: true,
|
49
|
+
},
|
50
|
+
],
|
51
|
+
},
|
52
|
+
},
|
53
|
+
},
|
54
|
+
},
|
55
|
+
},
|
42
56
|
}
|
43
57
|
|
44
58
|
cluster.search_indexes.upsert_index(index)
|
@@ -48,6 +62,7 @@ rescue Error::IndexNotFound
|
|
48
62
|
sleep(1)
|
49
63
|
num = cluster.search_indexes.get_indexed_documents_count(search_index_name)
|
50
64
|
break if num_indexed == num
|
65
|
+
|
51
66
|
num_indexed = num
|
52
67
|
puts "indexing #{search_index_name.inspect}: #{num_indexed} documents"
|
53
68
|
end
|
@@ -59,9 +74,9 @@ collection = cluster.bucket(bucket_name).default_collection
|
|
59
74
|
# and supply mutation tokens from those operations.
|
60
75
|
random_string = ("a".."z").to_a.sample(10).join
|
61
76
|
res = collection.upsert("user:#{random_string}", {
|
62
|
-
|
63
|
-
|
64
|
-
|
77
|
+
"name" => "Brass Doorknob",
|
78
|
+
"email" => "brass.doorknob@example.com",
|
79
|
+
"data" => random_string,
|
65
80
|
})
|
66
81
|
|
67
82
|
state = MutationState.new(res.mutation_token)
|
@@ -74,10 +89,8 @@ options.consistent_with(state)
|
|
74
89
|
res = cluster.search_query(search_index_name, query, options)
|
75
90
|
|
76
91
|
res.rows.each do |row|
|
77
|
-
if row.id == "user:#{random_string}"
|
78
|
-
|
79
|
-
end
|
80
|
-
if ENV['REMOVE_DOOR_KNOBS']
|
92
|
+
puts "--- Found our newly created document!" if row.id == "user:#{random_string}"
|
93
|
+
if ENV["REMOVE_DOOR_KNOBS"]
|
81
94
|
puts "Removing #{row.id} (requested via env)"
|
82
95
|
collection.remove(row.id)
|
83
96
|
end
|
data/examples/subdocument.rb
CHANGED
@@ -1,5 +1,19 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# Copyright 2020 Couchbase, Inc.
|
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
|
+
require "couchbase"
|
16
|
+
include Couchbase # rubocop:disable Style/MixinUsage for brevity
|
3
17
|
|
4
18
|
options = Cluster::ClusterOptions.new
|
5
19
|
options.authenticate("Administrator", "password")
|
@@ -8,44 +22,42 @@ bucket = cluster.bucket("default")
|
|
8
22
|
collection = bucket.default_collection
|
9
23
|
|
10
24
|
document = {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
}
|
25
|
+
name: "Douglas Reynholm",
|
26
|
+
email: "douglas@reynholmindustries.com",
|
27
|
+
addresses: {
|
28
|
+
billing: {
|
29
|
+
line1: "123 Any Street",
|
30
|
+
line2: "Anytown",
|
31
|
+
country: "United Kingdom",
|
32
|
+
},
|
33
|
+
delivery: {
|
34
|
+
line1: "123 Any Street",
|
35
|
+
line2: "Anytown",
|
36
|
+
country: "United Kingdom",
|
24
37
|
},
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
38
|
+
},
|
39
|
+
purchases: {
|
40
|
+
complete: [339, 976, 442, 666],
|
41
|
+
abandoned: [157, 42, 999],
|
42
|
+
},
|
29
43
|
}
|
30
44
|
collection.upsert("customer123", document)
|
31
45
|
|
32
46
|
res = collection.mutate_in("customer123", [
|
33
|
-
|
34
|
-
])
|
47
|
+
MutateInSpec.upsert("fax", "311-555-0151"),
|
48
|
+
])
|
35
49
|
puts "The document has been modified successfully: cas=#{res.cas}"
|
36
50
|
|
37
51
|
res = collection.mutate_in("customer123", [
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
])
|
52
|
+
MutateInSpec.upsert("_framework.model_type", "Customer").xattr,
|
53
|
+
MutateInSpec.remove("addresses.billing[2]"),
|
54
|
+
MutateInSpec.replace("email", "dougr96@hotmail.com"),
|
55
|
+
])
|
42
56
|
puts "The document has been modified successfully: cas=#{res.cas}"
|
43
57
|
|
44
58
|
res = collection.lookup_in "customer123", [
|
45
|
-
|
46
|
-
|
59
|
+
LookupInSpec.get("addresses.delivery.country"),
|
60
|
+
LookupInSpec.exists("purchases.pending[-1]"),
|
47
61
|
]
|
48
62
|
puts "The customer's delivery country is #{res.content(0)}"
|
49
|
-
if res.exists?(1)
|
50
|
-
puts "The customer has pending purchases"
|
51
|
-
end
|
63
|
+
puts "The customer has pending purchases" if res.exists?(1)
|
data/examples/view.rb
CHANGED
@@ -1,8 +1,20 @@
|
|
1
|
-
#
|
1
|
+
# Copyright 2020 Couchbase, Inc.
|
2
2
|
#
|
3
|
-
|
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
|
+
require "couchbase"
|
4
16
|
|
5
|
-
include Couchbase
|
17
|
+
include Couchbase # rubocop:disable Style/MixinUsage for brevity
|
6
18
|
|
7
19
|
options = Cluster::ClusterOptions.new
|
8
20
|
options.authenticate("Administrator", "password")
|
@@ -26,17 +38,16 @@ options.order = :descending
|
|
26
38
|
res = bucket.view_query("beer", "brewery_beers", options)
|
27
39
|
puts "\nTotal documents in 'beer/brewery_beers' index: #{res.meta_data.total_rows}"
|
28
40
|
puts "Last #{options.limit} documents:"
|
29
|
-
res.rows.
|
41
|
+
res.rows.each do |row|
|
30
42
|
doc = collection.get(row.id)
|
31
43
|
puts "#{row.id} (type: #{doc.content['type']}, key: #{row.key})"
|
32
44
|
end
|
33
45
|
|
34
|
-
|
35
46
|
random_number = rand(0..1_000_000_000)
|
36
47
|
unique_brewery_id = "random_brewery:#{random_number}"
|
37
48
|
collection.upsert("random_brewery:#{random_number}", {
|
38
|
-
|
39
|
-
|
49
|
+
"name" => "Random brewery: #{random_number}",
|
50
|
+
"type" => "brewery",
|
40
51
|
})
|
41
52
|
puts "\nRequest with consistency. Generated brewery name: #{unique_brewery_id}"
|
42
53
|
options = Bucket::ViewOptions.new
|
@@ -44,7 +55,5 @@ options.start_key = ["random_brewery:"]
|
|
44
55
|
options.scan_consistency = :request_plus
|
45
56
|
res = bucket.view_query("beer", "brewery_beers", options)
|
46
57
|
res.rows.each do |row|
|
47
|
-
if row.id == unique_brewery_id
|
48
|
-
puts "Found newly created document: #{collection.get(row.id).content}"
|
49
|
-
end
|
58
|
+
puts "Found newly created document: #{collection.get(row.id).content}" if row.id == unique_brewery_id
|
50
59
|
end
|
data/ext/CMakeLists.txt
CHANGED
@@ -8,6 +8,36 @@ if(CCACHE)
|
|
8
8
|
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
|
9
9
|
endif()
|
10
10
|
|
11
|
+
include(CMakePushCheckState)
|
12
|
+
include(CheckSymbolExists)
|
13
|
+
|
14
|
+
cmake_push_check_state(RESET)
|
15
|
+
find_library(EXECINFO_LIBRARY NAMES execinfo)
|
16
|
+
if(EXECINFO_LIBRARY)
|
17
|
+
set(CMAKE_REQUIRED_LIBRARIES "${EXECINFO_LIBRARY}")
|
18
|
+
list(APPEND PLATFORM_LIBRARIES "${EXECINFO_LIBRARY}")
|
19
|
+
endif(EXECINFO_LIBRARY)
|
20
|
+
check_symbol_exists(backtrace execinfo.h HAVE_BACKTRACE)
|
21
|
+
cmake_pop_check_state()
|
22
|
+
|
23
|
+
cmake_push_check_state(RESET)
|
24
|
+
set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE")
|
25
|
+
find_library(DL_LIBRARY NAMES dl)
|
26
|
+
if(DL_LIBRARY)
|
27
|
+
set(CMAKE_REQUIRED_LIBRARIES "${DL_LIBRARY}")
|
28
|
+
list(APPEND PLATFORM_LIBRARIES "${DL_LIBRARY}")
|
29
|
+
endif(DL_LIBRARY)
|
30
|
+
check_symbol_exists(dladdr dlfcn.h HAVE_DLADDR)
|
31
|
+
cmake_pop_check_state()
|
32
|
+
|
33
|
+
if(HAVE_BACKTRACE)
|
34
|
+
add_definitions(-DHAVE_BACKTRACE=1)
|
35
|
+
endif()
|
36
|
+
|
37
|
+
if(HAVE_DLADDR)
|
38
|
+
add_definitions(-DHAVE_DLADDR=1)
|
39
|
+
endif()
|
40
|
+
|
11
41
|
add_subdirectory(third_party/gsl)
|
12
42
|
add_subdirectory(third_party/json)
|
13
43
|
add_subdirectory(third_party/spdlog)
|
@@ -90,6 +120,12 @@ else()
|
|
90
120
|
-Wuseless-cast # warn if you perform a cast to the same type
|
91
121
|
)
|
92
122
|
endif()
|
123
|
+
|
124
|
+
if(HAVE_BACKTRACE OR HAVE_DLADDR)
|
125
|
+
target_compile_options(project_options INTERFACE -ggdb3)
|
126
|
+
target_link_libraries(project_options INTERFACE -rdynamic)
|
127
|
+
add_definitions(-D_GNU_SOURCE=1)
|
128
|
+
endif()
|
93
129
|
endif()
|
94
130
|
|
95
131
|
# Read more at https://wiki.wireshark.org/TLS
|
@@ -102,8 +138,10 @@ message(STATUS "OPENSSL_LIBRARIES: ${OPENSSL_LIBRARIES}")
|
|
102
138
|
|
103
139
|
include_directories(${CMAKE_SOURCE_DIR}/couchbase)
|
104
140
|
|
105
|
-
add_library(
|
106
|
-
|
141
|
+
add_library(
|
142
|
+
platform OBJECT couchbase/platform/string_hex.cc couchbase/platform/uuid.cc couchbase/platform/random.cc
|
143
|
+
couchbase/platform/base64.cc couchbase/platform/backtrace.c couchbase/platform/terminate_handler.cc)
|
144
|
+
target_include_directories(platform PRIVATE ${PROJECT_BINARY_DIR}/generated)
|
107
145
|
|
108
146
|
add_library(cbcrypto OBJECT couchbase/cbcrypto/cbcrypto.cc)
|
109
147
|
|
data/ext/build_version.hxx.in
CHANGED
@@ -22,5 +22,5 @@
|
|
22
22
|
#define BACKEND_C_COMPILER "@CMAKE_C_COMPILER_ID@ @CMAKE_C_COMPILER_VERSION@"
|
23
23
|
#define BACKEND_SYSTEM "@CMAKE_SYSTEM@"
|
24
24
|
#define BACKEND_SYSTEM_PROCESSOR "@CMAKE_SYSTEM_PROCESSOR@"
|
25
|
-
#define BACKEND_GIT_REVISION "
|
25
|
+
#define BACKEND_GIT_REVISION "a23527c044e32c037f4a001c2b2a836716d85d35"
|
26
26
|
|
data/ext/couchbase/bucket.hxx
CHANGED
@@ -42,6 +42,7 @@ class bucket : public std::enable_shared_from_this<bucket>
|
|
42
42
|
, origin_(std::move(origin))
|
43
43
|
, known_features_(known_features)
|
44
44
|
{
|
45
|
+
log_prefix_ = fmt::format("[{}/{}]", client_id_, name_);
|
45
46
|
}
|
46
47
|
|
47
48
|
~bucket()
|
@@ -54,6 +55,142 @@ class bucket : public std::enable_shared_from_this<bucket>
|
|
54
55
|
return name_;
|
55
56
|
}
|
56
57
|
|
58
|
+
/**
|
59
|
+
* copies nodes from rhs that are not in lhs to output vector
|
60
|
+
*/
|
61
|
+
static void diff_nodes(const std::vector<configuration::node>& lhs,
|
62
|
+
const std::vector<configuration::node>& rhs,
|
63
|
+
std::vector<configuration::node>& output)
|
64
|
+
{
|
65
|
+
for (const auto& re : rhs) {
|
66
|
+
bool known = false;
|
67
|
+
for (const auto& le : lhs) {
|
68
|
+
if (le.hostname == re.hostname && le.services_plain.management.value_or(0) == re.services_plain.management.value_or(0)) {
|
69
|
+
known = true;
|
70
|
+
break;
|
71
|
+
}
|
72
|
+
}
|
73
|
+
if (!known) {
|
74
|
+
output.push_back(re);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
void update_config(const configuration& config)
|
80
|
+
{
|
81
|
+
if (!config_) {
|
82
|
+
spdlog::debug("{} initialize configuration rev={}", log_prefix_, config.rev);
|
83
|
+
} else if (config.rev > config_->rev) {
|
84
|
+
spdlog::debug("{} will update the configuration old={} -> new={}", log_prefix_, config_->rev, config.rev);
|
85
|
+
} else {
|
86
|
+
return;
|
87
|
+
}
|
88
|
+
|
89
|
+
std::vector<configuration::node> added{};
|
90
|
+
std::vector<configuration::node> removed{};
|
91
|
+
if (config_) {
|
92
|
+
diff_nodes(config_->nodes, config.nodes, added);
|
93
|
+
diff_nodes(config.nodes, config_->nodes, removed);
|
94
|
+
} else {
|
95
|
+
added = config.nodes;
|
96
|
+
}
|
97
|
+
config_ = config;
|
98
|
+
if (!added.empty() || removed.empty()) {
|
99
|
+
std::map<size_t, std::shared_ptr<io::mcbp_session>> new_sessions{};
|
100
|
+
|
101
|
+
for (auto entry : sessions_) {
|
102
|
+
std::size_t new_index = config.nodes.size() + 1;
|
103
|
+
for (const auto& node : config.nodes) {
|
104
|
+
if (entry.second->bootstrap_hostname() == node.hostname_for(origin_.options().network) &&
|
105
|
+
entry.second->bootstrap_port() ==
|
106
|
+
std::to_string(node.port_or(origin_.options().network, service_type::kv, origin_.options().enable_tls, 0))) {
|
107
|
+
new_index = node.index;
|
108
|
+
break;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
if (new_index < config.nodes.size()) {
|
112
|
+
spdlog::debug(R"({} rev={}, preserve session="{}", address="{}:{}")",
|
113
|
+
log_prefix_,
|
114
|
+
config.rev,
|
115
|
+
entry.second->id(),
|
116
|
+
entry.second->bootstrap_hostname(),
|
117
|
+
entry.second->bootstrap_port());
|
118
|
+
new_sessions.emplace(new_index, std::move(entry.second));
|
119
|
+
} else {
|
120
|
+
spdlog::debug(R"({} rev={}, drop session="{}", address="{}:{}")",
|
121
|
+
log_prefix_,
|
122
|
+
config.rev,
|
123
|
+
entry.second->id(),
|
124
|
+
entry.second->bootstrap_hostname(),
|
125
|
+
entry.second->bootstrap_port());
|
126
|
+
entry.second.reset();
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
for (const auto& node : config.nodes) {
|
131
|
+
if (new_sessions.find(node.index) != new_sessions.end()) {
|
132
|
+
continue;
|
133
|
+
}
|
134
|
+
|
135
|
+
auto hostname = node.hostname_for(origin_.options().network);
|
136
|
+
auto port = node.port_or(origin_.options().network, service_type::kv, origin_.options().enable_tls, 0);
|
137
|
+
couchbase::origin origin(origin_.credentials(), hostname, port, origin_.options());
|
138
|
+
std::shared_ptr<io::mcbp_session> session;
|
139
|
+
if (origin_.options().enable_tls) {
|
140
|
+
session = std::make_shared<io::mcbp_session>(client_id_, ctx_, tls_, origin, name_, known_features_);
|
141
|
+
} else {
|
142
|
+
session = std::make_shared<io::mcbp_session>(client_id_, ctx_, origin, name_, known_features_);
|
143
|
+
}
|
144
|
+
spdlog::debug(R"({} rev={}, add session="{}", address="{}:{}")", log_prefix_, config.rev, session->id(), hostname, port);
|
145
|
+
session->bootstrap(
|
146
|
+
[self = shared_from_this(), session](std::error_code err, const configuration& cfg) {
|
147
|
+
if (!err) {
|
148
|
+
self->update_config(cfg);
|
149
|
+
session->on_configuration_update([self](const configuration& new_config) { self->update_config(new_config); });
|
150
|
+
session->on_stop([index = session->index(), self](io::retry_reason reason) {
|
151
|
+
if (reason == io::retry_reason::socket_closed_while_in_flight) {
|
152
|
+
self->restart_node(index);
|
153
|
+
}
|
154
|
+
});
|
155
|
+
}
|
156
|
+
},
|
157
|
+
true);
|
158
|
+
new_sessions.emplace(node.index, std::move(session));
|
159
|
+
}
|
160
|
+
sessions_ = new_sessions;
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
void restart_node(std::size_t index)
|
165
|
+
{
|
166
|
+
auto ptr = sessions_.find(index);
|
167
|
+
if (ptr == sessions_.end()) {
|
168
|
+
spdlog::debug(R"({} requested to restart session idx={}, which does not exist, ignoring)", log_prefix_, index);
|
169
|
+
return;
|
170
|
+
}
|
171
|
+
auto& old_session = ptr->second;
|
172
|
+
auto hostname = old_session->bootstrap_hostname();
|
173
|
+
auto port = old_session->bootstrap_port();
|
174
|
+
spdlog::debug(R"({} restarting session idx={}, id="{}", address="{}")", log_prefix_, index, old_session->id(), hostname, port);
|
175
|
+
couchbase::origin origin(origin_.credentials(), hostname, port, origin_.options());
|
176
|
+
sessions_.erase(ptr);
|
177
|
+
std::shared_ptr<io::mcbp_session> session;
|
178
|
+
if (origin_.options().enable_tls) {
|
179
|
+
session = std::make_shared<io::mcbp_session>(client_id_, ctx_, tls_, origin, name_, known_features_);
|
180
|
+
} else {
|
181
|
+
session = std::make_shared<io::mcbp_session>(client_id_, ctx_, origin, name_, known_features_);
|
182
|
+
}
|
183
|
+
session->bootstrap(
|
184
|
+
[self = shared_from_this(), session](std::error_code err, const configuration& config) {
|
185
|
+
if (!err) {
|
186
|
+
self->update_config(config);
|
187
|
+
session->on_configuration_update([self](const configuration& new_config) { self->update_config(new_config); });
|
188
|
+
}
|
189
|
+
},
|
190
|
+
true);
|
191
|
+
sessions_.emplace(index, std::move(session));
|
192
|
+
}
|
193
|
+
|
57
194
|
template<typename Handler>
|
58
195
|
void bootstrap(Handler&& handler)
|
59
196
|
{
|
@@ -66,52 +203,37 @@ class bucket : public std::enable_shared_from_this<bucket>
|
|
66
203
|
new_session->bootstrap([self = shared_from_this(), new_session, h = std::forward<Handler>(handler)](
|
67
204
|
std::error_code ec, const configuration& cfg) mutable {
|
68
205
|
if (!ec) {
|
69
|
-
self->config_ = cfg;
|
70
206
|
size_t this_index = new_session->index();
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
couchbase::origin origin(
|
76
|
-
self->origin_.get_username(),
|
77
|
-
self->origin_.get_password(),
|
78
|
-
n.hostname_for(self->origin_.options().network),
|
79
|
-
n.port_or(self->origin_.options().network, service_type::kv, self->origin_.options().enable_tls, 0),
|
80
|
-
self->origin_.options());
|
81
|
-
std::shared_ptr<io::mcbp_session> s;
|
82
|
-
if (self->origin_.options().enable_tls) {
|
83
|
-
s = std::make_shared<io::mcbp_session>(
|
84
|
-
self->client_id_, self->ctx_, self->tls_, origin, self->name_, self->known_features_);
|
85
|
-
} else {
|
86
|
-
s = std::make_shared<io::mcbp_session>(
|
87
|
-
self->client_id_, self->ctx_, origin, self->name_, self->known_features_);
|
88
|
-
}
|
89
|
-
s->bootstrap([host = n.hostname, bucket = self->name_](std::error_code err, const configuration& /*config*/) {
|
90
|
-
// TODO: retry, we know that auth is correct
|
91
|
-
if (err) {
|
92
|
-
spdlog::warn("unable to bootstrap node {} ({}): {}", host, bucket, err.message());
|
93
|
-
}
|
94
|
-
});
|
95
|
-
self->sessions_.emplace(n.index, std::move(s));
|
96
|
-
}
|
207
|
+
new_session->on_configuration_update([self](const configuration& config) { self->update_config(config); });
|
208
|
+
new_session->on_stop([this_index, self](io::retry_reason reason) {
|
209
|
+
if (reason == io::retry_reason::socket_closed_while_in_flight) {
|
210
|
+
self->restart_node(this_index);
|
97
211
|
}
|
98
|
-
}
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
212
|
+
});
|
213
|
+
|
214
|
+
self->sessions_.emplace(this_index, std::move(new_session));
|
215
|
+
self->update_config(cfg);
|
216
|
+
self->drain_deferred_queue();
|
103
217
|
}
|
104
218
|
h(ec, cfg);
|
105
219
|
});
|
106
220
|
}
|
107
221
|
|
222
|
+
void drain_deferred_queue()
|
223
|
+
{
|
224
|
+
while (!deferred_commands_.empty()) {
|
225
|
+
deferred_commands_.front()();
|
226
|
+
deferred_commands_.pop();
|
227
|
+
}
|
228
|
+
}
|
229
|
+
|
108
230
|
template<typename Request, typename Handler>
|
109
231
|
void execute(Request request, Handler&& handler)
|
110
232
|
{
|
111
233
|
if (closed_) {
|
112
234
|
return;
|
113
235
|
}
|
114
|
-
auto cmd = std::make_shared<operations::mcbp_command<Request>>(ctx_, request);
|
236
|
+
auto cmd = std::make_shared<operations::mcbp_command<bucket, Request>>(ctx_, shared_from_this(), request);
|
115
237
|
cmd->start([cmd, handler = std::forward<Handler>(handler)](std::error_code ec, std::optional<io::mcbp_message> msg) mutable {
|
116
238
|
using encoded_response_type = typename Request::encoded_response_type;
|
117
239
|
handler(make_response(ec, cmd->request, msg ? encoded_response_type(*msg) : encoded_response_type{}));
|
@@ -129,18 +251,46 @@ class bucket : public std::enable_shared_from_this<bucket>
|
|
129
251
|
return;
|
130
252
|
}
|
131
253
|
closed_ = true;
|
254
|
+
|
255
|
+
drain_deferred_queue();
|
132
256
|
for (auto& session : sessions_) {
|
133
|
-
session.second->stop();
|
257
|
+
session.second->stop(io::retry_reason::do_not_retry);
|
134
258
|
}
|
135
259
|
}
|
136
260
|
|
137
261
|
template<typename Request>
|
138
|
-
void map_and_send(std::shared_ptr<operations::mcbp_command<Request>> cmd)
|
262
|
+
void map_and_send(std::shared_ptr<operations::mcbp_command<bucket, Request>> cmd)
|
139
263
|
{
|
140
|
-
|
264
|
+
if (closed_) {
|
265
|
+
return cmd->cancel(io::retry_reason::do_not_retry);
|
266
|
+
}
|
267
|
+
std::int16_t index = 0;
|
141
268
|
std::tie(cmd->request.partition, index) = config_->map_key(cmd->request.id.key);
|
142
|
-
|
143
|
-
|
269
|
+
if (index < 0) {
|
270
|
+
return io::retry_orchestrator::maybe_retry(
|
271
|
+
cmd->manager_, cmd, io::retry_reason::node_not_available, std::make_error_code(error::common_errc::request_canceled));
|
272
|
+
}
|
273
|
+
cmd->send_to(sessions_.at(static_cast<std::size_t>(index)));
|
274
|
+
}
|
275
|
+
|
276
|
+
template<typename Request>
|
277
|
+
void schedule_for_retry(std::shared_ptr<operations::mcbp_command<bucket, Request>> cmd, std::chrono::milliseconds duration)
|
278
|
+
{
|
279
|
+
if (closed_) {
|
280
|
+
return cmd->cancel(io::retry_reason::do_not_retry);
|
281
|
+
}
|
282
|
+
cmd->retry_backoff.expires_after(duration);
|
283
|
+
cmd->retry_backoff.async_wait([self = shared_from_this(), cmd](std::error_code ec) mutable {
|
284
|
+
if (ec == asio::error::operation_aborted) {
|
285
|
+
return;
|
286
|
+
}
|
287
|
+
self->map_and_send(cmd);
|
288
|
+
});
|
289
|
+
}
|
290
|
+
|
291
|
+
[[nodiscard]] const std::string& log_prefix()
|
292
|
+
{
|
293
|
+
return log_prefix_;
|
144
294
|
}
|
145
295
|
|
146
296
|
private:
|
@@ -157,5 +307,7 @@ class bucket : public std::enable_shared_from_this<bucket>
|
|
157
307
|
|
158
308
|
bool closed_{ false };
|
159
309
|
std::map<size_t, std::shared_ptr<io::mcbp_session>> sessions_{};
|
310
|
+
|
311
|
+
std::string log_prefix_{};
|
160
312
|
};
|
161
313
|
} // namespace couchbase
|