couchbase 3.0.0.alpha.1-universal-darwin-19 → 3.0.0.alpha.2-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/.github/workflows/tests-6.0.3.yml +49 -0
- data/.github/workflows/tests.yml +47 -0
- data/.gitmodules +3 -0
- data/.idea/dictionaries/gem_terms.xml +5 -0
- data/.idea/inspectionProfiles/Project_Default.xml +1 -0
- data/.idea/vcs.xml +1 -0
- data/Gemfile +1 -0
- data/README.md +55 -2
- data/Rakefile +18 -0
- data/bin/init-cluster +62 -0
- data/bin/setup +1 -0
- data/couchbase.gemspec +3 -2
- data/examples/crud.rb +1 -2
- data/examples/managing_buckets.rb +47 -0
- data/examples/managing_collections.rb +58 -0
- data/examples/managing_query_indexes.rb +63 -0
- data/examples/query.rb +3 -2
- data/examples/query_with_consistency.rb +76 -0
- data/examples/subdocument.rb +23 -1
- data/ext/.clang-format +1 -1
- data/ext/.idea/dictionaries/couchbase_terms.xml +2 -0
- data/ext/.idea/vcs.xml +1 -0
- data/ext/CMakeLists.txt +30 -12
- data/ext/build_version.hxx.in +26 -0
- data/ext/couchbase/bucket.hxx +69 -8
- data/ext/couchbase/cluster.hxx +70 -54
- data/ext/couchbase/collections_manifest.hxx +3 -3
- data/ext/couchbase/configuration.hxx +14 -0
- data/ext/couchbase/couchbase.cxx +2044 -383
- data/ext/couchbase/{operations/document_id.hxx → document_id.hxx} +5 -4
- data/ext/couchbase/io/http_message.hxx +5 -1
- data/ext/couchbase/io/http_parser.hxx +2 -1
- data/ext/couchbase/io/http_session.hxx +6 -3
- data/ext/couchbase/io/{binary_message.hxx → mcbp_message.hxx} +15 -12
- data/ext/couchbase/io/mcbp_parser.hxx +99 -0
- data/ext/couchbase/io/{key_value_session.hxx → mcbp_session.hxx} +200 -95
- data/ext/couchbase/io/session_manager.hxx +37 -22
- data/ext/couchbase/mutation_token.hxx +2 -1
- data/ext/couchbase/operations.hxx +38 -8
- data/ext/couchbase/operations/bucket_create.hxx +138 -0
- data/ext/couchbase/operations/bucket_drop.hxx +65 -0
- data/ext/couchbase/operations/bucket_flush.hxx +65 -0
- data/ext/couchbase/operations/bucket_get.hxx +69 -0
- data/ext/couchbase/operations/bucket_get_all.hxx +62 -0
- data/ext/couchbase/operations/bucket_settings.hxx +111 -0
- data/ext/couchbase/operations/bucket_update.hxx +115 -0
- data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +60 -0
- data/ext/couchbase/operations/collection_create.hxx +86 -0
- data/ext/couchbase/operations/collection_drop.hxx +82 -0
- data/ext/couchbase/operations/command.hxx +10 -10
- data/ext/couchbase/operations/document_decrement.hxx +80 -0
- data/ext/couchbase/operations/document_exists.hxx +80 -0
- data/ext/couchbase/operations/{get.hxx → document_get.hxx} +4 -2
- data/ext/couchbase/operations/document_get_and_lock.hxx +64 -0
- data/ext/couchbase/operations/document_get_and_touch.hxx +64 -0
- data/ext/couchbase/operations/document_increment.hxx +80 -0
- data/ext/couchbase/operations/document_insert.hxx +74 -0
- data/ext/couchbase/operations/{lookup_in.hxx → document_lookup_in.hxx} +2 -2
- data/ext/couchbase/operations/{mutate_in.hxx → document_mutate_in.hxx} +11 -2
- data/ext/couchbase/operations/{query.hxx → document_query.hxx} +101 -6
- data/ext/couchbase/operations/document_remove.hxx +67 -0
- data/ext/couchbase/operations/document_replace.hxx +76 -0
- data/ext/couchbase/operations/{upsert.hxx → document_touch.hxx} +14 -14
- data/ext/couchbase/operations/{remove.hxx → document_unlock.hxx} +12 -10
- data/ext/couchbase/operations/document_upsert.hxx +74 -0
- data/ext/couchbase/operations/query_index_build_deferred.hxx +85 -0
- data/ext/couchbase/operations/query_index_create.hxx +134 -0
- data/ext/couchbase/operations/query_index_drop.hxx +108 -0
- data/ext/couchbase/operations/query_index_get_all.hxx +106 -0
- data/ext/couchbase/operations/scope_create.hxx +81 -0
- data/ext/couchbase/operations/scope_drop.hxx +79 -0
- data/ext/couchbase/operations/scope_get_all.hxx +72 -0
- data/ext/couchbase/protocol/client_opcode.hxx +35 -0
- data/ext/couchbase/protocol/client_request.hxx +56 -9
- data/ext/couchbase/protocol/client_response.hxx +52 -15
- data/ext/couchbase/protocol/cmd_cluster_map_change_notification.hxx +81 -0
- data/ext/couchbase/protocol/cmd_decrement.hxx +187 -0
- data/ext/couchbase/protocol/cmd_exists.hxx +171 -0
- data/ext/couchbase/protocol/cmd_get.hxx +31 -8
- data/ext/couchbase/protocol/cmd_get_and_lock.hxx +142 -0
- data/ext/couchbase/protocol/cmd_get_and_touch.hxx +142 -0
- data/ext/couchbase/protocol/cmd_get_cluster_config.hxx +16 -3
- data/ext/couchbase/protocol/cmd_get_collections_manifest.hxx +16 -3
- data/ext/couchbase/protocol/cmd_get_error_map.hxx +16 -3
- data/ext/couchbase/protocol/cmd_hello.hxx +24 -8
- data/ext/couchbase/protocol/cmd_increment.hxx +187 -0
- data/ext/couchbase/protocol/cmd_info.hxx +1 -0
- data/ext/couchbase/protocol/cmd_insert.hxx +172 -0
- data/ext/couchbase/protocol/cmd_lookup_in.hxx +28 -13
- data/ext/couchbase/protocol/cmd_mutate_in.hxx +65 -13
- data/ext/couchbase/protocol/cmd_remove.hxx +59 -4
- data/ext/couchbase/protocol/cmd_replace.hxx +172 -0
- data/ext/couchbase/protocol/cmd_sasl_auth.hxx +15 -3
- data/ext/couchbase/protocol/cmd_sasl_list_mechs.hxx +15 -3
- data/ext/couchbase/protocol/cmd_sasl_step.hxx +15 -3
- data/ext/couchbase/protocol/cmd_select_bucket.hxx +14 -2
- data/ext/couchbase/protocol/cmd_touch.hxx +102 -0
- data/ext/couchbase/protocol/cmd_unlock.hxx +95 -0
- data/ext/couchbase/protocol/cmd_upsert.hxx +50 -14
- data/ext/couchbase/protocol/durability_level.hxx +67 -0
- data/ext/couchbase/protocol/frame_info_id.hxx +187 -0
- data/ext/couchbase/protocol/hello_feature.hxx +137 -0
- data/ext/couchbase/protocol/server_opcode.hxx +57 -0
- data/ext/couchbase/protocol/server_request.hxx +122 -0
- data/ext/couchbase/protocol/unsigned_leb128.h +15 -15
- data/ext/couchbase/utils/byteswap.hxx +1 -2
- data/ext/couchbase/utils/url_codec.hxx +225 -0
- data/ext/couchbase/version.hxx +3 -1
- data/ext/extconf.rb +4 -1
- data/ext/test/main.cxx +37 -113
- data/ext/third_party/snappy/.appveyor.yml +36 -0
- data/ext/third_party/snappy/.gitignore +8 -0
- data/ext/third_party/snappy/.travis.yml +98 -0
- data/ext/third_party/snappy/AUTHORS +1 -0
- data/ext/third_party/snappy/CMakeLists.txt +345 -0
- data/ext/third_party/snappy/CONTRIBUTING.md +26 -0
- data/ext/third_party/snappy/COPYING +54 -0
- data/ext/third_party/snappy/NEWS +188 -0
- data/ext/third_party/snappy/README.md +148 -0
- data/ext/third_party/snappy/cmake/SnappyConfig.cmake.in +33 -0
- data/ext/third_party/snappy/cmake/config.h.in +59 -0
- data/ext/third_party/snappy/docs/README.md +72 -0
- data/ext/third_party/snappy/format_description.txt +110 -0
- data/ext/third_party/snappy/framing_format.txt +135 -0
- data/ext/third_party/snappy/snappy-c.cc +90 -0
- data/ext/third_party/snappy/snappy-c.h +138 -0
- data/ext/third_party/snappy/snappy-internal.h +315 -0
- data/ext/third_party/snappy/snappy-sinksource.cc +121 -0
- data/ext/third_party/snappy/snappy-sinksource.h +182 -0
- data/ext/third_party/snappy/snappy-stubs-internal.cc +42 -0
- data/ext/third_party/snappy/snappy-stubs-internal.h +493 -0
- data/ext/third_party/snappy/snappy-stubs-public.h.in +63 -0
- data/ext/third_party/snappy/snappy-test.cc +613 -0
- data/ext/third_party/snappy/snappy-test.h +526 -0
- data/ext/third_party/snappy/snappy.cc +1770 -0
- data/ext/third_party/snappy/snappy.h +209 -0
- data/ext/third_party/snappy/snappy_compress_fuzzer.cc +60 -0
- data/ext/third_party/snappy/snappy_uncompress_fuzzer.cc +58 -0
- data/ext/third_party/snappy/snappy_unittest.cc +1512 -0
- data/ext/third_party/snappy/testdata/alice29.txt +3609 -0
- data/ext/third_party/snappy/testdata/asyoulik.txt +4122 -0
- data/ext/third_party/snappy/testdata/baddata1.snappy +0 -0
- data/ext/third_party/snappy/testdata/baddata2.snappy +0 -0
- data/ext/third_party/snappy/testdata/baddata3.snappy +0 -0
- data/ext/third_party/snappy/testdata/fireworks.jpeg +0 -0
- data/ext/third_party/snappy/testdata/geo.protodata +0 -0
- data/ext/third_party/snappy/testdata/html +1 -0
- data/ext/third_party/snappy/testdata/html_x_4 +1 -0
- data/ext/third_party/snappy/testdata/kppkn.gtb +0 -0
- data/ext/third_party/snappy/testdata/lcet10.txt +7519 -0
- data/ext/third_party/snappy/testdata/paper-100k.pdf +600 -2
- data/ext/third_party/snappy/testdata/plrabn12.txt +10699 -0
- data/ext/third_party/snappy/testdata/urls.10K +10000 -0
- data/lib/couchbase/binary_collection.rb +33 -76
- data/lib/couchbase/binary_collection_options.rb +94 -0
- data/lib/couchbase/bucket.rb +9 -3
- data/lib/couchbase/cluster.rb +161 -23
- data/lib/couchbase/collection.rb +108 -191
- data/lib/couchbase/collection_options.rb +430 -0
- data/lib/couchbase/errors.rb +136 -134
- data/lib/couchbase/json_transcoder.rb +32 -0
- data/lib/couchbase/management/analytics_index_manager.rb +185 -9
- data/lib/couchbase/management/bucket_manager.rb +84 -33
- data/lib/couchbase/management/collection_manager.rb +166 -1
- data/lib/couchbase/management/query_index_manager.rb +261 -0
- data/lib/couchbase/management/search_index_manager.rb +291 -0
- data/lib/couchbase/management/user_manager.rb +12 -10
- data/lib/couchbase/management/view_index_manager.rb +151 -1
- data/lib/couchbase/mutation_state.rb +11 -1
- data/lib/couchbase/scope.rb +4 -4
- data/lib/couchbase/version.rb +1 -1
- metadata +113 -18
- data/.travis.yml +0 -7
- data/ext/couchbase/io/binary_parser.hxx +0 -64
- data/lib/couchbase/results.rb +0 -307
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'couchbase'
|
2
|
+
include Couchbase
|
3
|
+
|
4
|
+
def measure(msg)
|
5
|
+
start = Time.now
|
6
|
+
yield
|
7
|
+
printf "%s in %.2f seconds\n", msg, Time.now - start
|
8
|
+
end
|
9
|
+
|
10
|
+
def display_indexes(indexes, bucket_name)
|
11
|
+
puts "There are #{indexes.size} query indexes in the bucket \"#{bucket_name}\":"
|
12
|
+
indexes.each do |index|
|
13
|
+
print " * [#{index.state}] #{index.name}"
|
14
|
+
if index.primary?
|
15
|
+
print " (primary)"
|
16
|
+
end
|
17
|
+
unless index.index_key.empty?
|
18
|
+
print " on [#{index.index_key.join(", ")}]"
|
19
|
+
end
|
20
|
+
if index.condition
|
21
|
+
print " where #{index.condition}"
|
22
|
+
end
|
23
|
+
puts
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
bucket_name = "beer-sample"
|
28
|
+
|
29
|
+
options = Cluster::ClusterOptions.new
|
30
|
+
options.authenticate("Administrator", "password")
|
31
|
+
cluster = Cluster.connect("couchbase://192.168.42.101", options)
|
32
|
+
|
33
|
+
display_indexes(cluster.query_indexes.get_all_indexes(bucket_name), bucket_name)
|
34
|
+
|
35
|
+
index_name = "demo_index"
|
36
|
+
options = Management::QueryIndexManager::DropIndexOptions.new
|
37
|
+
options.ignore_if_does_not_exist = true
|
38
|
+
measure("Index \"#{index_name}\" has been dropped") { cluster.query_indexes.drop_index(bucket_name, index_name, options) }
|
39
|
+
|
40
|
+
options = Management::QueryIndexManager::CreateIndexOptions.new
|
41
|
+
options.ignore_if_exists = true
|
42
|
+
options.condition = "abv > 2"
|
43
|
+
measure("Index \"#{index_name}\" has been created") { cluster.query_indexes.create_index(bucket_name, index_name, %w[`type` `name`], options) }
|
44
|
+
|
45
|
+
options = Management::QueryIndexManager::DropPrimaryIndexOptions.new
|
46
|
+
options.ignore_if_does_not_exist = true
|
47
|
+
measure("Primary index \"#{bucket_name}\" has been dropped") { cluster.query_indexes.drop_primary_index(bucket_name, options) }
|
48
|
+
|
49
|
+
options = Management::QueryIndexManager::CreatePrimaryIndexOptions.new
|
50
|
+
options.deferred = true
|
51
|
+
measure("Primary index \"#{bucket_name}\" has been created") { cluster.query_indexes.create_primary_index(bucket_name, options) }
|
52
|
+
|
53
|
+
display_indexes(cluster.query_indexes.get_all_indexes(bucket_name), bucket_name)
|
54
|
+
|
55
|
+
measure("Build of the indexes for \"#{bucket_name}\" has been triggered") { cluster.query_indexes.build_deferred_indexes(bucket_name) }
|
56
|
+
|
57
|
+
display_indexes(cluster.query_indexes.get_all_indexes(bucket_name), bucket_name)
|
58
|
+
|
59
|
+
options = Management::QueryIndexManager::WatchIndexesOptions.new
|
60
|
+
options.watch_primary = true
|
61
|
+
measure("Watching for primary index build completion for \"#{bucket_name}\" has been finished") { cluster.query_indexes.watch_indexes(bucket_name, [], 10_000_000, options) }
|
62
|
+
|
63
|
+
display_indexes(cluster.query_indexes.get_all_indexes(bucket_name), bucket_name)
|
data/examples/query.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'couchbase'
|
2
|
-
require 'byebug'
|
3
2
|
|
4
3
|
include Couchbase
|
5
4
|
|
@@ -7,11 +6,13 @@ options = Cluster::ClusterOptions.new
|
|
7
6
|
options.authenticate("Administrator", "password")
|
8
7
|
cluster = Cluster.connect("couchbase://localhost", options)
|
9
8
|
|
9
|
+
cluster.bucket("travel-sample") # this is necessary for 6.0.x
|
10
|
+
|
10
11
|
options = Cluster::QueryOptions.new
|
11
12
|
options.named_parameters({type: "hotel"})
|
12
13
|
options.metrics = true
|
13
14
|
res = cluster.query("SELECT * FROM `travel-sample` WHERE type = $type LIMIT 10", options)
|
14
15
|
res.rows.each do |row|
|
15
|
-
puts "#{row[
|
16
|
+
puts "#{row["travel-sample"]["country"]}. #{row["travel-sample"]["name"]}"
|
16
17
|
end
|
17
18
|
puts "Status: #{res.meta_data.status}. Execution time: #{res.meta_data.metrics.execution_time}"
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'couchbase'
|
2
|
+
|
3
|
+
include Couchbase
|
4
|
+
|
5
|
+
options = Cluster::ClusterOptions.new
|
6
|
+
options.authenticate("Administrator", "password")
|
7
|
+
cluster = Cluster.connect("couchbase://localhost", options)
|
8
|
+
|
9
|
+
options = Management::QueryIndexManager::CreatePrimaryIndexOptions.new
|
10
|
+
options.ignore_if_exists = true
|
11
|
+
cluster.query_indexes.create_primary_index("default", options)
|
12
|
+
|
13
|
+
collection = cluster.bucket("default").default_collection
|
14
|
+
|
15
|
+
# METHOD 1
|
16
|
+
#
|
17
|
+
# The easiest way to enforce consistency is just set scan_consistency option to :request_plus
|
18
|
+
# Note: it waits until all documents queued to be indexed when the request has been receive,
|
19
|
+
# will be proceed and stored in the index. Often more granular approach is possible (skip to the next section)
|
20
|
+
puts "METHOD 1: using :request_plus"
|
21
|
+
|
22
|
+
random_number = rand(0..1_000_000_000)
|
23
|
+
collection.upsert("user:#{random_number}", {
|
24
|
+
"name" => ["Brass", "Doorknob"],
|
25
|
+
"email" => "brass.doorknob@example.com",
|
26
|
+
"data" => random_number,
|
27
|
+
})
|
28
|
+
|
29
|
+
options = Cluster::QueryOptions.new
|
30
|
+
options.timeout = 10_000
|
31
|
+
options.positional_parameters(["Brass"])
|
32
|
+
options.scan_consistency = :request_plus
|
33
|
+
res = cluster.query("SELECT name, email, data, META(`default`).id FROM `default` WHERE $1 IN name", options)
|
34
|
+
res.rows.each do |row|
|
35
|
+
puts "Name: #{row["name"].join(" ")}, e-mail: #{row["email"]}, data: #{row["data"]}"
|
36
|
+
if row["data"] == random_number
|
37
|
+
puts "--- Found our newly created document!"
|
38
|
+
end
|
39
|
+
if ENV['REMOVE_DOOR_KNOBS']
|
40
|
+
puts "Removing #{row["id"]} (requested via env)"
|
41
|
+
collection.remove(row["id"])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# METHOD 2
|
46
|
+
#
|
47
|
+
# More granular and light-weight approach is to use AT_PLUS consistency.
|
48
|
+
# The application need to to know exactly which mutation affect the result,
|
49
|
+
# and supply mutation tokens from those operations.
|
50
|
+
puts "METHOD 2: using MutationState"
|
51
|
+
|
52
|
+
random_number = rand(0..1_000_000_000)
|
53
|
+
res = collection.upsert("user:#{random_number}", {
|
54
|
+
"name" => ["Brass", "Doorknob"],
|
55
|
+
"email" => "brass.doorknob@example.com",
|
56
|
+
"data" => random_number,
|
57
|
+
})
|
58
|
+
|
59
|
+
state = MutationState.new(res.mutation_token)
|
60
|
+
# state.add(*tokens) could be used to add more tokens
|
61
|
+
|
62
|
+
options = Cluster::QueryOptions.new
|
63
|
+
options.timeout = 10_000
|
64
|
+
options.positional_parameters(["Brass"])
|
65
|
+
options.consistent_with(state)
|
66
|
+
res = cluster.query("SELECT name, email, data, META(`default`).id FROM `default` WHERE $1 IN name", options)
|
67
|
+
res.rows.each do |row|
|
68
|
+
puts "Name: #{row["name"].join(" ")}, e-mail: #{row["email"]}, data: #{row["data"]}"
|
69
|
+
if row["data"] == random_number
|
70
|
+
puts "--- Found our newly created document!"
|
71
|
+
end
|
72
|
+
if ENV['REMOVE_DOOR_KNOBS']
|
73
|
+
puts "Removing #{row["id"]} (requested via env)"
|
74
|
+
collection.remove(row["id"])
|
75
|
+
end
|
76
|
+
end
|
data/examples/subdocument.rb
CHANGED
@@ -7,6 +7,28 @@ cluster = Cluster.connect("couchbase://localhost", options)
|
|
7
7
|
bucket = cluster.bucket("default")
|
8
8
|
collection = bucket.default_collection
|
9
9
|
|
10
|
+
document = {
|
11
|
+
name: "Douglas Reynholm",
|
12
|
+
email: "douglas@reynholmindustries.com",
|
13
|
+
addresses: {
|
14
|
+
billing: {
|
15
|
+
line1: "123 Any Street",
|
16
|
+
line2: "Anytown",
|
17
|
+
country: "United Kingdom"
|
18
|
+
},
|
19
|
+
delivery: {
|
20
|
+
line1: "123 Any Street",
|
21
|
+
line2: "Anytown",
|
22
|
+
country: "United Kingdom"
|
23
|
+
}
|
24
|
+
},
|
25
|
+
purchases: {
|
26
|
+
complete: [339, 976, 442, 666],
|
27
|
+
abandoned: [157, 42, 999]
|
28
|
+
}
|
29
|
+
}
|
30
|
+
collection.upsert("customer123", document)
|
31
|
+
|
10
32
|
res = collection.mutate_in("customer123", [
|
11
33
|
MutateInSpec.dict_upsert("fax", "311-555-0151")
|
12
34
|
])
|
@@ -19,7 +41,7 @@ res = collection.mutate_in("customer123", [
|
|
19
41
|
])
|
20
42
|
puts "The document has been modified successfully: cas=#{res.cas}"
|
21
43
|
|
22
|
-
res = collection.lookup_in"customer123", [
|
44
|
+
res = collection.lookup_in "customer123", [
|
23
45
|
LookupInSpec.get("addresses.delivery.country"),
|
24
46
|
LookupInSpec.exists("purchases.pending[-1]"),
|
25
47
|
]
|
data/ext/.clang-format
CHANGED
@@ -8,7 +8,7 @@ UseTab: Never
|
|
8
8
|
IndentWidth: 4
|
9
9
|
ColumnLimit: 140
|
10
10
|
AllowShortFunctionsOnASingleLine: None
|
11
|
-
AllowShortBlocksOnASingleLine:
|
11
|
+
AllowShortBlocksOnASingleLine: Empty
|
12
12
|
AllowShortCaseLabelsOnASingleLine: false
|
13
13
|
BreakBeforeBraces: Linux
|
14
14
|
SortIncludes: false
|
data/ext/.idea/vcs.xml
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
<mapping directory="$PROJECT_DIR$/third_party/gsl" vcs="Git" />
|
7
7
|
<mapping directory="$PROJECT_DIR$/third_party/http_parser" vcs="Git" />
|
8
8
|
<mapping directory="$PROJECT_DIR$/third_party/json" vcs="Git" />
|
9
|
+
<mapping directory="$PROJECT_DIR$/third_party/snappy" vcs="Git" />
|
9
10
|
<mapping directory="$PROJECT_DIR$/third_party/spdlog" vcs="Git" />
|
10
11
|
</component>
|
11
12
|
</project>
|
data/ext/CMakeLists.txt
CHANGED
@@ -11,6 +11,7 @@ endif()
|
|
11
11
|
add_subdirectory(third_party/gsl)
|
12
12
|
add_subdirectory(third_party/json)
|
13
13
|
add_subdirectory(third_party/spdlog)
|
14
|
+
add_subdirectory(third_party/snappy)
|
14
15
|
|
15
16
|
include_directories(BEFORE SYSTEM third_party/gsl/include)
|
16
17
|
include_directories(BEFORE SYSTEM third_party/asio/asio/include)
|
@@ -44,6 +45,13 @@ else()
|
|
44
45
|
target_link_libraries(project_options INTERFACE -fsanitize=address)
|
45
46
|
endif()
|
46
47
|
|
48
|
+
option(ENABLE_TSAN "Enable thread sanitizer" FALSE)
|
49
|
+
|
50
|
+
if(ENABLE_TSAN)
|
51
|
+
target_compile_options(project_options INTERFACE -fsanitize=thread)
|
52
|
+
target_link_libraries(project_options INTERFACE -fsanitize=thread)
|
53
|
+
endif()
|
54
|
+
|
47
55
|
target_compile_options(
|
48
56
|
project_warnings
|
49
57
|
INTERFACE -Wall
|
@@ -107,9 +115,22 @@ else()
|
|
107
115
|
message(STATUS "RUBY_EXECUTABLE: ${RUBY_EXECUTABLE}")
|
108
116
|
endif()
|
109
117
|
message(STATUS "RUBY_INCLUDE_DIR: ${RUBY_INCLUDE_DIR}")
|
118
|
+
message(STATUS "RUBY_LIBRARY: ${RUBY_LIBRARY}")
|
110
119
|
include_directories(BEFORE SYSTEM "${RUBY_INCLUDE_DIR}")
|
111
120
|
|
121
|
+
find_program(GIT git)
|
122
|
+
if(GIT)
|
123
|
+
execute_process(
|
124
|
+
COMMAND git rev-parse HEAD
|
125
|
+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
126
|
+
OUTPUT_STRIP_TRAILING_WHITESPACE
|
127
|
+
OUTPUT_VARIABLE BACKEND_GIT_REVISION)
|
128
|
+
endif()
|
129
|
+
|
130
|
+
string(TIMESTAMP BACKEND_BUILD_TIMESTAMP "%Y-%m-%d %H:%M:%S" UTC)
|
131
|
+
configure_file(${PROJECT_SOURCE_DIR}/build_version.hxx.in ${PROJECT_BINARY_DIR}/generated/build_version.hxx @ONLY)
|
112
132
|
add_library(couchbase SHARED couchbase/couchbase.cxx)
|
133
|
+
target_include_directories(couchbase PRIVATE ${PROJECT_BINARY_DIR}/generated)
|
113
134
|
target_link_libraries(
|
114
135
|
couchbase
|
115
136
|
PRIVATE project_options
|
@@ -120,8 +141,9 @@ target_link_libraries(
|
|
120
141
|
cbcrypto
|
121
142
|
cbsasl
|
122
143
|
http_parser
|
144
|
+
snappy
|
123
145
|
spdlog::spdlog_header_only)
|
124
|
-
set_target_properties(cbcrypto cbsasl platform PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
|
146
|
+
set_target_properties(cbcrypto cbsasl platform snappy PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
|
125
147
|
|
126
148
|
if(APPLE)
|
127
149
|
target_link_options(couchbase PRIVATE -Wl,-undefined,dynamic_lookup)
|
@@ -130,16 +152,12 @@ else()
|
|
130
152
|
endif()
|
131
153
|
|
132
154
|
if(BUILD_EXAMPLES)
|
155
|
+
file(
|
156
|
+
GENERATE
|
157
|
+
OUTPUT ${PROJECT_BINARY_DIR}/generated/generated_config.hxx
|
158
|
+
CONTENT "#pragma once\n#define LIBCOUCHBASE_EXT_PATH \"$<TARGET_FILE:couchbase>\"")
|
133
159
|
add_executable(main test/main.cxx)
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
project_warnings
|
138
|
-
OpenSSL::SSL
|
139
|
-
OpenSSL::Crypto
|
140
|
-
platform
|
141
|
-
cbcrypto
|
142
|
-
cbsasl
|
143
|
-
http_parser
|
144
|
-
spdlog::spdlog_header_only)
|
160
|
+
target_include_directories(main PRIVATE ${PROJECT_BINARY_DIR}/generated)
|
161
|
+
target_link_libraries(main PRIVATE project_options project_warnings ${RUBY_LIBRARY} spdlog::spdlog_header_only)
|
162
|
+
add_dependencies(main couchbase)
|
145
163
|
endif()
|
@@ -0,0 +1,26 @@
|
|
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
|
+
#define BACKEND_BUILD_TIMESTAMP "@BACKEND_BUILD_TIMESTAMP@"
|
21
|
+
#define BACKEND_CXX_COMPILER "@CMAKE_CXX_COMPILER_ID@ @CMAKE_CXX_COMPILER_VERSION@"
|
22
|
+
#define BACKEND_C_COMPILER "@CMAKE_C_COMPILER_ID@ @CMAKE_C_COMPILER_VERSION@"
|
23
|
+
#define BACKEND_SYSTEM "@CMAKE_SYSTEM@"
|
24
|
+
#define BACKEND_SYSTEM_PROCESSOR "@CMAKE_SYSTEM_PROCESSOR@"
|
25
|
+
#define BACKEND_GIT_REVISION "5b91db73c89347cfb4985490051aea4d82f56c0e"
|
26
|
+
|
data/ext/couchbase/bucket.hxx
CHANGED
@@ -35,41 +35,102 @@ class bucket
|
|
35
35
|
{
|
36
36
|
}
|
37
37
|
|
38
|
+
~bucket()
|
39
|
+
{
|
40
|
+
close();
|
41
|
+
}
|
42
|
+
|
38
43
|
[[nodiscard]] const std::string& name() const
|
39
44
|
{
|
40
45
|
return name_;
|
41
46
|
}
|
42
47
|
|
43
|
-
void set_node(size_t index, std::shared_ptr<io::
|
48
|
+
void set_node(size_t index, std::shared_ptr<io::mcbp_session> session)
|
44
49
|
{
|
50
|
+
if (closed_) {
|
51
|
+
return;
|
52
|
+
}
|
53
|
+
|
54
|
+
auto session_manifest = session->manifest();
|
55
|
+
if (!manifest_cache_) {
|
56
|
+
if (session_manifest) {
|
57
|
+
manifest_cache_ = session_manifest.value();
|
58
|
+
}
|
59
|
+
} else {
|
60
|
+
if (session_manifest && session_manifest->uid > manifest_cache_->uid) {
|
61
|
+
manifest_cache_ = session->manifest().value();
|
62
|
+
}
|
63
|
+
}
|
45
64
|
sessions_.emplace(index, std::move(session));
|
46
65
|
}
|
47
66
|
|
48
|
-
|
67
|
+
void remove_node(size_t index)
|
49
68
|
{
|
50
|
-
|
69
|
+
if (closed_) {
|
70
|
+
return;
|
71
|
+
}
|
72
|
+
sessions_.erase(index);
|
51
73
|
}
|
52
74
|
|
53
75
|
template<typename Request, typename Handler>
|
54
76
|
void execute(Request request, Handler&& handler)
|
55
77
|
{
|
56
|
-
|
78
|
+
if (closed_) {
|
79
|
+
return;
|
80
|
+
}
|
57
81
|
size_t index = 0;
|
58
|
-
std::tie(
|
59
|
-
|
82
|
+
std::tie(request.partition, index) = config_.map_key(request.id.key);
|
83
|
+
auto session = sessions_.at(index);
|
84
|
+
if (manifest_cache_) {
|
85
|
+
request.id.collection_uid = get_collection_uid(request.id.collection);
|
86
|
+
} else {
|
87
|
+
if (!request.id.collection.empty() && request.id.collection != "_default._default") {
|
88
|
+
handler(make_response(std::make_error_code(error::common_errc::unsupported_operation), request, {}));
|
89
|
+
return;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
auto cmd = std::make_shared<operations::command<Request>>(ctx_, std::move(request));
|
93
|
+
cmd->send_to(session, std::forward<Handler>(handler));
|
60
94
|
}
|
61
95
|
|
62
96
|
void close()
|
63
97
|
{
|
98
|
+
if (closed_) {
|
99
|
+
return;
|
100
|
+
}
|
101
|
+
closed_ = true;
|
64
102
|
for (auto& session : sessions_) {
|
65
103
|
session.second->stop();
|
66
104
|
}
|
67
105
|
}
|
68
106
|
|
69
107
|
private:
|
108
|
+
[[nodiscard]] uint32_t get_collection_uid(const std::string& collection_path)
|
109
|
+
{
|
110
|
+
Expects(manifest_cache_.has_value());
|
111
|
+
Expects(!collection_path.empty());
|
112
|
+
auto dot = collection_path.find('.');
|
113
|
+
Expects(dot != std::string::npos);
|
114
|
+
std::string scope = collection_path.substr(0, dot);
|
115
|
+
std::string collection = collection_path.substr(dot + 1);
|
116
|
+
for (const auto& s : manifest_cache_->scopes) {
|
117
|
+
if (s.name == scope) {
|
118
|
+
for (const auto& c : s.collections) {
|
119
|
+
if (c.name == collection) {
|
120
|
+
return gsl::narrow_cast<std::uint32_t>(c.uid);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
Ensures(false); // FIXME: return collection not found
|
126
|
+
return 0;
|
127
|
+
}
|
128
|
+
|
70
129
|
asio::io_context& ctx_;
|
71
130
|
std::string name_;
|
72
131
|
configuration config_;
|
73
|
-
|
132
|
+
bool closed_{ false };
|
133
|
+
std::optional<collections_manifest> manifest_cache_{};
|
134
|
+
std::map<size_t, std::shared_ptr<io::mcbp_session>> sessions_{};
|
74
135
|
};
|
75
|
-
} // namespace couchbase
|
136
|
+
} // namespace couchbase
|
data/ext/couchbase/cluster.hxx
CHANGED
@@ -20,11 +20,11 @@
|
|
20
20
|
#include <utility>
|
21
21
|
#include <thread>
|
22
22
|
|
23
|
-
#include <io/
|
23
|
+
#include <io/mcbp_session.hxx>
|
24
24
|
#include <io/session_manager.hxx>
|
25
25
|
#include <bucket.hxx>
|
26
26
|
#include <operations.hxx>
|
27
|
-
#include <operations/
|
27
|
+
#include <operations/document_query.hxx>
|
28
28
|
|
29
29
|
namespace couchbase
|
30
30
|
{
|
@@ -56,15 +56,14 @@ class cluster
|
|
56
56
|
: id_(uuid::random())
|
57
57
|
, ctx_(ctx)
|
58
58
|
, work_(asio::make_work_guard(ctx_))
|
59
|
-
, session_(std::make_shared<io::
|
60
|
-
, session_manager_(id_, ctx_)
|
59
|
+
, session_(std::make_shared<io::mcbp_session>(id_, ctx_))
|
60
|
+
, session_manager_(std::make_shared<io::session_manager>(id_, ctx_))
|
61
61
|
{
|
62
62
|
}
|
63
63
|
|
64
64
|
~cluster()
|
65
65
|
{
|
66
66
|
work_.reset();
|
67
|
-
close();
|
68
67
|
}
|
69
68
|
|
70
69
|
template<typename Handler>
|
@@ -72,16 +71,26 @@ class cluster
|
|
72
71
|
{
|
73
72
|
auto address = origin.get_address();
|
74
73
|
origin_ = origin;
|
75
|
-
session_->bootstrap(address.first,
|
76
|
-
|
74
|
+
session_->bootstrap(address.first,
|
75
|
+
address.second,
|
76
|
+
origin.get_username(),
|
77
|
+
origin.get_password(),
|
78
|
+
[this, handler = std::forward<Handler>(handler)](std::error_code ec, configuration config) mutable {
|
79
|
+
session_manager_->set_configuration(config);
|
80
|
+
handler(ec);
|
81
|
+
});
|
77
82
|
}
|
78
83
|
|
79
|
-
|
84
|
+
template<typename Handler>
|
85
|
+
void close(Handler&& handler)
|
80
86
|
{
|
81
|
-
|
82
|
-
|
83
|
-
bucket
|
84
|
-
|
87
|
+
asio::post(asio::bind_executor(ctx_, [this, handler = std::forward<Handler>(handler)]() {
|
88
|
+
session_->stop();
|
89
|
+
for (auto& bucket : buckets_) {
|
90
|
+
bucket.second->close();
|
91
|
+
}
|
92
|
+
handler();
|
93
|
+
}));
|
85
94
|
}
|
86
95
|
|
87
96
|
template<typename Handler>
|
@@ -92,38 +101,42 @@ class cluster
|
|
92
101
|
}
|
93
102
|
configuration config = session_->config();
|
94
103
|
auto& node = config.nodes.front();
|
95
|
-
auto new_session = std::make_shared<io::
|
96
|
-
new_session->bootstrap(
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
104
|
+
auto new_session = std::make_shared<io::mcbp_session>(id_, ctx_, bucket_name);
|
105
|
+
new_session->bootstrap(
|
106
|
+
node.hostname,
|
107
|
+
std::to_string(*node.services_plain.key_value),
|
108
|
+
origin_.get_username(),
|
109
|
+
origin_.get_password(),
|
110
|
+
[this, name = bucket_name, new_session, h = std::forward<Handler>(handler)](std::error_code ec, configuration cfg) mutable {
|
111
|
+
if (!ec) {
|
112
|
+
if (!session_->supports_gcccp()) {
|
113
|
+
session_manager_->set_configuration(cfg);
|
114
|
+
}
|
115
|
+
auto b = std::make_shared<bucket>(ctx_, name, cfg);
|
116
|
+
size_t this_index = new_session->index();
|
117
|
+
b->set_node(this_index, new_session);
|
118
|
+
if (cfg.nodes.size() > 1) {
|
119
|
+
for (const auto& n : cfg.nodes) {
|
120
|
+
if (n.index != this_index) {
|
121
|
+
auto s = std::make_shared<io::mcbp_session>(id_, ctx_, name);
|
122
|
+
b->set_node(n.index, s);
|
123
|
+
s->bootstrap(n.hostname,
|
124
|
+
std::to_string(*n.services_plain.key_value),
|
125
|
+
origin_.get_username(),
|
126
|
+
origin_.get_password(),
|
127
|
+
[s, i = n.index, b](std::error_code err, configuration /*config*/) {
|
128
|
+
if (err) {
|
129
|
+
spdlog::warn("unable to bootstrap node: {}", err.message());
|
130
|
+
b->remove_node(i);
|
119
131
|
}
|
120
|
-
}
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
132
|
+
});
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
136
|
+
buckets_.emplace(name, std::move(b));
|
137
|
+
}
|
138
|
+
h(ec);
|
139
|
+
});
|
127
140
|
}
|
128
141
|
|
129
142
|
template<class Request, class Handler>
|
@@ -133,17 +146,20 @@ class cluster
|
|
133
146
|
if (bucket == buckets_.end()) {
|
134
147
|
return handler(operations::make_response(std::make_error_code(error::common_errc::bucket_not_found), request, {}));
|
135
148
|
}
|
136
|
-
return bucket->second
|
149
|
+
return bucket->second->execute(request, std::forward<Handler>(handler));
|
137
150
|
}
|
138
151
|
|
139
|
-
template<class Handler>
|
140
|
-
void
|
152
|
+
template<class Request, class Handler>
|
153
|
+
void execute_http(Request request, Handler&& handler)
|
141
154
|
{
|
142
|
-
auto session = session_manager_
|
143
|
-
|
144
|
-
|
155
|
+
auto session = session_manager_->check_out(Request::type, origin_.username, origin_.password);
|
156
|
+
if (!session) {
|
157
|
+
return handler(operations::make_response(std::make_error_code(error::common_errc::service_not_available), request, {}));
|
158
|
+
}
|
159
|
+
auto cmd = std::make_shared<operations::command<Request>>(ctx_, std::move(request));
|
160
|
+
cmd->send_to(session, [this, session, handler = std::forward<Handler>(handler)](typename Request::response_type resp) mutable {
|
145
161
|
handler(std::move(resp));
|
146
|
-
session_manager_
|
162
|
+
session_manager_->check_in(Request::type, session);
|
147
163
|
});
|
148
164
|
}
|
149
165
|
|
@@ -151,9 +167,9 @@ class cluster
|
|
151
167
|
uuid::uuid_t id_;
|
152
168
|
asio::io_context& ctx_;
|
153
169
|
asio::executor_work_guard<asio::io_context::executor_type> work_;
|
154
|
-
std::shared_ptr<io::
|
155
|
-
io::session_manager session_manager_;
|
156
|
-
std::map<std::string, bucket
|
170
|
+
std::shared_ptr<io::mcbp_session> session_;
|
171
|
+
std::shared_ptr<io::session_manager> session_manager_;
|
172
|
+
std::map<std::string, std::shared_ptr<bucket>> buckets_;
|
157
173
|
origin origin_;
|
158
174
|
};
|
159
|
-
} // namespace couchbase
|
175
|
+
} // namespace couchbase
|