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,81 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <tao/json.hpp>
|
21
|
+
|
22
|
+
#include <version.hxx>
|
23
|
+
#include <operations/bucket_settings.hxx>
|
24
|
+
#include <utils/url_codec.hxx>
|
25
|
+
|
26
|
+
namespace couchbase::operations
|
27
|
+
{
|
28
|
+
|
29
|
+
struct scope_create_response {
|
30
|
+
std::error_code ec;
|
31
|
+
std::uint64_t uid{ 0 };
|
32
|
+
};
|
33
|
+
|
34
|
+
struct scope_create_request {
|
35
|
+
using response_type = scope_create_response;
|
36
|
+
using encoded_request_type = io::http_request;
|
37
|
+
using encoded_response_type = io::http_response;
|
38
|
+
|
39
|
+
static const inline service_type type = service_type::management;
|
40
|
+
|
41
|
+
std::string bucket_name;
|
42
|
+
std::string scope_name;
|
43
|
+
|
44
|
+
void encode_to(encoded_request_type& encoded)
|
45
|
+
{
|
46
|
+
encoded.method = "POST";
|
47
|
+
encoded.path = fmt::format("/pools/default/buckets/{}/collections", bucket_name);
|
48
|
+
encoded.headers["content-type"] = "application/x-www-form-urlencoded";
|
49
|
+
encoded.body = fmt::format("name={}", utils::string_codec::form_encode(scope_name));
|
50
|
+
}
|
51
|
+
};
|
52
|
+
|
53
|
+
scope_create_response
|
54
|
+
make_response(std::error_code ec, scope_create_request&, scope_create_request::encoded_response_type encoded)
|
55
|
+
{
|
56
|
+
scope_create_response response{ ec };
|
57
|
+
if (!ec) {
|
58
|
+
switch (encoded.status_code) {
|
59
|
+
case 400:
|
60
|
+
if (encoded.body.find("Not allowed on this version") != std::string::npos) {
|
61
|
+
response.ec = std::make_error_code(error::common_errc::unsupported_operation);
|
62
|
+
} else {
|
63
|
+
response.ec = std::make_error_code(error::management_errc::scope_exists);
|
64
|
+
}
|
65
|
+
break;
|
66
|
+
case 404:
|
67
|
+
response.ec = std::make_error_code(error::common_errc::bucket_not_found);
|
68
|
+
break;
|
69
|
+
case 200: {
|
70
|
+
tao::json::value payload = tao::json::from_string(encoded.body);
|
71
|
+
response.uid = std::stoull(payload.at("uid").get_string(), 0, 16);
|
72
|
+
} break;
|
73
|
+
default:
|
74
|
+
response.ec = std::make_error_code(error::common_errc::internal_server_failure);
|
75
|
+
break;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
return response;
|
79
|
+
}
|
80
|
+
|
81
|
+
} // namespace couchbase::operations
|
@@ -0,0 +1,79 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <tao/json.hpp>
|
21
|
+
|
22
|
+
#include <version.hxx>
|
23
|
+
#include <operations/bucket_settings.hxx>
|
24
|
+
#include <utils/url_codec.hxx>
|
25
|
+
|
26
|
+
namespace couchbase::operations
|
27
|
+
{
|
28
|
+
|
29
|
+
struct scope_drop_response {
|
30
|
+
std::error_code ec;
|
31
|
+
std::uint64_t uid{ 0 };
|
32
|
+
};
|
33
|
+
|
34
|
+
struct scope_drop_request {
|
35
|
+
using response_type = scope_drop_response;
|
36
|
+
using encoded_request_type = io::http_request;
|
37
|
+
using encoded_response_type = io::http_response;
|
38
|
+
|
39
|
+
static const inline service_type type = service_type::management;
|
40
|
+
|
41
|
+
std::string bucket_name;
|
42
|
+
std::string scope_name;
|
43
|
+
|
44
|
+
void encode_to(encoded_request_type& encoded)
|
45
|
+
{
|
46
|
+
encoded.method = "DELETE";
|
47
|
+
encoded.path = fmt::format("/pools/default/buckets/{}/collections/{}", bucket_name, scope_name);
|
48
|
+
}
|
49
|
+
};
|
50
|
+
|
51
|
+
scope_drop_response
|
52
|
+
make_response(std::error_code ec, scope_drop_request&, scope_drop_request::encoded_response_type encoded)
|
53
|
+
{
|
54
|
+
scope_drop_response response{ ec };
|
55
|
+
if (!ec) {
|
56
|
+
switch (encoded.status_code) {
|
57
|
+
case 400:
|
58
|
+
response.ec = std::make_error_code(error::common_errc::unsupported_operation);
|
59
|
+
break;
|
60
|
+
case 404:
|
61
|
+
if (encoded.body.find("Scope with this name is not found") != std::string::npos) {
|
62
|
+
response.ec = std::make_error_code(error::common_errc::scope_not_found);
|
63
|
+
} else {
|
64
|
+
response.ec = std::make_error_code(error::common_errc::bucket_not_found);
|
65
|
+
}
|
66
|
+
break;
|
67
|
+
case 200: {
|
68
|
+
tao::json::value payload = tao::json::from_string(encoded.body);
|
69
|
+
response.uid = std::stoull(payload.at("uid").get_string(), 0, 16);
|
70
|
+
} break;
|
71
|
+
default:
|
72
|
+
response.ec = std::make_error_code(error::common_errc::internal_server_failure);
|
73
|
+
break;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
return response;
|
77
|
+
}
|
78
|
+
|
79
|
+
} // namespace couchbase::operations
|
@@ -0,0 +1,72 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <tao/json.hpp>
|
21
|
+
|
22
|
+
#include <version.hxx>
|
23
|
+
#include <operations/bucket_settings.hxx>
|
24
|
+
|
25
|
+
namespace couchbase::operations
|
26
|
+
{
|
27
|
+
|
28
|
+
struct scope_get_all_response {
|
29
|
+
std::error_code ec;
|
30
|
+
collections_manifest manifest{};
|
31
|
+
};
|
32
|
+
|
33
|
+
struct scope_get_all_request {
|
34
|
+
using response_type = scope_get_all_response;
|
35
|
+
using encoded_request_type = io::http_request;
|
36
|
+
using encoded_response_type = io::http_response;
|
37
|
+
|
38
|
+
static const inline service_type type = service_type::management;
|
39
|
+
|
40
|
+
std::string bucket_name;
|
41
|
+
|
42
|
+
void encode_to(encoded_request_type& encoded)
|
43
|
+
{
|
44
|
+
encoded.method = "GET";
|
45
|
+
encoded.path = fmt::format("/pools/default/buckets/{}/collections", bucket_name);
|
46
|
+
}
|
47
|
+
};
|
48
|
+
|
49
|
+
scope_get_all_response
|
50
|
+
make_response(std::error_code ec, scope_get_all_request&, scope_get_all_request::encoded_response_type encoded)
|
51
|
+
{
|
52
|
+
scope_get_all_response response{ ec };
|
53
|
+
if (!ec) {
|
54
|
+
switch (encoded.status_code) {
|
55
|
+
case 400:
|
56
|
+
response.ec = std::make_error_code(error::common_errc::unsupported_operation);
|
57
|
+
break;
|
58
|
+
case 404:
|
59
|
+
response.ec = std::make_error_code(error::common_errc::bucket_not_found);
|
60
|
+
break;
|
61
|
+
case 200:
|
62
|
+
response.manifest = tao::json::from_string(encoded.body).as<collections_manifest>();
|
63
|
+
break;
|
64
|
+
default:
|
65
|
+
response.ec = std::make_error_code(error::common_errc::internal_server_failure);
|
66
|
+
break;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
return response;
|
70
|
+
}
|
71
|
+
|
72
|
+
} // namespace couchbase::operations
|
@@ -28,11 +28,18 @@ enum class client_opcode : uint8_t {
|
|
28
28
|
insert = 0x02,
|
29
29
|
replace = 0x03,
|
30
30
|
remove = 0x04,
|
31
|
+
increment = 0x05,
|
32
|
+
decrement = 0x06,
|
33
|
+
touch = 0x1c,
|
34
|
+
get_and_touch = 0x1d,
|
31
35
|
hello = 0x1f,
|
32
36
|
sasl_list_mechs = 0x20,
|
33
37
|
sasl_auth = 0x21,
|
34
38
|
sasl_step = 0x22,
|
35
39
|
select_bucket = 0x89,
|
40
|
+
observe = 0x92,
|
41
|
+
get_and_lock = 0x94,
|
42
|
+
unlock = 0x95,
|
36
43
|
get_collections_manifest = 0xba,
|
37
44
|
subdoc_multi_lookup = 0xd0,
|
38
45
|
subdoc_multi_mutation = 0xd1,
|
@@ -79,6 +86,13 @@ is_valid_client_opcode(uint8_t code)
|
|
79
86
|
case client_opcode::get_error_map:
|
80
87
|
case client_opcode::invalid:
|
81
88
|
case client_opcode::get_collections_manifest:
|
89
|
+
case client_opcode::touch:
|
90
|
+
case client_opcode::observe:
|
91
|
+
case client_opcode::get_and_lock:
|
92
|
+
case client_opcode::unlock:
|
93
|
+
case client_opcode::get_and_touch:
|
94
|
+
case client_opcode::increment:
|
95
|
+
case client_opcode::decrement:
|
82
96
|
return true;
|
83
97
|
}
|
84
98
|
return false;
|
@@ -161,6 +175,27 @@ struct fmt::formatter |
|
161
175
|
case couchbase::protocol::client_opcode::get_collections_manifest:
|
162
176
|
name = "get_collections_manifest";
|
163
177
|
break;
|
178
|
+
case couchbase::protocol::client_opcode::touch:
|
179
|
+
name = "touch";
|
180
|
+
break;
|
181
|
+
case couchbase::protocol::client_opcode::observe:
|
182
|
+
name = "observe";
|
183
|
+
break;
|
184
|
+
case couchbase::protocol::client_opcode::get_and_lock:
|
185
|
+
name = "get_and_lock";
|
186
|
+
break;
|
187
|
+
case couchbase::protocol::client_opcode::unlock:
|
188
|
+
name = "unlock";
|
189
|
+
break;
|
190
|
+
case couchbase::protocol::client_opcode::get_and_touch:
|
191
|
+
name = "get_and_touch";
|
192
|
+
break;
|
193
|
+
case couchbase::protocol::client_opcode::increment:
|
194
|
+
name = "increment";
|
195
|
+
break;
|
196
|
+
case couchbase::protocol::client_opcode::decrement:
|
197
|
+
name = "decrement";
|
198
|
+
break;
|
164
199
|
}
|
165
200
|
return formatter<string_view>::format(name, ctx);
|
166
201
|
}
|
@@ -21,6 +21,8 @@
|
|
21
21
|
#include <arpa/inet.h>
|
22
22
|
#endif
|
23
23
|
|
24
|
+
#include <snappy.h>
|
25
|
+
|
24
26
|
#include <gsl/gsl_util>
|
25
27
|
#include <protocol/client_opcode.hxx>
|
26
28
|
#include <protocol/magic.hxx>
|
@@ -37,12 +39,12 @@ class client_request
|
|
37
39
|
using response_type = client_response<response_body_type>;
|
38
40
|
|
39
41
|
private:
|
40
|
-
|
41
|
-
static const magic magic_ = magic::client_request;
|
42
|
+
magic magic_{ magic::client_request };
|
42
43
|
|
43
44
|
client_opcode opcode_{ Body::opcode };
|
44
45
|
std::uint16_t partition_{ 0 };
|
45
46
|
std::uint32_t opaque_{ 0 };
|
47
|
+
std::uint64_t cas_{ 0 };
|
46
48
|
Body body_;
|
47
49
|
std::vector<std::uint8_t> payload_;
|
48
50
|
|
@@ -57,6 +59,11 @@ class client_request
|
|
57
59
|
opaque_ = val;
|
58
60
|
}
|
59
61
|
|
62
|
+
void cas(std::uint64_t val)
|
63
|
+
{
|
64
|
+
cas_ = val;
|
65
|
+
}
|
66
|
+
|
60
67
|
std::uint32_t opaque()
|
61
68
|
{
|
62
69
|
return opaque_;
|
@@ -77,23 +84,42 @@ class client_request
|
|
77
84
|
return body_;
|
78
85
|
}
|
79
86
|
|
80
|
-
std::vector<std::uint8_t>& data()
|
87
|
+
std::vector<std::uint8_t>& data(bool try_to_compress = false)
|
81
88
|
{
|
82
|
-
|
89
|
+
switch (opcode_) {
|
90
|
+
case protocol::client_opcode::insert:
|
91
|
+
case protocol::client_opcode::upsert:
|
92
|
+
case protocol::client_opcode::replace:
|
93
|
+
write_payload(try_to_compress);
|
94
|
+
break;
|
95
|
+
default:
|
96
|
+
write_payload(false);
|
97
|
+
break;
|
98
|
+
}
|
83
99
|
return payload_;
|
84
100
|
}
|
85
101
|
|
86
102
|
private:
|
87
|
-
void write_payload()
|
103
|
+
void write_payload(bool try_to_compress)
|
88
104
|
{
|
89
105
|
payload_.resize(header_size + body_.size(), 0);
|
90
106
|
payload_[0] = static_cast<uint8_t>(magic_);
|
91
107
|
payload_[1] = static_cast<uint8_t>(opcode_);
|
92
108
|
|
93
|
-
|
94
|
-
|
109
|
+
auto framing_extras = body_.framing_extras();
|
110
|
+
|
111
|
+
uint16_t key_size = gsl::narrow_cast<uint16_t>(body_.key().size());
|
112
|
+
if (framing_extras.size() == 0) {
|
113
|
+
key_size = htons(key_size);
|
114
|
+
memcpy(payload_.data() + 2, &key_size, sizeof(key_size));
|
115
|
+
} else {
|
116
|
+
magic_ = protocol::magic::alt_client_request;
|
117
|
+
payload_[0] = static_cast<uint8_t>(magic_);
|
118
|
+
payload_[2] = gsl::narrow_cast<std::uint8_t>(framing_extras.size());
|
119
|
+
payload_[3] = gsl::narrow_cast<std::uint8_t>(key_size);
|
120
|
+
}
|
95
121
|
|
96
|
-
uint8_t ext_size = gsl::narrow_cast<uint8_t>(body_.
|
122
|
+
uint8_t ext_size = gsl::narrow_cast<uint8_t>(body_.extras().size());
|
97
123
|
memcpy(payload_.data() + 4, &ext_size, sizeof(ext_size));
|
98
124
|
|
99
125
|
uint16_t vbucket = ntohs(gsl::narrow_cast<uint16_t>(partition_));
|
@@ -103,10 +129,31 @@ class client_request
|
|
103
129
|
memcpy(payload_.data() + 8, &body_size, sizeof(body_size));
|
104
130
|
|
105
131
|
memcpy(payload_.data() + 12, &opaque_, sizeof(opaque_));
|
132
|
+
memcpy(payload_.data() + 16, &cas_, sizeof(cas_));
|
106
133
|
|
107
134
|
auto body_itr = payload_.begin() + header_size;
|
108
|
-
|
135
|
+
if (framing_extras.size() > 0) {
|
136
|
+
body_itr = std::copy(framing_extras.begin(), framing_extras.end(), body_itr);
|
137
|
+
}
|
138
|
+
body_itr = std::copy(body_.extras().begin(), body_.extras().end(), body_itr);
|
109
139
|
body_itr = std::copy(body_.key().begin(), body_.key().end(), body_itr);
|
140
|
+
|
141
|
+
static const std::size_t min_size_to_compress = 32;
|
142
|
+
static const double min_ratio = 0.83;
|
143
|
+
if (try_to_compress && body_.value().size() > min_size_to_compress) {
|
144
|
+
std::string compressed;
|
145
|
+
std::size_t compressed_size =
|
146
|
+
snappy::Compress(reinterpret_cast<const char*>(body_.value().data()), body_.value().size(), &compressed);
|
147
|
+
if (gsl::narrow_cast<double>(compressed_size) / gsl::narrow_cast<double>(body().value().size()) < min_ratio) {
|
148
|
+
std::copy(compressed.begin(), compressed.end(), body_itr);
|
149
|
+
payload_[5] |= static_cast<uint8_t>(protocol::datatype::snappy);
|
150
|
+
size_t new_body_size = body_.size() - (body_.value().size() - compressed_size);
|
151
|
+
body_size = htonl(gsl::narrow_cast<uint32_t>(new_body_size));
|
152
|
+
memcpy(payload_.data() + 8, &body_size, sizeof(body_size));
|
153
|
+
payload_.resize(header_size + new_body_size);
|
154
|
+
return;
|
155
|
+
}
|
156
|
+
}
|
110
157
|
std::copy(body_.value().begin(), body_.value().end(), body_itr);
|
111
158
|
}
|
112
159
|
};
|
@@ -26,6 +26,7 @@
|
|
26
26
|
#include <protocol/status.hxx>
|
27
27
|
#include <protocol/datatype.hxx>
|
28
28
|
#include <protocol/cmd_info.hxx>
|
29
|
+
#include <protocol/frame_info_id.hxx>
|
29
30
|
|
30
31
|
namespace couchbase::protocol
|
31
32
|
{
|
@@ -39,27 +40,29 @@ template
|
|
39
40
|
class client_response
|
40
41
|
{
|
41
42
|
private:
|
42
|
-
static const inline magic magic_ = magic::client_response;
|
43
|
-
|
44
43
|
Body body_;
|
44
|
+
magic magic_{ magic::client_response };
|
45
45
|
client_opcode opcode_{ client_opcode::invalid };
|
46
|
-
header_buffer header_;
|
47
|
-
uint8_t data_type_;
|
48
|
-
std::vector<std::uint8_t> data_;
|
49
|
-
std::
|
50
|
-
|
46
|
+
header_buffer header_{};
|
47
|
+
uint8_t data_type_{ 0 };
|
48
|
+
std::vector<std::uint8_t> data_{};
|
49
|
+
std::uint16_t key_size_{ 0 };
|
50
|
+
std::uint8_t framing_extras_size_{ 0 };
|
51
|
+
std::uint8_t extras_size_{ 0 };
|
52
|
+
std::size_t body_size_{ 0 };
|
53
|
+
protocol::status status_{};
|
51
54
|
std::optional<enhanced_error> error_;
|
52
|
-
std::uint32_t opaque_;
|
53
|
-
std::uint64_t cas_;
|
54
|
-
cmd_info info_;
|
55
|
+
std::uint32_t opaque_{};
|
56
|
+
std::uint64_t cas_{};
|
57
|
+
cmd_info info_{};
|
55
58
|
|
56
59
|
public:
|
57
60
|
client_response() = default;
|
58
|
-
explicit client_response(io::
|
61
|
+
explicit client_response(io::mcbp_message& msg)
|
59
62
|
{
|
60
63
|
std::memcpy(header_.data(), &msg.header, sizeof(msg.header));
|
61
|
-
verify_header();
|
62
64
|
data_ = std::move(msg.body);
|
65
|
+
verify_header();
|
63
66
|
parse_body();
|
64
67
|
}
|
65
68
|
|
@@ -105,8 +108,10 @@ class client_response
|
|
105
108
|
|
106
109
|
void verify_header()
|
107
110
|
{
|
108
|
-
Expects(header_[0] == static_cast<std::uint8_t>(
|
111
|
+
Expects(header_[0] == static_cast<std::uint8_t>(magic::alt_client_response) ||
|
112
|
+
header_[0] == static_cast<std::uint8_t>(magic::client_response));
|
109
113
|
Expects(header_[1] == static_cast<std::uint8_t>(Body::opcode));
|
114
|
+
magic_ = static_cast<magic>(header_[0]);
|
110
115
|
opcode_ = static_cast<client_opcode>(header_[1]);
|
111
116
|
data_type_ = header_[5];
|
112
117
|
|
@@ -116,6 +121,15 @@ class client_response
|
|
116
121
|
Expects(protocol::is_valid_status(status));
|
117
122
|
status_ = static_cast<protocol::status>(status);
|
118
123
|
|
124
|
+
extras_size_ = header_[4];
|
125
|
+
if (magic_ == magic::alt_client_response) {
|
126
|
+
framing_extras_size_ = header_[2];
|
127
|
+
key_size_ = header_[3];
|
128
|
+
} else {
|
129
|
+
memcpy(&key_size_, header_.data() + 2, sizeof(key_size_));
|
130
|
+
key_size_ = ntohs(key_size_);
|
131
|
+
}
|
132
|
+
|
119
133
|
uint32_t field = 0;
|
120
134
|
memcpy(&field, header_.data() + 8, sizeof(field));
|
121
135
|
body_size_ = ntohl(field);
|
@@ -136,9 +150,10 @@ class client_response
|
|
136
150
|
|
137
151
|
void parse_body()
|
138
152
|
{
|
139
|
-
|
153
|
+
parse_framing_extras();
|
154
|
+
bool parsed = body_.parse(status_, header_, framing_extras_size_, key_size_, extras_size_, data_, info_);
|
140
155
|
if (status_ != protocol::status::success && !parsed && has_json_datatype(data_type_)) {
|
141
|
-
auto error = tao::json::from_string(std::string(data_.begin(), data_.end()));
|
156
|
+
auto error = tao::json::from_string(std::string(data_.begin() + framing_extras_size_ + extras_size_ + key_size_, data_.end()));
|
142
157
|
if (error.is_object()) {
|
143
158
|
auto& err_obj = error["error"];
|
144
159
|
if (err_obj.is_object()) {
|
@@ -157,6 +172,28 @@ class client_response
|
|
157
172
|
}
|
158
173
|
}
|
159
174
|
|
175
|
+
void parse_framing_extras()
|
176
|
+
{
|
177
|
+
if (framing_extras_size_ == 0) {
|
178
|
+
return;
|
179
|
+
}
|
180
|
+
size_t offset = 0;
|
181
|
+
while (offset < framing_extras_size_) {
|
182
|
+
std::uint8_t frame_size = data_[offset] & 0xfU;
|
183
|
+
std::uint8_t frame_id = (static_cast<std::uint32_t>(data_[offset]) >> 4U) & 0xfU;
|
184
|
+
offset++;
|
185
|
+
if (frame_id == static_cast<std::uint8_t>(response_frame_info_id::server_duration)) {
|
186
|
+
if (frame_size == 2 && framing_extras_size_ - offset >= frame_size) {
|
187
|
+
std::uint16_t encoded_duration{};
|
188
|
+
std::memcpy(&encoded_duration, data_.data() + offset, sizeof(encoded_duration));
|
189
|
+
encoded_duration = ntohs(encoded_duration);
|
190
|
+
info_.server_duration_us = std::pow(encoded_duration, 1.74) / 2;
|
191
|
+
}
|
192
|
+
}
|
193
|
+
offset += frame_size;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
160
197
|
[[nodiscard]] std::vector<std::uint8_t>& data()
|
161
198
|
{
|
162
199
|
return data_;
|