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.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests-6.0.3.yml +49 -0
  3. data/.github/workflows/tests.yml +47 -0
  4. data/.gitmodules +3 -0
  5. data/.idea/dictionaries/gem_terms.xml +5 -0
  6. data/.idea/inspectionProfiles/Project_Default.xml +1 -0
  7. data/.idea/vcs.xml +1 -0
  8. data/Gemfile +1 -0
  9. data/README.md +55 -2
  10. data/Rakefile +18 -0
  11. data/bin/init-cluster +62 -0
  12. data/bin/setup +1 -0
  13. data/couchbase.gemspec +3 -2
  14. data/examples/crud.rb +1 -2
  15. data/examples/managing_buckets.rb +47 -0
  16. data/examples/managing_collections.rb +58 -0
  17. data/examples/managing_query_indexes.rb +63 -0
  18. data/examples/query.rb +3 -2
  19. data/examples/query_with_consistency.rb +76 -0
  20. data/examples/subdocument.rb +23 -1
  21. data/ext/.clang-format +1 -1
  22. data/ext/.idea/dictionaries/couchbase_terms.xml +2 -0
  23. data/ext/.idea/vcs.xml +1 -0
  24. data/ext/CMakeLists.txt +30 -12
  25. data/ext/build_version.hxx.in +26 -0
  26. data/ext/couchbase/bucket.hxx +69 -8
  27. data/ext/couchbase/cluster.hxx +70 -54
  28. data/ext/couchbase/collections_manifest.hxx +3 -3
  29. data/ext/couchbase/configuration.hxx +14 -0
  30. data/ext/couchbase/couchbase.cxx +2044 -383
  31. data/ext/couchbase/{operations/document_id.hxx → document_id.hxx} +5 -4
  32. data/ext/couchbase/io/http_message.hxx +5 -1
  33. data/ext/couchbase/io/http_parser.hxx +2 -1
  34. data/ext/couchbase/io/http_session.hxx +6 -3
  35. data/ext/couchbase/io/{binary_message.hxx → mcbp_message.hxx} +15 -12
  36. data/ext/couchbase/io/mcbp_parser.hxx +99 -0
  37. data/ext/couchbase/io/{key_value_session.hxx → mcbp_session.hxx} +200 -95
  38. data/ext/couchbase/io/session_manager.hxx +37 -22
  39. data/ext/couchbase/mutation_token.hxx +2 -1
  40. data/ext/couchbase/operations.hxx +38 -8
  41. data/ext/couchbase/operations/bucket_create.hxx +138 -0
  42. data/ext/couchbase/operations/bucket_drop.hxx +65 -0
  43. data/ext/couchbase/operations/bucket_flush.hxx +65 -0
  44. data/ext/couchbase/operations/bucket_get.hxx +69 -0
  45. data/ext/couchbase/operations/bucket_get_all.hxx +62 -0
  46. data/ext/couchbase/operations/bucket_settings.hxx +111 -0
  47. data/ext/couchbase/operations/bucket_update.hxx +115 -0
  48. data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +60 -0
  49. data/ext/couchbase/operations/collection_create.hxx +86 -0
  50. data/ext/couchbase/operations/collection_drop.hxx +82 -0
  51. data/ext/couchbase/operations/command.hxx +10 -10
  52. data/ext/couchbase/operations/document_decrement.hxx +80 -0
  53. data/ext/couchbase/operations/document_exists.hxx +80 -0
  54. data/ext/couchbase/operations/{get.hxx → document_get.hxx} +4 -2
  55. data/ext/couchbase/operations/document_get_and_lock.hxx +64 -0
  56. data/ext/couchbase/operations/document_get_and_touch.hxx +64 -0
  57. data/ext/couchbase/operations/document_increment.hxx +80 -0
  58. data/ext/couchbase/operations/document_insert.hxx +74 -0
  59. data/ext/couchbase/operations/{lookup_in.hxx → document_lookup_in.hxx} +2 -2
  60. data/ext/couchbase/operations/{mutate_in.hxx → document_mutate_in.hxx} +11 -2
  61. data/ext/couchbase/operations/{query.hxx → document_query.hxx} +101 -6
  62. data/ext/couchbase/operations/document_remove.hxx +67 -0
  63. data/ext/couchbase/operations/document_replace.hxx +76 -0
  64. data/ext/couchbase/operations/{upsert.hxx → document_touch.hxx} +14 -14
  65. data/ext/couchbase/operations/{remove.hxx → document_unlock.hxx} +12 -10
  66. data/ext/couchbase/operations/document_upsert.hxx +74 -0
  67. data/ext/couchbase/operations/query_index_build_deferred.hxx +85 -0
  68. data/ext/couchbase/operations/query_index_create.hxx +134 -0
  69. data/ext/couchbase/operations/query_index_drop.hxx +108 -0
  70. data/ext/couchbase/operations/query_index_get_all.hxx +106 -0
  71. data/ext/couchbase/operations/scope_create.hxx +81 -0
  72. data/ext/couchbase/operations/scope_drop.hxx +79 -0
  73. data/ext/couchbase/operations/scope_get_all.hxx +72 -0
  74. data/ext/couchbase/protocol/client_opcode.hxx +35 -0
  75. data/ext/couchbase/protocol/client_request.hxx +56 -9
  76. data/ext/couchbase/protocol/client_response.hxx +52 -15
  77. data/ext/couchbase/protocol/cmd_cluster_map_change_notification.hxx +81 -0
  78. data/ext/couchbase/protocol/cmd_decrement.hxx +187 -0
  79. data/ext/couchbase/protocol/cmd_exists.hxx +171 -0
  80. data/ext/couchbase/protocol/cmd_get.hxx +31 -8
  81. data/ext/couchbase/protocol/cmd_get_and_lock.hxx +142 -0
  82. data/ext/couchbase/protocol/cmd_get_and_touch.hxx +142 -0
  83. data/ext/couchbase/protocol/cmd_get_cluster_config.hxx +16 -3
  84. data/ext/couchbase/protocol/cmd_get_collections_manifest.hxx +16 -3
  85. data/ext/couchbase/protocol/cmd_get_error_map.hxx +16 -3
  86. data/ext/couchbase/protocol/cmd_hello.hxx +24 -8
  87. data/ext/couchbase/protocol/cmd_increment.hxx +187 -0
  88. data/ext/couchbase/protocol/cmd_info.hxx +1 -0
  89. data/ext/couchbase/protocol/cmd_insert.hxx +172 -0
  90. data/ext/couchbase/protocol/cmd_lookup_in.hxx +28 -13
  91. data/ext/couchbase/protocol/cmd_mutate_in.hxx +65 -13
  92. data/ext/couchbase/protocol/cmd_remove.hxx +59 -4
  93. data/ext/couchbase/protocol/cmd_replace.hxx +172 -0
  94. data/ext/couchbase/protocol/cmd_sasl_auth.hxx +15 -3
  95. data/ext/couchbase/protocol/cmd_sasl_list_mechs.hxx +15 -3
  96. data/ext/couchbase/protocol/cmd_sasl_step.hxx +15 -3
  97. data/ext/couchbase/protocol/cmd_select_bucket.hxx +14 -2
  98. data/ext/couchbase/protocol/cmd_touch.hxx +102 -0
  99. data/ext/couchbase/protocol/cmd_unlock.hxx +95 -0
  100. data/ext/couchbase/protocol/cmd_upsert.hxx +50 -14
  101. data/ext/couchbase/protocol/durability_level.hxx +67 -0
  102. data/ext/couchbase/protocol/frame_info_id.hxx +187 -0
  103. data/ext/couchbase/protocol/hello_feature.hxx +137 -0
  104. data/ext/couchbase/protocol/server_opcode.hxx +57 -0
  105. data/ext/couchbase/protocol/server_request.hxx +122 -0
  106. data/ext/couchbase/protocol/unsigned_leb128.h +15 -15
  107. data/ext/couchbase/utils/byteswap.hxx +1 -2
  108. data/ext/couchbase/utils/url_codec.hxx +225 -0
  109. data/ext/couchbase/version.hxx +3 -1
  110. data/ext/extconf.rb +4 -1
  111. data/ext/test/main.cxx +37 -113
  112. data/ext/third_party/snappy/.appveyor.yml +36 -0
  113. data/ext/third_party/snappy/.gitignore +8 -0
  114. data/ext/third_party/snappy/.travis.yml +98 -0
  115. data/ext/third_party/snappy/AUTHORS +1 -0
  116. data/ext/third_party/snappy/CMakeLists.txt +345 -0
  117. data/ext/third_party/snappy/CONTRIBUTING.md +26 -0
  118. data/ext/third_party/snappy/COPYING +54 -0
  119. data/ext/third_party/snappy/NEWS +188 -0
  120. data/ext/third_party/snappy/README.md +148 -0
  121. data/ext/third_party/snappy/cmake/SnappyConfig.cmake.in +33 -0
  122. data/ext/third_party/snappy/cmake/config.h.in +59 -0
  123. data/ext/third_party/snappy/docs/README.md +72 -0
  124. data/ext/third_party/snappy/format_description.txt +110 -0
  125. data/ext/third_party/snappy/framing_format.txt +135 -0
  126. data/ext/third_party/snappy/snappy-c.cc +90 -0
  127. data/ext/third_party/snappy/snappy-c.h +138 -0
  128. data/ext/third_party/snappy/snappy-internal.h +315 -0
  129. data/ext/third_party/snappy/snappy-sinksource.cc +121 -0
  130. data/ext/third_party/snappy/snappy-sinksource.h +182 -0
  131. data/ext/third_party/snappy/snappy-stubs-internal.cc +42 -0
  132. data/ext/third_party/snappy/snappy-stubs-internal.h +493 -0
  133. data/ext/third_party/snappy/snappy-stubs-public.h.in +63 -0
  134. data/ext/third_party/snappy/snappy-test.cc +613 -0
  135. data/ext/third_party/snappy/snappy-test.h +526 -0
  136. data/ext/third_party/snappy/snappy.cc +1770 -0
  137. data/ext/third_party/snappy/snappy.h +209 -0
  138. data/ext/third_party/snappy/snappy_compress_fuzzer.cc +60 -0
  139. data/ext/third_party/snappy/snappy_uncompress_fuzzer.cc +58 -0
  140. data/ext/third_party/snappy/snappy_unittest.cc +1512 -0
  141. data/ext/third_party/snappy/testdata/alice29.txt +3609 -0
  142. data/ext/third_party/snappy/testdata/asyoulik.txt +4122 -0
  143. data/ext/third_party/snappy/testdata/baddata1.snappy +0 -0
  144. data/ext/third_party/snappy/testdata/baddata2.snappy +0 -0
  145. data/ext/third_party/snappy/testdata/baddata3.snappy +0 -0
  146. data/ext/third_party/snappy/testdata/fireworks.jpeg +0 -0
  147. data/ext/third_party/snappy/testdata/geo.protodata +0 -0
  148. data/ext/third_party/snappy/testdata/html +1 -0
  149. data/ext/third_party/snappy/testdata/html_x_4 +1 -0
  150. data/ext/third_party/snappy/testdata/kppkn.gtb +0 -0
  151. data/ext/third_party/snappy/testdata/lcet10.txt +7519 -0
  152. data/ext/third_party/snappy/testdata/paper-100k.pdf +600 -2
  153. data/ext/third_party/snappy/testdata/plrabn12.txt +10699 -0
  154. data/ext/third_party/snappy/testdata/urls.10K +10000 -0
  155. data/lib/couchbase/binary_collection.rb +33 -76
  156. data/lib/couchbase/binary_collection_options.rb +94 -0
  157. data/lib/couchbase/bucket.rb +9 -3
  158. data/lib/couchbase/cluster.rb +161 -23
  159. data/lib/couchbase/collection.rb +108 -191
  160. data/lib/couchbase/collection_options.rb +430 -0
  161. data/lib/couchbase/errors.rb +136 -134
  162. data/lib/couchbase/json_transcoder.rb +32 -0
  163. data/lib/couchbase/management/analytics_index_manager.rb +185 -9
  164. data/lib/couchbase/management/bucket_manager.rb +84 -33
  165. data/lib/couchbase/management/collection_manager.rb +166 -1
  166. data/lib/couchbase/management/query_index_manager.rb +261 -0
  167. data/lib/couchbase/management/search_index_manager.rb +291 -0
  168. data/lib/couchbase/management/user_manager.rb +12 -10
  169. data/lib/couchbase/management/view_index_manager.rb +151 -1
  170. data/lib/couchbase/mutation_state.rb +11 -1
  171. data/lib/couchbase/scope.rb +4 -4
  172. data/lib/couchbase/version.rb +1 -1
  173. metadata +113 -18
  174. data/.travis.yml +0 -7
  175. data/ext/couchbase/io/binary_parser.hxx +0 -64
  176. 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 : 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
- static const size_t header_size = 24;
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
- write_payload();
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
- uint16_t key_size = htons(gsl::narrow_cast<uint16_t>(body_.key().size()));
94
- memcpy(payload_.data() + 2, &key_size, sizeof(key_size));
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_.extension().size());
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
- body_itr = std::copy(body_.extension().begin(), body_.extension().end(), body_itr);
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::size_t body_size_;
50
- protocol::status status_;
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::binary_message& msg)
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>(magic_));
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
- bool parsed = body_.parse(status_, header_, data_, info_);
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_;